ifconfig调用过程

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


### 如何在 Ubuntu 中使用 `ifconfig` 命令 #### 安装必要的软件包 如果遇到 `-bash: ifconfig: command not found` 的错误提示,这表明当前环境中缺少 `net-tools` 软件包。为了能够正常使用 `ifconfig` 命令,需先通过以下指令来安装此工具集: ```shell sudo apt update && sudo apt install net-tools -y ``` 完成上述操作之后便可以顺利调用 `ifconfig` 来查看或调整网络接口的状态了[^1]。 #### 查看所有网络接口状态 要列出所有的活动以及非活动的网络设备及其参数,只需输入简单的命令而无需附加任何额外选项: ```shell ifconfig ``` 这条语句会返回一系列有关各个网卡的数据,包括但不限于 IP 地址、子网掩码、广播地址等重要详情[^2]。 #### 获取特定网络接口的信息 当只需要关注某个具体的网络端口时,则可以在后面跟上相应的名称作为参数传递给 `ifconfig` 函数。比如想要了解名为 eth0 接口的具体情况就可以这样写: ```shell ifconfig eth0 ``` 如此一来就能集中精力分析单一指定连接通道的相关特性而不必面对过多无关紧要的内容干扰视线[^3]。 #### 启动/关闭选定的网络接口 对于某些维护工作而言可能需要用到即时启用或者禁用某张网卡的功能,在这种情况下可借助 up 和 down 参数实现快速切换目的: 启动: ```shell sudo ifconfig wlan0 up ``` 停止: ```shell sudo ifconfig wlan0 down ``` 这里以无线局域网适配器为例进行了说明,实际应用过程中应当依据实际情况替换为对应的物理硬件标识符[^4]。 #### 设置静态IP地址 除了基本查询之外,`ifconfig` 还允许临时更改主机所持有的公网或私有IPv4数值。例如赋予eth0一个新的固定IP地址192.168.1.100,并指明其所属范围内的默认网关位置: ```shell sudo ifconfig eth0 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255 ``` 值得注意的是这类变动仅限于本次会话有效,重启计算机后将会恢复初始设定除非采取进一步措施将其保存下来成为永久性的改变[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值