]> git.ipfire.org Git - people/arne_f/network.git/blame - functions.device
network: device_set_{down,up} do set-up/tear-down their parent devices.
[people/arne_f/network.git] / functions.device
CommitLineData
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
1b7a1578 22function devicify() {
1848564d
MT
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
41function 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
58function 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
68function 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
77function device_is_bonding() {
78 [ -d "/sys/class/net/${1}/bonding" ]
79}
80
81# Check if the device bonded in a bonding device
82function 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
100function device_is_bridge() {
101 [ -d "/sys/class/net/${1}/bridge" ]
102}
103
81ed640c
MT
104function device_is_bridge_attached() {
105 local device=${1}
106
107 [ -d "${SYS_CLASS_NET}/${device}/brport" ]
108}
109
1848564d
MT
110# Check if the device is a virtual device
111function device_is_virtual() {
112 local device=${1}
113
114 [ -e "/proc/net/vlan/${device}" ]
115}
116
117# Check if the device has virtual devices
118function device_has_virtuals() {
fb02e543
MT
119 local device=${1}
120
121 if device_is_virtual ${device}; then
122 return 1
123 fi
124
1848564d
MT
125 if [ ! -e "/proc/net/vlan/config" ]; then
126 return 1
127 fi
128 grep -q "${1}$" /proc/net/vlan/config
129}
130
131function 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
138function 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
145function device_is_loopback() {
146 local device=$(devicify ${1})
147 [ "${device}" = "lo" ]
148}
149
150# Check if the device is a physical network interface
151function 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
173function 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
199function device_get_address() {
200 local device=${1}
201
202 cat ${SYS_CLASS_NET}/${device}/address 2>/dev/null
203}
204
205function device_set_address() {
1b7a1578
MT
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}
1848564d
MT
234}
235
236function 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
244function device_has_carrier() {
245 local device=$(devicify ${1})
246 [ "$(<${SYS_CLASS_NET}/${device}/carrier)" = "1" ]
247}
248
249# Check if the device is free
250function device_is_free() {
81ed640c 251 ! device_is_used $@
1848564d
MT
252}
253
254# Check if the device is used
255function device_is_used() {
256 local device=$(devicify ${1})
257
fb02e543
MT
258 device_has_virtuals ${device} && \
259 return ${EXIT_OK}
1848564d 260 device_is_bonded ${device} && \
fb02e543 261 return ${EXIT_OK}
81ed640c
MT
262 device_is_bridge_attached ${device} && \
263 return ${EXIT_OK}
1848564d 264
fb02e543 265 return ${EXIT_ERROR}
1848564d
MT
266}
267
268# XXX to be removed I think
269function 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
1848564d 287function device_rename() {
1b7a1578
MT
288 warning_log "Called deprecated function 'device_rename'"
289
290 device_set_name $@
291}
292
293function device_hash() {
294 local device=${1}
295
296 macify ${device} | tr -d ':'
297}
298
299# Give the device a new name
300function device_set_name() {
1848564d
MT
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
1848564d
MT
322# Set device up
323function 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
81ed640c
MT
329 device_set_parent_up ${device}
330
331 log DEBUG "Setting up device '${device}'"
332
1848564d
MT
333 ip link set ${device} up
334}
335
81ed640c
MT
336function 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
1848564d
MT
354# Set device down
355function device_set_down() {
356 local device=$(devicify ${1})
357
81ed640c
MT
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}
1848564d 368
81ed640c
MT
369 return ${ret}
370}
371
372function 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}
1848564d
MT
389}
390
391# Set new address to a device
392function device_set_mac() {
1b7a1578 393 warning_log "Called deprecated function 'device_set_mac'"
1848564d 394
1b7a1578 395 device_set_address $@
1848564d
MT
396}
397
398function 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
410function device_set_mtu() {
1b7a1578 411 local device=${1}
1848564d
MT
412 local mtu=${2}
413
1b7a1578
MT
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
1848564d 428 local up
1b7a1578
MT
429 if device_is_up ${device}; then
430 device_set_down ${device}
1848564d
MT
431 up=1
432 fi
433
1b7a1578 434 ip link set ${device} mtu ${mtu}
1848564d
MT
435 local ret=$?
436
437 if [ "${up}" = "1" ]; then
1b7a1578
MT
438 device_set_up ${device}
439 fi
440
441 if [ "${ret}" != "0" ]; then
442 error_log "Could not set mtu '${mtu}' on device '${device}'."
1848564d
MT
443 fi
444
445 return ${ret}
446}
447
448function device_discover() {
449 local device=${1}
450
1b7a1578
MT
451 log INFO "Running discovery process on device '${device}'."
452
1848564d
MT
453 local hook
454 for hook in $(hooks_get_all); do
455 hook_exec ${hook} discover ${device}
456 done
457}
458
459function device_create_virtual() {
460 log WARN "Called deprecated function device_create_virtual"
461 device_virtual_create $@
462}
463
464function 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
1b7a1578
MT
474 log INFO "Creating virtual device '${newport}' with address '${mac}'."
475
fb02e543 476 local oldport=$(device_virtual_get_by_parent_and_vid ${port} ${vid})
1848564d 477
fb02e543
MT
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}'."
1b7a1578
MT
523 return ${EXIT_ERROR}
524 fi
1848564d
MT
525
526 # The device is expected to be named like ${port}.${vid}
527 # and will be renamed to the virtual schema
fb02e543 528 device_set_name ${oldport} ${newport}
1848564d 529
1b7a1578
MT
530 if [ $? -ne ${EXIT_OK} ]; then
531 error_log "Could not set name of virtual device '${newport}'."
532 return ${EXIT_ERROR}
533 fi
534
fb02e543
MT
535 assert device_exists ${newport}
536
1848564d
MT
537 # Setting new mac address
538 device_set_address ${newport} ${mac}
1b7a1578
MT
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
1848564d
MT
544
545 # Bring up the new device
546 device_set_up ${newport}
547
1848564d
MT
548 return ${EXIT_OK}
549}
550
551function device_virtual_remove() {
552 local device=$(devicify ${1})
553
81ed640c 554 log INFO "Removing virtual device '${device}' with address '$(macify ${device})'."
1b7a1578 555
1848564d
MT
556 device_set_down ${device}
557
558 vconfig rem ${device} >/dev/null
1848564d 559
1b7a1578
MT
560 if [ $? -ne ${EXIT_OK} ]; then
561 error_log "Could not remote virtual device '${newport}'."
562 return ${EXIT_ERROR}
563 fi
564
1848564d
MT
565 return ${EXIT_OK}
566}
567
81ed640c
MT
568function 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
fb02e543
MT
581function 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
1848564d
MT
600function device_bonding_create() {
601 local device=${1}
602 local mac=${2}
603
604 [ -z "${mac}" ] && mac=$(mac_generate)
605
1b7a1578
MT
606 log INFO "Creating bonding device '${device}' (${mac})."
607
1848564d
MT
608 echo "+${device}" > /sys/class/net/bonding_masters
609 device_set_mac ${mac}
610 device_set_up ${device}
611}
612
613function device_bonding_remove() {
614 local device=$(devicify ${1})
615
1b7a1578
MT
616 log INFO "Remove bonding device '${device}'."
617
1848564d
MT
618 device_set_down ${device}
619 echo "-${device}" > /sys/class/net/bonding_masters
620}
621
622function bonding_set_mode() {
623 local device=${1}
624 local mode=${2}
625
1b7a1578
MT
626 log INFO "Setting bonding mode on '${device}' '${mode}'."
627
1848564d
MT
628 echo "${mode}" > /sys/class/net/${device}/bonding/mode
629}
630
631function bonding_enslave_device() {
632 local device=$(devicify ${1})
633 local slave=$(devicify ${2})
1b7a1578
MT
634 shift 2
635
636 log INFO "Enslaving slave '${slave}' to '${device}'."
1848564d
MT
637
638 device_set_down ${slave}
639 echo "+${slave}" > /sys/class/net/${device}/bonding/slaves
640}
641
642function 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
1b7a1578
MT
656 log INFO "Attaching device '${device}' to bridge '${bridge}'."
657
1848564d
MT
658 # XXX device_set_up ${device} # Do we need this here?
659
660 brctl addif ${bridge} ${device}
661}
662
663function 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
1b7a1578
MT
677 log INFO "Detaching device '${device}' from bridge '${bridge}'."
678
679 brctl delif ${bridge} ${device}
1848564d
MT
680
681 device_set_down ${device}
682}
683
684function 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
705function 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
721function 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}