Linux

ifup, ifdown 在 Ubuntu 和 Raspbian 中使用網路命名空間時獲取介面狀態錯誤

  • April 21, 2020

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介面、網橋、關聯iptablessysctl設置,所以我真的希望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 execnsenter

為持久掛載命名空間創建目錄

這需要在啟動後執行一次,而不是針對每個命名空間

# 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 execuse nsenter --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/

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