]> git.ipfire.org Git - people/ms/network.git/blame_incremental - src/hooks/zones/bridge
Makefile: Fix typo in localstatedir
[people/ms/network.git] / src / hooks / zones / bridge
... / ...
CommitLineData
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. /usr/lib/network/header-zone
23
24HOOK_MANPAGE="network-zone-bridge"
25
26HOOK_SETTINGS=(
27 "ADDRESS"
28 "STP"
29 "STP_FORWARD_DELAY"
30 "STP_HELLO STP_MAXAGE"
31 "STP_PRIORITY"
32 "MTU"
33)
34
35HOOK_PORT_SETTINGS=(
36 "COST"
37 "PRIORITY"
38)
39
40# Default values
41DEFAULT_STP="on"
42DEFAULT_STP_FORWARD_DELAY=0
43DEFAULT_STP_HELLO=2
44DEFAULT_STP_MAXAGE=20
45DEFAULT_STP_PRIORITY=512
46
47hook_check_settings() {
48 assert ismac ADDRESS
49 assert isset MTU && assert mtu_is_valid "ethernet" "${MTU}"
50
51 # Spanning Tree Protocol
52 assert isbool STP
53 assert isinteger STP_HELLO
54 assert isinteger STP_FORWARD_DELAY
55 assert isinteger STP_PRIORITY
56}
57
58hook_parse_cmdline() {
59 while [ $# -gt 0 ]; do
60 case "${1}" in
61 --address=*)
62 ADDRESS="$(cli_get_val "${1}")"
63
64 if ! mac_is_valid "${ADDRESS}"; then
65 error "Invalid MAC address: ${ADDRESS}"
66 return ${EXIT_ERROR}
67 fi
68 ;;
69
70 --mtu=*)
71 MTU="$(cli_get_val "${1}")"
72
73 if ! mtu_is_valid "ethernet" "${MTU}"; then
74 error "Invalid MTU: ${MTU}"
75 return ${EXIT_ERROR}
76 fi
77 ;;
78
79 --stp=*)
80 STP="$(cli_get_val "${1}")"
81
82 if enabled STP; then
83 STP="on"
84 elif disabled STP; then
85 STP="off"
86 else
87 error "Invalid value for STP: ${STP}"
88 return ${EXIT_ERROR}
89 fi
90 ;;
91
92 --stp-forward-delay=*)
93 STP_FORWARD_DELAY="$(cli_get_val "${1}")"
94
95 if ! isinteger STP_FORWARD_DELAY; then
96 error "Invalid STP forwarding delay: ${STP_FORWARD_DELAY}"
97 return ${EXIT_ERROR}
98 fi
99 ;;
100
101 --stp-hello=*)
102 STP_HELLO="$(cli_get_val "${1}")"
103
104 if ! isinteger STP_HELLO; then
105 error "Invalid STP hello time: ${STP_HELLO}"
106 return ${EXIT_ERROR}
107 fi
108 ;;
109
110 --stp-max-age=*)
111 STP_MAXAGE="$(cli_get_val "${1}")"
112
113 if ! isinteger STP_MAXAGE; then
114 error "Invalid STP max age: ${STP_MAXAGE}"
115 return ${EXIT_ERROR}
116 fi
117 ;;
118
119 --stp-priority=*)
120 STP_PRIORITY="$(cli_get_val "${1}")"
121
122 if ! isinteger STP_PRIORITY; then
123 error "Invalid STP priority: ${STP_PRIORITY}"
124 return ${EXIT_ERROR}
125 fi
126 ;;
127
128 *)
129 error "Unknown argument: ${1}"
130 return ${EXIT_ERROR}
131 ;;
132 esac
133 shift
134 done
135
136 # Generate a random MAC address if the user passed none
137 if ! isset ADDRESS; then
138 ADDRESS="$(mac_generate)"
139 fi
140
141 return ${EXIT_OK}
142}
143
144hook_up() {
145 local zone=${1}
146 assert isset zone
147
148 zone_settings_read "${zone}"
149
150 # Create the bridge if it does not already exist.
151 if ! device_exists "${zone}"; then
152 bridge_create "${zone}" \
153 --address="${ADDRESS}" \
154 --mtu="${MTU}"
155 fi
156
157 # Enable STP
158 if enabled STP; then
159 stp_enable "${zone}"
160
161 if isset STP_FORWARD_DELAY; then
162 stp_bridge_set_forward_delay "${zone}" "${STP_FORWARD_DELAY}"
163 fi
164
165 if isset STP_HELLO; then
166 stp_bridge_set_hello_time "${zone}" "${STP_HELLO}"
167 fi
168
169 if isset STP_MAXAGE; then
170 stp_bridge_set_max_age "${zone}" "${STP_MAXAGE}"
171 fi
172
173 if isset STP_PRIORITY; then
174 stp_bridge_set_priority "${zone}" "${STP_PRIORITY}"
175 fi
176 else
177 stp_disable "${zone}"
178 fi
179
180 device_set_up "${zone}"
181
182 # XXX Currently, there is a bug (in the linux kernel?) that we need to
183 # set our bridges to promisc mode.
184 device_set_promisc "${zone}" on
185
186 # Bring up all configurations
187 zone_configs_up "${zone}"
188
189 exit ${EXIT_OK}
190}
191
192hook_down() {
193 local zone="${1}"
194 assert isset zone
195
196 if ! device_is_up "${zone}"; then
197 warning "Zone '${zone}' is not up"
198 exit ${EXIT_OK}
199 fi
200
201 # Stop all the configs.
202 zone_configs_down "${zone}"
203
204 # Bring down all the ports.
205 zone_ports_down "${zone}"
206 zone_ports_remove "${zone}"
207
208 # Remove the bridge.
209 device_set_down "${zone}"
210 bridge_delete "${zone}"
211
212 exit ${EXIT_OK}
213}
214
215hook_status() {
216 local zone="${1}"
217 assert isset zone
218
219 # Print the default header.
220 cli_device_headline "${zone}"
221
222 # Exit if zone is down
223 if ! zone_is_up "${zone}"; then
224 echo # Empty line
225 exit ${EXIT_ERROR}
226 fi
227
228 cli_headline 2 "Spanning Tree Protocol information"
229 if stp_is_enabled "${zone}"; then
230 cli_print_fmt1 2 "ID" "$(stp_bridge_get_id ${zone})"
231 cli_print_fmt1 2 "Priority" "$(stp_bridge_get_priority ${zone})"
232
233 if stp_bridge_is_root ${zone}; then
234 cli_print 2 "This bridge is root."
235 else
236 cli_print_fmt1 2 "Designated root" \
237 "$(stp_bridge_get_designated_root ${zone})"
238 cli_print_fmt1 2 "Root path cost" \
239 "$(stp_bridge_get_root_path_cost ${zone})"
240 fi
241 cli_space
242
243 # Topology information
244 cli_print_fmt1 2 "Topology changing" \
245 "$(stp_bridge_get_topology_change_detected ${zone})"
246 cli_print_fmt1 2 "Topology change time" \
247 "$(beautify_time $(stp_bridge_get_topology_change_timer ${zone}))"
248 cli_print_fmt1 2 "Topology change count" \
249 "$(stp_bridge_get_topology_change_count ${zone})"
250 cli_space
251 else
252 cli_print 2 "Disabled"
253 cli_space
254 fi
255
256 cli_headline 2 "Ports"
257 zone_ports_status "${zone}"
258 cli_space
259
260 cli_headline 2 "Configurations"
261 zone_configs_cmd status "${zone}"
262 cli_space
263
264 exit ${EXIT_OK}
265}
266
267hook_hotplug() {
268 local zone="${1}"
269 assert isset zone
270
271 case "$(hotplug_action)" in
272 add)
273 # Attach all ports when zone is coming up
274 if hotplug_event_interface_is_zone "${zone}"; then
275 # Bring up all ports
276 local port
277 for port in $(zone_get_ports "${zone}"); do
278 log DEBUG "Trying to attach port ${port} to ${zone}"
279
280 hook_port_up "${zone}" "${port}"
281 done
282
283 # Handle ports of this zone that have just been added
284 elif hotplug_event_interface_is_port_of_zone "${zone}"; then
285 # Attach the device if the parent bridge is up
286 if zone_is_active "${zone}"; then
287 hook_port_up "${zone}" "${INTERFACE}"
288 fi
289 fi
290 ;;
291
292 remove)
293 if hotplug_event_interface_is_zone "${zone}"; then
294 # Bring down/destroy all ports
295 local port
296 for port in $(zone_get_ports "${zone}"); do
297 log DEBUG "Trying to detach port ${port} from ${zone}"
298
299 hook_port_down "${zone}" "${port}"
300 done
301
302 # Handle ports of this zone that have just been removed
303 elif hotplug_event_interface_is_port_of_zone "${zone}"; then
304 hook_port_down "${zone}" "${INTERFACE}"
305 fi
306 ;;
307
308 *)
309 exit ${EXIT_NOT_HANDLED}
310 ;;
311 esac
312
313 exit ${EXIT_OK}
314}
315
316hook_check_port_settings() {
317 if isset COST; then
318 assert isinteger COST
319 fi
320
321 if isset PRIORITY; then
322 assert isinteger PRIORITY
323 fi
324}
325
326hook_port_attach() {
327 # Excepting at least two arguments here
328 assert [ $# -ge 2 ]
329
330 local zone="${1}"
331 local port="${2}"
332 shift 2
333
334 if zone_has_port "${zone}" "${port}"; then
335 zone_port_settings_read "${zone}" "${port}"
336 fi
337
338 local arg
339 local val
340 while read arg; do
341 case "${arg}" in
342 --cost=*)
343 COST="$(cli_get_val "${arg}")"
344 ;;
345 --priority=*)
346 PRIORITY="$(cli_get_val "${arg}")"
347 ;;
348 esac
349 done <<< "$(args "$@")"
350
351 if ! zone_port_settings_write "${zone}" "${port}"; then
352 exit ${EXIT_ERROR}
353 fi
354
355 exit ${EXIT_OK}
356}
357
358hook_port_detach() {
359 assert [ $# -eq 2 ]
360
361 local zone="${1}"
362 local port="${2}"
363
364 # Shut down the port (if possible)
365 port_down "${port}"
366
367 if ! zone_port_settings_remove "${zone}" "${port}"; then
368 exit ${EXIT_ERROR}
369 fi
370
371 exit ${EXIT_OK}
372}
373
374hook_port_edit() {
375 hook_port_attach "$@"
376}
377
378hook_port_up() {
379 assert [ $# -eq 2 ]
380
381 local zone="${1}"
382 local port="${2}"
383
384 # Try bringing up the port if it has not been
385 # brought up before.
386 # We will get here as soon as the port device has
387 # been created and will then connect it with the bridge.
388 if ! device_exists "${port}"; then
389 port_create "${port}"
390
391 return ${EXIT_OK}
392 fi
393
394 # Read configuration values
395 zone_port_settings_read "${zone}" "${port}" ${HOOK_PORT_SETTINGS}
396
397 # Make sure that the port is up
398 port_up "${port}"
399
400 # Attach the port to the bridge
401 bridge_attach_device "${zone}" "${port}"
402
403 # Set STP configuration
404 if isset COST; then
405 stp_port_set_cost "${zone}" "${port}" "${COST}"
406 fi
407
408 if isset PRIORITY; then
409 stp_port_set_priority "${zone}" "${port}" "${PRIORITY}"
410 fi
411
412 return ${EXIT_OK}
413}
414
415hook_port_down() {
416 assert [ $# -eq 2 ]
417
418 local zone="${1}"
419 local port="${2}"
420
421 if device_exists "${port}"; then
422 bridge_detach_device "${zone}" "${port}"
423
424 port_down "${port}"
425 fi
426
427 return ${EXIT_OK}
428}
429
430hook_port_status() {
431 assert [ $# -eq 2 ]
432
433 local zone="${1}"
434 local port="${2}"
435
436 # Do nothing for devices which are not up and running.
437 device_exists "${port}" || exit ${EXIT_OK}
438
439 local status
440
441 # Check if the device is down.
442 if ! device_is_up "${port}"; then
443 status="${MSG_DEVICE_STATUS_DOWN}"
444
445 # Check if the device has no carrier.
446 elif ! device_has_carrier "${port}"; then
447 status="${MSG_DEVICE_STATUS_NOCARRIER}"
448
449 # Check for STP information.
450 elif stp_is_enabled "${zone}"; then
451 local state="$(stp_port_get_state "${zone}" "${port}")"
452 state="MSG_STP_${state}"
453 status="${!state}"
454
455 status="${status} - DSR: $(stp_port_get_designated_root "${zone}" "${port}")"
456 status="${status} - Cost: $(stp_port_get_cost "${zone}" "${port}")"
457 else
458 status="${MSG_DEVICE_STATUS_UP}"
459 fi
460 cli_statusline 3 "${port}" "${status}"
461
462 exit ${EXIT_OK}
463}