]> git.ipfire.org Git - people/ms/network.git/blob - functions.device
network: device_set_{down,up} do set-up/tear-down their parent devices.
[people/ms/network.git] / functions.device
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 function devicify() {
23 local device=${1}
24
25 if device_exists ${device}; then
26 echo "${device}"
27 return ${EXIT_OK}
28 fi
29
30 local d
31 for d in $(devices_get_all); do
32 if [ "$(device_get_address ${d})" = "${device}" ]; then
33 echo "${d}"
34 return ${EXIT_OK}
35 fi
36 done
37
38 return ${EXIT_ERROR}
39 }
40
41 function macify() {
42 local device=${1}
43
44 if mac_is_valid ${device}; then
45 echo "${device}"
46 return ${EXIT_OK}
47 fi
48
49 if device_exists ${device}; then
50 device_get_address ${device}
51 return ${EXIT_OK}
52 fi
53
54 return ${EXIT_ERROR}
55 }
56
57 # Check if the device exists
58 function device_exists() {
59 local device=${1}
60
61 # If device name was not found, exit.
62 [ -n "${device}" ] || return ${EXIT_ERROR}
63
64 [ -d "${SYS_CLASS_NET}/${device}" ]
65 }
66
67 # Check if the device is up
68 function device_is_up() {
69 local device=${1}
70
71 device_exists ${device} || return ${EXIT_ERROR}
72
73 ip link show ${device} 2>/dev/null | grep -qE "<.*UP.*>"
74 }
75
76 # Check if the device is a bonding device
77 function device_is_bonding() {
78 [ -d "/sys/class/net/${1}/bonding" ]
79 }
80
81 # Check if the device bonded in a bonding device
82 function device_is_bonded() {
83 local dev
84 for dev in /sys/class/net/*; do
85 # Skip crappy files
86 [ -d "${dev}" ] || continue
87
88 # Continue if not a bonding device
89 device_is_bonding "${dev##*/}" || continue
90
91 if grep -q "\<${1}\>" ${dev}/bonding/slaves; then
92 return 0
93 fi
94 done
95
96 return 1
97 }
98
99 # Check if the device is a bridge
100 function device_is_bridge() {
101 [ -d "/sys/class/net/${1}/bridge" ]
102 }
103
104 function device_is_bridge_attached() {
105 local device=${1}
106
107 [ -d "${SYS_CLASS_NET}/${device}/brport" ]
108 }
109
110 # Check if the device is a virtual device
111 function device_is_virtual() {
112 local device=${1}
113
114 [ -e "/proc/net/vlan/${device}" ]
115 }
116
117 # Check if the device has virtual devices
118 function device_has_virtuals() {
119 local device=${1}
120
121 if device_is_virtual ${device}; then
122 return 1
123 fi
124
125 if [ ! -e "/proc/net/vlan/config" ]; then
126 return 1
127 fi
128 grep -q "${1}$" /proc/net/vlan/config
129 }
130
131 function device_is_vlan() { # XXX Compat function
132 log DEBUG "Deprecated function device_is_vlan() was used."
133
134 device_is_virtual $@
135 }
136
137 # Check if the device is a ppp device
138 function device_is_ppp() {
139 local device=${1}
140
141 ip link show ${device} 2>/dev/null | grep -qE "<.*POINTOPOINT.*>"
142 }
143
144 # Check if the device is a loopback device
145 function device_is_loopback() {
146 local device=$(devicify ${1})
147 [ "${device}" = "lo" ]
148 }
149
150 # Check if the device is a physical network interface
151 function device_is_real() {
152 local device=${1}
153
154 device_is_loopback ${device} && \
155 return ${EXIT_ERROR}
156
157 device_is_bonding ${device} && \
158 return ${EXIT_ERROR}
159
160 device_is_bridge ${device} && \
161 return ${EXIT_ERROR}
162
163 device_is_ppp ${device} && \
164 return ${EXIT_ERROR}
165
166 device_is_virtual ${device} && \
167 return ${EXIT_ERROR}
168
169 return ${EXIT_OK}
170 }
171
172 # Get the device type
173 function device_get_type() {
174 local device=$(devicify ${1})
175
176 if device_is_vlan ${device}; then
177 echo "vlan"
178
179 elif device_is_bonding ${device}; then
180 echo "bonding"
181
182 elif device_is_bridge ${device}; then
183 echo "bridge"
184
185 elif device_is_ppp ${device}; then
186 echo "ppp"
187
188 elif device_is_loopback ${device}; then
189 echo "loopback"
190
191 elif device_is_real ${device}; then
192 echo "real"
193
194 else
195 echo "unknown"
196 fi
197 }
198
199 function device_get_address() {
200 local device=${1}
201
202 cat ${SYS_CLASS_NET}/${device}/address 2>/dev/null
203 }
204
205 function device_set_address() {
206 local device=${1}
207 local addr=${2}
208
209 if ! device_exists ${device}; then
210 error "Device '${device}' does not exist."
211 return ${EXIT_ERROR}
212 fi
213
214 log INFO "Setting address of '${device}' to '${addr}' - was $(device_get_address ${device})."
215
216 local up
217 if device_is_up ${device}; then
218 device_set_down ${device}
219 up=1
220 fi
221
222 ip link set ${device} address ${addr}
223 local ret=$?
224
225 if [ "${up}" = "1" ]; then
226 device_set_up ${device}
227 fi
228
229 if [ "${ret}" != "0" ]; then
230 error_log "Could not set address '${addr}' on device '${device}'."
231 fi
232
233 return ${ret}
234 }
235
236 function devices_get_all() {
237 local device
238 for device in ${SYS_CLASS_NET}/*; do
239 echo "$(basename ${device})"
240 done | sort
241 }
242
243 # Check if a device has a cable plugged in
244 function device_has_carrier() {
245 local device=$(devicify ${1})
246 [ "$(<${SYS_CLASS_NET}/${device}/carrier)" = "1" ]
247 }
248
249 # Check if the device is free
250 function device_is_free() {
251 ! device_is_used $@
252 }
253
254 # Check if the device is used
255 function device_is_used() {
256 local device=$(devicify ${1})
257
258 device_has_virtuals ${device} && \
259 return ${EXIT_OK}
260 device_is_bonded ${device} && \
261 return ${EXIT_OK}
262 device_is_bridge_attached ${device} && \
263 return ${EXIT_OK}
264
265 return ${EXIT_ERROR}
266 }
267
268 # XXX to be removed I think
269 function device_get_free() {
270 local destination=${1}
271
272 # Replace + by a valid number
273 if grep -q "+$" <<<${destination}; then
274 local number=0
275 destination=$(sed -e "s/+//" <<<$destination)
276 while [ "${number}" -le "100" ]; do
277 if ! device_exists "${destination}${number}"; then
278 destination="${destination}${number}"
279 break
280 fi
281 number=$(($number + 1))
282 done
283 fi
284 echo "${destination}"
285 }
286
287 function device_rename() {
288 warning_log "Called deprecated function 'device_rename'"
289
290 device_set_name $@
291 }
292
293 function device_hash() {
294 local device=${1}
295
296 macify ${device} | tr -d ':'
297 }
298
299 # Give the device a new name
300 function device_set_name() {
301 local source=$1
302 local destination=$(device_get_free ${2})
303
304 # Check if devices exists
305 if ! device_exists ${source} || device_exists ${destination}; then
306 return 4
307 fi
308
309 local up
310 if device_is_up ${source}; then
311 ip link set ${source} down
312 up=1
313 fi
314
315 ip link set ${source} name ${destination}
316
317 if [ "${up}" = "1" ]; then
318 ip link set ${destination} up
319 fi
320 }
321
322 # Set device up
323 function device_set_up() {
324 local device=$(devicify ${1})
325
326 # Do nothing if device is already up
327 device_is_up ${device} && return ${EXIT_OK}
328
329 device_set_parent_up ${device}
330
331 log DEBUG "Setting up device '${device}'"
332
333 ip link set ${device} up
334 }
335
336 function device_set_parent_up() {
337 local device=${1}
338 local parent
339
340 if device_is_virtual ${device}; then
341 parent=$(device_virtual_get_parent ${device})
342
343 device_is_up ${parent} && return ${EXIT_OK}
344
345 log DEBUG "Setting up parent device '${parent}' of '${device}'"
346
347 device_set_up ${parent}
348 return $?
349 fi
350
351 return ${EXIT_OK}
352 }
353
354 # Set device down
355 function device_set_down() {
356 local device=$(devicify ${1})
357
358 local ret=${EXIT_OK}
359
360 if device_is_up ${device}; then
361 log DEBUG "Tearing down device '${device}'"
362
363 ip link set ${device} down
364 ret=$?
365 fi
366
367 device_set_parent_down ${device}
368
369 return ${ret}
370 }
371
372 function device_set_parent_down() {
373 local device=${1}
374 local parent
375
376 if device_is_virtual ${device}; then
377 parent=$(device_virtual_get_parent ${device})
378
379 device_is_up ${parent} || return ${EXIT_OK}
380
381 if device_is_free ${parent}; then
382 log DEBUG "Tearing down parent device '${parent}' of '${device}'"
383
384 device_set_down ${parent}
385 fi
386 fi
387
388 return ${EXIT_OK}
389 }
390
391 # Set new address to a device
392 function device_set_mac() {
393 warning_log "Called deprecated function 'device_set_mac'"
394
395 device_set_address $@
396 }
397
398 function device_get_mtu() {
399 local device=${1}
400
401 if ! device_exists ${device}; then
402 error "Device '${device}' does not exist."
403 return ${EXIT_ERROR}
404 fi
405
406 cat ${SYS_CLASS_NET}/${device}/mtu
407 }
408
409 # Set mtu to a device
410 function device_set_mtu() {
411 local device=${1}
412 local mtu=${2}
413
414 if ! device_exists ${device}; then
415 error "Device '${device}' does not exist."
416 return ${EXIT_ERROR}
417 fi
418
419 local oldmtu=$(device_get_mtu ${device})
420
421 if [ "${oldmtu}" = "${mtu}" ]; then
422 # No need to set mtu.
423 return ${EXIT_OK}
424 fi
425
426 log INFO "Setting mtu of '${device}' to '${mtu}' - was ${oldmtu}."
427
428 local up
429 if device_is_up ${device}; then
430 device_set_down ${device}
431 up=1
432 fi
433
434 ip link set ${device} mtu ${mtu}
435 local ret=$?
436
437 if [ "${up}" = "1" ]; then
438 device_set_up ${device}
439 fi
440
441 if [ "${ret}" != "0" ]; then
442 error_log "Could not set mtu '${mtu}' on device '${device}'."
443 fi
444
445 return ${ret}
446 }
447
448 function device_discover() {
449 local device=${1}
450
451 log INFO "Running discovery process on device '${device}'."
452
453 local hook
454 for hook in $(hooks_get_all); do
455 hook_exec ${hook} discover ${device}
456 done
457 }
458
459 function device_create_virtual() {
460 log WARN "Called deprecated function device_create_virtual"
461 device_virtual_create $@
462 }
463
464 function device_virtual_create() {
465 local port=$(devicify ${1})
466 local vid=${2}
467 local mac=${3}
468 local newport=${port}v${vid}
469
470 if [ -z "${mac}" ]; then
471 mac=$(mac_generate)
472 fi
473
474 log INFO "Creating virtual device '${newport}' with address '${mac}'."
475
476 local oldport=$(device_virtual_get_by_parent_and_vid ${port} ${vid})
477
478 if device_exists ${oldport}; then
479 local differences
480
481 if [ "${oldport}" != "${newport}" ]; then
482 differences="${differences} name"
483 fi
484 if [ "$(device_get_address ${oldport})" != "${mac}" ]; then
485 differences="${differences} address"
486 fi
487
488 echo "differences: $differences"
489
490 if [ -n "${differences}" ]; then
491 if device_is_used ${oldport}; then
492 error_log "There was a device '${oldport}' set up with VID '${vid}' and parent '${port}' which is used somewhere else. Cannot go on."
493 return ${EXIT_ERROR}
494 else
495 log DEBUG "There is a device '${oldport}' but it not used, so we grab it to ourselves."
496 fi
497 else
498 log DEBUG "Device '${newport}' already exists and reflects our configuration. Go on."
499
500 device_set_up ${oldport}
501 return ${EXIT_OK}
502 fi
503
504 else
505 log DEBUG "Virtual device '${newport}' does not exist, yet."
506
507 vconfig set_name_type DEV_PLUS_VID_NO_PAD >/dev/null
508 vconfig add ${port} ${vid} >/dev/null
509
510 if [ $? -ne ${EXIT_OK} ]; then
511 error_log "Could not create virtual device '${newport}'."
512 return ${EXIT_ERROR}
513 fi
514
515 oldport=$(device_virtual_get_by_parent_and_vid ${port} ${vid})
516
517 fi
518
519 assert device_exists ${oldport}
520
521 if ! device_exists ${oldport}; then
522 error "Could not determine the created virtual device '${newport}'."
523 return ${EXIT_ERROR}
524 fi
525
526 # The device is expected to be named like ${port}.${vid}
527 # and will be renamed to the virtual schema
528 device_set_name ${oldport} ${newport}
529
530 if [ $? -ne ${EXIT_OK} ]; then
531 error_log "Could not set name of virtual device '${newport}'."
532 return ${EXIT_ERROR}
533 fi
534
535 assert device_exists ${newport}
536
537 # Setting new mac address
538 device_set_address ${newport} ${mac}
539
540 if [ $? -ne ${EXIT_OK} ]; then
541 error_log "Could not set address '${mac}' to virtual device '${newport}'."
542 return ${EXIT_ERROR}
543 fi
544
545 # Bring up the new device
546 device_set_up ${newport}
547
548 return ${EXIT_OK}
549 }
550
551 function device_virtual_remove() {
552 local device=$(devicify ${1})
553
554 log INFO "Removing virtual device '${device}' with address '$(macify ${device})'."
555
556 device_set_down ${device}
557
558 vconfig rem ${device} >/dev/null
559
560 if [ $? -ne ${EXIT_OK} ]; then
561 error_log "Could not remote virtual device '${newport}'."
562 return ${EXIT_ERROR}
563 fi
564
565 return ${EXIT_OK}
566 }
567
568 function device_virtual_get_parent() {
569 local device=${1}
570
571 local parent=$(grep "^${device}" < /proc/net/vlan/config | awk '{ print $NF }')
572
573 if device_exists ${parent}; then
574 echo "${parent}"
575 return ${EXIT_OK}
576 fi
577
578 return ${EXIT_ERROR}
579 }
580
581 function device_virtual_get_by_parent_and_vid() {
582 local parent=${1}
583 local vid=${2}
584
585 local v_port
586 local v_id
587 local v_parent
588
589 fgrep '|' < /proc/net/vlan/config | tr -d '|' | \
590 while read v_port v_id v_parent; do
591 if [ "${v_parent}" = "${parent}" ] && [ "${v_id}" = "${vid}" ]; then
592 echo "${v_port}"
593 return ${EXIT_OK}
594 fi
595 done
596
597 return ${EXIT_ERROR}
598 }
599
600 function device_bonding_create() {
601 local device=${1}
602 local mac=${2}
603
604 [ -z "${mac}" ] && mac=$(mac_generate)
605
606 log INFO "Creating bonding device '${device}' (${mac})."
607
608 echo "+${device}" > /sys/class/net/bonding_masters
609 device_set_mac ${mac}
610 device_set_up ${device}
611 }
612
613 function device_bonding_remove() {
614 local device=$(devicify ${1})
615
616 log INFO "Remove bonding device '${device}'."
617
618 device_set_down ${device}
619 echo "-${device}" > /sys/class/net/bonding_masters
620 }
621
622 function bonding_set_mode() {
623 local device=${1}
624 local mode=${2}
625
626 log INFO "Setting bonding mode on '${device}' '${mode}'."
627
628 echo "${mode}" > /sys/class/net/${device}/bonding/mode
629 }
630
631 function bonding_enslave_device() {
632 local device=$(devicify ${1})
633 local slave=$(devicify ${2})
634 shift 2
635
636 log INFO "Enslaving slave '${slave}' to '${device}'."
637
638 device_set_down ${slave}
639 echo "+${slave}" > /sys/class/net/${device}/bonding/slaves
640 }
641
642 function bridge_attach_device() {
643 local bridge=${1}
644 local device=${2}
645
646 if ! device_exists ${bridge}; then
647 error "Bridge '${bridge}' does not exist."
648 return ${EXIT_ERROR}
649 fi
650
651 if ! device_exists ${device}; then
652 error "Device '${device}' does not exist."
653 return ${EXIT_ERROR}
654 fi
655
656 log INFO "Attaching device '${device}' to bridge '${bridge}'."
657
658 # XXX device_set_up ${device} # Do we need this here?
659
660 brctl addif ${bridge} ${device}
661 }
662
663 function bridge_detach_device() {
664 local bridge=${1}
665 local device=${2}
666
667 if ! device_exists ${bridge}; then
668 error "Bridge '${bridge}' does not exist."
669 return ${EXIT_ERROR}
670 fi
671
672 if ! device_exists ${device}; then
673 error "Device '${device}' does not exist."
674 return ${EXIT_ERROR}
675 fi
676
677 log INFO "Detaching device '${device}' from bridge '${bridge}'."
678
679 brctl delif ${bridge} ${device}
680
681 device_set_down ${device}
682 }
683
684 function bridge_is_forwarding() {
685 local seconds=45
686 local zone=${1}
687
688 bridge_has_carrier ${zone} || return ${EXIT_ERROR}
689
690 local device
691 while [ ${seconds} -gt 0 ]; do
692 for device in ${SYS_CLASS_NET}/${zone}/brif/*; do
693 [ -e "${device}/state" ] || continue
694 if [ "$(<${device}/state)" = "3" ]; then
695 return ${EXIT_OK}
696 fi
697 done
698 sleep 1
699 seconds=$((${seconds} - 1))
700 done
701
702 return ${EXIT_ERROR}
703 }
704
705 function bridge_has_carrier() {
706 local zone=${1}
707
708 local has_carrier=${EXIT_ERROR}
709
710 local device
711 for device in ${SYS_CLASS_NET}/${zone}/brif/*; do
712 device=$(basename ${device})
713 device_exists ${device} || continue
714
715 device_has_carrier ${device} && has_carrier=${EXIT_OK}
716 done
717
718 return ${has_carrier}
719 }
720
721 function device_has_ipv4() {
722 local device=${1}
723 local addr=${2}
724
725 if ! device_exists ${device}; then
726 error "Device '${device}' does not exist."
727 return ${EXIT_ERROR}
728 fi
729
730 ip addr show ${device} | grep -q -e "inet " -e "${addr}"
731 }