我是靠谱客的博主 乐观大叔,最近开发中收集的这篇文章主要介绍多次 ifconfig down 无效的问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

多次 ifconfig down 无效的问题

ifconfig up、down 是怎样工作的

ifconfig 通过 ioctl 来完成工作。ifconfig 程序中与接口的 up、down 有关的代码如下:

	if (!strcmp(*spp, "up")) {
	    goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
	    spp++;
	    continue;
	}
	if (!strcmp(*spp, "down")) {
	    goterr |= clr_flag(ifr.ifr_name, IFF_UP);
	    spp++;
	    continue;

上述代码中 spp表示的是命令行参数,这里匹配的 up、down 字符串就是我们在命令行中指定的 up、down。

从上面的代码里面可以看出,设定接口为 up 时,IFF_UP 与 IFF_RUNNING 标志位将会被置位;设定接口为 down 时,IFF_UP 标志位将会被清 0。

set_flag 与 clr_flag 函数

set_flag 函数的源码如下:

/* Set a certain interface flag. */
static int set_flag(char *ifname, short flag)
{
    struct ifreq ifr;

    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
		fprintf(stderr, _("%s: ERROR while getting interface flags: %sn"),
				ifname,	strerror(errno));
		return (-1);
    }
    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_flags |= flag;
    if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
		perror("SIOCSIFFLAGS");
		return -1;
    }
    return (0);
}

这里执行了两次 ioctl 函数,第一次指定给 ioctl 函数的命令为 SIOCGIFFLAGS。此命令获取指定网卡的当前状态,ifr.ifr_flags中存储获取到的网卡相关标志信息。set_flags通过 | (或) 操作来使能新的标志位,这之后执行 SIOCSIFFLAGS命令并将 ifr 传递给 ioctl 来修改网卡的标志。

clr_flag函数与 set_flag函数的逻辑大致相同,不过 clr_flag函数会将设定的标志位清零,这通过执行 ifr.ifr_flags &= ~flag;来实现。

ioctl 的内核流程

这之后,ioctl 在内核中进行多次分发,最终分发到 __dev_change_flags函数中,并在此函数中调用底层 netdev_ops 中注册的虚函数。

主要流程如下:

compat_ifreq_ioctl -> sock_do_ioctl -> dev_ifconf -> dev_ioctl -> dev_ifsioc -> dev_change_flags -> __dev_change_flags -> dev->netdev_ops

__dev_change_flags 函数

在内核中,ifconfig up、down 最终调用的关键函数为 __dev_change_flags,与 up、down 相关的主要代码如下:

   if ((old_flags ^ flags) & IFF_UP) {
		if (old_flags & IFF_UP)
			__dev_close(dev);
		else
			ret = __dev_open(dev);
	}

old_flags 是旧的 flags 状态。old_flags ^ flags 判断的是新设定的标志与旧标志是否相同,相同则值为 0,不同则值为 1。

IFF_UP 是 flags 中的一位。用 old_flags ^ flags 的结果与 IFF_UP 按位取 &,当得到一个非零值时 old_flags 与 flags 中 IFF_UP 位的取值有如下两种可能。

  1. old_flags IFF_UP is 0、flags IFF_UP is 1
  2. old_flags IFF_UP is 1、flags IFF_UP is 0

对上面的两种可能进行判断处理,在 old_flags 与 flags 中的 IFF_UP 不同时,根据 old_flags 中的取值就能够分发到不同的逻辑上。

当 old_flags 中 IFF_UP 位为 1 时,flags 中的 IFF_UP 位为 0,此时调用 __dev_close(dev) down 掉网卡;当 old_flags 中 IFF_UP 位为 0 时,flags 中的 IFF_UP 位为 1,此时调用 __dev_open(dev) up 网卡。

多次执行 ifconfig down 与单次执行 ifconfig down

根据上面的逻辑,在执行了一次 ifconfig down 之后,多次执行 ifconfig down 会因为 old_flags 与 flags 相同而不执行具体的 down 操作。在这样的情况下得出 down 不掉的结论是不正确的。对于系统来说当前网卡的状态已经是 down 了,就不应该重复调用底层的函数。

更进一步的思考

同理我们可以看出 __dev_change_flags函数应当仅在 flags有变化的时候才去调用底层网卡驱动中的相关函数,flags无变化则不进行任何操作。

最后

以上就是乐观大叔为你收集整理的多次 ifconfig down 无效的问题的全部内容,希望文章能够帮你解决多次 ifconfig down 无效的问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部