首頁  >  文章  >  運維  >  Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

若昕
若昕轉載
2019-04-01 13:03:505550瀏覽

本文介紹了veth-pair和它的連通性,以及兩個namespace 之間的連結性.

01 veth-pair 是什麼

顧名思義,veth-pair 就是一對的虛擬設備接口,和tap/tun 設備不同的是,它都是成對出現的。一端連協定棧,一端彼此相連。如下圖所示:

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

正因為有這個特性,它常常充當著一個橋樑,連接著各種虛擬網路設備,典型的例子像「兩個namespace 之間的連接”,“Bridge、OVS 之間的連接”,“Docker 容器之間的連接” 等等,以此構建出非常複雜的虛擬網絡結構,例如OpenStack Neutron。

02 veth-pair 的連通性

我們給上圖的 veth0 和 veth1 分別配上 IP:10.1.1.2 和 10.1.1.3,然後從 veth0 ping 一下 veth1。理論上它們處於同網段,是能 ping 通的,但結果卻是 ping 不通。

抓包看看,tcpdump -nnt -i veth0

root@ubuntu:~# 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 10.1.1.3 tell 10.1.1.2, length 28
ARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28

可以看到,由於veth0 和veth1 處於同一個網段,且是第一次連接,所以會事先發送ARP 包,但veth1 並沒有回應ARP 包。

經過查閱,這是由於我使用的 Ubuntu 系統核心中一些 ARP 相關的預設設定限制所導致的,需要修改一下設定項:

echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local
echo 1 > /proc/sys/net/ipv4/conf/veth0/accept_local
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/veth0/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter

完了再 ping 就行了。

root@ubuntu:~# ping -I veth0 10.1.1.3 -c 2
PING 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 ms
64 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 3008ms
rtt min/avg/max/mdev = 0.047/0.072/0.113/0.025 ms

我們對這個通訊過程比較有興趣,可以抓包看看。

對於veth0 口:

root@ubuntu:~# 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 10.1.1.3 tell 10.1.1.2, length 28
ARP, Reply 10.1.1.3 is-at 5a:07:76:8e:fb:cd, length 28
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 1, length 64
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 2, length 64
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 3, length 64
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2244, seq 1, length 64

對於veth1 口:

root@ubuntu:~# 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 10.1.1.3 tell 10.1.1.2, length 28
ARP, Reply 10.1.1.3 is-at 5a:07:76:8e:fb:cd, length 28
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 1, length 64
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 2, length 64
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 2189, seq 3, length 64
IP 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 lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 1, length 64
IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 2, length 64
IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 2244, seq 3, length 64
IP 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 連著 veth1,所以 ICMP request 直接發給 veth1。
  4. veth1 收到請求後,交給另一端的協定堆疊。
  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 套件。

整個流程如下圖所示:

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

#03 兩個namespace 之間的連結性

namespace 是Linux 2.6.x 核心版本之後支援的特性,主要用於資源的隔離。有了 namespace,一個 Linux 系統就可以抽像出多個網路子系統,各子系統間都有自己的網路設備,協定棧等,彼此之間互不影響。

如果各個 namespace 之間需要通信,怎麼辦呢,答案就是用 veth-pair 來做橋樑。

根據連接的方式和規模,可以分為“直接連接”,“通過 Bridge 連接” 和 “通過 OVS 連接”。

3.1 直接相連

直接連結是最簡單的方式,如下圖,一對 veth-pair 直接將兩個 namespace 連接在一起。

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

給veth-pair 設定IP,測試連結性:

# 创建 namespace
ip netns a ns1
ip netns a ns2

# 创建一对 veth-pair veth0 veth1
ip l a veth0 type veth peer name veth1

# 将 veth0 veth1 分别加入两个 ns
ip l s veth0 netns ns1
ip l s veth1 netns ns2

# 给两个 veth0 veth1 配上 IP 并启用
ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0
ip netns exec ns1 ip l s veth0 up
ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1
ip netns exec ns2 ip l s veth1 up

# 从 veth0 ping veth1
[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3
PING 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 ms
64 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 14000ms
rtt 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 上。

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

同樣給veth-pair 配置IP,測試其連結性:

# 首先创建 bridge br0
ip l a br0 type bridge
ip l s br0 up 

# 然后创建两对 veth-pair
ip l a veth0 type veth peer name br-veth0
ip l a veth1 type veth peer name br-veth1

# 分别将两对 veth-pair 加入两个 ns 和 br0
ip l s veth0 netns ns1
ip l s br-veth0 master br0
ip l s br-veth0 up

ip l s veth1 netns ns2
ip l s br-veth1 master br0
ip l s br-veth1 up

# 给两个 ns 中的 veth 配置 IP 并启用
ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0
ip netns exec ns1 ip l s veth0 up

ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1
ip netns exec ns2 ip l s veth1 up

# veth0 ping veth1
[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3
PING 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 ms
64 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 999ms
rtt min/avg/max/mdev = 0.060/0.082/0.105/0.024 ms

3.3 透過OVS 相連

#OVS 是第三方開源的Bridge,功能比Linux Bridge 更強大,對於同樣的實驗,我們用OVS 來看看是什麼效果。

如下圖所示:

Linux 虛擬網路設備 veth-pair 詳解,這篇料很足

同樣測試兩個 namespace 之間的連結性:

# 用 ovs 提供的命令创建一个 ovs bridge
ovs-vsctl add-br ovs-br

# 创建两对 veth-pair
ip l a veth0 type veth peer name ovs-veth0
ip l a veth1 type veth peer name ovs-veth1

# 将 veth-pair 两端分别加入到 ns 和 ovs bridge 中
ip l s veth0 netns ns1
ovs-vsctl add-port ovs-br ovs-veth0
ip l s ovs-veth0 up

ip l s veth1 netns ns2
ovs-vsctl add-port ovs-br ovs-veth1
ip l s ovs-veth1 up

# 给 ns 中的 veth 配置 IP 并启用
ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0
ip netns exec ns1 ip l s veth0 up

ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1
ip netns exec ns2 ip l s veth1 up

# veth0 ping veth1
[root@localhost ~]# ip netns exec ns1 ping 10.1.1.3
PING 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 ms
64 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 999ms
rtt min/avg/max/mdev = 0.087/0.199/0.311/0.112 ms

相关课程推荐:Linux视频教程

总结

veth-pair 在虚拟网络中充当着桥梁的角色,连接多种网络设备构成复杂的网络。

veth-pair 的三个经典实验,直接相连、通过 Bridge 相连和通过 OVS 相连。

参考

http://www.opencloudblog.com/?p=66

https://segmentfault.com/a/1190000009251098

以上是Linux 虛擬網路設備 veth-pair 詳解,這篇料很足的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除