aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/veth.c15
-rw-r--r--include/net/rtnetlink.h2
-rw-r--r--net/core/rtnetlink.c52
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,
428err_register_dev: 432err_register_dev:
429 /* nothing to do */ 433 /* nothing to do */
430err_alloc_name: 434err_alloc_name:
435err_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);
87extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); 87extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]);
88extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net, 88extern 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[]);
90extern int rtnl_configure_link(struct net_device *dev,
91 const struct ifinfomsg *ifm);
90extern const struct nla_policy ifla_policy[IFLA_MAX+1]; 92extern 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
552static 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
552static void copy_rtnl_link_stats(struct rtnl_link_stats *a, 565static 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
1063int 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}
1081EXPORT_SYMBOL(rtnl_configure_link);
1082
1056struct net_device *rtnl_create_link(struct net *src_net, struct net *net, 1083struct 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);
1273out:
1240 put_net(dest_net); 1274 put_net(dest_net);
1241 return err; 1275 return err;
1242 } 1276 }