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)
spin_lock_bh(&br->lock);
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);
spin_unlock_bh(&br->lock);
......
......@@ -19,58 +19,59 @@
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
};
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
struct net_device *dev;
struct net_bridge_port *p;
struct net_device *dev = ptr;
struct net_bridge_port *p = dev->br_port;
struct net_bridge *br;
dev = ptr;
p = dev->br_port;
if (p == NULL)
return NOTIFY_DONE;
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) {
case NETDEV_CHANGEADDR:
spin_lock_bh(&br->lock);
br_fdb_changeaddr(p, dev->dev_addr);
if (br->dev->flags & IFF_UP)
br_stp_recalculate_bridge_id(br);
spin_unlock_bh(&br->lock);
break;
case NETDEV_CHANGEMTU:
dev_set_mtu(br->dev, br_min_mtu(br));
case NETDEV_CHANGE: /* device is up but carrier changed */
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;
case NETDEV_DOWN:
if (br->dev->flags & IFF_UP) {
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
}
break;
case NETDEV_UP:
if (br->dev->flags & IFF_UP) {
spin_lock_bh(&br->lock);
if (netif_carrier_ok(dev))
br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
}
break;
case NETDEV_UNREGISTER:
br_del_if(br, dev);
break;
}
spin_unlock_bh(&br->lock);
return NOTIFY_DONE;
}
......@@ -52,7 +52,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
br_config_bpdu_generation(br);
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);
}
......
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