aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-02-26 01:34:54 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-27 05:43:40 -0500
commit3729d5021257b283f7fce33d957893162ccb2c9d (patch)
treed44d5333dfb0cf11cfec8b05a8c7697b5c8d4c07 /net/core
parentbd38081160bb3d036db98472e537b6a7dd4da51a (diff)
rtnetlink: support specifying device flags on device creation
commit e8469ed959c373c2ff9e6f488aa5a14971aebe1f Author: Patrick McHardy <kaber@trash.net> Date: Tue Feb 23 20:41:30 2010 +0100 Support specifying the initial device flags when creating a device though rtnl_link. Devices allocated by rtnl_create_link() are marked as INITIALIZING in order to surpress netlink registration notifications. To complete setup, rtnl_configure_link() must be called, which performs the device flag changes and invokes the deferred notifiers if everything went well. Two examples: # add macvlan to eth0 # $ ip link add link eth0 up allmulticast on type macvlan [LINK]11: macvlan0@eth0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether 26:f8:84:02:f9:2a brd ff:ff:ff:ff:ff:ff [ROUTE]ff00::/8 dev macvlan0 table local metric 256 mtu 1500 advmss 1440 hoplimit 0 [ROUTE]fe80::/64 dev macvlan0 proto kernel metric 256 mtu 1500 advmss 1440 hoplimit 0 [LINK]11: macvlan0@eth0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 link/ether 26:f8:84:02:f9:2a [ADDR]11: macvlan0 inet6 fe80::24f8:84ff:fe02:f92a/64 scope link valid_lft forever preferred_lft forever [ROUTE]local fe80::24f8:84ff:fe02:f92a via :: dev lo table local proto none metric 0 mtu 16436 advmss 16376 hoplimit 0 [ROUTE]default via fe80::215:e9ff:fef0:10f8 dev macvlan0 proto kernel metric 1024 mtu 1500 advmss 1440 hoplimit 0 [NEIGH]fe80::215:e9ff:fef0:10f8 dev macvlan0 lladdr 00:15:e9:f0:10:f8 router STALE [ROUTE]2001:6f8:974::/64 dev macvlan0 proto kernel metric 256 expires 0sec mtu 1500 advmss 1440 hoplimit 0 [PREFIX]prefix 2001:6f8:974::/64 dev macvlan0 onlink autoconf valid 14400 preferred 131084 [ADDR]11: macvlan0 inet6 2001:6f8:974:0:24f8:84ff:fe02:f92a/64 scope global dynamic valid_lft 86399sec preferred_lft 14399sec # add VLAN to eth1, eth1 is down # $ ip link add link eth1 up type vlan id 1000 RTNETLINK answers: Network is down <no events> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/rtnetlink.c52
1 files changed, 43 insertions, 9 deletions
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 }