|
@@ -733,6 +733,20 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
|
|
[IFLA_INFO_DATA] = { .type = NLA_NESTED },
|
|
[IFLA_INFO_DATA] = { .type = NLA_NESTED },
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
|
|
|
+{
|
|
|
|
+ struct net *net;
|
|
|
|
+ /* Examine the link attributes and figure out which
|
|
|
|
+ * network namespace we are talking about.
|
|
|
|
+ */
|
|
|
|
+ if (tb[IFLA_NET_NS_PID])
|
|
|
|
+ net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
|
|
|
|
+ else
|
|
|
|
+ net = get_net(src_net);
|
|
|
|
+ return net;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(rtnl_link_get_net);
|
|
|
|
+
|
|
static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
|
|
static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
|
|
{
|
|
{
|
|
if (dev) {
|
|
if (dev) {
|
|
@@ -756,8 +770,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
|
int err;
|
|
int err;
|
|
|
|
|
|
if (tb[IFLA_NET_NS_PID]) {
|
|
if (tb[IFLA_NET_NS_PID]) {
|
|
- struct net *net;
|
|
|
|
- net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
|
|
|
|
|
|
+ struct net *net = rtnl_link_get_net(dev_net(dev), tb);
|
|
if (IS_ERR(net)) {
|
|
if (IS_ERR(net)) {
|
|
err = PTR_ERR(net);
|
|
err = PTR_ERR(net);
|
|
goto errout;
|
|
goto errout;
|
|
@@ -976,8 +989,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-struct net_device *rtnl_create_link(struct net *net, char *ifname,
|
|
|
|
- const struct rtnl_link_ops *ops, struct nlattr *tb[])
|
|
|
|
|
|
+struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
|
|
|
|
+ char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[])
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
@@ -985,7 +998,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
|
|
unsigned int real_num_queues = 1;
|
|
unsigned int real_num_queues = 1;
|
|
|
|
|
|
if (ops->get_tx_queues) {
|
|
if (ops->get_tx_queues) {
|
|
- err = ops->get_tx_queues(net, tb, &num_queues,
|
|
|
|
|
|
+ err = ops->get_tx_queues(src_net, tb, &num_queues,
|
|
&real_num_queues);
|
|
&real_num_queues);
|
|
if (err)
|
|
if (err)
|
|
goto err;
|
|
goto err;
|
|
@@ -995,16 +1008,16 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
|
|
if (!dev)
|
|
if (!dev)
|
|
goto err;
|
|
goto err;
|
|
|
|
|
|
|
|
+ dev_net_set(dev, net);
|
|
|
|
+ dev->rtnl_link_ops = ops;
|
|
dev->real_num_tx_queues = real_num_queues;
|
|
dev->real_num_tx_queues = real_num_queues;
|
|
|
|
+
|
|
if (strchr(dev->name, '%')) {
|
|
if (strchr(dev->name, '%')) {
|
|
err = dev_alloc_name(dev, dev->name);
|
|
err = dev_alloc_name(dev, dev->name);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
goto err_free;
|
|
goto err_free;
|
|
}
|
|
}
|
|
|
|
|
|
- dev_net_set(dev, net);
|
|
|
|
- dev->rtnl_link_ops = ops;
|
|
|
|
-
|
|
|
|
if (tb[IFLA_MTU])
|
|
if (tb[IFLA_MTU])
|
|
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
|
|
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
|
|
if (tb[IFLA_ADDRESS])
|
|
if (tb[IFLA_ADDRESS])
|
|
@@ -1083,6 +1096,7 @@ replay:
|
|
|
|
|
|
if (1) {
|
|
if (1) {
|
|
struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
|
|
struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
|
|
|
|
+ struct net *dest_net;
|
|
|
|
|
|
if (ops) {
|
|
if (ops) {
|
|
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
|
|
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
|
|
@@ -1147,17 +1161,19 @@ replay:
|
|
if (!ifname[0])
|
|
if (!ifname[0])
|
|
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
|
|
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
|
|
|
|
|
|
- dev = rtnl_create_link(net, ifname, ops, tb);
|
|
|
|
|
|
+ dest_net = rtnl_link_get_net(net, tb);
|
|
|
|
+ dev = rtnl_create_link(net, dest_net, ifname, ops, tb);
|
|
|
|
|
|
if (IS_ERR(dev))
|
|
if (IS_ERR(dev))
|
|
err = PTR_ERR(dev);
|
|
err = PTR_ERR(dev);
|
|
else if (ops->newlink)
|
|
else if (ops->newlink)
|
|
- err = ops->newlink(dev, tb, data);
|
|
|
|
|
|
+ err = ops->newlink(net, dev, tb, data);
|
|
else
|
|
else
|
|
err = register_netdevice(dev);
|
|
err = register_netdevice(dev);
|
|
-
|
|
|
|
if (err < 0 && !IS_ERR(dev))
|
|
if (err < 0 && !IS_ERR(dev))
|
|
free_netdev(dev);
|
|
free_netdev(dev);
|
|
|
|
+
|
|
|
|
+ put_net(dest_net);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
}
|