1. 程式人生 > 其它 >Linux之29—— ip netns 命令

Linux之29—— ip netns 命令

ip netns 命令用來管理 network namespace。它可以建立命名的 network namespace,然後通過名字來引用 network namespace,所以使用起來很方便。

ip netns 命令格式如下:
ip [ OPTIONS ] netns { COMMAND | help }

可以通過 help 命令檢視 ip netns 所有操作的幫助資訊:

network namespace

network namespace 在邏輯上是網路堆疊的一個副本,它有自己的路由、防火牆規則和網路裝置。
預設情況下,子程序繼承其父程序的 network namespace。也就是說,如果不顯式建立新的 network namespace,所有程序都從 init 程序繼承相同的預設 network namespace。


根據約定,命名的 network namespace 是可以開啟的 /var/run/netns/ 目錄下的一個物件。比如有一個名稱為 net1 的 network namespace 物件,則可以由開啟 /var/run/netns/net1 物件產生的檔案描述符引用 network namespace net1。通過引用該檔案描述符,可以修改程序的 network namespace。

顯示所有命名的 network namespace

ip netns list 命令顯示所有命名的 network namesapce,其實就是顯示 /var/run/netns 目錄下的所有 network namespace 物件:

建立命名的 network namespace

ip netns add NAME 命令建立一個命名的 network namespace:

刪除命名的 network namespace

ip [-all] netns del [ NAME ] 命令刪除指定名稱的 network namespace。如果指定了 -all 選項,則嘗試刪除所有的 network namespace。

注意,如果我們把網絡卡設定到了某個 network namespace 中,並在該 network namespace 中啟動了程序:

$ sudo ip netns add net0
$ sudo ip link set dev eth0 netns net0
$ 
sudo ip netns exec net0 bash

在另一個 bash 程序中刪除 network namespace net0:

$ sudo ip netns del net0

此時雖然可以刪除 netowrk namespace,但是在程序退出之前,網絡卡一直會保持在你已經刪除了的那個 network namespace 中。

檢視程序的 network namespace

ip netns identify [PID] 命令用來檢視程序的 network namespace。如果不指定 PID 就顯示當前程序的 network namespace:

下面的命令指定了 PID:

檢視 network namespace 中程序的 PID

ip netns pids NAME 命令用來檢視指定的 network namespace 中的程序的 PID。這個命令其實就是去檢查 /proc 下的所有程序,看程序的 network namespace 是不是指定的 network namespace:

在指定的 network namespace 中執行命令

ip [-all] netns exec [ NAME ] cmd 命令用來在指定的 network namespace 中執行命令。比如我們要看一下某個 network namespace 中有哪些網絡卡:

ip netns exec 後面跟著 namespace 的名字,比如這裡的 neta,然後是要執行的命令,只要是合法的 shell 命令都能執行,比如上面的 ip addr 或者 bash。
更棒的是,執行的可以是任何命令,不只是和網路相關的(當然,和網路無關命令執行的結果和在外部執行沒有區別)。比如下面例子中,執行 bash 命令之後,後面所有的命令都是在這個 network namespace 中執行的,好處是不用每次執行命令都要把 ip netns exec NAME 補全,缺點是你無法清楚知道自己當前所在的 shell,容易混淆:

通過 -all 引數我們可以同時在所有的 network namespace 執行命令:

輸出中的 netns: 指示在某個 network namespace 中執行的結果。

監控對 network namespace 的操作

ip netns monitor 命令用來監控對 network namespace 的操作。比如我們刪除一個 network namespace 時就會收到相應的通知:

理解 ip netns add 命令

我們通過下面的演示來理解 ip netns add 命令的本質。
檢視預設 network namespace 的 ID:

$ readlink /proc/$$/ns/net

在 /var/run/netns 目錄下建立一個用於繫結 network namespace 的檔案,名為 mynet:

$ sudo mkdir -p /var/run/netns
$ sudo touch /var/run/netns/mynet

通過 unshare 命令建立新的 network namespace,並在新的 namespace 中啟動新的 bash:

$ sudo unshare --net bash

檢視新的 network namespace ID:

# readlink /proc/$$/ns/net

通過繫結掛載把當前 bash 程序的 network namespace 檔案掛載到前面建立的 mynet 檔案上:

# mount --bind /proc/$$/ns/net /var/run/netns/mynet
# ls -I /var/run/netns/mynet

通過 ls -I 命令可以看到檔案 mynet 的 inode 號和 network namespace 的 ID 相同,說明繫結成功:

退出新建立的 bash,再檢查一次 mynet 檔案的 inode:

# exit
$ ls -I /var/run/netns/mynet

可以看出 mynet 檔案的 inode 沒有發生變化,說明我們使用了繫結掛載後,雖然新的 network namespace 中已經沒有程序了,但這個新的 network namespace 還繼續存在。

上面的一系列操作其實等同於執行了命令:sudo ip netns add mynet
下面的 nsenter 命令則等同於執行了命令: sudo ip netns exec mynet bash

$ sudo nsenter --net=/var/run/netns/mynet bash
# readlink /proc/$$/ns/net

通過 nsenter 命令新建了一個 bash 程序,並把它加入 mynet 所關聯的 network namespace(net:[4026532616])。

從上面的示例可以看出,建立命名的 network namespace 其實就是建立一個檔案,然後通過繫結掛載的方式將新建立的 network namespace 檔案(/proc/$$/ns/net)和該檔案繫結,就算該 network namespace 裡的所有程序都退出了,核心還是會保留該 network namespace,以後我們還可以通過這個繫結的檔案來加入該 network namespace。

參考:
ip netns man page
Linux Namespace系列(06):network namespace