aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
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
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')
-rw-r--r--net/bridge/br.c1
-rw-r--r--net/bridge/br_device.c41
-rw-r--r--net/bridge/br_if.c83
-rw-r--r--net/bridge/br_netlink.c57
-rw-r--r--net/bridge/br_notify.c6
5 files changed, 101 insertions, 87 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 84bbb82599b..f20c4fd915a 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -104,3 +104,4 @@ module_init(br_init)
104module_exit(br_deinit) 104module_exit(br_deinit)
105MODULE_LICENSE("GPL"); 105MODULE_LICENSE("GPL");
106MODULE_VERSION(BR_VERSION); 106MODULE_VERSION(BR_VERSION);
107MODULE_ALIAS_RTNL_LINK("bridge");
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 21e5901186e..45cfd54b06d 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -74,6 +74,17 @@ out:
74 return NETDEV_TX_OK; 74 return NETDEV_TX_OK;
75} 75}
76 76
77static int br_dev_init(struct net_device *dev)
78{
79 struct net_bridge *br = netdev_priv(dev);
80
81 br->stats = alloc_percpu(struct br_cpu_netstats);
82 if (!br->stats)
83 return -ENOMEM;
84
85 return 0;
86}
87
77static int br_dev_open(struct net_device *dev) 88static int br_dev_open(struct net_device *dev)
78{ 89{
79 struct net_bridge *br = netdev_priv(dev); 90 struct net_bridge *br = netdev_priv(dev);
@@ -334,6 +345,7 @@ static const struct ethtool_ops br_ethtool_ops = {
334static const struct net_device_ops br_netdev_ops = { 345static const struct net_device_ops br_netdev_ops = {
335 .ndo_open = br_dev_open, 346 .ndo_open = br_dev_open,
336 .ndo_stop = br_dev_stop, 347 .ndo_stop = br_dev_stop,
348 .ndo_init = br_dev_init,
337 .ndo_start_xmit = br_dev_xmit, 349 .ndo_start_xmit = br_dev_xmit,
338 .ndo_get_stats64 = br_get_stats64, 350 .ndo_get_stats64 = br_get_stats64,
339 .ndo_set_mac_address = br_set_mac_address, 351 .ndo_set_mac_address = br_set_mac_address,
@@ -357,18 +369,47 @@ static void br_dev_free(struct net_device *dev)
357 free_netdev(dev); 369 free_netdev(dev);
358} 370}
359 371
372static struct device_type br_type = {
373 .name = "bridge",
374};
375
360void br_dev_setup(struct net_device *dev) 376void br_dev_setup(struct net_device *dev)
361{ 377{
378 struct net_bridge *br = netdev_priv(dev);
379
362 random_ether_addr(dev->dev_addr); 380 random_ether_addr(dev->dev_addr);
363 ether_setup(dev); 381 ether_setup(dev);
364 382
365 dev->netdev_ops = &br_netdev_ops; 383 dev->netdev_ops = &br_netdev_ops;
366 dev->destructor = br_dev_free; 384 dev->destructor = br_dev_free;
367 SET_ETHTOOL_OPS(dev, &br_ethtool_ops); 385 SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
386 SET_NETDEV_DEVTYPE(dev, &br_type);
368 dev->tx_queue_len = 0; 387 dev->tx_queue_len = 0;
369 dev->priv_flags = IFF_EBRIDGE; 388 dev->priv_flags = IFF_EBRIDGE;
370 389
371 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 390 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
372 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX | 391 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
373 NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX; 392 NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX;
393
394 br->dev = dev;
395 spin_lock_init(&br->lock);
396 INIT_LIST_HEAD(&br->port_list);
397 spin_lock_init(&br->hash_lock);
398
399 br->bridge_id.prio[0] = 0x80;
400 br->bridge_id.prio[1] = 0x00;
401
402 memcpy(br->group_addr, br_group_address, ETH_ALEN);
403
404 br->feature_mask = dev->features;
405 br->stp_enabled = BR_NO_STP;
406 br->designated_root = br->bridge_id;
407 br->bridge_max_age = br->max_age = 20 * HZ;
408 br->bridge_hello_time = br->hello_time = 2 * HZ;
409 br->bridge_forward_delay = br->forward_delay = 15 * HZ;
410 br->ageing_time = 300 * HZ;
411
412 br_netfilter_rtable_init(br);
413 br_stp_timer_init(br);
414 br_multicast_init(br);
374} 415}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 718b60366df..7f5379c593d 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -175,56 +175,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
175 unregister_netdevice_queue(br->dev, head); 175 unregister_netdevice_queue(br->dev, head);
176} 176}
177 177
178static struct net_device *new_bridge_dev(struct net *net, const char *name)
179{
180 struct net_bridge *br;
181 struct net_device *dev;
182
183 dev = alloc_netdev(sizeof(struct net_bridge), name,
184 br_dev_setup);
185
186 if (!dev)
187 return NULL;
188 dev_net_set(dev, net);
189
190 br = netdev_priv(dev);
191 br->dev = dev;
192
193 br->stats = alloc_percpu(struct br_cpu_netstats);
194 if (!br->stats) {
195 free_netdev(dev);
196 return NULL;
197 }
198
199 spin_lock_init(&br->lock);
200 INIT_LIST_HEAD(&br->port_list);
201 spin_lock_init(&br->hash_lock);
202
203 br->bridge_id.prio[0] = 0x80;
204 br->bridge_id.prio[1] = 0x00;
205
206 memcpy(br->group_addr, br_group_address, ETH_ALEN);
207
208 br->feature_mask = dev->features;
209 br->stp_enabled = BR_NO_STP;
210 br->designated_root = br->bridge_id;
211 br->root_path_cost = 0;
212 br->root_port = 0;
213 br->bridge_max_age = br->max_age = 20 * HZ;
214 br->bridge_hello_time = br->hello_time = 2 * HZ;
215 br->bridge_forward_delay = br->forward_delay = 15 * HZ;
216 br->topology_change = 0;
217 br->topology_change_detected = 0;
218 br->ageing_time = 300 * HZ;
219
220 br_netfilter_rtable_init(br);
221
222 br_stp_timer_init(br);
223 br_multicast_init(br);
224
225 return dev;
226}
227
228/* find an available port number */ 178/* find an available port number */
229static int find_portno(struct net_bridge *br) 179static int find_portno(struct net_bridge *br)
230{ 180{
@@ -277,42 +227,19 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
277 return p; 227 return p;
278} 228}
279 229
280static struct device_type br_type = {
281 .name = "bridge",
282};
283
284int br_add_bridge(struct net *net, const char *name) 230int br_add_bridge(struct net *net, const char *name)
285{ 231{
286 struct net_device *dev; 232 struct net_device *dev;
287 int ret;
288 233
289 dev = new_bridge_dev(net, name); 234 dev = alloc_netdev(sizeof(struct net_bridge), name,
235 br_dev_setup);
236
290 if (!dev) 237 if (!dev)
291 return -ENOMEM; 238 return -ENOMEM;
292 239
293 rtnl_lock(); 240 dev_net_set(dev, net);
294 if (strchr(dev->name, '%')) {
295 ret = dev_alloc_name(dev, dev->name);
296 if (ret < 0)
297 goto out_free;
298 }
299
300 SET_NETDEV_DEVTYPE(dev, &br_type);
301
302 ret = register_netdevice(dev);
303 if (ret)
304 goto out_free;
305
306 ret = br_sysfs_addbr(dev);
307 if (ret)
308 unregister_netdevice(dev);
309 out:
310 rtnl_unlock();
311 return ret;
312 241
313out_free: 242 return register_netdev(dev);
314 free_netdev(dev);
315 goto out;
316} 243}
317 244
318int br_del_bridge(struct net *net, const char *name) 245int br_del_bridge(struct net *net, const char *name)
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
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 7d337c9b608..7a03bb97537 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -36,6 +36,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
36 struct net_bridge *br; 36 struct net_bridge *br;
37 int err; 37 int err;
38 38
39 /* register of bridge completed, add sysfs entries */
40 if ((dev->priv_flags && IFF_EBRIDGE) && event == NETDEV_REGISTER) {
41 br_sysfs_addbr(dev);
42 return NOTIFY_DONE;
43 }
44
39 /* not a port of a bridge */ 45 /* not a port of a bridge */
40 p = br_port_get_rtnl(dev); 46 p = br_port_get_rtnl(dev);
41 if (!p) 47 if (!p)