2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
23 # We default to RSTP, because it has the better user experience and
24 # faster convergence times. Despite of that, it completely downgradeable
26 STP_DEFAULT_MODE
="rstp"
28 # Allowed modes of the spanning tree protocol.
29 STP_ALLOWED_MODES
="rstp stp"
31 function stp_enable
() {
35 # Tell the kernel to enable STP.
36 print
1 > ${SYS_CLASS_NET}/${bridge}/bridge
/stp_state
39 function stp_disable
() {
43 # Tell the kernel to disable STP.
44 print
0 > ${SYS_CLASS_NET}/${bridge}/bridge
/stp_state
47 function stp_is_enabled
() {
51 local state
=$
(__device_get_file
${bridge} bridge
/stp_state
)
63 function stp_is_userspace
() {
67 local state
=$
(__device_get_file
${bridge} bridge
/stp_state
)
78 function stp_get_name
() {
83 echo "Spanning Tree Protocol"
86 echo "Rapid Spanning Tree Protocol"
89 echo "Multiple Spanning Tree Protocol"
96 function stp_bridge_set_protocol
() {
103 if ! listmatch
${mode} ${STP_ALLOWED_MODES}; then
104 log WARNING
"Unknown protocol version: ${mode}."
105 log WARNING
"Using default mode."
107 mode
="${STP_DEFAULT_MODE}"
110 cmd mstpctl setforcevers
${bridge} ${mode}
114 function stp_bridge_get_protocol
() {
119 # Let's check what the kernel is telling us about it's STP state.
120 local state
=$
(__device_get_file
${bridge} "bridge/stp_state")
128 # Kernel mode STP is running.
133 # User-space STP is running.
136 log ERROR
"Kernel is running in an unknown STP state."
141 # We get here, when STP is running in user-space mode.
143 # Get the current protocol version.
144 mstpctl showbridge
${bridge} force-protocol-version
2>/dev
/null
149 function stp_bridge_get_id
() {
153 __device_get_file
${bridge} "bridge/bridge_id"
158 function stp_bridge_get_forward_delay
() {
162 if stp_is_userspace
${bridge}; then
163 cmd mstpctl showbridge
${bridge} forward-delay
165 local output
=$
(__device_get_file
${bridge} bridge
/forward_delay
)
166 __stp_div_100
${output}
172 function stp_bridge_set_forward_delay
() {
177 assert isinteger fdelay
179 # The smallest value that may be set is 2.
180 if [ ${fdelay} -lt 2 ]; then
184 # Check if the setting we want is already set.
185 local current_fdelay
=$
(stp_bridge_get_forward_delay
${bridge})
186 [ ${fdelay} -eq ${current_fdelay} ] && return ${EXIT_OK}
189 log DEBUG
"Setting forward delay on bridge '${bridge}' from '${current_fdelay}' to '${fdelay}'"
190 fwrite
"${SYS_CLASS_NET}/${bridge}/bridge/forward_delay" "$(( ${fdelay} * 100 ))"
195 function stp_bridge_get_hello_time
() {
199 local ht
=$
(__device_get_file
${bridge} bridge
/hello_time
)
205 function stp_bridge_set_hello_time
() {
210 assert isinteger hello
212 # Check if the setting we want is already set.
213 local current_hello
=$
(stp_bridge_get_hello_time
${bridge})
214 [ ${hello} -eq ${current_hello} ] && return ${EXIT_OK}
217 log INFO
"Changing hello time for '${bridge}': ${current_hello} --> ${hello}"
218 print
"$(( ${hello} * 100 ))" > ${SYS_CLASS_NET}/${bridge}/bridge/hellow_time
223 function stp_bridge_get_max_age() {
227 local maxage=$(__device_get_file ${bridge} "bridge
/max_age
")
228 __stp_div_100 ${maxage}
233 function stp_bridge_set_max_age() {
238 assert isinteger maxage
240 # Check if the setting we want is already set.
241 local current_maxage=$(stp_bridge_get_max_age ${bridge})
242 [ ${maxage} -eq ${current_maxage} ] && return ${EXIT_OK}
245 log INFO "Changing max age
for '${bridge}': ${current_maxage} --> ${maxage}"
246 print "$(( ${maxage} * 100 ))" > ${SYS_CLASS_NET}/${bridge}/bridge/max_age
251 function stp_bridge_get_priority() {
255 __device_get_file ${bridge} "bridge/priority"
259 function stp_bridge_set_priority() {
264 assert isinteger priority
266 # Check if the setting we want is already set.
267 local current_priority=$(stp_bridge_get_priority ${bridge})
268 [ ${priority} -eq ${current_priority} ] && return ${EXIT_OK}
271 log INFO "Changing priority for '${bridge}': ${current_priority} --> ${priority}"
272 print "${priority}" > ${SYS_CLASS_NET}/${bridge}/bridge
/priority
277 function stp_bridge_get_designated_root
() {
283 if stp_is_userspace
${bridge}; then
284 output
=$
(cmd mstpctl showbridge
${bridge} designated-root
)
286 output
=$
(__device_get_file
${bridge} bridge
/root_id
)
290 # Print output (lowercase).
293 if isset output
; then
300 function stp_bridge_get_root_path_cost
() {
304 if stp_is_userspace
${bridge}; then
305 cmd mstpctl showbridge
${bridge} path-cost
307 __device_get_file
${bridge} bridge
/root_path_cost
313 function stp_bridge_get_root_port_id
() {
317 if stp_is_userspace
${bridge}; then
318 local root_port
=$
(cmd mstpctl showbridge
${bridge} root-port
)
320 # Return error, when there is no root port.
321 if [ "${root_port}" = "none" ]; then
327 __device_get_file
${bridge} bridge
/root_port_id
333 function stp_bridge_get_root_port
() {
337 local id
=$
(stp_bridge_get_root_port_id
${bridge})
339 local member member_id
340 for member
in $
(bridge_get_members
${bridge}); do
341 member_id
=$
(stp_port_get_id
${bridge} ${member})
343 if [ "${id}" = "${member_id}" ]; then
352 function stp_bridge_is_root
() {
356 local root_path_cost
=$
(stp_bridge_get_root_path_cost
${bridge})
358 if [ "${root_path_cost}" = "0" ]; then
365 function stp_bridge_get_topology_change_count
() {
369 if stp_is_userspace
${bridge}; then
370 cmd mstpctl showbridge
${bridge} topology-change-count
372 __device_get_file
${bridge} bridge
/topology_change
378 function stp_bridge_get_topology_change_timer
() {
382 if stp_is_userspace
${bridge}; then
383 cmd mstpctl showbridge
${bridge} time-since-topology-change
385 __device_get_file
${bridge} bridge
/topology_change_timer
391 function stp_bridge_get_topology_change_detected
() {
397 if stp_is_userspace
${bridge}; then
398 change
=$
(mstpctl showbridge
${bridge} topology-change
)
400 change
=$
(__device_get_file
${bridge} bridge
/topology_change_detected
)
403 if enabled change
; then
412 function stp_port_get_state
() {
420 if stp_is_userspace
${bridge}; then
421 state
=$
(mstpctl showportdetail
${bridge} ${port} state
)
424 state
=$
(__device_get_file
${bridge} brif
/${port}/state
)
451 function stp_port_get_id
() {
458 dec $
(__device_get_file
${bridge} "brif/${port}/port_no")
462 function stp_port_get_cost
() {
469 if stp_is_userspace
${bridge}; then
470 cmd mstpctl showportdetail
${bridge} ${port} external-port-cost
472 __device_get_file
${bridge} brif
/${port}/path_cost
478 function stp_port_set_cost
() {
485 local old_cost
="$(stp_port_get_cost "${bridge}" "${port}")"
486 if [ "${cost}" = "${old_cost}" ]; then
490 log DEBUG
"Setting STP path costs of port '${port}' (bridge '${bridge}') to '${cost}'"
492 if stp_is_userspace
"${bridge}"; then
493 cmd mstpctl setportpathcost
"${bridge}" "${port}" "${cost}"
495 __device_set_file
"${bridge}" "brif/${port}/path_cost" "${cost}"
499 function stp_port_get_designated_root
() {
508 if stp_is_userspace
${bridge}; then
509 output
=$
(cmd mstpctl showportdetail
${bridge} ${port} designated-root
)
512 output
=$
(__device_get_file
${bridge} brif
/${port}/designated_root
)
516 if isset output
; then
524 function __stp_div_100
() {
527 local split=$
((${#val} - 2))
528 val
="${val:0:${split}}.${val:${split}:2}"
531 print
"%.0f" "${val}"