本文发自 http://www.binss.me/blog/learning-computer-network-by-the-output-of-ifconfig/,转载请注明出处。

在折腾linux的过程中,有不止100个新名词蹦跶到我面前,而我却由于还有砖还要搬而无可奈何,只能把其先记到小本本里。最近趁着闲下来把这些词进行了归类,并一一查阅资料,最后结合自身的理解,通过文章的形式进行知识的沉淀。本篇主要以ifconfig的输出为例,对Linux的网络设备进行说明。

在计算机网络课上,我学习到主要的网络设备有以下这些:

网卡(Network Interface Card,NIC)

又称网络适配器(Network Adapter),是一块用于计算机网络通讯的基础硬件,属于OSI模型的第一层(Physical)和第二层(Data Link)。一般来说,其通过唯一的MAC地址来标识自己。

常见的网卡可达到10/100/1000Mbits/sMbps),这就是我们常说的百兆、千兆网卡。常用的标准有Ethernet(有线网卡)和Wi-Fi(无线网卡)。

中继器(Repeater)

一种将输入信号增强放大的硬件设备。它工作于OSI模型的第一层(Physical)。它通过对数据信号的重新发送或者转发,来扩大数据的传输距离。

网桥(Network Bridge)

又称桥接器,是一种用于网络桥接的硬件设备。它工作于OSI模型的第二层(Data Link)。

网桥将网络的多个网段在数据链路层连接起来。相对于中继器只是简单地转发信号,网桥在对帧进行转发时,根据其存储的MAC table进行过滤,只转发MAC地址在table内的帧。

由于交换机的普及,网桥已经很少见了。

路由器(Router)

又称网关(Gateway),是一种用于网络路由硬件设备。它工作于OSI模型的第三层(Network)。

提供路由与转发两种功能,即可以决定数据包从来源端到目的端所经过的路由路径(host到host之间的传输路径),也可以在内部把输入端的数据包移送至适当的输出端。

路由器中维护着一张路由表,记录着有去往不同网络地址应送往的端口号。当一台路由器收到一个IP数据包时,它将根据数据包中的目的IP地址项查找路由表,根据查找的结果将此IP数据包送往对应端口。

交换机(Switch)

交换机能为子网中提供更多的连接端口,以便连接更多的电脑。

这个种类就多了,目前有二层交换机(Data link),相当于强化版网桥;三层交换机(Network),有一定的路由功能,还有四层交换机(transport)和七层交换器。

以上这些设备概念,是我们分析ifconfig的输出的基础。让我们查看下本机(ubuntu 14.04)上的网络设备:

$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:c5:73:4c:74
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:c5ff:fe73:4c74/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1300 (1.3 KB)  TX bytes:258 (258.0 B)

eth0      Link encap:Ethernet  HWaddr f2:3c:91:18:9f:1e
          inet addr:106.186.116.111  Bcast:106.186.116.255  Mask:255.255.255.0
          inet6 addr: fe80::f03c:91ff:fe18:9f1e/64 Scope:Link
          inet6 addr: 2400:8900::f03c:91ff:fe18:9f1e/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:505691 errors:0 dropped:0 overruns:0 frame:0
          TX packets:371319 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:580961694 (580.9 MB)  TX bytes:532954539 (532.9 MB)

eth0:1    Link encap:Ethernet  HWaddr f2:3c:91:18:9f:1e
          inet addr:192.168.192.143  Bcast:0.0.0.0  Mask:255.255.128.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:11992 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11992 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2477900 (2.4 MB)  TX bytes:2477900 (2.4 MB)

veth741a889 Link encap:Ethernet  HWaddr 92:94:59:84:6e:e8
          inet6 addr: fe80::9094:59ff:fe84:6ee8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

eth开头的是网卡:eth0 表示第一块网卡

Link encap:Ethernet  HWaddr f2:3c:91:18:9f:1e

连接类型为Ethernet ,网卡的MAC地址为 f2:3c:91:18:9f:1e

inet addr:106.186.116.111  Bcast:106.186.116.255  Mask:255.255.255.0

网卡的IPv4地址为106.186.116.111,广播地址为106.186.116.255,掩码为255.255.255.0

inet6 addr: fe80::f03c:91ff:fe18:9f1e/64 Scope:Link
inet6 addr: 2400:8900::f03c:91ff:fe18:9f1e/64 Scope:Global

网卡的IPv6本地链路地址为fe80::f03c:91ff:fe18:9f1e/64(内网使用,路由器不会转发包含它的包),全局地址为2400:8900::f03c:91ff:fe18:9f1e/64(任何网络下使用)

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

Ethernet接口的相关内核模块已加载,支持广播,网卡处于就绪状态,支持组播,最大传输单元(包)为1500字节,权值(越低越高,然而用ifconfig设并不会起作用)

RX packets:505691 errors:0 dropped:0 overruns:0 frame:0

接收数据包总数、出错数、丢弃数(系统原因丢弃)、丢弃数(网卡的fifo已满丢弃)、frame alignment错误数

TX packets:371319 errors:0 dropped:0 overruns:0 carrier:0

发送数据包总数、出错数、丢弃数(系统原因丢弃)、丢弃数(网卡的fifo已满丢弃),丢失carriers数

collisions:0 txqueuelen:1000

冲突包数(可体现网络拥塞程度)为0,发送队列的长度

RX bytes:580961694 (580.9 MB)  TX bytes:532954539 (532.9 MB)

接收的总流量为580.9 MB,发送的总流量为532.9 MB

