ip netns 命令用來管理 network namespace。它能夠建立命名的 network namespace,而後經過名字來引用 network namespace,因此使用起來很方便。html
ip netns 命令格式以下:
ip [ OPTIONS ] netns { COMMAND | help }node
能夠經過 help 命令查看 ip netns 全部操做的幫助信息:linux
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。shell
ip netns list 命令顯示全部命名的 network namesapce,其實就是顯示 /var/run/netns 目錄下的全部 network namespace 對象:segmentfault
ip netns add NAME 命令建立一個命名的 network namespace:bash
ip [-all] netns del [ NAME ] 命令刪除指定名稱的 network namespace。若是指定了 -all 選項,則嘗試刪除全部的 network namespace。網絡
注意,若是咱們把網卡設置到了某個 network namespace 中,並在該 network namespace 中啓動了進程:ide
$ sudo ip netns add net0 $ sudo ip link set dev eth0 netns net0 $ sudo ip netns exec net0 bash
在另外一個 bash 進程中刪除 network namespace net0:spa
$ sudo ip netns del net0
此時雖然能夠刪除 netowrk namespace,可是在進程退出以前,網卡一直會保持在你已經刪除了的那個 network namespace 中。3d
ip netns identify [PID] 命令用來查看進程的 network namespace。若是不指定 PID 就顯示當前進程的 network namespace:
下面的命令指定了 PID:
ip netns pids NAME 命令用來查看指定的 network namespace 中的進程的 PID。這個命令其實就是去檢查 /proc 下的全部進程,看進程的 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 中執行的結果。
ip netns monitor 命令用來監控對 network namespace 的操做。好比咱們刪除一個 network namespace 時就會收到相應的通知:
咱們經過下面的演示來理解 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。