概述
多次 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 位的取值有如下两种可能。
- old_flags IFF_UP is 0、flags IFF_UP is 1
- 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 无效的问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复