diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-03-21 17:22:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:28:48 -0400 |
commit | 9cde070874b822d4677f4f01fe146991785813b1 (patch) | |
tree | 2e3a444ad82e026237ce99a4f8cad201f6ca807d /net/bridge/br_stp_if.c | |
parent | 9cf637473c8535b5abe27fee79254c2d552e042a (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.c | 56 |
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 | ||
126 | static 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 | |||
148 | static 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 | |||
169 | void 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 */ |
127 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) | 183 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) |
128 | { | 184 | { |