在 Ubuntu 和 Raspbian 中使用网络命名空间时 ifup、ifdown 接口状态错误

在 Ubuntu 和 Raspbian 中使用网络命名空间时 ifup、ifdown 接口状态错误

我用,创建了几个网络命名空间ip netns add ns1ip netns add ns2

当我尝试启动/停止网络命名空间内的网络接口时,ifup接口ifdown状态错误:

$ ifup lo
ifup: interface lo already configured

我相信这是因为 /run/network/ 是保存状态的位置ifupifdown并且在按上述方式创建时,它在默认网络命名空间和附加网络命名空间之间共享。我这么认为是因为当我在网络命名空间内创建 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没有被ifuped 过。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

好的,现在在第二个命名空间上执行相同的向上/向下/向上操作,会导致错误

$ 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 在第二个命名空间中停止,但在第一个命名空间中报告为关闭。

不幸的是,这适用于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

我对创建网络命名空间的不同方法持开放态度。我只需要某种跟踪事物的方法,以便我可以在不同的时间点在正确的命名空间中启动多个程序。

答案1

问题是ip netns add只创建了一个持久网络命名空间,ip netns exec ...进入持久网络命名空间的同时还创建了一个临时挂载命名空间。还有一个问题直接问到了这个问题,所以我在那里更详细地回答了它。https://unix.stackexchange.com/a/581618/142686

我的解决方案是使用 来创建持久的网络和挂载命名空间unshare。然后挂载tmpfs/run/network命名空间内部。这为命名空间提供了一个单独的副本以ifupifdown使用。

主要的含义是,至少在安装重要的地方,而不是现在必须使用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 link”仍然有效。

缺点是您无法获得/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/

相关内容