ifconfig调用过程

    xiaoxiao2021-04-12  42

    ifconfig命令是可以查看当前网络设备信息,在openwrt环境中,ifconfig源码位于busybox文件夹下

    找到入口函数ifconfig_main,位于ifconfig.c文件中

    int ifconfig_main(int argc UNUSED_PARAM, char **argv) { struct ifreq ifr; struct sockaddr_in sai; #if ENABLE_FEATURE_IFCONFIG_HW struct sockaddr sa; #endif const struct arg1opt *a1op; const struct options *op; int sockfd; /* socket fd we use to manipulate stuff with */ int selector; #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS unsigned int mask; unsigned int did_flags; unsigned int sai_hostname, sai_netmask; #else unsigned char mask; unsigned char did_flags; #endif char *p; /*char host[128];*/ const char *host = NULL; /* make gcc happy */ did_flags = 0; #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS sai_hostname = 0; sai_netmask = 0; #endif /* skip argv[0] */ ++argv; #if ENABLE_FEATURE_IFCONFIG_STATUS if (argv[0] && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { interface_opt_a = 1; ++argv; } #endif if (!argv[0] || !argv[1]) { /* one or no args */ #if ENABLE_FEATURE_IFCONFIG_STATUS return display_interfaces(argv[0] /* can be NULL */); #else bb_error_msg_and_die("no support for status display"); #endif } 若未配置任何信息则进入下面函数

    int FAST_FUNC display_interfaces(char *ifname) { int status; status = if_print(ifname); return (status < 0); /* status < 0 == 1 -- error */ } 若提供端口名字则查看对应名字的设备端口信息 static int if_print(char *ifname) { struct interface *ife; int res; if (!ifname) { /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/ if (!int_list && (if_readlist() < 0)) return -1; for (ife = int_list; ife; ife = ife->next) { int err = do_if_print(ife); /*, &interface_opt_a);*/ if (err) return err; } return 0; } ife = lookup_interface(ifname); res = do_if_fetch(ife); if (res >= 0) ife_print(ife); return res; }

    读取设备名称信息,首先从proc文件系统读取,若失败,则通过ioctl读取内核内的设备信息 static int if_readlist(void) { int err = if_readlist_proc(NULL); /* Needed in order to get ethN:M aliases */ if (!err) err = if_readconf(); return err; } 之后更新这些设备名称从通过ioctl从内核中读取详细信息

    static int if_fetch(struct interface *ife) { struct ifreq ifr; char *ifname = ife->name; int skfd; skfd = xsocket(AF_INET, SOCK_DGRAM, 0); strncpy_IFNAMSIZ(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { close(skfd); return -1; } ife->flags = ifr.ifr_flags; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(ife->hwaddr, 0, 32); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); ife->type = ifr.ifr_hwaddr.sa_family; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->metric = 0; if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) ife->metric = ifr.ifr_metric; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->mtu = 0; if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) ife->mtu = ifr.ifr_mtu; memset(&ife->map, 0, sizeof(struct ifmap)); #ifdef SIOCGIFMAP strncpy_IFNAMSIZ(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) ife->map = ifr.ifr_map; #endif #ifdef HAVE_TXQUEUELEN strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ife->tx_queue_len = -1; /* unknown value */ if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) ife->tx_queue_len = ifr.ifr_qlen; #else ife->tx_queue_len = -1; /* unknown value */ #endif strncpy_IFNAMSIZ(ifr.ifr_name, ifname); ifr.ifr_addr.sa_family = AF_INET; memset(&ife->addr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { ife->has_ip = 1; ife->addr = ifr.ifr_addr; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) ife->dstaddr = ifr.ifr_dstaddr; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) ife->broadaddr = ifr.ifr_broadaddr; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); memset(&ife->netmask, 0, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) ife->netmask = ifr.ifr_netmask; } close(skfd); return 0; }用的是ioctl方法。

    下面是内核部分解析,解析SIOCGIFFLAGS的的调用过程

    ioctl(skfd, SIOCGIFFLAGS, &ifr)

    内核部分进入的函数是sock_ioctl,位于socket。

    static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { struct socket *sock; struct sock *sk; void __user *argp = (void __user *)arg; int pid, err; struct net *net; sock = file->private_data; sk = sock->sk; net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { err = dev_ioctl(net, cmd, argp); } else #ifdef CONFIG_WEXT_CORE if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { err = dev_ioctl(net, cmd, argp); } else #endif

    进入dev_ioctl函数

    int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct ifreq ifr; int ret; char *colon; /* One special case: SIOCGIFCONF takes ifconf argument and requires shared lock, because it sleeps writing to user space. */ if (cmd == SIOCGIFCONF) {//ifconfig rtnl_lock(); ret = dev_ifconf(net, (char __user *) arg); rtnl_unlock(); return ret; } static int dev_ifconf(struct net *net, char __user *arg) { struct ifconf ifc; struct net_device *dev; char __user *pos; int len; int total; int i; /* * Fetch the caller's info block. */ if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; pos = ifc.ifc_buf; len = ifc.ifc_len; /* * Loop over the interfaces, and write an info block for each. */ total = 0; for_each_netdev(net, dev) { for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) {//inet_gifconf int done; if (!pos) done = gifconf_list[i](dev, NULL, 0); else done = gifconf_list[i](dev, pos + total, len - total); if (done < 0) return -EFAULT; total += done; } } } 遍历&(net)->dev_base_head链表上的net_device

    转载请注明原文地址: https://ju.6miu.com/read-667488.html

    最新回复(0)