想像一條兩端都插得上的網路線#

要把兩個 Network Namespace(網路命名空間)連起來,最直接的辦法是「拉一條網路線」。在 Linux 裡這條線叫做 veth pair(虛擬乙太網對,virtual ethernet pair)。

veth pair 的特色:

  • 一次建立會產生「一對」介面,例如 veth0veth1
  • 從一端送進去的封包,會立刻從另一端冒出來
  • 兩端可以分別放在不同的 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@veth1veth1@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 移到 ns1veth1 移到 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 show

veth0 應該只在 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 ns2

namespace 一刪,裡面的 veth 也會自動清掉。

延伸閱讀#

  • man 4 veth
  • man 8 ip-link
  • man 8 ip-netns