summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/can/dev.c2
-rw-r--r--drivers/net/macvlan.c4
-rw-r--r--drivers/net/veth.c15
-rw-r--r--include/net/rtnetlink.h8
-rw-r--r--net/8021q/vlan_netlink.c4
-rw-r--r--net/core/rtnetlink.c38
-rw-r--r--net/ipv4/ip_gre.c2
7 files changed, 50 insertions, 23 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index c3db111d2ff..5fe34d64ca2 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -674,7 +674,7 @@ nla_put_failure:
return -EMSGSIZE;
}
-static int can_newlink(struct net_device *dev,
+static int can_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
return -EOPNOTSUPP;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 20b7707f38e..d7dba3f6f76 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -504,7 +504,7 @@ static int macvlan_get_tx_queues(struct net *net,
return 0;
}
-static int macvlan_newlink(struct net_device *dev,
+static int macvlan_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct macvlan_dev *vlan = netdev_priv(dev);
@@ -515,7 +515,7 @@ static int macvlan_newlink(struct net_device *dev,
if (!tb[IFLA_LINK])
return -EINVAL;
- lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK]));
+ lowerdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
if (lowerdev == NULL)
return -ENODEV;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 9bed694cd21..2d657f2314c 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -340,7 +340,7 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
static struct rtnl_link_ops veth_link_ops;
-static int veth_newlink(struct net_device *dev,
+static int veth_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
int err;
@@ -348,6 +348,7 @@ static int veth_newlink(struct net_device *dev,
struct veth_priv *priv;
char ifname[IFNAMSIZ];
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+ struct net *net;
/*
* create and register peer first
@@ -380,14 +381,22 @@ static int veth_newlink(struct net_device *dev,
else
snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
- peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp);
- if (IS_ERR(peer))
+ net = rtnl_link_get_net(src_net, tbp);
+ if (IS_ERR(net))
+ return PTR_ERR(net);
+
+ peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp);
+ if (IS_ERR(peer)) {
+ put_net(net);
return PTR_ERR(peer);
+ }
if (tbp[IFLA_ADDRESS] == NULL)
random_ether_addr(peer->dev_addr);
err = register_netdevice(peer);
+ put_net(net);
+ net = NULL;
if (err < 0)
goto err_register_peer;
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index cd5af1f508f..48d3efcb088 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -55,7 +55,8 @@ struct rtnl_link_ops {
int (*validate)(struct nlattr *tb[],
struct nlattr *data[]);
- int (*newlink)(struct net_device *dev,
+ int (*newlink)(struct net *src_net,
+ struct net_device *dev,
struct nlattr *tb[],
struct nlattr *data[]);
int (*changelink)(struct net_device *dev,
@@ -83,8 +84,9 @@ extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops);
extern int rtnl_link_register(struct rtnl_link_ops *ops);
extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
-extern struct net_device *rtnl_create_link(struct net *net, char *ifname,
- const struct rtnl_link_ops *ops, struct nlattr *tb[]);
+extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]);
+extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
+ char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]);
extern const struct nla_policy ifla_policy[IFLA_MAX+1];
#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index a9150485019..3c9cf6a8e7f 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -119,7 +119,7 @@ static int vlan_get_tx_queues(struct net *net,
return 0;
}
-static int vlan_newlink(struct net_device *dev,
+static int vlan_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct vlan_dev_info *vlan = vlan_dev_info(dev);
@@ -131,7 +131,7 @@ static int vlan_newlink(struct net_device *dev,
if (!tb[IFLA_LINK])
return -EINVAL;
- real_dev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK]));
+ real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
if (!real_dev)
return -ENODEV;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e2f3317f290..33148a56819 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -733,6 +733,20 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
[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[])
{
if (dev) {
@@ -756,8 +770,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
int err;
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)) {
err = PTR_ERR(net);
goto errout;
@@ -976,8 +989,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
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;
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;
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);
if (err)
goto err;
@@ -995,16 +1008,16 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
if (!dev)
goto err;
+ dev_net_set(dev, net);
+ dev->rtnl_link_ops = ops;
dev->real_num_tx_queues = real_num_queues;
+
if (strchr(dev->name, '%')) {
err = dev_alloc_name(dev, dev->name);
if (err < 0)
goto err_free;
}
- dev_net_set(dev, net);
- dev->rtnl_link_ops = ops;
-
if (tb[IFLA_MTU])
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
if (tb[IFLA_ADDRESS])
@@ -1083,6 +1096,7 @@ replay:
if (1) {
struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
+ struct net *dest_net;
if (ops) {
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
@@ -1147,17 +1161,19 @@ replay:
if (!ifname[0])
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))
err = PTR_ERR(dev);
else if (ops->newlink)
- err = ops->newlink(dev, tb, data);
+ err = ops->newlink(net, dev, tb, data);
else
err = register_netdevice(dev);
-
if (err < 0 && !IS_ERR(dev))
free_netdev(dev);
+
+ put_net(dest_net);
return err;
}
}
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 71a3242fb7d..a7de9e3a8f1 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1483,7 +1483,7 @@ static void ipgre_tap_setup(struct net_device *dev)
dev->features |= NETIF_F_NETNS_LOCAL;
}
-static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
+static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
struct ip_tunnel *nt;