Linux

如何為現有的匿名網路命名空間分配名稱

  • April 19, 2021

我有一個 Linux 程序,它創建一個網路命名空間,而不在 /run/netns 中註冊它。該程序也有自己的 PID 命名空間。網路命名空間沒有名稱,我只能看到命名空間的 id:

# ip netns list-id
nsid 0
nsid 1

是否有可能為網路命名空間分配一個名稱,以便我可以使用方便的 ip-netns 命令來顯示和管理命名空間?

我找到了一篇文章如何訪問未命名的網路命名空間,但它對我不起作用,因為我的程序有自己的 PID 命名空間,所以我看不到根命名空間中的程序。

在命名空間的低級處理中不存在實際名稱。這一切都由iproute2套件中的每個命令完成的常見操作或期望處理。

為現有的匿名網路命名空間分配名稱實際上意味著:讓iproute2工具相信它們在創建此網路命名空間時進行了通常的設置。

那麼ip netns add foo真正在做什麼呢?它取消共享到一個新的網路命名空間,並且為了保持這個命名空間存在,即使沒有程序使用它,掛載它。在通常的 nix 哲學中,命名空間有一個inode編號,表示偽文件系統nsfs*中的偽文件。幾乎不能對文件進行任何操作(甚至不能讀取它),但可以打開它以將其用作命名空間操作的標記(例如setns(2)),也可以作為綁定掛載進行掛載。

唉,連結 nsid 不能直接使用:它不是代表另一個命名空間的全域值,而是代表到另一個命名空間的連結的**本地(本地唯一但可回收且不是全域唯一)ID 。多個值意味著:連結到多個其他命名空間,兩次相同的值意味著:兩個連結到相同的其他命名空間。

如果您必須從這裡開始找到其他命名空間,我邀請您在另一個 Q/A中檢查我的答案,我對此做出了回答。還有一個方便的映射工具可用:plotnetcfg它可以映射所有的網路命名空間。雖然它確實知道iproute2方法,但它似乎沒有單獨給出程序 ID,而是在**iproute2沒有“命名”時使用它命名一個帶有 PID 的命名空間。編輯範例(需要jq),以root身份執行:

# unshare -n -- sleep 999 &
[1] 677451
#  plotnetcfg -f json | jq '.namespaces[].name'
""
[...]
"PID 268150 (systemd)"
"PID 345878 (systemd)"
[...]
"PID 677451 (sleep)"

這裡""表示初始命名空間,兩個systemd來自兩個LXC實例,sleep同時找到執行的命令。

幫助解決兩種常見情況:

  • 對於 LXC:
lxc-info -H -p -n containername
  • 對於 Docker:
docker inspect --format '{{.State.Pid}}' containername

一旦您通過任何可用的方法在預期的網路名稱空間中找到了一個程序,您就可以模仿iproute2工具的作用。他們究竟做了什麼可能取決於他們的確切版本。從strace我的看來是這樣做的:

mkdir -p /run/netns

然後將其安裝在自身之上,以便將其設置為共享傳播:

mount --bind --make-shared /run/netns /run/netns

以上只應在尚未完成且僅一次的情況下完成。要讓工具為您執行此操作(並且僅在需要時),只需創建和刪除一個虛擬命名空間:

ip netns add dummy && ip netns delete dummy

現在選擇一個名稱,例如foo,創建一個空文件並將其模式更改為 000(這不是必需的,但模仿iproute2):

touch /run/netns/foo
chmod 0 /run/netns/foo

最後在給定 PID 的情況下掛載程序的命名空間(例如sleep從之前:677451):

mount --bind /proc/677451/ns/net /run/netns/foo

而已。即使sleep命令結束,命名空間現在仍然存在。所有iproute2工具現在都將其命名為foo。例如,如果有一個veth介面連接到它,ip link則將連結 nsid 的編號替換為foo.

如果你想刪除這個網路命名空間,ip netns del foo現在就這樣做(警告:像往常一樣,一旦沒有資源使用它,實際的網路命名空間就會真正消失,就像這個 sleep 命令一樣)。

在我的另一個答案中,有關iproute2沿網路名稱空間的特定附加功能的進一步文件。

引用自:https://unix.stackexchange.com/questions/633919