]>
Commit | Line | Data |
---|---|---|
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=( | |
27 | "ADDRESS" | |
28 | "STP" | |
29 | "STP_FORWARD_DELAY" | |
30 | "STP_HELLO STP_MAXAGE" | |
31 | "STP_PRIORITY" | |
32 | "MTU" | |
33 | ) | |
34 | ||
35 | HOOK_PORT_SETTINGS=( | |
36 | "COST" | |
37 | "PRIORITY" | |
38 | ) | |
39 | ||
40 | # Default values | |
41 | DEFAULT_STP="on" | |
42 | DEFAULT_STP_FORWARD_DELAY=0 | |
43 | DEFAULT_STP_HELLO=2 | |
44 | DEFAULT_STP_MAXAGE=20 | |
45 | DEFAULT_STP_PRIORITY=512 | |
46 | ||
47 | hook_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 | ||
58 | hook_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 | ||
144 | hook_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 | ||
192 | hook_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 | ||
215 | hook_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 | ||
267 | hook_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 | ||
316 | hook_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 | ||
326 | hook_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 | ||
358 | hook_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 | ||
374 | hook_port_edit() { | |
375 | hook_port_attach "$@" | |
376 | } | |
377 | ||
378 | hook_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 | ||
415 | hook_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 | ||
430 | hook_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 | } |