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