Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: Allow to specify ifindex when device is moved to another namespace

Currently, we can specify ifindex on link creation. This change allows
to specify ifindex when a device is moved to another network namespace.

Even now, a device ifindex can be changed if there is another device
with the same ifindex in the target namespace. So this change doesn't
introduce completely new behavior, it adds more control to the process.

CRIU users want to restore containers with pre-created network devices.
A user will provide network devices and instructions where they have to
be restored, then CRIU will restore network namespaces and move devices
into them. The problem is that devices have to be restored with the same
indexes that they have before C/R.

Cc: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Suggested-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Andrei Vagin <avagin@gmail.com>
Reviewed-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Andrei Vagin and committed by
David S. Miller
eeb85a14 d3295869

+39 -17
+1 -1
drivers/net/hyperv/netvsc_drv.c
··· 2354 2354 */ 2355 2355 if (!net_eq(dev_net(ndev), dev_net(vf_netdev))) { 2356 2356 ret = dev_change_net_namespace(vf_netdev, 2357 - dev_net(ndev), "eth%d"); 2357 + dev_net(ndev), "eth%d", 0); 2358 2358 if (ret) 2359 2359 netdev_err(vf_netdev, 2360 2360 "could not move to same namespace as %s: %d\n",
+2 -1
include/linux/netdevice.h
··· 4026 4026 int dev_change_name(struct net_device *, const char *); 4027 4027 int dev_set_alias(struct net_device *, const char *, size_t); 4028 4028 int dev_get_alias(const struct net_device *, char *, size_t); 4029 - int dev_change_net_namespace(struct net_device *, struct net *, const char *); 4029 + int dev_change_net_namespace(struct net_device *dev, struct net *net, 4030 + const char *pat, int new_ifindex); 4030 4031 int __dev_set_mtu(struct net_device *, int); 4031 4032 int dev_validate_mtu(struct net_device *dev, int mtu, 4032 4033 struct netlink_ext_ack *extack);
+17 -7
net/core/dev.c
··· 11067 11067 * @net: network namespace 11068 11068 * @pat: If not NULL name pattern to try if the current device name 11069 11069 * is already taken in the destination network namespace. 11070 + * @new_ifindex: If not zero, specifies device index in the target 11071 + * namespace. 11070 11072 * 11071 11073 * This function shuts down a device interface and moves it 11072 11074 * to a new network namespace. On success 0 is returned, on ··· 11077 11075 * Callers must hold the rtnl semaphore. 11078 11076 */ 11079 11077 11080 - int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) 11078 + int dev_change_net_namespace(struct net_device *dev, struct net *net, 11079 + const char *pat, int new_ifindex) 11081 11080 { 11082 11081 struct net *net_old = dev_net(dev); 11083 - int err, new_nsid, new_ifindex; 11082 + int err, new_nsid; 11084 11083 11085 11084 ASSERT_RTNL(); 11086 11085 ··· 11112 11109 goto out; 11113 11110 } 11114 11111 11112 + /* Check that new_ifindex isn't used yet. */ 11113 + err = -EBUSY; 11114 + if (new_ifindex && __dev_get_by_index(net, new_ifindex)) 11115 + goto out; 11116 + 11115 11117 /* 11116 11118 * And now a mini version of register_netdevice unregister_netdevice. 11117 11119 */ ··· 11144 11136 11145 11137 new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL); 11146 11138 /* If there is an ifindex conflict assign a new one */ 11147 - if (__dev_get_by_index(net, dev->ifindex)) 11148 - new_ifindex = dev_new_index(net); 11149 - else 11150 - new_ifindex = dev->ifindex; 11139 + if (!new_ifindex) { 11140 + if (__dev_get_by_index(net, dev->ifindex)) 11141 + new_ifindex = dev_new_index(net); 11142 + else 11143 + new_ifindex = dev->ifindex; 11144 + } 11151 11145 11152 11146 rtmsg_ifinfo_newnet(RTM_DELLINK, dev, ~0U, GFP_KERNEL, &new_nsid, 11153 11147 new_ifindex); ··· 11458 11448 snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); 11459 11449 if (__dev_get_by_name(&init_net, fb_name)) 11460 11450 snprintf(fb_name, IFNAMSIZ, "dev%%d"); 11461 - err = dev_change_net_namespace(dev, &init_net, fb_name); 11451 + err = dev_change_net_namespace(dev, &init_net, fb_name, 0); 11462 11452 if (err) { 11463 11453 pr_emerg("%s: failed to move %s to init_net: %d\n", 11464 11454 __func__, dev->name, err);
+15 -4
net/core/rtnetlink.c
··· 2266 2266 return -EINVAL; 2267 2267 } 2268 2268 2269 + if (tb[IFLA_NEW_IFINDEX] && nla_get_s32(tb[IFLA_NEW_IFINDEX]) <= 0) 2270 + return -EINVAL; 2271 + 2269 2272 if (tb[IFLA_AF_SPEC]) { 2270 2273 struct nlattr *af; 2271 2274 int rem, err; ··· 2606 2603 return err; 2607 2604 2608 2605 if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) { 2609 - struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev), 2610 - tb, CAP_NET_ADMIN); 2606 + struct net *net; 2607 + int new_ifindex; 2608 + 2609 + net = rtnl_link_get_net_capable(skb, dev_net(dev), 2610 + tb, CAP_NET_ADMIN); 2611 2611 if (IS_ERR(net)) { 2612 2612 err = PTR_ERR(net); 2613 2613 goto errout; 2614 2614 } 2615 2615 2616 - err = dev_change_net_namespace(dev, net, ifname); 2616 + if (tb[IFLA_NEW_IFINDEX]) 2617 + new_ifindex = nla_get_s32(tb[IFLA_NEW_IFINDEX]); 2618 + else 2619 + new_ifindex = 0; 2620 + 2621 + err = dev_change_net_namespace(dev, net, ifname, new_ifindex); 2617 2622 put_net(net); 2618 2623 if (err) 2619 2624 goto errout; ··· 3463 3452 if (err < 0) 3464 3453 goto out_unregister; 3465 3454 if (link_net) { 3466 - err = dev_change_net_namespace(dev, dest_net, ifname); 3455 + err = dev_change_net_namespace(dev, dest_net, ifname, 0); 3467 3456 if (err < 0) 3468 3457 goto out_unregister; 3469 3458 }
+2 -2
net/ieee802154/core.c
··· 205 205 if (!wpan_dev->netdev) 206 206 continue; 207 207 wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 208 - err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d"); 208 + err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d", 0); 209 209 if (err) 210 210 break; 211 211 wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; ··· 222 222 continue; 223 223 wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 224 224 err = dev_change_net_namespace(wpan_dev->netdev, net, 225 - "wpan%d"); 225 + "wpan%d", 0); 226 226 WARN_ON(err); 227 227 wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; 228 228 }
+2 -2
net/wireless/core.c
··· 165 165 if (!wdev->netdev) 166 166 continue; 167 167 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 168 - err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); 168 + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d", 0); 169 169 if (err) 170 170 break; 171 171 wdev->netdev->features |= NETIF_F_NETNS_LOCAL; ··· 182 182 continue; 183 183 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 184 184 err = dev_change_net_namespace(wdev->netdev, net, 185 - "wlan%d"); 185 + "wlan%d", 0); 186 186 WARN_ON(err); 187 187 wdev->netdev->features |= NETIF_F_NETNS_LOCAL; 188 188 }