diff options
author | Patrick McHardy <kaber@trash.net> | 2010-02-26 01:34:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-27 05:43:40 -0500 |
commit | 3729d5021257b283f7fce33d957893162ccb2c9d (patch) | |
tree | d44d5333dfb0cf11cfec8b05a8c7697b5c8d4c07 /net | |
parent | bd38081160bb3d036db98472e537b6a7dd4da51a (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')
-rw-r--r-- | net/core/rtnetlink.c | 52 |
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 | ||
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 | } |