内核中使用函数dev_change_net_namespace来变更接口的网络命名空间。目前从代码来看,变更的时候是一个mini版本的接口设备注销(unregister_netdevice)与注册(register_netdevice)的过程。改变命名空间使用dev_net_set完成。注销与重新注册操作比较简单直接,省去了netdevice的清理工作,相对来说比较安全。
int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat)
{
if (dev->features & NETIF_F_NETNS_LOCAL)
goto out;
/* Actually switch the network namespace */
dev_net_set(dev, net);
}
对于带有NETIF_F_NETNS_LOCAL标志的设备,不允许修改其命名空间。
$ ip netns add guest_net
$ ip link set dev eth0 netns guest_net
$ ip netns exec guest_net ip link
11: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 00:0c:29:0a:3e:24 brd ff:ff:ff:ff:ff:ff
$ ip link show type bridge
4: br_test: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
$ ip link set dev br_test netns guest_net
RTNETLINK answers: Invalid argument
例如对于网桥设备(br_test),在初始化时内核为其加入了NETIF_F_NETNS_LOCAL属性,控制其存在于创建时的命名空间,不允许移动。内核认为诸如回环接口(loopback)、网桥接口、Fallback tunnel等类型的设备都是命名空间本地的设备,改变其命名空间不安全:
void br_dev_setup(struct net_device *dev)
{
dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
内核版本
Linux-4.15