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