diff options
author | stephen hemminger <shemminger@vyatta.com> | 2011-04-04 10:03:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-04 20:22:28 -0400 |
commit | bb900b27a2f49b37bc38c08e656ea13048fee13b (patch) | |
tree | dbea65f697ee131de15a7b6d94466744ad346594 /net/bridge/br_netlink.c | |
parent | 36fd2b63e3b4336744cf3f6a6c9543ecbec334a7 (diff) |
bridge: allow creating bridge devices with netlink
Add netlink device ops to allow creating bridge device via netlink.
This works in a manner similar to vlan, macvlan and bonding.
Example:
# ip link add link dev br0 type bridge
# ip link del dev br0
The change required rearranging initializtion code to deal with
being called by create link. Most of the initialization happens
in br_dev_setup, but allocation of stats is done in ndo_init callback
to deal with allocation failure. Sysfs setup has to wait until
after the network device kobject is registered.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r-- | net/bridge/br_netlink.c | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fb7d5a7478f..134a2ff6b98 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -12,9 +12,11 @@ | |||
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/etherdevice.h> | ||
15 | #include <net/rtnetlink.h> | 16 | #include <net/rtnetlink.h> |
16 | #include <net/net_namespace.h> | 17 | #include <net/net_namespace.h> |
17 | #include <net/sock.h> | 18 | #include <net/sock.h> |
19 | |||
18 | #include "br_private.h" | 20 | #include "br_private.h" |
19 | 21 | ||
20 | static inline size_t br_nlmsg_size(void) | 22 | static inline size_t br_nlmsg_size(void) |
@@ -188,24 +190,61 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
188 | return 0; | 190 | return 0; |
189 | } | 191 | } |
190 | 192 | ||
193 | static int br_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
194 | { | ||
195 | if (tb[IFLA_ADDRESS]) { | ||
196 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | ||
197 | return -EINVAL; | ||
198 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | ||
199 | return -EADDRNOTAVAIL; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static struct rtnl_link_ops br_link_ops __read_mostly = { | ||
206 | .kind = "bridge", | ||
207 | .priv_size = sizeof(struct net_bridge), | ||
208 | .setup = br_dev_setup, | ||
209 | .validate = br_validate, | ||
210 | }; | ||
191 | 211 | ||
192 | int __init br_netlink_init(void) | 212 | int __init br_netlink_init(void) |
193 | { | 213 | { |
194 | if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo)) | 214 | int err; |
195 | return -ENOBUFS; | ||
196 | |||
197 | /* Only the first call to __rtnl_register can fail */ | ||
198 | __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); | ||
199 | 215 | ||
200 | __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); | 216 | err = rtnl_link_register(&br_link_ops); |
201 | __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); | 217 | if (err < 0) |
202 | __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); | 218 | goto err1; |
219 | |||
220 | err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo); | ||
221 | if (err) | ||
222 | goto err2; | ||
223 | err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); | ||
224 | if (err) | ||
225 | goto err3; | ||
226 | err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); | ||
227 | if (err) | ||
228 | goto err3; | ||
229 | err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); | ||
230 | if (err) | ||
231 | goto err3; | ||
232 | err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); | ||
233 | if (err) | ||
234 | goto err3; | ||
203 | 235 | ||
204 | return 0; | 236 | return 0; |
237 | |||
238 | err3: | ||
239 | rtnl_unregister_all(PF_BRIDGE); | ||
240 | err2: | ||
241 | rtnl_link_unregister(&br_link_ops); | ||
242 | err1: | ||
243 | return err; | ||
205 | } | 244 | } |
206 | 245 | ||
207 | void __exit br_netlink_fini(void) | 246 | void __exit br_netlink_fini(void) |
208 | { | 247 | { |
248 | rtnl_link_unregister(&br_link_ops); | ||
209 | rtnl_unregister_all(PF_BRIDGE); | 249 | rtnl_unregister_all(PF_BRIDGE); |
210 | } | 250 | } |
211 | |||