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