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