想像一條兩端都插得上的網路線#
要把兩個 Network Namespace(網路命名空間)連起來,最直接的辦法是「拉一條網路線」。在 Linux 裡這條線叫做 veth pair(虛擬乙太網對,virtual ethernet pair)。
veth pair 的特色:
- 一次建立會產生「一對」介面,例如
veth0與veth1 - 從一端送進去的封包,會立刻從另一端冒出來
- 兩端可以分別放在不同的 Network Namespace,把兩個原本隔離的網路堆疊接起來
除了 veth,Linux 還有 TUN/TAP 這類虛擬介面,但 veth 是最常拿來連接 namespace 的工具。
建立一對 veth#
使用 ip link 子命令:
sudo ip link add veth0 type veth peer name veth1
ip link show type veth預期會看到 veth0@veth1 與 veth1@veth0,兩端互為 peer。
這時兩端都還在主機的預設 namespace 裡,狀態是
DOWN,也沒有 IP。
建立兩個 Network Namespace#
sudo ip netns add ns1
sudo ip netns add ns2
ip netns list每個 namespace 一開始只有自己的 Loopback lo,互相之間完全隔離。
把一端塞進另一個 namespace#
把 veth0 移到 ns1,veth1 移到 ns2:
sudo ip link set veth0 netns ns1
sudo ip link set veth1 netns ns2接著到各自 namespace 裡確認:
sudo ip netns exec ns1 ip link show
sudo ip netns exec ns2 ip link showveth0 應該只在 ns1 看得到,veth1 只在 ns2 看得到。
給兩端設定 IP 並 up 起來#
把兩端設成同一個 /24 子網,例如 10.0.0.0/24:
sudo ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth0
sudo ip netns exec ns1 ip link set veth0 up
sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec ns2 ip link set veth1 up
sudo ip netns exec ns2 ip link set lo up兩端都 up、都有 IP 之後,從 ns1 ping ns2:
sudo ip netns exec ns1 ping -c 3 10.0.0.2預期會收到 ICMP(Internet Control Message Protocol)echo reply。背後發生的事:
- ICMP echo request 從
veth0出去,立刻從veth1冒出 ns2看到目的 IP 是自己的10.0.0.2,回一個 echo reply- reply 從
veth1進、veth0出,回到ns1
過程中 ARP(Address Resolution Protocol)也會在這對介面之間問一次「10.0.0.2 是誰」,由 ns2 回答自己的 MAC。
檢視封包流動#
想實際看封包,可以在任一端用 tcpdump 觀察:
sudo ip netns exec ns2 tcpdump -i veth1 -nn icmp預期會看到成對的 ICMP echo request / reply。如果想保存成 PCAP(Packet Capture)檔,可以加 -w capture.pcap。
veth pair 的兩個侷限#
veth pair 解決了「點對點」的問題,但實際應用會立刻撞到兩個限制:
- 一對 veth 只能連通兩個 namespace,三個以上就要拉很多對
- 兩端 IP 必須手動規劃,加新成員就要改設定
要連通多個 namespace、形成像區網一樣的拓撲,就要靠下一章的主角,Linux bridge。
清理#
實驗結束記得收乾淨:
sudo ip netns del ns1
sudo ip netns del ns2namespace 一刪,裡面的 veth 也會自動清掉。
延伸閱讀#
man 4 vethman 8 ip-linkman 8 ip-netns