eth0:1    Link encap:Ethernet  HWaddr f2:3c:91:18:9f:1e
          inet addr:192.168.192.143  Bcast:0.0.0.0  Mask:255.255.128.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0虚拟出来的一块网卡,其MAC地址为f2:3c:91:18:9f:1e,用于分配给eth0第2个IP:192.168.192.143(内网)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:11992 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11992 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2477900 (2.4 MB)  TX bytes:2477900 (2.4 MB)

lo开头为loop设备:

它是一个指向本机(127.0.0.1)的设备,一般是用来作网络应用的自测,从而避免了局域网和外网的其它主机或用户的访问。

和eth的不同之处还有:

  • MTU非常大,因为是发给本机,所以不用担心缓冲区满之类的拥塞问题。

  • 发送包数等于接收包数,发送总流量等于接收总流量,因为是自发自收。

  • txqueuelen为0,因为根本无需队列(?)。

然后我们还发现有叫docker0和veth741a889的设备,这些是什么呢?在对其进行分析之前,我们先了解下Linux中的虚拟设备:

在Linux中,如何进行网络的虚拟化?换句话说,如果新建一台虚拟机,那么虚拟机的网卡从何而来?答案是通过软件模拟一个。随着虚拟化技术的发展,越来越多的虚拟设备被加入了Linux。 再次强调,不同于之前介绍的网络设备是一个独立的硬件,虚拟设备完全由软件实现。

虚拟网卡(virtual network interface,VIF)

虚拟网卡通过实现一个字符设备来支持物理层,从而使应用层和物理层就通过这个字符设备联系起来,从这个字符设备读出来的就是虚拟网卡发往物理层的字节流,写入字符设备的数据作为字节流被虚拟网卡接收。

虚拟网卡可以像网卡一样进行配置,常见的虚拟网卡可有TUN/TAP和VEth。

TUN/TAP(Tunnel)

TUN工作在OSI第三层(network),实现了IP包的转发,相当于路由。

TAP工作在OSI第二层(data link),实现了Ethernet帧的转发,相当于网桥。

操作系统通过TUN/TAP设备向绑定该设备的用户空间的程序发送数据,反之,用户空间的程序也可以像操作硬件网络设备那样通过TUN/TAP设备发送数据,然后TUN/TAP设备会向操作系统的网络栈push(或inject)数据包,从而模拟从外部接受数据的过程。

TUN常用于VPN,通过使用TUN,VPN能够在IP包被发出去之前将其进行加密。

TAP常用于虚拟机,为虚拟机提供网卡。

创建tap

ip tuntap add mode tap

创建tun

ip tuntap add mode tun

VEth(Virtual Ethernet)

VEth是成对出现的,它的作用是反转通讯数据的方向,当数据从网络栈发送到VEth的一端时,数据被传送到VEth的另外一端流出,然后放回网络栈,相当于把需要接受的数据转换成需要发送的数据,

常用于虚拟化中穿透network namespace,把从一个 network namespace 发出的数据包转发到另一个 namespace。

创建一对VEth,名为veth1和veth2

ip link add veth1 type veth peer name veth2

虚拟网桥

Bridge也是一种虚拟设备,用于将多块网卡(包括虚拟网卡)连接起来。

值得注意的是, Linux中虚拟网桥是通用网络设备抽象的一种,能够绑定IP 地址。因此在把网卡接入到网桥上后,网卡原来绑定的IP会失效,如果还要像原来那样收发数据,需要把该IP绑定到网桥上。

添加网桥br0

ip link add br0 type bridge

把网卡接入网桥,在把eth0和eth1接入到br0后,两个网卡就可以进行通信了。

ip link set eth0 master br0
ip link set eth1 master br0

为网桥绑定ip

ip addr add xx.xx.xx.xx/xx dev br0

我们看回ifconfig的输出:

docker0   Link encap:Ethernet  HWaddr 02:42:c5:73:4c:74
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


veth741a889 Link encap:Ethernet  HWaddr 92:94:59:84:6e:e8
          inet6 addr: fe80::9094:59ff:fe84:6ee8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

通过ethtool可以查看设备的类型:

$ ethtool -i docker0
driver: bridge
version: 2.3
firmware-version: N/A
bus-info: N/A
supports-statistics: no
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

同理可以知道veth741a889为VEth设备。

通过观察,我发现docker0网桥随着docker的启动而启动,而VEth设备在容器启动的时候才动态创建。根据官方文档,Docker通过docker0网桥在内核层连通了其他的物理或虚拟网卡,从而将所有容器和宿主都放到同一个物理网络下。每次启动一个容器的时候,Docker会新建一对VETH设备,其中一个插在docker0上,另一个插在该容器里,然后从可用的地址段中选择一个空闲的IP地址分配给容器的VEth,使用docker0的IP作为默认网关,从而实现宿主机和容器的双向数据通讯。

我们可以验证一下:

$ ethtool -S veth741a889
NIC statistics:
     peer_ifindex: 23

$ ip link
24: veth741a889: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    link/ether 92:94:59:84:6e:e8 brd ff:ff:ff:ff:ff:ff

可以查到在宿主机上veth741a889的peer_ifindex为24,和它相对应的VEth设备的peer_ifindex为23。

然后我们进入容器查询:

root@4c04df175784:/# ip route show
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.1

root@4c04df175784:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:05
          inet addr:172.17.0.5  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

root@4c04df175784:/# ethtool -S eth0
NIC statistics:
     peer_ifindex: 24

root@4c04df175784:/# ethtool -i eth0
driver: veth
version: 1.0
firmware-version:
bus-info:
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

从这里可以看出veth741a889的“伙伴”确实是在容器中,被重命名为eth0作为容器的网卡,并绑定了ip172.17.0.5,网关为网桥的ip172.17.42.1。

至此,ifconfig的输出认识完毕。