diff options
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 160 |
1 files changed, 49 insertions, 111 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index c03d2c3ff03e..1bacca4cb676 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -36,8 +36,8 @@ static int port_cost(struct net_device *dev) | |||
36 | if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { | 36 | if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { |
37 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; | 37 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; |
38 | 38 | ||
39 | if (!dev->ethtool_ops->get_settings(dev, &ecmd)) { | 39 | if (!dev_ethtool_get_settings(dev, &ecmd)) { |
40 | switch(ecmd.speed) { | 40 | switch (ethtool_cmd_speed(&ecmd)) { |
41 | case SPEED_10000: | 41 | case SPEED_10000: |
42 | return 2; | 42 | return 2; |
43 | case SPEED_1000: | 43 | case SPEED_1000: |
@@ -61,30 +61,27 @@ static int port_cost(struct net_device *dev) | |||
61 | } | 61 | } |
62 | 62 | ||
63 | 63 | ||
64 | /* | 64 | /* Check for port carrier transistions. */ |
65 | * Check for port carrier transistions. | ||
66 | * Called from work queue to allow for calling functions that | ||
67 | * might sleep (such as speed check), and to debounce. | ||
68 | */ | ||
69 | void br_port_carrier_check(struct net_bridge_port *p) | 65 | void br_port_carrier_check(struct net_bridge_port *p) |
70 | { | 66 | { |
71 | struct net_device *dev = p->dev; | 67 | struct net_device *dev = p->dev; |
72 | struct net_bridge *br = p->br; | 68 | struct net_bridge *br = p->br; |
73 | 69 | ||
74 | if (netif_carrier_ok(dev)) | 70 | if (netif_running(dev) && netif_carrier_ok(dev)) |
75 | p->path_cost = port_cost(dev); | 71 | p->path_cost = port_cost(dev); |
76 | 72 | ||
77 | if (netif_running(br->dev)) { | 73 | if (!netif_running(br->dev)) |
78 | spin_lock_bh(&br->lock); | 74 | return; |
79 | if (netif_carrier_ok(dev)) { | 75 | |
80 | if (p->state == BR_STATE_DISABLED) | 76 | spin_lock_bh(&br->lock); |
81 | br_stp_enable_port(p); | 77 | if (netif_running(dev) && netif_carrier_ok(dev)) { |
82 | } else { | 78 | if (p->state == BR_STATE_DISABLED) |
83 | if (p->state != BR_STATE_DISABLED) | 79 | br_stp_enable_port(p); |
84 | br_stp_disable_port(p); | 80 | } else { |
85 | } | 81 | if (p->state != BR_STATE_DISABLED) |
86 | spin_unlock_bh(&br->lock); | 82 | br_stp_disable_port(p); |
87 | } | 83 | } |
84 | spin_unlock_bh(&br->lock); | ||
88 | } | 85 | } |
89 | 86 | ||
90 | static void release_nbp(struct kobject *kobj) | 87 | static void release_nbp(struct kobject *kobj) |
@@ -150,6 +147,9 @@ static void del_nbp(struct net_bridge_port *p) | |||
150 | dev->priv_flags &= ~IFF_BRIDGE_PORT; | 147 | dev->priv_flags &= ~IFF_BRIDGE_PORT; |
151 | 148 | ||
152 | netdev_rx_handler_unregister(dev); | 149 | netdev_rx_handler_unregister(dev); |
150 | synchronize_net(); | ||
151 | |||
152 | netdev_set_master(dev, NULL); | ||
153 | 153 | ||
154 | br_multicast_del_port(p); | 154 | br_multicast_del_port(p); |
155 | 155 | ||
@@ -176,56 +176,6 @@ static void del_br(struct net_bridge *br, struct list_head *head) | |||
176 | unregister_netdevice_queue(br->dev, head); | 176 | unregister_netdevice_queue(br->dev, head); |
177 | } | 177 | } |
178 | 178 | ||
179 | static struct net_device *new_bridge_dev(struct net *net, const char *name) | ||
180 | { | ||
181 | struct net_bridge *br; | ||
182 | struct net_device *dev; | ||
183 | |||
184 | dev = alloc_netdev(sizeof(struct net_bridge), name, | ||
185 | br_dev_setup); | ||
186 | |||
187 | if (!dev) | ||
188 | return NULL; | ||
189 | dev_net_set(dev, net); | ||
190 | |||
191 | br = netdev_priv(dev); | ||
192 | br->dev = dev; | ||
193 | |||
194 | br->stats = alloc_percpu(struct br_cpu_netstats); | ||
195 | if (!br->stats) { | ||
196 | free_netdev(dev); | ||
197 | return NULL; | ||
198 | } | ||
199 | |||
200 | spin_lock_init(&br->lock); | ||
201 | INIT_LIST_HEAD(&br->port_list); | ||
202 | spin_lock_init(&br->hash_lock); | ||
203 | |||
204 | br->bridge_id.prio[0] = 0x80; | ||
205 | br->bridge_id.prio[1] = 0x00; | ||
206 | |||
207 | memcpy(br->group_addr, br_group_address, ETH_ALEN); | ||
208 | |||
209 | br->feature_mask = dev->features; | ||
210 | br->stp_enabled = BR_NO_STP; | ||
211 | br->designated_root = br->bridge_id; | ||
212 | br->root_path_cost = 0; | ||
213 | br->root_port = 0; | ||
214 | br->bridge_max_age = br->max_age = 20 * HZ; | ||
215 | br->bridge_hello_time = br->hello_time = 2 * HZ; | ||
216 | br->bridge_forward_delay = br->forward_delay = 15 * HZ; | ||
217 | br->topology_change = 0; | ||
218 | br->topology_change_detected = 0; | ||
219 | br->ageing_time = 300 * HZ; | ||
220 | |||
221 | br_netfilter_rtable_init(br); | ||
222 | |||
223 | br_stp_timer_init(br); | ||
224 | br_multicast_init(br); | ||
225 | |||
226 | return dev; | ||
227 | } | ||
228 | |||
229 | /* find an available port number */ | 179 | /* find an available port number */ |
230 | static int find_portno(struct net_bridge *br) | 180 | static int find_portno(struct net_bridge *br) |
231 | { | 181 | { |
@@ -278,42 +228,19 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
278 | return p; | 228 | return p; |
279 | } | 229 | } |
280 | 230 | ||
281 | static struct device_type br_type = { | ||
282 | .name = "bridge", | ||
283 | }; | ||
284 | |||
285 | int br_add_bridge(struct net *net, const char *name) | 231 | int br_add_bridge(struct net *net, const char *name) |
286 | { | 232 | { |
287 | struct net_device *dev; | 233 | struct net_device *dev; |
288 | int ret; | ||
289 | 234 | ||
290 | dev = new_bridge_dev(net, name); | 235 | dev = alloc_netdev(sizeof(struct net_bridge), name, |
236 | br_dev_setup); | ||
237 | |||
291 | if (!dev) | 238 | if (!dev) |
292 | return -ENOMEM; | 239 | return -ENOMEM; |
293 | 240 | ||
294 | rtnl_lock(); | 241 | dev_net_set(dev, net); |
295 | if (strchr(dev->name, '%')) { | ||
296 | ret = dev_alloc_name(dev, dev->name); | ||
297 | if (ret < 0) | ||
298 | goto out_free; | ||
299 | } | ||
300 | |||
301 | SET_NETDEV_DEVTYPE(dev, &br_type); | ||
302 | |||
303 | ret = register_netdevice(dev); | ||
304 | if (ret) | ||
305 | goto out_free; | ||
306 | |||
307 | ret = br_sysfs_addbr(dev); | ||
308 | if (ret) | ||
309 | unregister_netdevice(dev); | ||
310 | out: | ||
311 | rtnl_unlock(); | ||
312 | return ret; | ||
313 | 242 | ||
314 | out_free: | 243 | return register_netdev(dev); |
315 | free_netdev(dev); | ||
316 | goto out; | ||
317 | } | 244 | } |
318 | 245 | ||
319 | int br_del_bridge(struct net *net, const char *name) | 246 | int br_del_bridge(struct net *net, const char *name) |
@@ -365,15 +292,15 @@ int br_min_mtu(const struct net_bridge *br) | |||
365 | /* | 292 | /* |
366 | * Recomputes features using slave's features | 293 | * Recomputes features using slave's features |
367 | */ | 294 | */ |
368 | void br_features_recompute(struct net_bridge *br) | 295 | u32 br_features_recompute(struct net_bridge *br, u32 features) |
369 | { | 296 | { |
370 | struct net_bridge_port *p; | 297 | struct net_bridge_port *p; |
371 | unsigned long features, mask; | 298 | u32 mask; |
372 | 299 | ||
373 | features = mask = br->feature_mask; | ||
374 | if (list_empty(&br->port_list)) | 300 | if (list_empty(&br->port_list)) |
375 | goto done; | 301 | return features; |
376 | 302 | ||
303 | mask = features; | ||
377 | features &= ~NETIF_F_ONE_FOR_ALL; | 304 | features &= ~NETIF_F_ONE_FOR_ALL; |
378 | 305 | ||
379 | list_for_each_entry(p, &br->port_list, list) { | 306 | list_for_each_entry(p, &br->port_list, list) { |
@@ -381,8 +308,7 @@ void br_features_recompute(struct net_bridge *br) | |||
381 | p->dev->features, mask); | 308 | p->dev->features, mask); |
382 | } | 309 | } |
383 | 310 | ||
384 | done: | 311 | return features; |
385 | br->dev->features = netdev_fix_features(features, NULL); | ||
386 | } | 312 | } |
387 | 313 | ||
388 | /* called with RTNL */ | 314 | /* called with RTNL */ |
@@ -390,6 +316,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
390 | { | 316 | { |
391 | struct net_bridge_port *p; | 317 | struct net_bridge_port *p; |
392 | int err = 0; | 318 | int err = 0; |
319 | bool changed_addr; | ||
393 | 320 | ||
394 | /* Don't allow bridging non-ethernet like devices */ | 321 | /* Don't allow bridging non-ethernet like devices */ |
395 | if ((dev->flags & IFF_LOOPBACK) || | 322 | if ((dev->flags & IFF_LOOPBACK) || |
@@ -412,6 +339,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
412 | if (IS_ERR(p)) | 339 | if (IS_ERR(p)) |
413 | return PTR_ERR(p); | 340 | return PTR_ERR(p); |
414 | 341 | ||
342 | call_netdevice_notifiers(NETDEV_JOIN, dev); | ||
343 | |||
415 | err = dev_set_promiscuity(dev, 1); | 344 | err = dev_set_promiscuity(dev, 1); |
416 | if (err) | 345 | if (err) |
417 | goto put_back; | 346 | goto put_back; |
@@ -432,19 +361,24 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
432 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) | 361 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) |
433 | goto err3; | 362 | goto err3; |
434 | 363 | ||
435 | err = netdev_rx_handler_register(dev, br_handle_frame, p); | 364 | err = netdev_set_master(dev, br->dev); |
436 | if (err) | 365 | if (err) |
437 | goto err3; | 366 | goto err3; |
438 | 367 | ||
368 | err = netdev_rx_handler_register(dev, br_handle_frame, p); | ||
369 | if (err) | ||
370 | goto err4; | ||
371 | |||
439 | dev->priv_flags |= IFF_BRIDGE_PORT; | 372 | dev->priv_flags |= IFF_BRIDGE_PORT; |
440 | 373 | ||
441 | dev_disable_lro(dev); | 374 | dev_disable_lro(dev); |
442 | 375 | ||
443 | list_add_rcu(&p->list, &br->port_list); | 376 | list_add_rcu(&p->list, &br->port_list); |
444 | 377 | ||
378 | netdev_update_features(br->dev); | ||
379 | |||
445 | spin_lock_bh(&br->lock); | 380 | spin_lock_bh(&br->lock); |
446 | br_stp_recalculate_bridge_id(br); | 381 | changed_addr = br_stp_recalculate_bridge_id(br); |
447 | br_features_recompute(br); | ||
448 | 382 | ||
449 | if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && | 383 | if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && |
450 | (br->dev->flags & IFF_UP)) | 384 | (br->dev->flags & IFF_UP)) |
@@ -453,11 +387,17 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
453 | 387 | ||
454 | br_ifinfo_notify(RTM_NEWLINK, p); | 388 | br_ifinfo_notify(RTM_NEWLINK, p); |
455 | 389 | ||
390 | if (changed_addr) | ||
391 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
392 | |||
456 | dev_set_mtu(br->dev, br_min_mtu(br)); | 393 | dev_set_mtu(br->dev, br_min_mtu(br)); |
457 | 394 | ||
458 | kobject_uevent(&p->kobj, KOBJ_ADD); | 395 | kobject_uevent(&p->kobj, KOBJ_ADD); |
459 | 396 | ||
460 | return 0; | 397 | return 0; |
398 | |||
399 | err4: | ||
400 | netdev_set_master(dev, NULL); | ||
461 | err3: | 401 | err3: |
462 | sysfs_remove_link(br->ifobj, p->dev->name); | 402 | sysfs_remove_link(br->ifobj, p->dev->name); |
463 | err2: | 403 | err2: |
@@ -478,20 +418,18 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) | |||
478 | { | 418 | { |
479 | struct net_bridge_port *p; | 419 | struct net_bridge_port *p; |
480 | 420 | ||
481 | if (!br_port_exists(dev)) | 421 | p = br_port_get_rtnl(dev); |
482 | return -EINVAL; | 422 | if (!p || p->br != br) |
483 | |||
484 | p = br_port_get(dev); | ||
485 | if (p->br != br) | ||
486 | return -EINVAL; | 423 | return -EINVAL; |
487 | 424 | ||
488 | del_nbp(p); | 425 | del_nbp(p); |
489 | 426 | ||
490 | spin_lock_bh(&br->lock); | 427 | spin_lock_bh(&br->lock); |
491 | br_stp_recalculate_bridge_id(br); | 428 | br_stp_recalculate_bridge_id(br); |
492 | br_features_recompute(br); | ||
493 | spin_unlock_bh(&br->lock); | 429 | spin_unlock_bh(&br->lock); |
494 | 430 | ||
431 | netdev_update_features(br->dev); | ||
432 | |||
495 | return 0; | 433 | return 0; |
496 | } | 434 | } |
497 | 435 | ||