IFF_UP 與 IFF_RUNNING
前言
近期,發現判斷網絡卡是否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