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