]>
Commit | Line | Data |
---|---|---|
1 | From b03b6dd58cef7d15b7c46a6729b83dd535ef08ab Mon Sep 17 00:00:00 2001 | |
2 | From: Vitalii Demianets <vitas@nppfactor.kiev.ua> | |
3 | Date: Fri, 25 Nov 2011 00:16:37 +0000 | |
4 | Subject: [PATCH] bridge: master device stuck in no-carrier state forever when | |
5 | in user-stp mode | |
6 | ||
7 | When in user-stp mode, bridge master do not follow state of its slaves, so | |
8 | after the following sequence of events it can stuck forever in no-carrier | |
9 | state: | |
10 | 1) turn stp off | |
11 | 2) put all slaves down - master device will follow their state and also go in | |
12 | no-carrier state | |
13 | 3) turn stp on with bridge-stp script returning 0 (go to the user-stp mode) | |
14 | Now bridge master won't follow slaves' state and will never reach running | |
15 | state. | |
16 | ||
17 | This patch solves the problem by making user-stp and kernel-stp behavior | |
18 | similar regarding master following slaves' states. | |
19 | ||
20 | Signed-off-by: Vitalii Demianets <vitas@nppfactor.kiev.ua> | |
21 | Acked-by: Stephen Hemminger <shemminger@vyatta.com> | |
22 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
23 | --- | |
24 | net/bridge/br_netlink.c | 6 ++++++ | |
25 | net/bridge/br_stp.c | 29 ++++++++++++++--------------- | |
26 | 2 files changed, 20 insertions(+), 15 deletions(-) | |
27 | ||
28 | diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c | |
29 | index e5f9ece3..a1daf82 100644 | |
30 | --- a/net/bridge/br_netlink.c | |
31 | +++ b/net/bridge/br_netlink.c | |
32 | @@ -18,6 +18,7 @@ | |
33 | #include <net/sock.h> | |
34 | ||
35 | #include "br_private.h" | |
36 | +#include "br_private_stp.h" | |
37 | ||
38 | static inline size_t br_nlmsg_size(void) | |
39 | { | |
40 | @@ -188,6 +189,11 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |
41 | ||
42 | p->state = new_state; | |
43 | br_log_state(p); | |
44 | + | |
45 | + spin_lock_bh(&p->br->lock); | |
46 | + br_port_state_selection(p->br); | |
47 | + spin_unlock_bh(&p->br->lock); | |
48 | + | |
49 | br_ifinfo_notify(RTM_NEWLINK, p); | |
50 | ||
51 | return 0; | |
52 | diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c | |
53 | index ad0a3f7..dd147d7 100644 | |
54 | --- a/net/bridge/br_stp.c | |
55 | +++ b/net/bridge/br_stp.c | |
56 | @@ -399,25 +399,24 @@ void br_port_state_selection(struct net_bridge *br) | |
57 | struct net_bridge_port *p; | |
58 | unsigned int liveports = 0; | |
59 | ||
60 | - /* Don't change port states if userspace is handling STP */ | |
61 | - if (br->stp_enabled == BR_USER_STP) | |
62 | - return; | |
63 | - | |
64 | list_for_each_entry(p, &br->port_list, list) { | |
65 | if (p->state == BR_STATE_DISABLED) | |
66 | continue; | |
67 | ||
68 | - if (p->port_no == br->root_port) { | |
69 | - p->config_pending = 0; | |
70 | - p->topology_change_ack = 0; | |
71 | - br_make_forwarding(p); | |
72 | - } else if (br_is_designated_port(p)) { | |
73 | - del_timer(&p->message_age_timer); | |
74 | - br_make_forwarding(p); | |
75 | - } else { | |
76 | - p->config_pending = 0; | |
77 | - p->topology_change_ack = 0; | |
78 | - br_make_blocking(p); | |
79 | + /* Don't change port states if userspace is handling STP */ | |
80 | + if (br->stp_enabled != BR_USER_STP) { | |
81 | + if (p->port_no == br->root_port) { | |
82 | + p->config_pending = 0; | |
83 | + p->topology_change_ack = 0; | |
84 | + br_make_forwarding(p); | |
85 | + } else if (br_is_designated_port(p)) { | |
86 | + del_timer(&p->message_age_timer); | |
87 | + br_make_forwarding(p); | |
88 | + } else { | |
89 | + p->config_pending = 0; | |
90 | + p->topology_change_ack = 0; | |
91 | + br_make_blocking(p); | |
92 | + } | |
93 | } | |
94 | ||
95 | if (p->state == BR_STATE_FORWARDING) | |
96 | -- | |
97 | 1.7.6.2 | |
98 |