diff options
-rw-r--r-- | drivers/net/veth.c | 15 | ||||
-rw-r--r-- | include/net/rtnetlink.h | 2 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 52 |
3 files changed, 55 insertions, 14 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 35609e64f6fd..b583d4968add 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c | |||
@@ -333,19 +333,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, | |||
333 | struct veth_priv *priv; | 333 | struct veth_priv *priv; |
334 | char ifname[IFNAMSIZ]; | 334 | char ifname[IFNAMSIZ]; |
335 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; | 335 | struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; |
336 | struct ifinfomsg *ifmp; | ||
336 | struct net *net; | 337 | struct net *net; |
337 | 338 | ||
338 | /* | 339 | /* |
339 | * create and register peer first | 340 | * create and register peer first |
340 | * | ||
341 | * struct ifinfomsg is at the head of VETH_INFO_PEER, but we | ||
342 | * skip it since no info from it is useful yet | ||
343 | */ | 341 | */ |
344 | |||
345 | if (data != NULL && data[VETH_INFO_PEER] != NULL) { | 342 | if (data != NULL && data[VETH_INFO_PEER] != NULL) { |
346 | struct nlattr *nla_peer; | 343 | struct nlattr *nla_peer; |
347 | 344 | ||
348 | nla_peer = data[VETH_INFO_PEER]; | 345 | nla_peer = data[VETH_INFO_PEER]; |
346 | ifmp = nla_data(nla_peer); | ||
349 | err = nla_parse(peer_tb, IFLA_MAX, | 347 | err = nla_parse(peer_tb, IFLA_MAX, |
350 | nla_data(nla_peer) + sizeof(struct ifinfomsg), | 348 | nla_data(nla_peer) + sizeof(struct ifinfomsg), |
351 | nla_len(nla_peer) - sizeof(struct ifinfomsg), | 349 | nla_len(nla_peer) - sizeof(struct ifinfomsg), |
@@ -358,8 +356,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, | |||
358 | return err; | 356 | return err; |
359 | 357 | ||
360 | tbp = peer_tb; | 358 | tbp = peer_tb; |
361 | } else | 359 | } else { |
360 | ifmp = NULL; | ||
362 | tbp = tb; | 361 | tbp = tb; |
362 | } | ||
363 | 363 | ||
364 | if (tbp[IFLA_IFNAME]) | 364 | if (tbp[IFLA_IFNAME]) |
365 | nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); | 365 | nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); |
@@ -387,6 +387,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, | |||
387 | 387 | ||
388 | netif_carrier_off(peer); | 388 | netif_carrier_off(peer); |
389 | 389 | ||
390 | err = rtnl_configure_link(peer, ifmp); | ||
391 | if (err < 0) | ||
392 | goto err_configure_peer; | ||
393 | |||
390 | /* | 394 | /* |
391 | * register dev last | 395 | * register dev last |
392 | * | 396 | * |
@@ -428,6 +432,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, | |||
428 | err_register_dev: | 432 | err_register_dev: |
429 | /* nothing to do */ | 433 | /* nothing to do */ |
430 | err_alloc_name: | 434 | err_alloc_name: |
435 | err_configure_peer: | ||
431 | unregister_netdevice(peer); | 436 | unregister_netdevice(peer); |
432 | return err; | 437 | return err; |
433 | 438 | ||
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 48d3efcb0880..af60fd050844 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h | |||
@@ -87,6 +87,8 @@ extern void rtnl_link_unregister(struct rtnl_link_ops *ops); | |||
87 | extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); | 87 | extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); |
88 | extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | 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[]); | 89 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); |
90 | extern int rtnl_configure_link(struct net_device *dev, | ||
91 | const struct ifinfomsg *ifm); | ||
90 | extern const struct nla_policy ifla_policy[IFLA_MAX+1]; | 92 | extern const struct nla_policy ifla_policy[IFLA_MAX+1]; |
91 | 93 | ||
92 | #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) | 94 | #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c21ec4236dd0..d1472a423323 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -549,6 +549,19 @@ static void set_operstate(struct net_device *dev, unsigned char transition) | |||
549 | } | 549 | } |
550 | } | 550 | } |
551 | 551 | ||
552 | static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, | ||
553 | const struct ifinfomsg *ifm) | ||
554 | { | ||
555 | unsigned int flags = ifm->ifi_flags; | ||
556 | |||
557 | /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ | ||
558 | if (ifm->ifi_change) | ||
559 | flags = (flags & ifm->ifi_change) | | ||
560 | (dev->flags & ~ifm->ifi_change); | ||
561 | |||
562 | return flags; | ||
563 | } | ||
564 | |||
552 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | 565 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, |
553 | const struct net_device_stats *b) | 566 | const struct net_device_stats *b) |
554 | { | 567 | { |
@@ -904,13 +917,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
904 | } | 917 | } |
905 | 918 | ||
906 | if (ifm->ifi_flags || ifm->ifi_change) { | 919 | if (ifm->ifi_flags || ifm->ifi_change) { |
907 | unsigned int flags = ifm->ifi_flags; | 920 | err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
908 | |||
909 | /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ | ||
910 | if (ifm->ifi_change) | ||
911 | flags = (flags & ifm->ifi_change) | | ||
912 | (dev->flags & ~ifm->ifi_change); | ||
913 | err = dev_change_flags(dev, flags); | ||
914 | if (err < 0) | 921 | if (err < 0) |
915 | goto errout; | 922 | goto errout; |
916 | } | 923 | } |
@@ -1053,6 +1060,26 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1053 | return 0; | 1060 | return 0; |
1054 | } | 1061 | } |
1055 | 1062 | ||
1063 | int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) | ||
1064 | { | ||
1065 | unsigned int old_flags; | ||
1066 | int err; | ||
1067 | |||
1068 | old_flags = dev->flags; | ||
1069 | if (ifm && (ifm->ifi_flags || ifm->ifi_change)) { | ||
1070 | err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); | ||
1071 | if (err < 0) | ||
1072 | return err; | ||
1073 | } | ||
1074 | |||
1075 | dev->rtnl_link_state = RTNL_LINK_INITIALIZED; | ||
1076 | rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); | ||
1077 | |||
1078 | __dev_notify_flags(dev, old_flags); | ||
1079 | return 0; | ||
1080 | } | ||
1081 | EXPORT_SYMBOL(rtnl_configure_link); | ||
1082 | |||
1056 | struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | 1083 | struct net_device *rtnl_create_link(struct net *src_net, struct net *net, |
1057 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 1084 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) |
1058 | { | 1085 | { |
@@ -1074,6 +1101,7 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | |||
1074 | 1101 | ||
1075 | dev_net_set(dev, net); | 1102 | dev_net_set(dev, net); |
1076 | dev->rtnl_link_ops = ops; | 1103 | dev->rtnl_link_ops = ops; |
1104 | dev->rtnl_link_state = RTNL_LINK_INITIALIZING; | ||
1077 | dev->real_num_tx_queues = real_num_queues; | 1105 | dev->real_num_tx_queues = real_num_queues; |
1078 | 1106 | ||
1079 | if (strchr(dev->name, '%')) { | 1107 | if (strchr(dev->name, '%')) { |
@@ -1203,7 +1231,7 @@ replay: | |||
1203 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) | 1231 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) |
1204 | return -ENODEV; | 1232 | return -ENODEV; |
1205 | 1233 | ||
1206 | if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change) | 1234 | if (ifm->ifi_index) |
1207 | return -EOPNOTSUPP; | 1235 | return -EOPNOTSUPP; |
1208 | if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) | 1236 | if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) |
1209 | return -EOPNOTSUPP; | 1237 | return -EOPNOTSUPP; |
@@ -1234,9 +1262,15 @@ replay: | |||
1234 | err = ops->newlink(net, dev, tb, data); | 1262 | err = ops->newlink(net, dev, tb, data); |
1235 | else | 1263 | else |
1236 | err = register_netdevice(dev); | 1264 | err = register_netdevice(dev); |
1237 | if (err < 0 && !IS_ERR(dev)) | 1265 | if (err < 0 && !IS_ERR(dev)) { |
1238 | free_netdev(dev); | 1266 | free_netdev(dev); |
1267 | goto out; | ||
1268 | } | ||
1239 | 1269 | ||
1270 | err = rtnl_configure_link(dev, ifm); | ||
1271 | if (err < 0) | ||
1272 | unregister_netdevice(dev); | ||
1273 | out: | ||
1240 | put_net(dest_net); | 1274 | put_net(dest_net); |
1241 | return err; | 1275 | return err; |
1242 | } | 1276 | } |