千家信息网

Linux 虚拟网络设备 veth-pair有什么用

发表于:2024-11-15 作者:千家信息网编辑
千家信息网最后更新 2024年11月15日,这篇文章将为大家详细讲解有关Linux 虚拟网络设备 veth-pair有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。01 veth-pair 是什么顾名思
千家信息网最后更新 2024年11月15日Linux 虚拟网络设备 veth-pair有什么用

这篇文章将为大家详细讲解有关Linux 虚拟网络设备 veth-pair有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。


01 veth-pair 是什么

顾名思义,veth-pair 就是一对的虚拟设备接口,和 tap/tun 设备不同的是,它都是成对出现的。一端连着协议栈,一端彼此相连着。如下图所示:

正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备,典型的例子像"两个 namespace 之间的连接","Bridge、OVS 之间的连接","Docker 容器之间的连接" 等等,以此构建出非常复杂的虚拟网络结构,比如 OpenStack Neutron。

02 veth-pair 的连通性

我们给上图中的 veth0 和 veth2 分别配上 IP:10.1.1.2 和 10.1.1.3,然后从 veth0 ping 一下 veth2。理论上它们处于同网段,是能 ping 通的,但结果却是 ping 不通。

抓个包看看,tcpdump -nnt -i veth0

root@ubuntu:~# tcpdump -nnt -i veth0tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytesARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28ARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28

可以看到,由于 veth0 和 veth2 处于同一个网段,且是第一次连接,所以会事先发 ARP 包,但 veth2 并没有响应 ARP 包。

经查阅,这是由于我使用的 Ubuntu 系统内核中一些 ARP 相关的默认配置限制所导致的,需要修改一下配置项:

echo 1 > /proc/sys/net/ipv4/conf/veth2/accept_localecho 1 > /proc/sys/net/ipv4/conf/veth0/accept_localecho 0 > /proc/sys/net/ipv4/conf/all/rp_filterecho 0 > /proc/sys/net/ipv4/conf/veth0/rp_filterecho 0 > /proc/sys/net/ipv4/conf/veth2/rp_filter

完了再 ping 就行了。

root@ubuntu:~# ping -I veth0 10.1.1.3 -c 2PING 10.1.1.3 (10.1.1.3) from 10.1.1.2 veth0: 56(84) bytes of data.64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.047 ms64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.064 ms--- 10.1.1.3 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 3008msrtt min/avg/max/mdev = 0.047/0.072/0.113/0.025 ms

我们对这个通信过程比较感兴趣,可以抓包看看。

对于 veth0 口:

root@ubuntu:~# tcpdump -nnt -i veth0tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on veth0, link-type EN10MB (Ethernet), capture size 262144 bytesARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28ARP, Reply 10.1.1.3 is-at 5a:07:76:8e:fb:cd, length 28IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 1, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 2, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 3, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2244, seq 1, length 64

对于 veth2 口:

root@ubuntu:~# tcpdump -nnt -i veth2tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on veth2, link-type EN10MB (Ethernet), capture size 262144 bytesARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28ARP, Reply 10.1.1.3 is-at 5a:07:76:8e:fb:cd, length 28IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 1, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 2, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 3, length 64IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2244, seq 1, length 64

奇怪,我们并没有看到 ICMP 的 echo reply 包,那它是怎么 ping 通的?

其实这里 echo reply 走的是 localback 口,不信抓个包看看:

root@ubuntu:~# tcpdump -nnt -i lotcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on lo, link-type EN10MB (Ethernet), capture size 262144 bytesIP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 1, length 64IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 2, length 64IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 3, length 64IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 4, length 64

为什么?

我们看下整个通信流程就明白了。

  1. 首先 ping 程序构造 ICMP echo request,通过 socket 发给协议栈。
  2. 由于 ping 指定了走 veth0 口,如果是第一次,则需要发 ARP 请求,否则协议栈直接将数据包交给 veth0。
  3. 由于 veth0 连着 veth2,所以 ICMP request 直接发给 veth2。
  4. veth2 收到请求后,交给另一端的协议栈。
  5. 协议栈看本地有 10.1.1.3 这个 IP,于是构造 ICMP reply 包,查看路由表,发现回给 10.1.1.0 网段的数据包应该走 localback 口,于是将 reply 包交给 lo 口(会优先查看路由表的 0 号表,ip route show table 0 查看)。
  6. lo 收到协议栈的 reply 包后,啥都没干,转手又回给协议栈。
  7. 协议栈收到 reply 包之后,发现有 socket 在等待包,于是将包给 socket。
  8. 等待在用户态的 ping 程序发现 socket 返回,于是就收到 ICMP 的 reply 包。

