*/
if (!net_eq(dev_net(ndev), dev_net(vf_netdev))) {
ret = dev_change_net_namespace(vf_netdev,
- dev_net(ndev), "eth%d");
+ dev_net(ndev), "eth%d", 0);
if (ret)
netdev_err(vf_netdev,
"could not move to same namespace as %s: %d\n",
int dev_change_name(struct net_device *, const char *);
int dev_set_alias(struct net_device *, const char *, size_t);
int dev_get_alias(const struct net_device *, char *, size_t);
-int dev_change_net_namespace(struct net_device *, struct net *, const char *);
+int dev_change_net_namespace(struct net_device *dev, struct net *net,
+ const char *pat, int new_ifindex);
int __dev_set_mtu(struct net_device *, int);
int dev_validate_mtu(struct net_device *dev, int mtu,
struct netlink_ext_ack *extack);
* @net: network namespace
* @pat: If not NULL name pattern to try if the current device name
* is already taken in the destination network namespace.
+ * @new_ifindex: If not zero, specifies device index in the target
+ * namespace.
*
* This function shuts down a device interface and moves it
* to a new network namespace. On success 0 is returned, on
* Callers must hold the rtnl semaphore.
*/
-int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat)
+int dev_change_net_namespace(struct net_device *dev, struct net *net,
+ const char *pat, int new_ifindex)
{
struct net *net_old = dev_net(dev);
- int err, new_nsid, new_ifindex;
+ int err, new_nsid;
ASSERT_RTNL();
goto out;
}
+ /* Check that new_ifindex isn't used yet. */
+ err = -EBUSY;
+ if (new_ifindex && __dev_get_by_index(net, new_ifindex))
+ goto out;
+
/*
* And now a mini version of register_netdevice unregister_netdevice.
*/
new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);
/* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex))
- new_ifindex = dev_new_index(net);
- else
- new_ifindex = dev->ifindex;
+ if (!new_ifindex) {
+ if (__dev_get_by_index(net, dev->ifindex))
+ new_ifindex = dev_new_index(net);
+ else
+ new_ifindex = dev->ifindex;
+ }
rtmsg_ifinfo_newnet(RTM_DELLINK, dev, ~0U, GFP_KERNEL, &new_nsid,
new_ifindex);
snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
if (__dev_get_by_name(&init_net, fb_name))
snprintf(fb_name, IFNAMSIZ, "dev%%d");
- err = dev_change_net_namespace(dev, &init_net, fb_name);
+ err = dev_change_net_namespace(dev, &init_net, fb_name, 0);
if (err) {
pr_emerg("%s: failed to move %s to init_net: %d\n",
__func__, dev->name, err);
return -EINVAL;
}
+ if (tb[IFLA_NEW_IFINDEX] && nla_get_s32(tb[IFLA_NEW_IFINDEX]) <= 0)
+ return -EINVAL;
+
if (tb[IFLA_AF_SPEC]) {
struct nlattr *af;
int rem, err;
return err;
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) {
- struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev),
- tb, CAP_NET_ADMIN);
+ struct net *net;
+ int new_ifindex;
+
+ net = rtnl_link_get_net_capable(skb, dev_net(dev),
+ tb, CAP_NET_ADMIN);
if (IS_ERR(net)) {
err = PTR_ERR(net);
goto errout;
}
- err = dev_change_net_namespace(dev, net, ifname);
+ if (tb[IFLA_NEW_IFINDEX])
+ new_ifindex = nla_get_s32(tb[IFLA_NEW_IFINDEX]);
+ else
+ new_ifindex = 0;
+
+ err = dev_change_net_namespace(dev, net, ifname, new_ifindex);
put_net(net);
if (err)
goto errout;
if (err < 0)
goto out_unregister;
if (link_net) {
- err = dev_change_net_namespace(dev, dest_net, ifname);
+ err = dev_change_net_namespace(dev, dest_net, ifname, 0);
if (err < 0)
goto out_unregister;
}
if (!wpan_dev->netdev)
continue;
wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
- err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d");
+ err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d", 0);
if (err)
break;
wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL;
continue;
wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wpan_dev->netdev, net,
- "wpan%d");
+ "wpan%d", 0);
WARN_ON(err);
wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL;
}
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
- err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
+ err = dev_change_net_namespace(wdev->netdev, net, "wlan%d", 0);
if (err)
break;
wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net,
- "wlan%d");
+ "wlan%d", 0);
WARN_ON(err);
wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
}