aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_netlink.c
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2011-04-04 10:03:32 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-04 20:22:28 -0400
commitbb900b27a2f49b37bc38c08e656ea13048fee13b (patch)
treedbea65f697ee131de15a7b6d94466744ad346594 /net/bridge/br_netlink.c
parent36fd2b63e3b4336744cf3f6a6c9543ecbec334a7 (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.c57
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
20static inline size_t br_nlmsg_size(void) 22static 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
193static 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
205static 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
192int __init br_netlink_init(void) 212int __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
238err3:
239 rtnl_unregister_all(PF_BRIDGE);
240err2:
241 rtnl_link_unregister(&br_link_ops);
242err1:
243 return err;
205} 244}
206 245
207void __exit br_netlink_fini(void) 246void __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