整个过程如下图所示:

03 两个 namespace 之间的连通性

namespace 是 Linux 2.6.x 内核版本之后支持的特性,主要用于资源的隔离。有了 namespace,一个 Linux 系统就可以抽象出多个网络子系统,各子系统间都有自己的网络设备,协议栈等,彼此之间互不影响。

如果各个 namespace 之间需要通信,怎么办呢,答案就是用 veth-pair 来做桥梁。

根据连接的方式和规模,可以分为"直接相连","通过 Bridge 相连" 和 "通过 OVS 相连"。

3.1 直接相连

直接相连是最简单的方式,如下图,一对 veth-pair 直接将两个 namespace 连接在一起。

给 veth-pair 配置 IP,测试连通性:

# 创建 namespaceip netns a ns1ip netns a ns2# 创建一对 veth-pair veth0 veth2ip l a veth0 type veth peer name veth2# 将 veth0 veth2 分别加入两个 nsip l s veth0 netns ns1ip l s veth2 netns ns2# 给两个 veth0 veth2 配上 IP 并启用ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0ip netns exec ns1 ip l s veth0 upip netns exec ns2 ip a a 10.1.1.3/24 dev veth2ip netns exec ns2 ip l s veth2 up# 从 veth0 ping veth2[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.073 ms64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.068 ms--- 10.1.1.3 ping statistics ---15 packets transmitted, 15 received, 0% packet loss, time 14000msrtt min/avg/max/mdev = 0.068/0.084/0.201/0.032 ms

3.2 通过 Bridge 相连

Linux Bridge 相当于一台交换机,可以中转两个 namespace 的流量,我们看看 veth-pair 在其中扮演什么角色。

如下图,两对 veth-pair 分别将两个 namespace 连到 Bridge 上。

同样给 veth-pair 配置 IP,测试其连通性:

# 首先创建 bridge br0ip l a br0 type bridgeip l s br0 up # 然后创建两对 veth-pairip l a veth0 type veth peer name br-veth0ip l a veth2 type veth peer name br-veth2# 分别将两对 veth-pair 加入两个 ns 和 br0ip l s veth0 netns ns1ip l s br-veth0 master br0ip l s br-veth0 upip l s veth2 netns ns2ip l s br-veth2 master br0ip l s br-veth2 up# 给两个 ns 中的 veth 配置 IP 并启用ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0ip netns exec ns1 ip l s veth0 upip netns exec ns2 ip a a 10.1.1.3/24 dev veth2ip netns exec ns2 ip l s veth2 up# veth0 ping veth2[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.060 ms64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.105 ms--- 10.1.1.3 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 999msrtt min/avg/max/mdev = 0.060/0.082/0.105/0.024 ms

3.3 通过 OVS 相连

OVS 是第三方开源的 Bridge,功能比 Linux Bridge 要更强大,对于同样的实验,我们用 OVS 来看看是什么效果。

如下图所示:

同样测试两个 namespace 之间的连通性:

# 用 ovs 提供的命令创建一个 ovs bridgeovs-vsctl add-br ovs-br# 创建两对 veth-pairip l a veth0 type veth peer name ovs-veth0ip l a veth2 type veth peer name ovs-veth2# 将 veth-pair 两端分别加入到 ns 和 ovs bridge 中ip l s veth0 netns ns1ovs-vsctl add-port ovs-br ovs-veth0ip l s ovs-veth0 upip l s veth2 netns ns2ovs-vsctl add-port ovs-br ovs-veth2ip l s ovs-veth2 up# 给 ns 中的 veth 配置 IP 并启用ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0ip netns exec ns1 ip l s veth0 upip netns exec ns2 ip a a 10.1.1.3/24 dev veth2ip netns exec ns2 ip l s veth2 up# veth0 ping veth2[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.311 ms64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.087 ms^C--- 10.1.1.3 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 999msrtt min/avg/max/mdev = 0.087/0.199/0.311/0.112 ms

关于Linux 虚拟网络设备 veth-pair有什么用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0