diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2004-07-29 00:40:24 -0700 |
---|---|---|
committer | David S. Miller <davem@nuts.davemloft.net> | 2004-07-29 00:40:24 -0700 |
commit | 87dd39edb1d4537f13562b18da0f34cab711633e (patch) | |
tree | 2fdd7e8ece579d76b159b0308dda5a5be7a17d8a /net | |
parent | 4fcf9675f4b52e4d1e0d451335e39e83111777d4 (diff) | |
download | history-87dd39edb1d4537f13562b18da0f34cab711633e.tar.gz |
[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: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@redhat.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_if.c | 3 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 47 | ||||
-rw-r--r-- | net/bridge/br_stp_if.c | 2 |
3 files changed, 27 insertions, 25 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index b81dee96015cae..588ead0731b0fd 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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); diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index dbc86ecbd244c1..70dc21f0c5ec50 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -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); + br_stp_recalculate_bridge_id(br); 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); - } + br_stp_disable_port(p); 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; } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 9e1d296b6e95b4..6c08fefcc75d55 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -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); } |