ifup, ifdown 在 Ubuntu 和 Raspbian 中使用網路命名空間時獲取介面狀態錯誤
ip netns add ns1
我用,創建了幾個網路命名空間ip netns add ns1
。當我嘗試在網路命名空間中啟動/停止網路介面
ifup
並且ifdown
介面狀態錯誤時:$ ifup lo ifup: interface lo already configured
我相信這是因為 /run/network/ 是保持狀態的位置,
ifup
並且ifdown
在按上述方式創建時在預設和其他網路命名空間之間共享。我是這麼認為的,因為當我在網路命名空間中創建 veth 介面時,相應的條目會出現在 /run/network 的主空間中。這個問題也適用於lo
介面。我在 Ubuntu-12-LTS 和 2020-02-13-raspbian-buster-lite 中看到了同樣的問題。我有一個模糊的記憶,不久前處理過類似
CentOS-7.4
的症狀,只是沒有調查它的原因。為了展示(在 Raspbian 上),我在每個網路命名空間中創建並 ifup/ifdown 一個橋接器,並在預設空間中檢查 /run/network/ 的內容。
設置
$ echo 'iface br2 inet manual' > /etc/network/interfaces.d/br2 $ ip netns add ns1 $ ip netns add ns2 $ ip netns exec ns1 ip link add br2 type bridge $ ip netns exec ns2 ip link add br2 type bridge
檢查
br2
狀態不存在$ cat /run/network/ifstate.br2 cat: /run/network/ifstate.br2: No such file or directory
很好,在任何命名空間中
br2
都沒有被ifup
編輯過。ifdown
在第一個命名空間上啟動/關閉/啟動介面$ ip netns exec ns1 ifup br2 $ cat /run/network/ifstate.br2 br2 $ ip netns exec ns1 ifdown br2 $ cat /run/network/ifstate.br2 $ ip netns exec ns1 ifup br2 $ cat /run/network/ifstate.br2 br2
好的,現在在第二個命名空間上執行相同的 up/down/up,導致錯誤
$ ip netns exec ns2 ifup br2 ifup: interface br2 already configured $ cat /run/network/ifstate.br2 br2
就是上面這個問題!通過第二個命名空間停止介面(注意它是通過第一個命名空間啟動的)
$ ip netns exec ns2 ifdown br2 $ cat /run/network/ifstate.br2
現在回到第一個命名空間
$ ip netns exec ns1 ifdown br2 ifdown: interface br2 not configured $ cat /run/network/ifstate.br2
上面是類似的問題,介面 wad 在第 2 個命名空間停止,但在第 1 個被報告為關閉。
不幸的是,這適用於
lo
因此不可能通過簡單地在每個命名空間內具有唯一名稱來避免它。我只需要保持使用“上/下/上”的循環界面來解決這個問題。我希望有一種更清潔的方法來做到這一點。**我的案例和目標:**我創建了多個與上面的測試類似的相同命名空間,僅包裝到 systemd 實例化服務單元中,啟動它們的介面(必須向上/向下/向上來解決問題)。在不同的時間,我在每個命名空間內啟動程序,
ip netns exec nsX prog args
通常也由其他 systemd 服務啟動。一段時間後,我拆除了某些命名空間,我需要小心地執行此操作。我需要ifdown
正確地完成它的工作,因為它會收拾東西。網路很重要,有幾個veth
介面、網橋、關聯iptables
和sysctl
設置,所以我真的希望ifup
並且ifdown
工作得很好,並且不會被其他命名空間的狀態所迷惑。例如ifdown
刪除veth
介面。當然解決方法是可能的,但它很快就會變得笨拙/骯髒。我覺得我需要以
/run/network
某種方式將 tmpfs 掛載到網路名稱空間內,但我不知道如何。ip netns exec
綁定似乎只在程序執行期間安裝了一些東西,而不是永久附加到網路命名空間本身。如果我在設置呼叫期間綁定掛載ip netns exec ns1 ifup ...
,它將退出並且稍後在我需要時不可用.... ifdown
。我對創建網路命名空間的不同方法持開放態度。我只需要一些跟踪事物的方法,這樣我就可以在不同的時間點在正確的命名空間中啟動多個程序。
問題是只
ip netns add
創建了持久化網路命名空間,ip netns exec ...
進入持久化網路命名空間的同時還創建了臨時掛載命名空間。還有另一個問題直接詢問這個問題,所以我在那裡更詳細地回答了它。https://unix.stackexchange.com/a/581618/142686我的解決方案是使用
unshare
.tmpfs
然後在命名空間內掛載/run/network
。這為命名空間提供了一個單獨的副本以供ifup
使用ifdown
。主要含義是,至少在無論如何安裝很重要的地方,而不是現在必須使用
ip netns exec
。nsenter
為持久掛載命名空間創建目錄
這需要在啟動後執行一次,而不是針對每個命名空間
# Create a dir for persistent mount namespaces $ mkdir /run/mntns # Bind mount it with --make-private as required by `unshare --mount=/path` $ mount --bind --make-private /run/mntns /run/mntns
創建網路+掛載持久命名空間
$ NSNAME=testns # give it a name # Create files for persistent mounts. # For network namespace use same paths as used by `ip netns` for interoperability $ touch /run/netns/${NSNAME} /run/mntns/${NSNAME} # Create persistent mount and network namespaces and # as part of the setup the command (inside the namespace) adds a mount. $ unshare --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \ mount -t tmpfs tmpfs /run/network
用它
# Bring up the loopback interface, this used to fail. $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \ ifup lo # Good.
更多測試
現在重要的部分。將網路介面移動到命名空間中。這裡使用
ip
很好。# Plug a veth interface into the namespace, use the `ip netns link` $ ip link add veth1a type veth peer name veth1b netns ${NSNAME} # Verify it is there (although here `ip netns exec` would work just as well) $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \ ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: veth1b@if17: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether e6:1b:ea:e5:77:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 0
重要的
這種方法有效,但不是使用
ip netns exec
usensenter --net=... --mount=...
!為了使用“ip 連結”在命名空間之間移動介面仍然有效。
缺點是您沒有獲得由
/etc/netns/NETNS_NAME/*
提供的自動綁定安裝,ip netns exec NETNS_NAME cmd
手動添加並不難。# either during unshare or later as nsenter. # The important difference is here it is done once and result persists # unlike with `ip netns exec` which does this every time NSNAME="${NSNAME}" \ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \ /bin/sh -e -x -c \ 'cd "/etc/netns/${NSNAME}"; for f in *; do mount --bind "/etc/netns/${NSNAME}/${f}" "/etc/${f}"; done;'
好處是您可以一次完成一致的安裝,而不是每次呼叫之間
ip netns exec
的內容髮生變化時都會發生變化。/etc/netns/NETNS_NAME/