]> git.ipfire.org Git - people/arne_f/network.git/blame - functions.device
network: New hook ipv6-static.
[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
1e4c26a4
MT
249function device_is_promisc() {
250 local device=${1}
251
252 ip link show ${device} | grep -qE "<.*PROMISC.*>"
253}
254
1848564d
MT
255# Check if the device is free
256function device_is_free() {
81ed640c 257 ! device_is_used $@
1848564d
MT
258}
259
260# Check if the device is used
261function device_is_used() {
262 local device=$(devicify ${1})
263
fb02e543
MT
264 device_has_virtuals ${device} && \
265 return ${EXIT_OK}
1848564d 266 device_is_bonded ${device} && \
fb02e543 267 return ${EXIT_OK}
81ed640c
MT
268 device_is_bridge_attached ${device} && \
269 return ${EXIT_OK}
1848564d 270
fb02e543 271 return ${EXIT_ERROR}
1848564d
MT
272}
273
274# XXX to be removed I think
275function device_get_free() {
276 local destination=${1}
277
278 # Replace + by a valid number
279 if grep -q "+$" <<<${destination}; then
280 local number=0
281 destination=$(sed -e "s/+//" <<<$destination)
282 while [ "${number}" -le "100" ]; do
283 if ! device_exists "${destination}${number}"; then
284 destination="${destination}${number}"
285 break
286 fi
287 number=$(($number + 1))
288 done
289 fi
290 echo "${destination}"
291}
292
1848564d 293function device_rename() {
1b7a1578
MT
294 warning_log "Called deprecated function 'device_rename'"
295
296 device_set_name $@
297}
298
299function device_hash() {
300 local device=${1}
301
37e4ec8b
MT
302 # Get mac address of device and remove all colons (:)
303 # that will result in a hash.
304 device=$(macify ${device})
305
306 echo "${device//:/}"
1b7a1578
MT
307}
308
309# Give the device a new name
310function device_set_name() {
1848564d
MT
311 local source=$1
312 local destination=$(device_get_free ${2})
313
314 # Check if devices exists
315 if ! device_exists ${source} || device_exists ${destination}; then
316 return 4
317 fi
318
319 local up
320 if device_is_up ${source}; then
321 ip link set ${source} down
322 up=1
323 fi
324
325 ip link set ${source} name ${destination}
326
327 if [ "${up}" = "1" ]; then
328 ip link set ${destination} up
329 fi
330}
331
1848564d
MT
332# Set device up
333function device_set_up() {
334 local device=$(devicify ${1})
335
336 # Do nothing if device is already up
337 device_is_up ${device} && return ${EXIT_OK}
338
81ed640c
MT
339 device_set_parent_up ${device}
340
341 log DEBUG "Setting up device '${device}'"
342
1848564d
MT
343 ip link set ${device} up
344}
345
81ed640c
MT
346function device_set_parent_up() {
347 local device=${1}
348 local parent
349
350 if device_is_virtual ${device}; then
351 parent=$(device_virtual_get_parent ${device})
352
353 device_is_up ${parent} && return ${EXIT_OK}
354
355 log DEBUG "Setting up parent device '${parent}' of '${device}'"
356
357 device_set_up ${parent}
358 return $?
359 fi
360
361 return ${EXIT_OK}
362}
363
1848564d
MT
364# Set device down
365function device_set_down() {
366 local device=$(devicify ${1})
367
81ed640c
MT
368 local ret=${EXIT_OK}
369
370 if device_is_up ${device}; then
371 log DEBUG "Tearing down device '${device}'"
372
373 ip link set ${device} down
374 ret=$?
375 fi
376
377 device_set_parent_down ${device}
1848564d 378
81ed640c
MT
379 return ${ret}
380}
381
382function device_set_parent_down() {
383 local device=${1}
384 local parent
385
386 if device_is_virtual ${device}; then
387 parent=$(device_virtual_get_parent ${device})
388
389 device_is_up ${parent} || return ${EXIT_OK}
390
391 if device_is_free ${parent}; then
392 log DEBUG "Tearing down parent device '${parent}' of '${device}'"
393
394 device_set_down ${parent}
395 fi
396 fi
397
398 return ${EXIT_OK}
1848564d
MT
399}
400
1848564d
MT
401function device_get_mtu() {
402 local device=${1}
403
404 if ! device_exists ${device}; then
405 error "Device '${device}' does not exist."
406 return ${EXIT_ERROR}
407 fi
408
f3e6fe50 409 echo $(<${SYS_CLASS_NET}/${device}/mtu)
1848564d
MT
410}
411
412# Set mtu to a device
413function device_set_mtu() {
1b7a1578 414 local device=${1}
1848564d
MT
415 local mtu=${2}
416
1b7a1578
MT
417 if ! device_exists ${device}; then
418 error "Device '${device}' does not exist."
419 return ${EXIT_ERROR}
420 fi
421
422 local oldmtu=$(device_get_mtu ${device})
423
424 if [ "${oldmtu}" = "${mtu}" ]; then
425 # No need to set mtu.
426 return ${EXIT_OK}
427 fi
428
429 log INFO "Setting mtu of '${device}' to '${mtu}' - was ${oldmtu}."
430
1848564d 431 local up
1b7a1578
MT
432 if device_is_up ${device}; then
433 device_set_down ${device}
1848564d
MT
434 up=1
435 fi
436
1b7a1578 437 ip link set ${device} mtu ${mtu}
1848564d
MT
438 local ret=$?
439
440 if [ "${up}" = "1" ]; then
1b7a1578
MT
441 device_set_up ${device}
442 fi
443
444 if [ "${ret}" != "0" ]; then
445 error_log "Could not set mtu '${mtu}' on device '${device}'."
1848564d
MT
446 fi
447
448 return ${ret}
449}
450
451function device_discover() {
452 local device=${1}
453
1b7a1578
MT
454 log INFO "Running discovery process on device '${device}'."
455
1848564d
MT
456 local hook
457 for hook in $(hooks_get_all); do
458 hook_exec ${hook} discover ${device}
459 done
460}
461
462function device_create_virtual() {
463 log WARN "Called deprecated function device_create_virtual"
464 device_virtual_create $@
465}
466
467function device_virtual_create() {
468 local port=$(devicify ${1})
469 local vid=${2}
470 local mac=${3}
471 local newport=${port}v${vid}
472
473 if [ -z "${mac}" ]; then
474 mac=$(mac_generate)
475 fi
476
1b7a1578
MT
477 log INFO "Creating virtual device '${newport}' with address '${mac}'."
478
fb02e543 479 local oldport=$(device_virtual_get_by_parent_and_vid ${port} ${vid})
1848564d 480
fb02e543
MT
481 if device_exists ${oldport}; then
482 local differences
483
484 if [ "${oldport}" != "${newport}" ]; then
485 differences="${differences} name"
486 fi
487 if [ "$(device_get_address ${oldport})" != "${mac}" ]; then
488 differences="${differences} address"
489 fi
490
491 echo "differences: $differences"
492
493 if [ -n "${differences}" ]; then
494 if device_is_used ${oldport}; then
495 error_log "There was a device '${oldport}' set up with VID '${vid}' and parent '${port}' which is used somewhere else. Cannot go on."
496 return ${EXIT_ERROR}
497 else
498 log DEBUG "There is a device '${oldport}' but it not used, so we grab it to ourselves."
499 fi
500 else
501 log DEBUG "Device '${newport}' already exists and reflects our configuration. Go on."
502
503 device_set_up ${oldport}
504 return ${EXIT_OK}
505 fi
506
507 else
508 log DEBUG "Virtual device '${newport}' does not exist, yet."
509
510 vconfig set_name_type DEV_PLUS_VID_NO_PAD >/dev/null
511 vconfig add ${port} ${vid} >/dev/null
512
513 if [ $? -ne ${EXIT_OK} ]; then
514 error_log "Could not create virtual device '${newport}'."
515 return ${EXIT_ERROR}
516 fi
517
518 oldport=$(device_virtual_get_by_parent_and_vid ${port} ${vid})
519
520 fi
521
522 assert device_exists ${oldport}
523
524 if ! device_exists ${oldport}; then
525 error "Could not determine the created virtual device '${newport}'."
1b7a1578
MT
526 return ${EXIT_ERROR}
527 fi
1848564d
MT
528
529 # The device is expected to be named like ${port}.${vid}
530 # and will be renamed to the virtual schema
fb02e543 531 device_set_name ${oldport} ${newport}
1848564d 532
1b7a1578
MT
533 if [ $? -ne ${EXIT_OK} ]; then
534 error_log "Could not set name of virtual device '${newport}'."
535 return ${EXIT_ERROR}
536 fi
537
fb02e543
MT
538 assert device_exists ${newport}
539
1848564d
MT
540 # Setting new mac address
541 device_set_address ${newport} ${mac}
1b7a1578
MT
542
543 if [ $? -ne ${EXIT_OK} ]; then
544 error_log "Could not set address '${mac}' to virtual device '${newport}'."
545 return ${EXIT_ERROR}
546 fi
1848564d
MT
547
548 # Bring up the new device
549 device_set_up ${newport}
550
1848564d
MT
551 return ${EXIT_OK}
552}
553
554function device_virtual_remove() {
555 local device=$(devicify ${1})
556
81ed640c 557 log INFO "Removing virtual device '${device}' with address '$(macify ${device})'."
1b7a1578 558
1848564d
MT
559 device_set_down ${device}
560
561 vconfig rem ${device} >/dev/null
1848564d 562
1b7a1578
MT
563 if [ $? -ne ${EXIT_OK} ]; then
564 error_log "Could not remote virtual device '${newport}'."
565 return ${EXIT_ERROR}
566 fi
567
1848564d
MT
568 return ${EXIT_OK}
569}
570
81ed640c
MT
571function device_virtual_get_parent() {
572 local device=${1}
573
574 local parent=$(grep "^${device}" < /proc/net/vlan/config | awk '{ print $NF }')
575
576 if device_exists ${parent}; then
577 echo "${parent}"
578 return ${EXIT_OK}
579 fi
580
581 return ${EXIT_ERROR}
582}
583
fb02e543
MT
584function device_virtual_get_by_parent_and_vid() {
585 local parent=${1}
586 local vid=${2}
587
588 local v_port
589 local v_id
590 local v_parent
591
592 fgrep '|' < /proc/net/vlan/config | tr -d '|' | \
593 while read v_port v_id v_parent; do
594 if [ "${v_parent}" = "${parent}" ] && [ "${v_id}" = "${vid}" ]; then
595 echo "${v_port}"
596 return ${EXIT_OK}
597 fi
598 done
599
600 return ${EXIT_ERROR}
601}
602
1848564d
MT
603function device_bonding_create() {
604 local device=${1}
605 local mac=${2}
606
607 [ -z "${mac}" ] && mac=$(mac_generate)
608
1b7a1578
MT
609 log INFO "Creating bonding device '${device}' (${mac})."
610
1848564d 611 echo "+${device}" > /sys/class/net/bonding_masters
7cbea20d 612 device_set_address ${mac}
1848564d
MT
613 device_set_up ${device}
614}
615
616function device_bonding_remove() {
617 local device=$(devicify ${1})
618
1b7a1578
MT
619 log INFO "Remove bonding device '${device}'."
620
1848564d
MT
621 device_set_down ${device}
622 echo "-${device}" > /sys/class/net/bonding_masters
623}
624
625function bonding_set_mode() {
626 local device=${1}
627 local mode=${2}
628
1b7a1578
MT
629 log INFO "Setting bonding mode on '${device}' '${mode}'."
630
1848564d
MT
631 echo "${mode}" > /sys/class/net/${device}/bonding/mode
632}
633
634function bonding_enslave_device() {
635 local device=$(devicify ${1})
636 local slave=$(devicify ${2})
1b7a1578
MT
637 shift 2
638
639 log INFO "Enslaving slave '${slave}' to '${device}'."
1848564d
MT
640
641 device_set_down ${slave}
642 echo "+${slave}" > /sys/class/net/${device}/bonding/slaves
643}
644
645function bridge_attach_device() {
646 local bridge=${1}
647 local device=${2}
648
649 if ! device_exists ${bridge}; then
650 error "Bridge '${bridge}' does not exist."
651 return ${EXIT_ERROR}
652 fi
653
654 if ! device_exists ${device}; then
655 error "Device '${device}' does not exist."
656 return ${EXIT_ERROR}
657 fi
658
1b7a1578
MT
659 log INFO "Attaching device '${device}' to bridge '${bridge}'."
660
1848564d
MT
661 # XXX device_set_up ${device} # Do we need this here?
662
663 brctl addif ${bridge} ${device}
664}
665
666function bridge_detach_device() {
667 local bridge=${1}
668 local device=${2}
669
670 if ! device_exists ${bridge}; then
671 error "Bridge '${bridge}' does not exist."
672 return ${EXIT_ERROR}
673 fi
674
675 if ! device_exists ${device}; then
676 error "Device '${device}' does not exist."
677 return ${EXIT_ERROR}
678 fi
679
1b7a1578
MT
680 log INFO "Detaching device '${device}' from bridge '${bridge}'."
681
682 brctl delif ${bridge} ${device}
1848564d
MT
683
684 device_set_down ${device}
685}
686
687function bridge_is_forwarding() {
688 local seconds=45
689 local zone=${1}
690
691 bridge_has_carrier ${zone} || return ${EXIT_ERROR}
692
693 local device
694 while [ ${seconds} -gt 0 ]; do
695 for device in ${SYS_CLASS_NET}/${zone}/brif/*; do
696 [ -e "${device}/state" ] || continue
697 if [ "$(<${device}/state)" = "3" ]; then
698 return ${EXIT_OK}
699 fi
700 done
701 sleep 1
702 seconds=$((${seconds} - 1))
703 done
704
705 return ${EXIT_ERROR}
706}
707
708function bridge_has_carrier() {
709 local zone=${1}
710
711 local has_carrier=${EXIT_ERROR}
712
713 local device
714 for device in ${SYS_CLASS_NET}/${zone}/brif/*; do
715 device=$(basename ${device})
716 device_exists ${device} || continue
717
718 device_has_carrier ${device} && has_carrier=${EXIT_OK}
719 done
720
721 return ${has_carrier}
722}
723
724function device_has_ipv4() {
725 local device=${1}
726 local addr=${2}
727
728 if ! device_exists ${device}; then
729 error "Device '${device}' does not exist."
730 return ${EXIT_ERROR}
731 fi
732
733 ip addr show ${device} | grep -q -e "inet " -e "${addr}"
734}
4231f419
MT
735
736function device_has_ipv6() {
737 local device=${1}
738 local addr=${2}
739
740 if ! device_exists ${device}; then
741 error "Device '${device}' does not exist."
742 return ${EXIT_ERROR}
743 fi
744
745 local prefix=${addr##*/}
746 addr=$(ipv6_implode ${addr%%/*})
747
748 if [ -n "${prefix}" ]; then
749 addr="${addr}/${prefix}"
750 fi
751
752 ip addr show ${device} | grep -q "inet6 ${addr}"
753}