Linux Network Namespace

今天要介紹的東西是 Linux Network Namespace。為什麼會知道這東西呢?主要是因為在研究 SDN 模擬器 mininet(正確來說是 OpenFlow 模擬器)時,發現它是透過 Linux Network Namespace 這個技術,將每個 Host 以及 Switch 獨立開來(Isolation),並在當中建立起虛擬的連線,藉這個概念在一台電腦內打造出虛擬的網路拓樸。所以就想說花點時間來看看如何使用這個技術。

我們先來看看在 Wikipedia 上關於 cgroups 的介紹:

cgroups (abbreviated from control groups) is a Linux kernel feature to limit, account, and isolate resource usage (CPU, memory, disk I/O, etc.) of process groups.

Namespace isolation
While not technically part of the cgroups work, a related feature of the Linux kernel is namespace isolation, where groups of processes are separated such that they cannot "see" resources in other groups. For example, a PID namespace provides a separate enumeration of process identifiers within each namespace. Also available are mount, UTS, network and SysV IPC namespaces.

簡單來說,就是透過 group 這樣的觀念,讓每個 process group 間所使用的資源能夠獨立開來而不會互相影響。而這樣的 group 就被稱做是 namespace。而今天要看的是 Network Namespace。用例子來看或許會比較容易了解,下面的例子主要是參考這個網頁所建立出來的。

1. 建立 Network Namespace

$ sudo ip netns add blue
$ ip netns list
blue

上面的指令應該可以很輕易的解讀,就是產生一個叫作 blue 的 network namespace。要注意的是,雖然 ip netns list 只顯示出 blue 這個 namespace,但其實預設還有一筆 default network namespace 是不顯示的。基本上如果不指定的話,所有的網路介面、程式都是使用 default network namespace 的。

2. 建立虛擬的網路介面與虛擬連線並加入到 Network Namespace

$ sudo ip link add veth0 type veth peer name veth1
$ ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 00:08:a1:36:6f:ab brd ff:ff:ff:ff:ff:ff
3: eth1:  mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:22:15:8b:3b:8c brd ff:ff:ff:ff:ff:ff
4: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether a6:f1:91:9b:2c:0e brd ff:ff:ff:ff:ff:ff
5: veth0:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether f2:e9:8a:05:da:56 brd ff:ff:ff:ff:ff:ff

可以看到上面的指令新增了兩張 interface,分別是 veth0 和  veth1,而且兩張往卡間還有一條虛擬的連線(virtual link)。接下來我們用下面的指令來將 veth1 加到 blue 這個 network namespace 裏面。

$ sudo ip link set veth1 netns blue
$ ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 00:08:a1:36:6f:ab brd ff:ff:ff:ff:ff:ff
3: eth1:  mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:22:15:8b:3b:8c brd ff:ff:ff:ff:ff:ff
5: veth0:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether f2:e9:8a:05:da:56 brd ff:ff:ff:ff:ff:ff
$ ip netns exec blue ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether a6:f1:91:9b:2c:0e brd ff:ff:ff:ff:ff:ff

很明顯可以看到,在原先的 default network namespace 中少了 veth1 ,而在 blue 這個 network namespace 中則出現了 veth1 這個 interface。

3. 設定網路

接下來我們要替 veth1 設定 IP Address。

$ ifconfig veth1
veth1: error fetching interface information: Device not found
$ sudo ip netns exec blue ifconfig veth1 192.168.200.3/24 up

很明顯,直接用 ifconfig 是沒用的。這是因為 ifconfig 預設是在 default network namespace 上作用的,而在 default network namespace 中根本沒有 veth1 這個 interface。所以 ifconfig  這個指令必須要執行在 blue 這個 network namespace 上。我們可以再做一個實驗:


$ ping 192.168.200.3
PING 192.168.200.3 (192.168.200.3) 56(84) bytes of data.
^C
--- 192.168.200.3 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3022ms

完全 ping 不到,可是只要替 veth0 設定 IP 以後就沒問題了,畢竟 veth0 和 veth1 中間有一條虛擬的連線:


$ sudo ifconfig veth0 192.168.200.2/24
$ ping 192.168.200.3 -c 1
PING 192.168.200.3 (192.168.200.3) 56(84) bytes of data.
64 bytes from 192.168.200.3: icmp_seq=1 ttl=64 time=0.032 ms

--- 192.168.200.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.032/0.032/0.032/0.000 ms
$ sudo ip netns exec blue ping 192.168.200.2 -c 1
PING 192.168.200.2 (192.168.200.2) 56(84) bytes of data.
64 bytes from 192.168.200.2: icmp_seq=1 ttl=64 time=0.038 ms

--- 192.168.200.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.038/0.038/0.038/0.000 ms


上面的例子也說明了可以從 veth1 ping 回 veth0。上面的這些實驗說明了如何切割 Network Namespace 以及如何讓彼此間互通,那麼 mininet 的模擬方法看起來也就沒那麼神奇了。

問題

其實我在做實驗的時候遇到了個問題,請看下面的指令:

$ sudo ip netns exec blue ping 192.168.200.3 -c 1
PING 192.168.200.3 (192.168.200.3) 56(84) bytes of data.

--- 192.168.200.3 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

我還在想到底為什麼 ...

問題解決 2014/07/04

找到原因了,一個很蠢的原因 ... 那就是我沒把 blue 上面的 lo 給叫起來。只要透過下面的指令就沒問題了: 


$ sudo ip netns exec blue ifconfig lo up
$ sudo ip netns exec blue ping 192.168.200.3 -c 1
PING 192.168.200.2 (192.168.200.2) 56(84) bytes of data.
64 bytes from 192.168.200.2: icmp_seq=1 ttl=64 time=0.039 ms

--- 192.168.200.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.039/0.039/0.039/0.000 ms

留言

這個網誌中的熱門文章

我弟家的新居感恩禮拜分享:善頌善禱

Openssl 範例程式:建立SSL連線

如何利用 Wireshark 來監聽 IEEE 802.11 的管理封包