]> git.ipfire.org Git - people/stevee/network.git/blob - src/functions/functions.stp
Remove the function keyword which is a bashism
[people/stevee/network.git] / src / functions / functions.stp
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
6 # #
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. #
11 # #
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. #
16 # #
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/>. #
19 # #
20 ###############################################################################
21
22 # The default mode.
23 # We default to RSTP, because it has the better user experience and
24 # faster convergence times. Despite of that, it completely downgradeable
25 # to plain STP.
26 STP_DEFAULT_MODE="rstp"
27
28 # Allowed modes of the spanning tree protocol.
29 STP_ALLOWED_MODES="rstp stp"
30
31 stp_enable() {
32 local bridge=${1}
33 assert isset bridge
34
35 # Tell the kernel to enable STP.
36 print 1 > ${SYS_CLASS_NET}/${bridge}/bridge/stp_state
37 }
38
39 stp_disable() {
40 local bridge=${1}
41 assert isset bridge
42
43 # Tell the kernel to disable STP.
44 print 0 > ${SYS_CLASS_NET}/${bridge}/bridge/stp_state
45 }
46
47 stp_is_enabled() {
48 local bridge=${1}
49 assert isset bridge
50
51 local state=$(__device_get_file ${bridge} bridge/stp_state)
52
53 case "${state}" in
54 0)
55 return ${EXIT_FALSE}
56 ;;
57 *)
58 return ${EXIT_TRUE}
59 ;;
60 esac
61 }
62
63 stp_is_userspace() {
64 local bridge=${1}
65 assert isset bridge
66
67 local state=$(__device_get_file ${bridge} bridge/stp_state)
68 case "${state}" in
69 2)
70 return ${EXIT_TRUE}
71 ;;
72 *)
73 return ${EXIT_FALSE}
74 ;;
75 esac
76 }
77
78 stp_get_name() {
79 local proto=${1}
80
81 case "${proto}" in
82 stp)
83 echo "Spanning Tree Protocol"
84 ;;
85 rstp)
86 echo "Rapid Spanning Tree Protocol"
87 ;;
88 mstp)
89 echo "Multiple Spanning Tree Protocol"
90 ;;
91 esac
92
93 return ${EXIT_OK}
94 }
95
96 stp_bridge_set_protocol() {
97 local bridge=${1}
98 assert isset bridge
99
100 local mode=${2}
101 assert isset mode
102
103 if ! listmatch ${mode} ${STP_ALLOWED_MODES}; then
104 log WARNING "Unknown protocol version: ${mode}."
105 log WARNING "Using default mode."
106
107 mode="${STP_DEFAULT_MODE}"
108 fi
109
110 cmd mstpctl setforcevers ${bridge} ${mode}
111 assert [ $? -eq 0 ]
112 }
113
114 stp_bridge_get_protocol() {
115 local bridge=${1}
116
117 assert isset bridge
118
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")
121
122 case "${state}" in
123 0)
124 # STP is disabled.
125 return ${EXIT_OK}
126 ;;
127 1)
128 # Kernel mode STP is running.
129 echo "stp"
130 return ${EXIT_OK}
131 ;;
132 2)
133 # User-space STP is running.
134 ;;
135 *)
136 log ERROR "Kernel is running in an unknown STP state."
137 return ${EXIT_ERROR}
138 ;;
139 esac
140
141 # We get here, when STP is running in user-space mode.
142
143 # Get the current protocol version.
144 mstpctl showbridge ${bridge} force-protocol-version 2>/dev/null
145
146 return ${EXIT_OK}
147 }
148
149 stp_bridge_get_id() {
150 local bridge=${1}
151 assert isset bridge
152
153 __device_get_file ${bridge} "bridge/bridge_id"
154
155 return $?
156 }
157
158 stp_bridge_get_forward_delay() {
159 local bridge=${1}
160 assert isset bridge
161
162 if stp_is_userspace ${bridge}; then
163 cmd mstpctl showbridge ${bridge} forward-delay
164 else
165 local output=$(__device_get_file ${bridge} bridge/forward_delay)
166 __stp_div_100 ${output}
167 fi
168
169 return ${EXIT_OK}
170 }
171
172 stp_bridge_set_forward_delay() {
173 local bridge=${1}
174 assert isset bridge
175
176 local fdelay=${2}
177 assert isinteger fdelay
178
179 # The smallest value that may be set is 2.
180 if [ ${fdelay} -lt 2 ]; then
181 fdelay=2
182 fi
183
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}
187
188 # Set the new value.
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 ))"
191
192 return ${EXIT_OK}
193 }
194
195 stp_bridge_get_hello_time() {
196 local bridge=${1}
197 assert isset bridge
198
199 local ht=$(__device_get_file ${bridge} bridge/hello_time)
200 __stp_div_100 ${ht}
201
202 return ${EXIT_OK}
203 }
204
205 stp_bridge_set_hello_time() {
206 local bridge=${1}
207 assert isset bridge
208
209 local hello=${2}
210 assert isinteger hello
211
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}
215
216 # Set the new value.
217 log INFO "Changing hello time for '${bridge}': ${current_hello} --> ${hello}"
218 print "$(( ${hello} * 100 ))" > ${SYS_CLASS_NET}/${bridge}/bridge/hellow_time
219
220 return ${EXIT_OK}
221 }
222
223 stp_bridge_get_max_age() {
224 local bridge=${1}
225 assert isset bridge
226
227 local maxage=$(__device_get_file ${bridge} "bridge/max_age")
228 __stp_div_100 ${maxage}
229
230 return ${EXIT_OK}
231 }
232
233 stp_bridge_set_max_age() {
234 local bridge=${1}
235 assert isset bridge
236
237 local maxage=${2}
238 assert isinteger maxage
239
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}
243
244 # Set the new value.
245 log INFO "Changing max age for '${bridge}': ${current_maxage} --> ${maxage}"
246 print "$(( ${maxage} * 100 ))" > ${SYS_CLASS_NET}/${bridge}/bridge/max_age
247
248 return ${EXIT_OK}
249 }
250
251 stp_bridge_get_priority() {
252 local bridge=${1}
253 assert isset bridge
254
255 __device_get_file ${bridge} "bridge/priority"
256 return ${EXIT_OK}
257 }
258
259 stp_bridge_set_priority() {
260 local bridge=${1}
261 assert isset bridge
262
263 local priority=${2}
264 assert isinteger priority
265
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}
269
270 # Set the new value.
271 log INFO "Changing priority for '${bridge}': ${current_priority} --> ${priority}"
272 print "${priority}" > ${SYS_CLASS_NET}/${bridge}/bridge/priority
273
274 return ${EXIT_OK}
275 }
276
277 stp_bridge_get_designated_root() {
278 local bridge=${1}
279 assert isset bridge
280
281 local output
282
283 if stp_is_userspace ${bridge}; then
284 output=$(cmd mstpctl showbridge ${bridge} designated-root)
285 else
286 output=$(__device_get_file ${bridge} bridge/root_id)
287 fi
288 output=${output:6}
289
290 # Print output (lowercase).
291 print "${output,,}"
292
293 if isset output; then
294 return ${EXIT_OK}
295 else
296 return ${EXIT_ERROR}
297 fi
298 }
299
300 stp_bridge_get_root_path_cost() {
301 local bridge=${1}
302 assert isset bridge
303
304 if stp_is_userspace ${bridge}; then
305 cmd mstpctl showbridge ${bridge} path-cost
306 else
307 __device_get_file ${bridge} bridge/root_path_cost
308 fi
309
310 return ${EXIT_OK}
311 }
312
313 stp_bridge_get_root_port_id() {
314 local bridge=${1}
315 assert isset bridge
316
317 if stp_is_userspace ${bridge}; then
318 local root_port=$(cmd mstpctl showbridge ${bridge} root-port)
319
320 # Return error, when there is no root port.
321 if [ "${root_port}" = "none" ]; then
322 return ${EXIT_ERROR}
323 fi
324
325 print "${root_port}"
326 else
327 __device_get_file ${bridge} bridge/root_port_id
328 fi
329
330 return ${EXIT_OK}
331 }
332
333 stp_bridge_get_root_port() {
334 local bridge=${1}
335 assert isset bridge
336
337 local id=$(stp_bridge_get_root_port_id ${bridge})
338
339 local member member_id
340 for member in $(bridge_get_members ${bridge}); do
341 member_id=$(stp_port_get_id ${bridge} ${member})
342
343 if [ "${id}" = "${member_id}" ]; then
344 print "${member}"
345 return ${EXIT_OK}
346 fi
347 done
348
349 return ${EXIT_ERROR}
350 }
351
352 stp_bridge_is_root() {
353 local bridge=${1}
354 assert isset bridge
355
356 local root_path_cost=$(stp_bridge_get_root_path_cost ${bridge})
357
358 if [ "${root_path_cost}" = "0" ]; then
359 return ${EXIT_TRUE}
360 fi
361
362 return ${EXIT_FALSE}
363 }
364
365 stp_bridge_get_topology_change_count() {
366 local bridge=${1}
367 assert isset bridge
368
369 if stp_is_userspace ${bridge}; then
370 cmd mstpctl showbridge ${bridge} topology-change-count
371 else
372 __device_get_file ${bridge} bridge/topology_change
373 fi
374
375 return ${EXIT_OK}
376 }
377
378 stp_bridge_get_topology_change_timer() {
379 local bridge=${1}
380 assert isset bridge
381
382 if stp_is_userspace ${bridge}; then
383 cmd mstpctl showbridge ${bridge} time-since-topology-change
384 else
385 __device_get_file ${bridge} bridge/topology_change_timer
386 fi
387
388 return ${EXIT_OK}
389 }
390
391 stp_bridge_get_topology_change_detected() {
392 local bridge=${1}
393 assert isset bridge
394
395 local change
396
397 if stp_is_userspace ${bridge}; then
398 change=$(mstpctl showbridge ${bridge} topology-change)
399 else
400 change=$(__device_get_file ${bridge} bridge/topology_change_detected)
401 fi
402
403 if enabled change; then
404 print "yes"
405 return ${EXIT_TRUE}
406 else
407 print "no"
408 return ${EXIT_FALSE}
409 fi
410 }
411
412 stp_port_get_state() {
413 local bridge=${1}
414 assert isset bridge
415
416 local port=${2}
417 assert isset port
418
419 local space
420 if stp_is_userspace ${bridge}; then
421 state=$(mstpctl showportdetail ${bridge} ${port} state)
422 print "${state^^}"
423 else
424 state=$(__device_get_file ${bridge} brif/${port}/state)
425
426 case "${state}" in
427 0)
428 print "DISABLED"
429 ;;
430 1)
431 print "LISTENING"
432 ;;
433 2)
434 print "LEARNING"
435 ;;
436 3)
437 print "FORWARDING"
438 ;;
439 4)
440 print "BLOCKING"
441 ;;
442 *)
443 return ${EXIT_ERROR}
444 ;;
445 esac
446 fi
447
448 return ${EXIT_OK}
449 }
450
451 stp_port_get_id() {
452 local bridge=${1}
453 assert isset bridge
454
455 local port=${2}
456 assert isset port
457
458 dec $(__device_get_file ${bridge} "brif/${port}/port_no")
459 return ${EXIT_OK}
460 }
461
462 stp_port_get_cost() {
463 local bridge=${1}
464 assert isset bridge
465
466 local port=${2}
467 assert isset port
468
469 if stp_is_userspace ${bridge}; then
470 cmd mstpctl showportdetail ${bridge} ${port} external-port-cost
471 else
472 __device_get_file ${bridge} brif/${port}/path_cost
473 fi
474
475 return ${EXIT_ERROR}
476 }
477
478 stp_port_set_cost() {
479 assert [ $# -eq 3 ]
480
481 local bridge="${1}"
482 local port="${2}"
483 local cost="${3}"
484
485 local old_cost="$(stp_port_get_cost "${bridge}" "${port}")"
486 if [ "${cost}" = "${old_cost}" ]; then
487 return ${EXIT_OK}
488 fi
489
490 log DEBUG "Setting STP path costs of port '${port}' (bridge '${bridge}') to '${cost}'"
491
492 if stp_is_userspace "${bridge}"; then
493 cmd mstpctl setportpathcost "${bridge}" "${port}" "${cost}"
494 else
495 __device_set_file "${bridge}" "brif/${port}/path_cost" "${cost}"
496 fi
497 }
498
499 stp_port_get_designated_root() {
500 local bridge=${1}
501 assert isset bridge
502
503 local port=${2}
504 assert isset port
505
506 local output
507
508 if stp_is_userspace ${bridge}; then
509 output=$(cmd mstpctl showportdetail ${bridge} ${port} designated-root)
510 output=${output:6}
511 else
512 output=$(__device_get_file ${bridge} brif/${port}/designated_root)
513 output=${output:5}
514 fi
515
516 if isset output; then
517 mac_format ${output}
518 return ${EXIT_OK}
519 fi
520
521 return ${EXIT_ERROR}
522 }
523
524 __stp_div_100() {
525 local val=${1}
526
527 local split=$((${#val} - 2))
528 val="${val:0:${split}}.${val:${split}:2}"
529
530 # Round the output.
531 print "%.0f" "${val}"
532 }