]> git.ipfire.org Git - people/ms/network.git/blob - src/functions/functions.device
Add "network device list" command
[people/ms/network.git] / src / functions / 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 assert isset device
26
27 if device_exists ${device}; then
28 echo "${device}"
29 return ${EXIT_OK}
30 fi
31
32 local d
33 for d in $(devices_get_all); do
34 if [ "$(device_get_address ${d})" = "${device}" ]; then
35 echo "${d}"
36 return ${EXIT_OK}
37 fi
38 done
39
40 return ${EXIT_ERROR}
41 }
42
43 function macify() {
44 local device=${1}
45
46 assert isset device
47
48 if mac_is_valid ${device}; then
49 echo "${device}"
50 return ${EXIT_OK}
51 fi
52
53 if device_exists ${device}; then
54 device_get_address ${device}
55 return ${EXIT_OK}
56 fi
57
58 return ${EXIT_ERROR}
59 }
60
61 function device_list() {
62 local devices
63
64 # Add all interfaces
65 list_append devices $(devices_get_all)
66
67 # Add all PHYs
68 list_append devices $(phy_list)
69
70 # Add all serial devices
71 list_append devices $(serial_list)
72
73 # Return a sorted result
74 list_sort ${devices}
75 }
76
77 # Check if the device exists
78 function device_exists() {
79 local device=${1}
80
81 # If device name was not found, exit.
82 [ -n "${device}" ] || return ${EXIT_ERROR}
83
84 # Check for a normal network device.
85 [ -d "${SYS_CLASS_NET}/${device}" ] && return ${EXIT_OK}
86
87 # If the check above did not find a result,
88 # we check for PHYs.
89 phy_exists "${device}" && return ${EXIT_OK}
90
91 # If the check above did not find a result,
92 # we check for serial devices.
93 serial_exists ${device}
94 }
95
96 function device_matches_pattern() {
97 local device="${1}"
98 assert isset device
99
100 local pattern="${2}"
101 assert isset pattern
102
103 pattern="^${pattern//N/[[:digit:]]+}$"
104
105 [[ ${device} =~ ${pattern} ]] \
106 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
107 }
108
109 function device_delete() {
110 local device=${1}
111 assert isset device
112
113 # Nothing to do, it device does not exist.
114 device_exists ${device} || return ${EXIT_OK}
115
116 # Delete the device.
117 cmd_quiet ip link delete ${device}
118 local ret=$?
119
120 if [ ${ret} -ne ${EXIT_OK} ]; then
121 log ERROR "device: Could not delete device '${device}': ${ret}"
122 return ${EXIT_ERROR}
123 fi
124
125 return ${ret}
126 }
127
128 function device_has_flag() {
129 local device=${1}
130 local flag=${2}
131
132 local flags=$(__device_get_file ${device} flags)
133
134 if [[ "$(( ${flags} & ${flag} ))" -eq 0 ]]; then
135 return ${EXIT_FALSE}
136 else
137 return ${EXIT_TRUE}
138 fi
139 }
140
141 # Check if the device is up
142 function device_is_up() {
143 local device=${1}
144
145 device_exists ${device} || return ${EXIT_ERROR}
146
147 device_has_flag ${device} 0x1
148 }
149
150 function device_ifindex_to_name() {
151 local idx=${1}
152 assert isset idx
153
154 local device device_idx
155 for device in ${SYS_CLASS_NET}/*; do
156 device=$(basename ${device})
157 device_exists ${device} || continue
158
159 device_idx=$(device_get_ifindex ${device})
160
161 if [ "${device_idx}" = "${idx}" ]; then
162 print "${device}"
163 return ${EXIT_OK}
164 fi
165 done
166
167 return ${EXIT_ERROR}
168 }
169
170 function device_get_ifindex() {
171 local device=${1}
172 assert isset device
173
174 local path="${SYS_CLASS_NET}/${1}/ifindex"
175
176 # Check if file can be read.
177 [ -r "${path}" ] || return ${EXIT_ERROR}
178
179 print "$(<${path})"
180 }
181
182 # Check if the device is a batman-adv bridge
183 function device_is_batman_adv() {
184 [ -d "${SYS_CLASS_NET}/${1}/mesh" ]
185 }
186
187 # Check if the device is a batman-adv slave port
188 function device_is_batman_adv_slave() {
189 local device="${1}"
190
191 if [ -d "${SYS_CLASS_NET}/${device}/batman_adv" ]; then
192 local status="$(<${SYS_CLASS_NET}/${device}/batman_adv/iface_status)"
193
194 case "${status}" in
195 "active")
196 return ${EXIT_TRUE}
197 ;;
198 *)
199 return ${EXIT_FALSE}
200 ;;
201 esac
202 fi
203
204 return ${EXIT_FALSE}
205 }
206
207 # Check if the device is a bonding device
208 function device_is_bonding() {
209 [ -d "/sys/class/net/${1}/bonding" ]
210 }
211
212 # Check if the device bonded in a bonding device
213 function device_is_bonded() {
214 local device=${1}
215
216 [ -d "${SYS_CLASS_NET}/${device}/bonding_slave" ]
217 }
218
219 # Check if the device is a bridge
220 function device_is_bridge() {
221 [ -d "/sys/class/net/${1}/bridge" ]
222 }
223
224 function device_is_bridge_attached() {
225 local device=${1}
226 [ -d "${SYS_CLASS_NET}/${device}/brport" ]
227 }
228
229 function device_is_wireless_monitor() {
230 local device="${1}"
231 assert isset device
232
233 device_is_wireless "${device}" && \
234 device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_MONITOR}"
235 }
236
237 function device_is_wireless_adhoc() {
238 local device="${1}"
239 assert isset device
240
241 device_is_wireless "${device}" && \
242 device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_ADHOC}"
243 }
244
245 function device_get_bridge() {
246 local device=${1}
247 assert isset device
248
249 # Check if device is attached to a bridge.
250 device_is_bridge_attached ${device} || return ${EXIT_ERROR}
251
252 local ifindex_path="${SYS_CLASS_NET}/${device}/brport/bridge/ifindex"
253 [ -r "${ifindex_path}" ] || return ${EXIT_ERROR}
254
255 local ifindex=$(<${ifindex_path})
256 assert isset ifindex
257
258 device_ifindex_to_name ${ifindex}
259 }
260
261 # Check if the device is a vlan device
262 function device_is_vlan() {
263 local device=${1}
264 assert isset device
265
266 [ -e "${PROC_NET_VLAN}/${device}" ]
267 }
268
269 # Check if the device has vlan devices
270 function device_has_vlans() {
271 local device=${1}
272 assert isset device
273
274 if device_is_vlan ${device}; then
275 return ${EXIT_FALSE}
276 fi
277
278 local vlans=$(device_get_vlans ${device})
279 [ -n "${vlans}" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
280 }
281
282 function device_get_vlans() {
283 local device=${1}
284 assert isset device
285
286 # If no 8021q module has been loaded into the kernel,
287 # we cannot do anything.
288 [ -r "${PROC_NET_VLAN_CONFIG}" ] || return ${EXIT_OK}
289
290 local dev spacer1 id spacer2 parent
291 while read dev spacer1 id spacer2 parent; do
292 [ "${parent}" = "${device}" ] || continue
293
294 print "${dev}"
295 done < ${PROC_NET_VLAN_CONFIG}
296 }
297
298 # Check if the device is a ppp device
299 function device_is_ppp() {
300 local device=${1}
301
302 local type=$(__device_get_file ${device} type)
303
304 [ "${type}" = "512" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
305 }
306
307 # Check if the device is a pointopoint device.
308 function device_is_ptp() {
309 local device=${1}
310
311 device_has_flag ${device} 0x10
312 }
313
314 # Check if the device is a loopback device
315 function device_is_loopback() {
316 local device=${1}
317
318 [ "${device}" = "lo" ]
319 }
320
321 # Check if the device is a dummy device
322 # This is the worst possible check, but all I could come up with
323 function device_is_dummy() {
324 local device="${1}"
325
326 [[ ${device} =~ ^dummy[0-9]+$ ]]
327 }
328
329 # Check if the device is a wireless device
330 function device_is_wireless() {
331 local device=${1}
332
333 [ -d "${SYS_CLASS_NET}/${device}/phy80211" ]
334 }
335
336 function device_get_phy() {
337 local device="${1}"
338
339 if device_is_wireless "${device}"; then
340 print "$(<${SYS_CLASS_NET}/${device}/phy80211/name)"
341 return ${EXIT_OK}
342 fi
343
344 return ${EXIT_ERROR}
345 }
346
347 function device_is_phy() {
348 phy_exists $@
349 }
350
351 function device_is_serial() {
352 serial_exists $@
353 }
354
355 # Check if the device is a physical network interface
356 function device_is_ethernet() {
357 local device=${1}
358
359 device_is_ethernet_compatible "${device}" || \
360 return ${EXIT_ERROR}
361
362 device_is_loopback ${device} && \
363 return ${EXIT_ERROR}
364
365 device_is_bonding ${device} && \
366 return ${EXIT_ERROR}
367
368 device_is_bridge ${device} && \
369 return ${EXIT_ERROR}
370
371 device_is_ppp ${device} && \
372 return ${EXIT_ERROR}
373
374 device_is_vlan ${device} && \
375 return ${EXIT_ERROR}
376
377 device_is_dummy ${device} && \
378 return ${EXIT_ERROR}
379
380 return ${EXIT_OK}
381 }
382
383 # Get the device type
384 function device_get_type() {
385 local device=${1}
386
387 # If the device does not exist (happens on udev remove events),
388 # we do not bother to run all checks.
389 if ! device_exists "${device}"; then
390 echo "unknown"
391
392 elif device_is_vlan ${device}; then
393 echo "vlan"
394
395 elif device_is_bonding ${device}; then
396 echo "bonding"
397
398 elif device_is_bridge ${device}; then
399 echo "bridge"
400
401 elif device_is_ppp ${device}; then
402 echo "ppp"
403
404 elif device_is_batman_adv ${device}; then
405 echo "batman-adv"
406
407 elif device_is_loopback ${device}; then
408 echo "loopback"
409
410 elif device_is_wireless_adhoc ${device}; then
411 echo "wireless-adhoc"
412
413 elif device_is_wireless ${device}; then
414 echo "wireless"
415
416 elif device_is_dummy ${device}; then
417 echo "dummy"
418
419 elif device_is_ethernet ${device}; then
420 echo "ethernet"
421
422 elif device_is_serial ${device}; then
423 echo "serial"
424
425 elif device_is_phy ${device}; then
426 echo "phy"
427
428 else
429 echo "unknown"
430 fi
431 }
432
433 function device_is_ethernet_compatible() {
434 local device="${1}"
435
436 # /sys/class/net/*/type must equal 1 for ethernet compatible devices
437 local type="$(__device_get_file "${device}" "type")"
438 [[ "${type}" = "1" ]]
439 }
440
441 function device_get_status() {
442 local device=${1}
443 assert isset device
444
445 local status=${STATUS_DOWN}
446
447 if device_is_up ${device}; then
448 status=${STATUS_UP}
449
450 if ! device_has_carrier ${device}; then
451 status=${STATUS_NOCARRIER}
452 fi
453 fi
454
455 echo "${status}"
456 }
457
458 function device_get_address() {
459 local device=${1}
460
461 cat ${SYS_CLASS_NET}/${device}/address 2>/dev/null
462 }
463
464 function device_set_address() {
465 assert [ $# -eq 2 ]
466
467 local device="${1}"
468 local addr="${2}"
469
470 if ! device_exists "${device}"; then
471 error "Device '${device}' does not exist."
472 return ${EXIT_ERROR}
473 fi
474
475 # Do nothing if the address has not changed
476 local old_addr="$(device_get_address "${device}")"
477 if [ -n "${old_addr}" -a "${addr}" = "${old_addr}" ]; then
478 return ${EXIT_OK}
479 fi
480
481 log DEBUG "Setting address of '${device}' from '${old_addr}' to '${addr}'"
482
483 local up
484 if device_is_up "${device}"; then
485 device_set_down "${device}"
486 up=1
487 fi
488
489 ip link set "${device}" address "${addr}"
490 local ret=$?
491
492 if [ "${up}" = "1" ]; then
493 device_set_up "${device}"
494 fi
495
496 if [ "${ret}" != "0" ]; then
497 error_log "Could not set address '${addr}' on device '${device}'"
498 fi
499
500 return ${ret}
501 }
502
503 function device_get() {
504 local device
505 local devices
506
507 for device in ${SYS_CLASS_NET}/*; do
508 device=$(basename ${device})
509
510 # bonding_masters is no device
511 [ "${device}" = "bonding_masters" ] && continue
512
513 devices="${devices} ${device}"
514 done
515
516 echo ${devices}
517 return ${EXIT_OK}
518 }
519
520 function devices_get_all() {
521 device_get
522 }
523
524 # Check if a device has a cable plugged in
525 function device_has_carrier() {
526 local device=${1}
527 assert isset device
528
529 local carrier=$(__device_get_file ${device} carrier)
530 [ "${carrier}" = "1" ]
531 }
532
533 function device_is_promisc() {
534 local device=${1}
535
536 device_has_flag ${device} 0x200
537 }
538
539 function device_set_promisc() {
540 local device=${1}
541 local state=${2}
542
543 assert device_exists ${device}
544 assert isset state
545 assert isoneof state on off
546
547 ip link set ${device} promisc ${state}
548 }
549
550 # Check if the device is free
551 function device_is_free() {
552 ! device_is_used $@
553 }
554
555 # Check if the device is used
556 function device_is_used() {
557 local device=${1}
558
559 device_has_vlans ${device} && \
560 return ${EXIT_OK}
561 device_is_bonded ${device} && \
562 return ${EXIT_OK}
563 device_is_bridge_attached ${device} && \
564 return ${EXIT_OK}
565
566 return ${EXIT_ERROR}
567 }
568
569 function device_hash() {
570 local device=${1}
571
572 # Get mac address of device and remove all colons (:)
573 # that will result in a hash.
574 device=$(macify ${device})
575
576 echo "${device//:/}"
577 }
578
579 # Give the device a new name
580 function device_set_name() {
581 local source=$1
582 local destination=${2}
583
584 # Check if devices exists
585 if ! device_exists ${source} || device_exists ${destination}; then
586 return 4
587 fi
588
589 local up
590 if device_is_up ${source}; then
591 ip link set ${source} down
592 up=1
593 fi
594
595 ip link set ${source} name ${destination}
596
597 if [ "${up}" = "1" ]; then
598 ip link set ${destination} up
599 fi
600 }
601
602 # Set device up
603 function device_set_up() {
604 local device=${1}
605
606 # Silently fail if device was not found
607 [ -z "${device}" ] && return ${EXIT_ERROR}
608
609 # Do nothing if device is already up
610 device_is_up ${device} && return ${EXIT_OK}
611
612 device_set_parent_up ${device}
613
614 log DEBUG "Setting up device '${device}'"
615
616 ip link set ${device} up
617 }
618
619 function device_set_parent_up() {
620 local device=${1}
621 local parent
622
623 if device_is_vlan ${device}; then
624 parent=$(vlan_get_parent ${device})
625
626 device_is_up ${parent} && return ${EXIT_OK}
627
628 log DEBUG "Setting up parent device '${parent}' of '${device}'"
629
630 device_set_up ${parent}
631 return $?
632 fi
633
634 return ${EXIT_OK}
635 }
636
637 # Set device down
638 function device_set_down() {
639 local device=${1}
640 assert isset device
641
642 local ret=${EXIT_OK}
643
644 if device_is_up ${device}; then
645 log DEBUG "Tearing down device '${device}'"
646
647 ip link set ${device} down
648 ret=$?
649 fi
650
651 device_set_parent_down ${device}
652
653 return ${ret}
654 }
655
656 function device_set_parent_down() {
657 local device=${1}
658 local parent
659
660 if device_is_vlan ${device}; then
661 parent=$(vlan_get_parent ${device})
662
663 device_is_up ${parent} || return ${EXIT_OK}
664
665 if device_is_free ${parent}; then
666 log DEBUG "Tearing down parent device '${parent}' of '${device}'"
667
668 device_set_down ${parent}
669 fi
670 fi
671
672 return ${EXIT_OK}
673 }
674
675 function device_get_mtu() {
676 local device=${1}
677
678 if ! device_exists ${device}; then
679 error "Device '${device}' does not exist."
680 return ${EXIT_ERROR}
681 fi
682
683 echo $(<${SYS_CLASS_NET}/${device}/mtu)
684 }
685
686 # Set mtu to a device
687 function device_set_mtu() {
688 local device=${1}
689 local mtu=${2}
690
691 if ! device_exists ${device}; then
692 error "Device '${device}' does not exist."
693 return ${EXIT_ERROR}
694 fi
695
696 local oldmtu=$(device_get_mtu ${device})
697
698 if [ "${oldmtu}" = "${mtu}" ]; then
699 # No need to set mtu.
700 return ${EXIT_OK}
701 fi
702
703 log INFO "Setting mtu of '${device}' to '${mtu}' - was ${oldmtu}."
704
705 local up
706 if device_is_up ${device}; then
707 device_set_down ${device}
708 up=1
709 fi
710
711 ip link set ${device} mtu ${mtu}
712 local ret=$?
713
714 if [ "${up}" = "1" ]; then
715 device_set_up ${device}
716 fi
717
718 if [ "${ret}" != "0" ]; then
719 error_log "Could not set mtu '${mtu}' on device '${device}'."
720 fi
721
722 return ${ret}
723 }
724
725 function device_adjust_mtu() {
726 assert [ $# -eq 2 ]
727
728 local device="${1}"
729 local other_device="${2}"
730
731 local mtu="$(device_get_mtu "${other_device}")"
732 device_set_mtu "${device}" "${mtu}"
733 }
734
735 function device_discover() {
736 local device=${1}
737
738 log INFO "Running discovery process on device '${device}'."
739
740 local hook
741 for hook in $(hook_zone_get_all); do
742 hook_zone_exec ${hook} discover ${device}
743 done
744 }
745
746 function device_has_ip() {
747 local device=${1}
748 local addr=${2}
749
750 assert isset addr
751 assert device_exists ${device}
752
753 # IPv6 addresses must be fully imploded
754 local protocol=$(ip_detect_protocol ${addr})
755 case "${protocol}" in
756 ipv6)
757 addr=$(ipv6_implode ${addr})
758 ;;
759 esac
760
761 listmatch ${addr} $(device_get_addresses ${device})
762 }
763
764 function device_get_addresses() {
765 local device=${1}
766
767 assert device_exists ${device}
768
769 local prot
770 local addr
771 local line
772 ip addr show ${device} | \
773 while read prot addr line; do
774 [ "${prot:0:4}" = "inet" ] && echo "${addr}"
775 done
776 }
777
778 function __device_get_file() {
779 local device=${1}
780 local file=${2}
781
782 assert isset device
783 assert isset file
784
785 local path="${SYS_CLASS_NET}/${device}/${file}"
786 [ -r "${path}" ] || return ${EXIT_ERROR}
787
788 echo "$(<${path})"
789 }
790
791 function __device_set_file() {
792 assert [ $# -eq 3 ]
793
794 local device="${1}"
795 local file="${2}"
796 local value="${3}"
797
798 local path="${SYS_CLASS_NET}/${device}/${file}"
799 if [ ! -w "${path}" ]; then
800 log DEBUG "Cannot write to file '${file}' (${value})"
801 return ${EXIT_ERROR}
802 fi
803
804 echo "${value}" > "${path}"
805 }
806
807 function device_get_rx_bytes() {
808 local device=${1}
809
810 __device_get_file ${device} statistics/rx_bytes
811 }
812
813 function device_get_tx_bytes() {
814 local device=${1}
815
816 __device_get_file ${device} statistics/tx_bytes
817 }
818
819 function device_get_rx_packets() {
820 local device=${1}
821
822 __device_get_file ${device} statistics/rx_packets
823 }
824
825 function device_get_tx_packets() {
826 local device=${1}
827
828 __device_get_file ${device} statistics/tx_packets
829 }
830
831 function device_get_rx_errors() {
832 local device=${1}
833
834 __device_get_file ${device} statistics/rx_errors
835 }
836
837 function device_get_tx_errors() {
838 local device=${1}
839
840 __device_get_file ${device} statistics/tx_errors
841 }
842
843 function device_get_speed() {
844 local device=${1}
845
846 __device_get_file ${device} speed
847 }
848
849 function device_get_duplex() {
850 local device=${1}
851
852 __device_get_file ${device} duplex
853 }
854
855 function device_get_link_string() {
856 local device="${1}"
857 assert isset device
858
859 local s
860
861 local speed="$(device_get_speed "${device}")"
862 if isset speed; then
863 list_append s "${speed} MBit/s"
864 fi
865
866 local duplex="$(device_get_duplex "${device}")"
867 if isset duplex; then
868 list_append s "${duplex} duplex"
869 fi
870
871 print "${s}"
872 }