IFF_UP 与 IFF_RUNNING

| 分类 Linux  | 标签 Linux 

前言

近期,发现判断网卡是否Ready的程序出了一些问题,有些网卡明明没有插线,依然会被判定为active的网卡。我去跟踪了下代码:

# struct ifreq { // FOR SIOCGIFFLAGS:
#   char ifrn_name[IFNAMSIZ]
#   short ifru_flags
# };
my $STRUCT_IFREQ_SIOCGIFFLAGS = 'Z' . IFNAMSIZ . 's1';
sub get_active_network_interfaces {
    # Use the interface name list from /proc/net/dev
    open my $fh, '<', '/proc/net/dev'
	or die "failed to open /proc/net/dev: $!\n";
    # And filter by IFF_UP flag fetched via a PF_INET6 socket ioctl:
    my $sock;
    socket($sock, PF_INET6, SOCK_DGRAM, &IPPROTO_IP)
    or socket($sock, PF_INET, SOCK_DGRAM, &IPPROTO_IP)
    or return [];

    my $ifaces = [];
    while(defined(my $line = <$fh>)) {
	next if $line !~ /^\s*([^:\s]+):/;
	my $ifname = $1;
	my $ifreq = pack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifname, 0);
	if (!defined(ioctl($sock, SIOCGIFFLAGS, $ifreq))) {
	    warn "failed to get interface flags for: $ifname\n";
	    next;
	}
	my ($name, $flags) = unpack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifreq);
	push @$ifaces, $ifname if ($flags & IFF_UP);
    }
    close $fh;
    close $sock;
    return $ifaces;
}

发现源码使用通过调用 ioctl SIOCGIFFLAGS 来判定网卡是否已经ready。

关于SIOCGIFFLAGS

Linux ioctl支持一下两个标志位:

  • SIOCGIFFLAGS: 获取设备的活动标志位
  • SIOCSIFFLAGS: 修改设备的活动标志位
       SIOCGIFFLAGS, SIOCSIFFLAGS
              Get or set the active flag word of the device.  ifr_flags contains a bit mask of the following values:

                                           Device flags
              IFF_UP            Interface is running.
              IFF_BROADCAST     Valid broadcast address set.
              IFF_DEBUG         Internal debugging flag.
              IFF_LOOPBACK      Interface is a loopback interface.

              IFF_POINTOPOINT   Interface is a point-to-point link.
              IFF_RUNNING       Resources allocated.
              IFF_NOARP         No arp protocol, L2 destination address not set.
              IFF_PROMISC       Interface is in promiscuous mode.
              IFF_NOTRAILERS    Avoid use of trailers.
              IFF_ALLMULTI      Receive all multicast packets.
              IFF_MASTER        Master of a load balancing bundle.
              IFF_SLAVE         Slave of a load balancing bundle.
              IFF_MULTICAST     Supports multicast
              IFF_PORTSEL       Is able to select media type via ifmap.
              IFF_AUTOMEDIA     Auto media selection active.
              IFF_DYNAMIC       The addresses are lost when the interface goes down.
              IFF_LOWER_UP      Driver signals L1 up (since Linux 2.6.17)
              IFF_DORMANT       Driver signals dormant (since Linux 2.6.17)
              IFF_ECHO          Echo sent packets (since Linux 2.6.25)本次我们重点介绍IFF_UP和 IFF_RUNNING。

IFF_UP: 这个标志位表示的是从管理上讲,这个网口是UP的,是Ready的,但是并不代表连接状态。即网卡已经准备好了,但是并不意味着网线已插。

IFF_RUNNING: 这个标志位表示operational state,如果置位的话,表示CONNECTED的。

验证

做个简单验证:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>

#define BUFSIZE 1024

int main(int argc, char *argv[])
{
	struct ifreq ifr;
	int sfd ;

	memset(&ifr, '\0' , sizeof(struct ifreq));
	strcpy(ifr.ifr_name, argv[1]);
	sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

	int ret = ioctl(sfd, SIOCGIFFLAGS, (char *)&ifr);
	if(ret !=0)
	{
		printf("failed to exec ioctl");
		goto out;
	}

	printf("%10s IFF_UP: %d\n", argv[1], !!(ifr.ifr_flags & IFF_UP));
	printf("%10s IFF_RUNNING: %d \n",argv[1], !!(ifr.ifr_flags & IFF_RUNNING));

out:
	close(sfd);
	exit(ret);
}

我的笔记本的网口情况如下:

manu-latitude3510 CODE/C » cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 1503282   11818    0    0    0     0          0         0  1503282   11818    0    0    0     0       0          0
  eno1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
wlp1s0: 14947732561 40405691    0 822774    0     0          0         0 650855154 3591298    0    0    0     0       0          0
manu-latitude3510 CODE/C »

其中eno1 是有线,并未插线,wlp1s0是无线,已经连接的状态。

manu-latitude3510 CODE/C » ./nettool eno1                                                                                                                
      eno1 IFF_UP: 1
      eno1 IFF_RUNNING: 0
manu-latitude3510 CODE/C » ./nettool wlp1s0
    wlp1s0 IFF_UP: 1
    wlp1s0 IFF_RUNNING: 1
manu-latitude3510 CODE/C » ./nettool lo
        lo IFF_UP: 1
        lo IFF_RUNNING: 1
manu-latitude3510 CODE/C

上一篇     下一篇