切换到网络命名空间不会改变 /sys/class/net?

The*_*veO 7 linux namespace network-namespaces

网络命名空间(7)的 Linux 手册页说:

网络命名空间提供与网络相关的系统资源的隔离:[...]、/sys/class/net 目录、[...]。

但是,简单地切换到不同的网络命名空间似乎不会改变/sys/class/net(有关如何重现,请参见下文)的内容。我只是误以为setns()进入网络命名空间已经足够了吗?是否总是需要重新挂载/sys才能正确/sys/class/net匹配当前加入的网络命名空间?还是我在这里错过了其他东西?

再现示例

拿一个*ubuntu系统,找到rtkit-daemon的PID,进入daemon的网络命名空间,显示它的网络接口,然后检查/sys/class/net

$ PID=`sudo lsns -t net -n -o PID,COMMAND | grep rtkit-daemon | cut -d ' ' -f 2`
$ sudo nsenter -t $PID -n
# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# ls /sys/class/net
docker0  enp3s0  lo  lxcbr0  ...
Run Code Online (Sandbox Code Playgroud)

请注意,虽然ip link show正确仅显示lo,但会/sys/class/net显示“根”网络命名空间(和“根”挂载命名空间)中可见的所有网络接口。

rtkit-daemon也输入它的挂载命名空间的情况下,没有任何区别:sudo nsenter -t $PID -n -m然后ls /sys/class/net仍然显示网络命名空间中不存在的网络接口。

“使固定”

许多荣誉给@Danila Kiver解释什么是真正的Linux内核幕后去。sysfs 加入正确的网络命名空间时重新挂载将显示正确的条目/sys/class/net

$ PID=`sudo lsns -t net -n -o PID,COMMAND | grep rtkit-daemon | cut -d ' ' -f 2`
$ sudo nsenter -t $PID -n
# MNT=`mktemp -d`
# mount -t sysfs none $MNT
# ls $MNT/class/net/
lo
# umount $MNT
# rmdir $MNT
# exit
Run Code Online (Sandbox Code Playgroud)

所以这现在产生了正确的结果/sys/class/net

Dan*_*ver 8

让我们来看看man 5 sysfs

/sys/class/net
    Each  of the entries in this directory is a symbolic link representing
    one of the real or virtual networking devices that are visible in 
    the network namespace of the process that is accessing the directory.
Run Code Online (Sandbox Code Playgroud)

因此,根据此联机帮助页, 的输出ls /sys/class/net必须取决于ls进程的网络命名空间。但是...实际行为似乎与本联机帮助页中的描述不同。有一个很好的内核文档说明它是如何工作的

每个sysfs挂载都有一个与之关联的命名空间标记。这个标签在 sysfs 被挂载时设置,并且取决于调用进程的网络命名空间。每个 sysfs 条目(例如 中的条目/sys/class/net)也可能有一个与之关联的命名空间标记

当您遍历 sysfs 目录时,内核获取sysfs mount命名空间标记,然后它遍历条目,过滤掉那些具有不同命名空间标记的条目。

因此,事实证明,迭代的结果/sys/class/net取决于发起/sys挂载的进程的网络命名空间,而不是当前进程的网络命名空间,因此,您必须始终挂载/sys在当前网络命名空间中(来自任何属于到此命名空间)以查看正确的结果。