diff options
| author | Vitalii Demianets <vitas@nppfactor.kiev.ua> | 2011-11-24 19:16:37 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-12-01 14:05:17 -0500 |
| commit | b03b6dd58cef7d15b7c46a6729b83dd535ef08ab (patch) | |
| tree | a193461397942346f330b782a200849feafa1991 | |
| parent | efbc368dcc6426d5430b9b8eeda944cf2cb74b8c (diff) | |
bridge: master device stuck in no-carrier state forever when in user-stp mode
When in user-stp mode, bridge master do not follow state of its slaves, so
after the following sequence of events it can stuck forever in no-carrier
state:
1) turn stp off
2) put all slaves down - master device will follow their state and also go in
no-carrier state
3) turn stp on with bridge-stp script returning 0 (go to the user-stp mode)
Now bridge master won't follow slaves' state and will never reach running
state.
This patch solves the problem by making user-stp and kernel-stp behavior
similar regarding master following slaves' states.
Signed-off-by: Vitalii Demianets <vitas@nppfactor.kiev.ua>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/bridge/br_netlink.c | 6 | ||||
| -rw-r--r-- | net/bridge/br_stp.c | 29 |
2 files changed, 20 insertions, 15 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index e5f9ece3c9a0..a1daf8227ed1 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <net/sock.h> | 18 | #include <net/sock.h> |
| 19 | 19 | ||
| 20 | #include "br_private.h" | 20 | #include "br_private.h" |
| 21 | #include "br_private_stp.h" | ||
| 21 | 22 | ||
| 22 | static inline size_t br_nlmsg_size(void) | 23 | static inline size_t br_nlmsg_size(void) |
| 23 | { | 24 | { |
| @@ -188,6 +189,11 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 188 | 189 | ||
| 189 | p->state = new_state; | 190 | p->state = new_state; |
| 190 | br_log_state(p); | 191 | br_log_state(p); |
| 192 | |||
| 193 | spin_lock_bh(&p->br->lock); | ||
| 194 | br_port_state_selection(p->br); | ||
| 195 | spin_unlock_bh(&p->br->lock); | ||
| 196 | |||
| 191 | br_ifinfo_notify(RTM_NEWLINK, p); | 197 | br_ifinfo_notify(RTM_NEWLINK, p); |
| 192 | 198 | ||
| 193 | return 0; | 199 | return 0; |
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index ad0a3f7cf6cc..dd147d78a588 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c | |||
| @@ -399,25 +399,24 @@ void br_port_state_selection(struct net_bridge *br) | |||
| 399 | struct net_bridge_port *p; | 399 | struct net_bridge_port *p; |
| 400 | unsigned int liveports = 0; | 400 | unsigned int liveports = 0; |
| 401 | 401 | ||
| 402 | /* Don't change port states if userspace is handling STP */ | ||
| 403 | if (br->stp_enabled == BR_USER_STP) | ||
| 404 | return; | ||
| 405 | |||
| 406 | list_for_each_entry(p, &br->port_list, list) { | 402 | list_for_each_entry(p, &br->port_list, list) { |
| 407 | if (p->state == BR_STATE_DISABLED) | 403 | if (p->state == BR_STATE_DISABLED) |
| 408 | continue; | 404 | continue; |
| 409 | 405 | ||
| 410 | if (p->port_no == br->root_port) { | 406 | /* Don't change port states if userspace is handling STP */ |
| 411 | p->config_pending = 0; | 407 | if (br->stp_enabled != BR_USER_STP) { |
| 412 | p->topology_change_ack = 0; | 408 | if (p->port_no == br->root_port) { |
| 413 | br_make_forwarding(p); | 409 | p->config_pending = 0; |
| 414 | } else if (br_is_designated_port(p)) { | 410 | p->topology_change_ack = 0; |
| 415 | del_timer(&p->message_age_timer); | 411 | br_make_forwarding(p); |
| 416 | br_make_forwarding(p); | 412 | } else if (br_is_designated_port(p)) { |
| 417 | } else { | 413 | del_timer(&p->message_age_timer); |
| 418 | p->config_pending = 0; | 414 | br_make_forwarding(p); |
| 419 | p->topology_change_ack = 0; | 415 | } else { |
| 420 | br_make_blocking(p); | 416 | p->config_pending = 0; |
| 417 | p->topology_change_ack = 0; | ||
| 418 | br_make_blocking(p); | ||
| 419 | } | ||
| 421 | } | 420 | } |
| 422 | 421 | ||
| 423 | if (p->state == BR_STATE_FORWARDING) | 422 | if (p->state == BR_STATE_FORWARDING) |
