diff options
-rw-r--r-- | drivers/net/can/dev.c | 2 | ||||
-rw-r--r-- | drivers/net/macvlan.c | 4 | ||||
-rw-r--r-- | drivers/net/veth.c | 15 | ||||
-rw-r--r-- | include/net/rtnetlink.h | 8 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 4 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 38 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 2 |
7 files changed, 50 insertions, 23 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index c3db111d2ff5..5fe34d64ca2a 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
@@ -674,7 +674,7 @@ nla_put_failure: | |||
674 | return -EMSGSIZE; | 674 | return -EMSGSIZE; |
675 | } | 675 | } |
676 | 676 | ||
677 | static int can_newlink(struct net_device *dev, | 677 | static int can_newlink(struct net *src_net, struct net_device *dev, |
678 | struct nlattr *tb[], struct nlattr *data[]) | 678 | struct nlattr *tb[], struct nlattr *data[]) |
679 | { | 679 | { |
680 | return -EOPNOTSUPP; | 680 | return -EOPNOTSUPP; |
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 20b7707f38ef..d7dba3f6f763 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -504,7 +504,7 @@ static int macvlan_get_tx_queues(struct net *net, | |||
504 | return 0; | 504 | return 0; |
505 | } | 505 | } |
506 | 506 | ||
507 | static int macvlan_newlink(struct net_device *dev, | 507 | static int macvlan_newlink(struct net *src_net, struct net_device *dev, |
508 | struct nlattr *tb[], struct nlattr *data[]) | 508 | struct nlattr *tb[], struct nlattr *data[]) |
509 | { | 509 | { |
510 | struct macvlan_dev *vlan = netdev_priv(dev); | 510 | struct macvlan_dev *vlan = netdev_priv(dev); |
@@ -515,7 +515,7 @@ static int macvlan_newlink(struct net_device *dev, | |||
515 | if (!tb[IFLA_LINK]) | 515 | if (!tb[IFLA_LINK]) |
516 | return -EINVAL; | 516 | return -EINVAL; |
517 | 517 | ||
518 | lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); | 518 | lowerdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); |
519 | if (lowerdev == NULL) | 519 | if (lowerdev == NULL) |
520 | return -ENODEV; | 520 | return -ENODEV; |
521 | 521 | ||
diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 9bed694cd215..2d657f2314cb 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[]) | |||
340 | 340 | ||
341 | static struct rtnl_link_ops veth_link_ops; | 341 | static struct rtnl_link_ops veth_link_ops; |
342 | 342 | ||
343 | static int veth_newlink(struct net_device *dev, | 343 | static int veth_newlink(struct net *src_net, struct net_device *dev, |
344 | struct nlattr *tb[], struct nlattr *data[]) | 344 | struct nlattr *tb[], struct nlattr *data[]) |
345 | { | 345 | { |
346 | int err; | 346 | int err; |
@@ -348,6 +348,7 @@ static int veth_newlink(struct net_device *dev, | |||
348 | struct veth_priv *priv; | 348 | struct veth_priv *priv; |
349 | char ifname[IFNAMSIZ]; | 349 | char ifname[IFNAMSIZ]; |
350 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; | 350 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; |
351 | struct net *net; | ||
351 | 352 | ||
352 | /* | 353 | /* |
353 | * create and register peer first | 354 | * create and register peer first |
@@ -380,14 +381,22 @@ static int veth_newlink(struct net_device *dev, | |||
380 | else | 381 | else |
381 | snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); | 382 | snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); |
382 | 383 | ||
383 | peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp); | 384 | net = rtnl_link_get_net(src_net, tbp); |
384 | if (IS_ERR(peer)) | 385 | if (IS_ERR(net)) |
386 | return PTR_ERR(net); | ||
387 | |||
388 | peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp); | ||
389 | if (IS_ERR(peer)) { | ||
390 | put_net(net); | ||
385 | return PTR_ERR(peer); | 391 | return PTR_ERR(peer); |
392 | } | ||
386 | 393 | ||
387 | if (tbp[IFLA_ADDRESS] == NULL) | 394 | if (tbp[IFLA_ADDRESS] == NULL) |
388 | random_ether_addr(peer->dev_addr); | 395 | random_ether_addr(peer->dev_addr); |
389 | 396 | ||
390 | err = register_netdevice(peer); | 397 | err = register_netdevice(peer); |
398 | put_net(net); | ||
399 | net = NULL; | ||
391 | if (err < 0) | 400 | if (err < 0) |
392 | goto err_register_peer; | 401 | goto err_register_peer; |
393 | 402 | ||
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index cd5af1f508f2..48d3efcb0880 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h | |||
@@ -55,7 +55,8 @@ struct rtnl_link_ops { | |||
55 | int (*validate)(struct nlattr *tb[], | 55 | int (*validate)(struct nlattr *tb[], |
56 | struct nlattr *data[]); | 56 | struct nlattr *data[]); |
57 | 57 | ||
58 | int (*newlink)(struct net_device *dev, | 58 | int (*newlink)(struct net *src_net, |
59 | struct net_device *dev, | ||
59 | struct nlattr *tb[], | 60 | struct nlattr *tb[], |
60 | struct nlattr *data[]); | 61 | struct nlattr *data[]); |
61 | int (*changelink)(struct net_device *dev, | 62 | int (*changelink)(struct net_device *dev, |
@@ -83,8 +84,9 @@ extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops); | |||
83 | extern int rtnl_link_register(struct rtnl_link_ops *ops); | 84 | extern int rtnl_link_register(struct rtnl_link_ops *ops); |
84 | extern void rtnl_link_unregister(struct rtnl_link_ops *ops); | 85 | extern void rtnl_link_unregister(struct rtnl_link_ops *ops); |
85 | 86 | ||
86 | extern struct net_device *rtnl_create_link(struct net *net, char *ifname, | 87 | extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); |
87 | const struct rtnl_link_ops *ops, struct nlattr *tb[]); | 88 | extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net, |
89 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); | ||
88 | extern const struct nla_policy ifla_policy[IFLA_MAX+1]; | 90 | extern const struct nla_policy ifla_policy[IFLA_MAX+1]; |
89 | 91 | ||
90 | #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) | 92 | #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 a91504850195..3c9cf6a8e7fb 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, | |||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | static int vlan_newlink(struct net_device *dev, | 122 | static int vlan_newlink(struct net *src_net, struct net_device *dev, |
123 | struct nlattr *tb[], struct nlattr *data[]) | 123 | struct nlattr *tb[], struct nlattr *data[]) |
124 | { | 124 | { |
125 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 125 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
@@ -131,7 +131,7 @@ static int vlan_newlink(struct net_device *dev, | |||
131 | 131 | ||
132 | if (!tb[IFLA_LINK]) | 132 | if (!tb[IFLA_LINK]) |
133 | return -EINVAL; | 133 | return -EINVAL; |
134 | real_dev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); | 134 | real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); |
135 | if (!real_dev) | 135 | if (!real_dev) |
136 | return -ENODEV; | 136 | return -ENODEV; |
137 | 137 | ||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e2f3317f290f..33148a568199 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] = { | |||
733 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 733 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
734 | }; | 734 | }; |
735 | 735 | ||
736 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | ||
737 | { | ||
738 | struct net *net; | ||
739 | /* Examine the link attributes and figure out which | ||
740 | * network namespace we are talking about. | ||
741 | */ | ||
742 | if (tb[IFLA_NET_NS_PID]) | ||
743 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | ||
744 | else | ||
745 | net = get_net(src_net); | ||
746 | return net; | ||
747 | } | ||
748 | EXPORT_SYMBOL(rtnl_link_get_net); | ||
749 | |||
736 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | 750 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) |
737 | { | 751 | { |
738 | if (dev) { | 752 | if (dev) { |
@@ -756,8 +770,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
756 | int err; | 770 | int err; |
757 | 771 | ||
758 | if (tb[IFLA_NET_NS_PID]) { | 772 | if (tb[IFLA_NET_NS_PID]) { |
759 | struct net *net; | 773 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); |
760 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | ||
761 | if (IS_ERR(net)) { | 774 | if (IS_ERR(net)) { |
762 | err = PTR_ERR(net); | 775 | err = PTR_ERR(net); |
763 | goto errout; | 776 | goto errout; |
@@ -976,8 +989,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
976 | return 0; | 989 | return 0; |
977 | } | 990 | } |
978 | 991 | ||
979 | struct net_device *rtnl_create_link(struct net *net, char *ifname, | 992 | struct net_device *rtnl_create_link(struct net *src_net, struct net *net, |
980 | const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 993 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) |
981 | { | 994 | { |
982 | int err; | 995 | int err; |
983 | struct net_device *dev; | 996 | struct net_device *dev; |
@@ -985,7 +998,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, | |||
985 | unsigned int real_num_queues = 1; | 998 | unsigned int real_num_queues = 1; |
986 | 999 | ||
987 | if (ops->get_tx_queues) { | 1000 | if (ops->get_tx_queues) { |
988 | err = ops->get_tx_queues(net, tb, &num_queues, | 1001 | err = ops->get_tx_queues(src_net, tb, &num_queues, |
989 | &real_num_queues); | 1002 | &real_num_queues); |
990 | if (err) | 1003 | if (err) |
991 | goto err; | 1004 | goto err; |
@@ -995,16 +1008,16 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, | |||
995 | if (!dev) | 1008 | if (!dev) |
996 | goto err; | 1009 | goto err; |
997 | 1010 | ||
1011 | dev_net_set(dev, net); | ||
1012 | dev->rtnl_link_ops = ops; | ||
998 | dev->real_num_tx_queues = real_num_queues; | 1013 | dev->real_num_tx_queues = real_num_queues; |
1014 | |||
999 | if (strchr(dev->name, '%')) { | 1015 | if (strchr(dev->name, '%')) { |
1000 | err = dev_alloc_name(dev, dev->name); | 1016 | err = dev_alloc_name(dev, dev->name); |
1001 | if (err < 0) | 1017 | if (err < 0) |
1002 | goto err_free; | 1018 | goto err_free; |
1003 | } | 1019 | } |
1004 | 1020 | ||
1005 | dev_net_set(dev, net); | ||
1006 | dev->rtnl_link_ops = ops; | ||
1007 | |||
1008 | if (tb[IFLA_MTU]) | 1021 | if (tb[IFLA_MTU]) |
1009 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | 1022 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); |
1010 | if (tb[IFLA_ADDRESS]) | 1023 | if (tb[IFLA_ADDRESS]) |
@@ -1083,6 +1096,7 @@ replay: | |||
1083 | 1096 | ||
1084 | if (1) { | 1097 | if (1) { |
1085 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; | 1098 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; |
1099 | struct net *dest_net; | ||
1086 | 1100 | ||
1087 | if (ops) { | 1101 | if (ops) { |
1088 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { | 1102 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
@@ -1147,17 +1161,19 @@ replay: | |||
1147 | if (!ifname[0]) | 1161 | if (!ifname[0]) |
1148 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 1162 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
1149 | 1163 | ||
1150 | dev = rtnl_create_link(net, ifname, ops, tb); | 1164 | dest_net = rtnl_link_get_net(net, tb); |
1165 | dev = rtnl_create_link(net, dest_net, ifname, ops, tb); | ||
1151 | 1166 | ||
1152 | if (IS_ERR(dev)) | 1167 | if (IS_ERR(dev)) |
1153 | err = PTR_ERR(dev); | 1168 | err = PTR_ERR(dev); |
1154 | else if (ops->newlink) | 1169 | else if (ops->newlink) |
1155 | err = ops->newlink(dev, tb, data); | 1170 | err = ops->newlink(net, dev, tb, data); |
1156 | else | 1171 | else |
1157 | err = register_netdevice(dev); | 1172 | err = register_netdevice(dev); |
1158 | |||
1159 | if (err < 0 && !IS_ERR(dev)) | 1173 | if (err < 0 && !IS_ERR(dev)) |
1160 | free_netdev(dev); | 1174 | free_netdev(dev); |
1175 | |||
1176 | put_net(dest_net); | ||
1161 | return err; | 1177 | return err; |
1162 | } | 1178 | } |
1163 | } | 1179 | } |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 71a3242fb7d0..a7de9e3a8f18 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) | |||
1483 | dev->features |= NETIF_F_NETNS_LOCAL; | 1483 | dev->features |= NETIF_F_NETNS_LOCAL; |
1484 | } | 1484 | } |
1485 | 1485 | ||
1486 | static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[], | 1486 | static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], |
1487 | struct nlattr *data[]) | 1487 | struct nlattr *data[]) |
1488 | { | 1488 | { |
1489 | struct ip_tunnel *nt; | 1489 | struct ip_tunnel *nt; |