【NetDevOps】新一代网工需要了解的那点事儿(二)---veth-pari
2 虚拟网络设备veth-pair
veth从名字上来看是 Virtual Ethernet 的缩写,veth是成对出现的一种虚拟网络设备。一端连接着协议栈,一端连接着彼此,数据从一端出,从另一端进,通常也称作veth-pair(如下图所示)。它的作用很简单,就是要把从一个 network namespace 发出的数据包转发到另一个 namespace中。正因为它的这个特性,常常被用来连接不同的虚拟网络组件,构建大规模的虚拟网络拓扑,比如连接Bridge、OVS、LXC、Docker容器等。很常见的案例就是它被用于Docker网络还有OpenStack Neutron,构建非常复杂的网络形态。
Veth Pair
+--------------+ +--------------+
| Socket API | | Socket API |
+-------+------+ +-------+------+
| |
User Space | |
+------------------------------------------------------------------+
Kernel Space + +
raw ethernet raw ethernet
+ +
+-------+-------+ +-------+-------+
| Network Stack | | Network Stack |
+-------+-------+ +-------+-------+
| |
+-------+-------+ +-------+-------+
| vethX | | vethX |
+-------+-------+ +-------+-------+
| |
+---------------------------+
2.1 创建veth-pair
我们通过"ip link"相关命令,创建一对虚拟网卡veth0和veth1。其中给veth0配置IP为12.1.1.1/24,veth1配置IP为12.1.1.2/24,并激活这一对虚拟网卡。"ip link"命令相关参数比较多,可以使用"ip link help"查看这里就不做过多解释。最后通过"ip link list"查看虚拟网卡相关状态,连接图及创建过程如下:
+--------------------------------------------------------------------------------------+
| +-------------------------------------------------------------+ |
| | Network Protocol Stack | |
| +------+------------------------+-----------------------+-----+ |
| ^ ^ ^ |
| | | | |
+--------------------------------------------------------------------------------------+
| | | | |
| v v v |
| +-------+------+ +-----+-----+ +-----+-----+ |
| | Eth0 | | Veth0 | | Veth1 | |
| +-------+------+ +-----+-----+ +------+----+ |
| ^ ^ ^ |
| 10.10.10.137 | 12.1.1.1/24| |12.1.1.2/24 |
| | +------------------------+ |
| | |
+--------------------v-----------------------------------------------------------------+
| Physical Network By:[F0rGeEk] |
+--------------------------------------------------------------------------------------+
- 创建一对veth
[root@d1 ~]# ip link add veth0 type veth peer name veth1
# 查看是否创建成功
[root@d1 ~]# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:97:0f:70 brd ff:ff:ff:ff:ff:ff
3: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 12:64:bd:95:4f:40 brd ff:ff:ff:ff:ff:ff
4: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 96:10:c9:07:77:d9 brd ff:ff:ff:ff:ff:ff
- 为虚拟网卡配置IP
[root@d1 ~]# ip addr add 12.1.1.1/24 dev veth0
[root@d1 ~]# ip addr add 12.1.1.2/24 dev veth1
# 查看是否配置成功
[root@d1 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:97:0f:70 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.137/24 brd 10.10.10.255 scope global noprefixroute dynamic ens33
valid_lft 5444486sec preferred_lft 5444486sec
inet6 fe80::d956:a6bf:6a6e:b6a7/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 12:64:bd:95:4f:40 brd ff:ff:ff:ff:ff:ff
inet 12.1.1.2/24 scope global veth1
valid_lft forever preferred_lft forever
4: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 96:10:c9:07:77:d9 brd ff:ff:ff:ff:ff:ff
inet 12.1.1.1/24 scope global veth0
valid_lft forever preferred_lft forever
- 激活这一对虚拟网卡
[root@d1 ~]# ip link set veth0 up
[root@d1 ~]# ip link set veth1 up
# 查看是否激活
[root@d1 ~]# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:97:0f:70 brd ff:ff:ff:ff:ff:ff
3: veth1@veth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 12:64:bd:95:4f:40 brd ff:ff:ff:ff:ff:ff
4: veth0@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 96:10:c9:07:77:d9 brd ff:ff:ff:ff:ff:ff
2.2 veth-pair连通性
接1.4.1步骤这一对虚拟网卡IP地址在同一段且均已激活,这里我们用veth0 ping veth1,查看网络是否可以连通。测试过程如下:
[root@d1 ~]# ping 12.1.1.2 -c 3 -I veth0
PING 12.1.1.2 (12.1.1.2) from 12.1.1.1 veth0: 56(84) bytes of data.
--- 12.1.1.2 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
由上面步骤可以看出,实际上这一对虚拟网卡并不能互相通信。可是依据理论来讲,他们是可以互相通信的。这里我们通过抓包来分析一下原因,首先从veth0长pingveth1,然后分别抓veth0和veth1这两个虚拟网卡的包:
- veth0
[root@d1 ~]# tcpdump -nnt -i veth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
- veth1
[root@d1 ~]# tcpdump -nnt -i veth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
ARP, Request who-has 12.1.1.2 tell 12.1.1.1, length 28
通过以上抓包分析:veth0和veth1处于同一网段12.1.1.0/24,由于是第一次通信会通过ARP来确定MAC。可是在两个网卡的抓包情况来看,只有veth0发出的Request包并没有veth1回应的Raply包。有一定传统网络Trouble Shooting功底的您,看到这种现象肯定会想这肯定是防火墙策略阻止了吧😷您的猜测完全正确,经过查阅相关文档得知:大部分发行版Linux在默认情况下,内核中关于ARP是有一定限制的。所以为了使这一对虚拟网卡在根NS能直接互通,必须要修改默认的策略:
# 修改IP路由默认策略及默认ARP策略
[root@d1 ~]# echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local
[root@d1 ~]# echo 1 > /proc/sys/net/ipv4/conf/veth0/accept_local
[root@d1 ~]# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
[root@d1 ~]# echo 0 > /proc/sys/net/ipv4/conf/veth0/rp_filter
[root@d1 ~]# echo 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter
# 接下来再测试连通性
[root@d1 ~]# ping 12.1.1.2 -c 3 -I veth0
PING 12.1.1.2 (12.1.1.2) from 12.1.1.1 veth0: 56(84) bytes of data.
64 bytes from 12.1.1.2: icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from 12.1.1.2: icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from 12.1.1.2: icmp_seq=3 ttl=64 time=0.045 ms
--- 12.1.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2034ms
rtt min/avg/max/mdev = 0.037/0.044/0.051/0.005 ms
注:至于为什么修改上述策略才能通信,过两天还是单独写一篇文章来解释吧。
2.3 在NS中的连通性
接下来我们将veth1关联到1.3章节中创建的NS,然后看看和veth0通信的过程。
[root@d1 ~]# ip link set veth1 netns forgeek
[root@d1 ~]# ip netns exec forgeek ifconfig veth1 12.1.1.2/24
[root@d1 ~]# ip netns exec forgeek ip link set dev veth1 up
[root@d1 ~]# ping 12.1.1.2 -c 3 -I veth0
PING 12.1.1.2 (12.1.1.2) from 12.1.1.1 veth0: 56(84) bytes of data.
64 bytes from 12.1.1.2: icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from 12.1.1.2: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 12.1.1.2: icmp_seq=3 ttl=64 time=0.072 ms
--- 12.1.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.066/0.084/0.115/0.023 ms
2.4 NS之间的连通性
之前我们说veth-pair主要是用来解决不同NS之间通信的,那么接下来我们来创建两个NS:ns1,ns2。然后将veth0
加入到ns1中,veth1加入到ns2中,分别给veth0和veth1配置IP地址如下图所示:
+------------------------------------------------------------------+
| |
| +-----------------+ +-----------------+ |
| | NS1 | | NS2 | |
| | +--+ Veth pair +--+ | |
| | | +--------------------------+ | | |
| | +--+veth0 veth1+--+ | |
| | Name Space |12.1.1.1 12.1.1.2| Name Space | |
| +-----------------+ +-----------------+ |
| |
| Linux Server |
| By:[F0rGeEk] |
+------------------------------------------------------------------|
操作过程如下:
[root@d1 ~]# ip netns add ns1
[root@d1 ~]# ip netns add ns2
[root@d1 ~]# ip link set veth0 netns ns1
[root@d1 ~]# ip link set veth1 netns ns2
# 验证网卡是否加入对应的NS中
[root@d1 ~]# ip netns exec ns1 ip link ls
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 02:77:ea:e8:3a:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@d1 ~]# ip netns exec ns2 ip link ls
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth1@if8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether ce:47:33:1f:90:fe brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 激活相应的网卡
[root@d1 ~]# ip netns exec ns1 ip link set dev veth0 up
[root@d1 ~]# ip netns exec ns2 ip link set dev veth1 up
# 为网卡配置IP地址
[root@d1 ~]# ip netns exec ns1 ifconfig veth0 12.1.1.1/24
[root@d1 ~]# ip netns exec ns2 ifconfig veth1 12.1.1.2/24
# 测试连通性
[root@d1 ~]# ip netns exec ns1 ping 12.1.1.2 -c 3 -I veth0
PING 12.1.1.2 (12.1.1.2) from 12.1.1.1 veth0: 56(84) bytes of data.
64 bytes from 12.1.1.2: icmp_seq=1 ttl=64 time=0.051 ms
64 bytes from 12.1.1.2: icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from 12.1.1.2: icmp_seq=3 ttl=64 time=0.052 ms
--- 12.1.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.051/0.053/0.057/0.006 ms