aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_stp_if.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-03-21 17:22:44 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:28:48 -0400
commit9cde070874b822d4677f4f01fe146991785813b1 (patch)
tree2e3a444ad82e026237ce99a4f8cad201f6ca807d /net/bridge/br_stp_if.c
parent9cf637473c8535b5abe27fee79254c2d552e042a (diff)
bridge: add support for user mode STP
This patchset based on work by Aji_Srinivas@emc.com provides allows spanning tree to be controled from userspace. Like hotplug, it uses call_usermodehelper when spanning tree is enabled so there is no visible API change. If call to start usermode STP fails it falls back to existing kernel STP. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Diffstat (limited to 'net/bridge/br_stp_if.c')
-rw-r--r--net/bridge/br_stp_if.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index a285897a2fb4..1c1806d7c489 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -123,6 +123,62 @@ void br_stp_disable_port(struct net_bridge_port *p)
123 br_become_root_bridge(br); 123 br_become_root_bridge(br);
124} 124}
125 125
126static void br_stp_start(struct net_bridge *br)
127{
128 int r;
129 char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
130 char *envp[] = { NULL };
131
132 r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
133 if (r == 0) {
134 br->stp_enabled = BR_USER_STP;
135 printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
136 } else {
137 br->stp_enabled = BR_KERNEL_STP;
138 printk(KERN_INFO "%s: starting userspace STP failed, "
139 "staring kernel STP\n", br->dev->name);
140
141 /* To start timers on any ports left in blocking */
142 spin_lock_bh(&br->lock);
143 br_port_state_selection(br);
144 spin_unlock_bh(&br->lock);
145 }
146}
147
148static void br_stp_stop(struct net_bridge *br)
149{
150 int r;
151 char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL };
152 char *envp[] = { NULL };
153
154 if (br->stp_enabled == BR_USER_STP) {
155 r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
156 printk(KERN_INFO "%s: userspace STP stopped, return code %d\n",
157 br->dev->name, r);
158
159
160 /* To start timers on any ports left in blocking */
161 spin_lock_bh(&br->lock);
162 br_port_state_selection(br);
163 spin_unlock_bh(&br->lock);
164 }
165
166 br->stp_enabled = BR_NO_STP;
167}
168
169void br_stp_set_enabled(struct net_bridge *br, unsigned long val)
170{
171 ASSERT_RTNL();
172
173 if (val) {
174 if (br->stp_enabled == BR_NO_STP)
175 br_stp_start(br);
176 } else {
177 if (br->stp_enabled != BR_NO_STP)
178 br_stp_stop(br);
179 }
180}
181
126/* called under bridge lock */ 182/* called under bridge lock */
127void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) 183void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
128{ 184{