Commit 87dd39ed authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[BRIDGE]: linkstate handling

This makes bridge port status reflect both the state of the interface
from software (up/down) and the carrier.  It makes STP handle link failure
(cable breakage, etc).  The original concept comes from a 
Mark Ruijter <bridge@siennax.com> who implemented it differently.
My way is simpler and requires no polling.

Obviously, this link state detection will only work if the network card
handles the events properly.
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent 4fcf9675
...@@ -344,7 +344,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -344,7 +344,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);
br_stp_recalculate_bridge_id(br); br_stp_recalculate_bridge_id(br);
if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP)) if ((br->dev->flags & IFF_UP)
&& (dev->flags & IFF_UP) && netif_carrier_ok(dev))
br_stp_enable_port(p); br_stp_enable_port(p);
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
......
...@@ -19,58 +19,59 @@ ...@@ -19,58 +19,59 @@
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr); static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr);
struct notifier_block br_device_notifier = struct notifier_block br_device_notifier = {
{
.notifier_call = br_device_event .notifier_call = br_device_event
}; };
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{ {
struct net_device *dev; struct net_device *dev = ptr;
struct net_bridge_port *p; struct net_bridge_port *p = dev->br_port;
struct net_bridge *br; struct net_bridge *br;
dev = ptr;
p = dev->br_port;
if (p == NULL) if (p == NULL)
return NOTIFY_DONE; return NOTIFY_DONE;
br = p->br; br = p->br;
if ( !(br->dev->flags & IFF_UP))
return NOTIFY_DONE;
if (event == NETDEV_CHANGEMTU) {
dev_set_mtu(br->dev, br_min_mtu(br));
return NOTIFY_DONE;
}
spin_lock_bh(&br->lock);
switch (event) { switch (event) {
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
spin_lock_bh(&br->lock);
br_fdb_changeaddr(p, dev->dev_addr); br_fdb_changeaddr(p, dev->dev_addr);
if (br->dev->flags & IFF_UP) br_stp_recalculate_bridge_id(br);
br_stp_recalculate_bridge_id(br);
spin_unlock_bh(&br->lock);
break; break;
case NETDEV_CHANGEMTU: case NETDEV_CHANGE: /* device is up but carrier changed */
dev_set_mtu(br->dev, br_min_mtu(br)); if (netif_carrier_ok(dev)) {
if (p->state == BR_STATE_DISABLED)
br_stp_enable_port(p);
} else {
if (p->state != BR_STATE_DISABLED)
br_stp_disable_port(p);
}
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
if (br->dev->flags & IFF_UP) { br_stp_disable_port(p);
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
}
break; break;
case NETDEV_UP: case NETDEV_UP:
if (br->dev->flags & IFF_UP) { if (netif_carrier_ok(dev))
spin_lock_bh(&br->lock);
br_stp_enable_port(p); br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
}
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
br_del_if(br, dev); br_del_if(br, dev);
break; break;
} }
spin_unlock_bh(&br->lock);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -52,7 +52,7 @@ void br_stp_enable_bridge(struct net_bridge *br) ...@@ -52,7 +52,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
br_config_bpdu_generation(br); br_config_bpdu_generation(br);
list_for_each_entry(p, &br->port_list, list) { list_for_each_entry(p, &br->port_list, list) {
if (p->dev->flags & IFF_UP) if ((p->dev->flags & IFF_UP) && netif_carrier_ok(p->dev))
br_stp_enable_port(p); br_stp_enable_port(p);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment