本文首發於個人公衆號 Linux雲計算網絡(id: cloud_dev),專一於乾貨分享,號內有 10T 書籍和視頻資源,後臺回覆「1024」便可領取,歡迎你們關注,二維碼文末能夠掃。編程
前面這篇文章介紹了 tap/tun 設備以後,你們應該對虛擬網絡設備有了必定的瞭解,本文來看另一種虛擬網絡設備 veth-pair。ubuntu
顧名思義,veth-pair 就是一對的虛擬設備接口,和 tap/tun 設備不一樣的是,它都是成對出現的。一端連着協議棧,一端彼此相連着。以下圖所示:segmentfault
正由於有這個特性,它經常充當着一個橋樑,鏈接着各類虛擬網絡設備,典型的例子像「兩個 namespace 之間的鏈接」,「Bridge、OVS 之間的鏈接」,「Docker 容器之間的鏈接」 等等,以此構建出很是複雜的虛擬網絡結構,好比 OpenStack Neutron。網絡
咱們給上圖中的 veth0 和 veth1 分別配上 IP:10.1.1.2 和 10.1.1.3,而後從 veth0 ping 一下 veth1。理論上它們處於同網段,是能 ping 通的,但結果倒是 ping 不通。socket
抓個包看看,tcpdump -nnt -i veth0
tcp
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
咱們對這個通訊過程比較感興趣,能夠抓包看看。spa
對於 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
爲何?
咱們看下整個通訊流程就明白了。
echo request
,經過 socket 發給協議棧。ip route show table 0
查看)。整個過程以下圖所示:
namespace 是 Linux 2.6.x 內核版本以後支持的特性,主要用於資源的隔離。有了 namespace,一個 Linux 系統就能夠抽象出多個網絡子系統,各子系統間都有本身的網絡設備,協議棧等,彼此之間互不影響。
若是各個 namespace 之間須要通訊,怎麼辦呢,答案就是用 veth-pair 來作橋樑。
根據鏈接的方式和規模,能夠分爲「直接相連」,「經過 Bridge 相連」 和 「經過 OVS 相連」。
直接相連是最簡單的方式,以下圖,一對 veth-pair 直接將兩個 namespace 鏈接在一塊兒。
給 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
Linux Bridge 至關於一臺交換機,能夠中轉兩個 namespace 的流量,咱們看看 veth-pair 在其中扮演什麼角色。
以下圖,兩對 veth-pair 分別將兩個 namespace 連到 Bridge 上。
一樣給 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
OVS 是第三方開源的 Bridge,功能比 Linux Bridge 要更強大,對於一樣的實驗,咱們用 OVS 來看看是什麼效果。
以下圖所示:
一樣測試兩個 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
veth-pair 在虛擬網絡中充當着橋樑的角色,鏈接多種網絡設備構成複雜的網絡。
veth-pair 的三個經典實驗,直接相連、經過 Bridge 相連和經過 OVS 相連。
http://www.opencloudblog.com/?p=66
https://segmentfault.com/a/1190000009251098
個人公衆號 「Linux雲計算網絡」(id: cloud_dev) ,號內有 10T 書籍和視頻資源,後臺回覆 「1024」 便可領取,分享的內容包括但不限於 Linux、網絡、雲計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++編程技術等內容,歡迎你們關注。