网络命名空间 (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 ...
请注意,虽然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
所以这现在产生了正确的结果/sys/class/net
。
让我们看看
man 5 sysfs
:所以,根据这个手册页, 的输出
ls /sys/class/net
必须依赖于ls
进程的网络命名空间。但是...实际行为似乎与本手册中的描述不同。关于它是如何工作的,有一个很好的内核文档。每个
sysfs
挂载都有一个与之关联的命名空间标签。这个标签是在 sysfs 被挂载时设置的,它依赖于调用进程的网络命名空间。每个 sysfs 条目(例如 中的条目/sys/class/net
)也可能具有与其关联的名称空间标记。当您遍历 sysfs 目录时,内核会获取sysfs mount 的命名空间标签,然后它会遍历条目,过滤掉具有不同命名空间标签的条目。
因此,事实证明,迭代的结果
/sys/class/net
取决于启动/sys
挂载的进程的网络命名空间,而不是当前进程的网络命名空间,因此,您必须始终挂载/sys
在当前的网络命名空间中(来自任何属于到此命名空间)以查看正确的结果。