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 /net/bridge | |
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>
Diffstat (limited to 'net/bridge')
-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) |