]> git.ipfire.org Git - people/stevee/network.git/blob - src/functions/functions.device
Remove B.A.T.M.A.N.
[people/stevee/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 device_list() {
23 local devices
24
25 # Add all interfaces
26 local device
27 for device in $(list_directory ${SYS_CLASS_NET}); do
28 list_append_one devices "${device}"
29 done
30
31 # Add all PHYs
32 list_append devices $(phy_list)
33
34 # Add all serial devices
35 list_append devices $(serial_list)
36
37 # Return a sorted result
38 list_sort ${devices}
39 }
40
41 # Check if the device exists
42 device_exists() {
43 local device=${1}
44
45 # If device name was not found, exit.
46 [ -n "${device}" ] || return ${EXIT_ERROR}
47
48 # Check for a normal network device.
49 [ -d "${SYS_CLASS_NET}/${device}" ] && return ${EXIT_OK}
50
51 # If the check above did not find a result,
52 # we check for PHYs.
53 phy_exists "${device}" && return ${EXIT_OK}
54
55 # If the check above did not find a result,
56 # we check for serial devices.
57 serial_exists ${device}
58 }
59
60 device_matches_pattern() {
61 local device="${1}"
62 assert isset device
63
64 local pattern="${2}"
65 assert isset pattern
66
67 pattern="^${pattern//N/[[:digit:]]+}$"
68
69 [[ ${device} =~ ${pattern} ]] \
70 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
71 }
72
73 device_delete() {
74 local device=${1}
75 assert isset device
76
77 # Nothing to do, it device does not exist.
78 device_exists ${device} || return ${EXIT_OK}
79
80 # Delete the device.
81 cmd_quiet ip link delete ${device}
82 local ret=$?
83
84 if [ ${ret} -ne ${EXIT_OK} ]; then
85 log ERROR "device: Could not delete device '${device}': ${ret}"
86 return ${EXIT_ERROR}
87 fi
88
89 return ${ret}
90 }
91
92 device_has_flag() {
93 local device=${1}
94 local flag=${2}
95
96 local flags=$(__device_get_file ${device} flags)
97
98 if [[ "$(( ${flags} & ${flag} ))" -eq 0 ]]; then
99 return ${EXIT_FALSE}
100 else
101 return ${EXIT_TRUE}
102 fi
103 }
104
105 # Check if the device is up
106 device_is_up() {
107 local device=${1}
108
109 device_exists ${device} || return ${EXIT_ERROR}
110
111 device_has_flag ${device} 0x1
112 }
113
114 device_ifindex_to_name() {
115 local idx=${1}
116 assert isset idx
117
118 local device device_idx
119 for device in $(list_directory "${SYS_CLASS_NET}"); do
120 device_idx=$(device_get_ifindex ${device})
121
122 if [ "${device_idx}" = "${idx}" ]; then
123 print "${device}"
124 return ${EXIT_OK}
125 fi
126 done
127
128 return ${EXIT_ERROR}
129 }
130
131 device_get_ifindex() {
132 local device=${1}
133 assert isset device
134
135 local path="${SYS_CLASS_NET}/${1}/ifindex"
136
137 # Check if file can be read.
138 [ -r "${path}" ] || return ${EXIT_ERROR}
139
140 print "$(<${path})"
141 }
142
143 # Check if the device is a bonding device
144 device_is_bonding() {
145 [ -d "/sys/class/net/${1}/bonding" ]
146 }
147
148 # Check if the device bonded in a bonding device
149 device_is_bonded() {
150 local device=${1}
151
152 [ -d "${SYS_CLASS_NET}/${device}/bonding_slave" ]
153 }
154
155 # Check if the device is a bridge
156 device_is_bridge() {
157 [ -d "/sys/class/net/${1}/bridge" ]
158 }
159
160 device_is_bridge_attached() {
161 local device=${1}
162 [ -d "${SYS_CLASS_NET}/${device}/brport" ]
163 }
164
165 device_is_wireless_monitor() {
166 local device="${1}"
167 assert isset device
168
169 device_is_wireless "${device}" && \
170 device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_MONITOR}"
171 }
172
173 device_is_wireless_adhoc() {
174 local device="${1}"
175 assert isset device
176
177 device_is_wireless "${device}" && \
178 device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_ADHOC}"
179 }
180
181 device_get_bridge() {
182 local device=${1}
183 assert isset device
184
185 # Check if device is attached to a bridge.
186 device_is_bridge_attached ${device} || return ${EXIT_ERROR}
187
188 local ifindex_path="${SYS_CLASS_NET}/${device}/brport/bridge/ifindex"
189 [ -r "${ifindex_path}" ] || return ${EXIT_ERROR}
190
191 local ifindex=$(<${ifindex_path})
192 assert isset ifindex
193
194 device_ifindex_to_name ${ifindex}
195 }
196
197 # Check if the device is a vlan device
198 device_is_vlan() {
199 local device=${1}
200 assert isset device
201
202 [ -e "${PROC_NET_VLAN}/${device}" ]
203 }
204
205 # Check if the device has vlan devices
206 device_has_vlans() {
207 local device=${1}
208 assert isset device
209
210 if device_is_vlan ${device}; then
211 return ${EXIT_FALSE}
212 fi
213
214 local vlans=$(device_get_vlans ${device})
215 [ -n "${vlans}" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
216 }
217
218 device_get_vlans() {
219 local device=${1}
220 assert isset device
221
222 # If no 8021q module has been loaded into the kernel,
223 # we cannot do anything.
224 [ -r "${PROC_NET_VLAN_CONFIG}" ] || return ${EXIT_OK}
225
226 local dev spacer1 id spacer2 parent
227 while read dev spacer1 id spacer2 parent; do
228 [ "${parent}" = "${device}" ] || continue
229
230 print "${dev}"
231 done < ${PROC_NET_VLAN_CONFIG}
232 }
233
234 # Check if the device is a ppp device
235 device_is_ppp() {
236 local device=${1}
237
238 local type=$(__device_get_file ${device} type)
239
240 [ "${type}" = "512" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
241 }
242
243 # Check if the device is a pointopoint device.
244 device_is_ptp() {
245 local device=${1}
246
247 device_has_flag ${device} 0x10
248 }
249
250 # Check if the device is a loopback device
251 device_is_loopback() {
252 local device=${1}
253
254 [ "${device}" = "lo" ]
255 }
256
257 # Check if the device is a dummy device
258 # This is the worst possible check, but all I could come up with
259 device_is_dummy() {
260 local device="${1}"
261
262 [[ ${device} =~ ^dummy[0-9]+$ ]]
263 }
264
265 device_is_ipsec() {
266 local device="${1}"
267
268 [[ ${device} =~ ^ipsec\- ]]
269 }
270
271 # Check if the device is a wireless device
272 device_is_wireless() {
273 local device=${1}
274
275 [ -d "${SYS_CLASS_NET}/${device}/phy80211" ]
276 }
277
278 device_is_vti() {
279 local device=${1}
280
281 local type=$(__device_get_file ${device} type)
282
283 [ "${type}" = "768" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
284 }
285
286 device_get_phy() {
287 local device="${1}"
288
289 if device_is_wireless "${device}"; then
290 print "$(<${SYS_CLASS_NET}/${device}/phy80211/name)"
291 return ${EXIT_OK}
292 fi
293
294 return ${EXIT_ERROR}
295 }
296
297 device_is_phy() {
298 phy_exists "$@"
299 }
300
301 device_is_serial() {
302 serial_exists "$@"
303 }
304
305 # Returns true if a device is a tun device
306 device_is_tun() {
307 local device="${1}"
308
309 [ -e "${SYS_CLASS_NET}/${device}/tun_flags" ]
310 }
311
312 # Check if the device is a physical network interface
313 device_is_ethernet() {
314 local device=${1}
315
316 device_is_ethernet_compatible "${device}" || \
317 return ${EXIT_ERROR}
318
319 device_is_loopback ${device} && \
320 return ${EXIT_ERROR}
321
322 device_is_bonding ${device} && \
323 return ${EXIT_ERROR}
324
325 device_is_bridge ${device} && \
326 return ${EXIT_ERROR}
327
328 device_is_ppp ${device} && \
329 return ${EXIT_ERROR}
330
331 device_is_vlan ${device} && \
332 return ${EXIT_ERROR}
333
334 device_is_dummy ${device} && \
335 return ${EXIT_ERROR}
336
337 device_is_tun ${device} && \
338 return ${EXIT_ERROR}
339
340 return ${EXIT_OK}
341 }
342
343 # Get the device type
344 device_get_type() {
345 local device=${1}
346
347 # If the device does not exist (happens on udev remove events),
348 # we do not bother to run all checks.
349 if ! device_exists "${device}"; then
350 echo "unknown"
351
352 elif device_is_vlan ${device}; then
353 echo "vlan"
354
355 elif device_is_bonding ${device}; then
356 echo "bonding"
357
358 elif device_is_bridge ${device}; then
359 echo "bridge"
360
361 elif device_is_ppp ${device}; then
362 echo "ppp"
363
364 elif device_is_loopback ${device}; then
365 echo "loopback"
366
367 elif device_is_wireless_adhoc ${device}; then
368 echo "wireless-adhoc"
369
370 elif device_is_wireless ${device}; then
371 echo "wireless"
372
373 elif device_is_dummy ${device}; then
374 echo "dummy"
375
376 elif device_is_tun ${device}; then
377 echo "tun"
378
379 elif device_is_ethernet ${device}; then
380 echo "ethernet"
381
382 elif device_is_serial ${device}; then
383 echo "serial"
384
385 elif device_is_phy ${device}; then
386 echo "phy"
387
388 elif device_is_vti ${device}; then
389 echo "vti"
390
391 else
392 echo "unknown"
393 fi
394 }
395
396 device_is_ethernet_compatible() {
397 local device="${1}"
398
399 # /sys/class/net/*/type must equal 1 for ethernet compatible devices
400 local type="$(__device_get_file "${device}" "type")"
401 [[ "${type}" = "1" ]]
402 }
403
404 device_get_status() {
405 local device=${1}
406 assert isset device
407
408 local status=${STATUS_DOWN}
409
410 if device_is_up ${device}; then
411 status=${STATUS_UP}
412
413 if ! device_has_carrier ${device}; then
414 status=${STATUS_NOCARRIER}
415 fi
416 fi
417
418 echo "${status}"
419 }
420
421 device_get_address() {
422 local device=${1}
423
424 cat ${SYS_CLASS_NET}/${device}/address 2>/dev/null
425 }
426
427 device_set_address() {
428 assert [ $# -eq 2 ]
429
430 local device="${1}"
431 local addr="${2}"
432
433 if ! device_exists "${device}"; then
434 error "Device '${device}' does not exist."
435 return ${EXIT_ERROR}
436 fi
437
438 # Do nothing if the address has not changed
439 local old_addr="$(device_get_address "${device}")"
440 if [ -n "${old_addr}" -a "${addr}" = "${old_addr}" ]; then
441 return ${EXIT_OK}
442 fi
443
444 log DEBUG "Setting address of '${device}' from '${old_addr}' to '${addr}'"
445
446 local up
447 if device_is_up "${device}"; then
448 device_set_down "${device}"
449 up=1
450 fi
451
452 ip link set "${device}" address "${addr}"
453 local ret=$?
454
455 if [ "${up}" = "1" ]; then
456 device_set_up "${device}"
457 fi
458
459 if [ "${ret}" != "0" ]; then
460 error_log "Could not set address '${addr}' on device '${device}'"
461 fi
462
463 return ${ret}
464 }
465
466 device_get() {
467 local device
468 for device in $(list_directory "${SYS_CLASS_NET}"); do
469 # bonding_masters is no device
470 [ "${device}" = "bonding_masters" ] && continue
471
472 echo "${device}"
473 done
474
475 return ${EXIT_OK}
476 }
477
478 # Check if a device has a cable plugged in
479 device_has_carrier() {
480 local device=${1}
481 assert isset device
482
483 local carrier=$(__device_get_file ${device} carrier)
484 [ "${carrier}" = "1" ]
485 }
486
487 device_is_promisc() {
488 local device=${1}
489
490 device_has_flag ${device} 0x200
491 }
492
493 device_set_promisc() {
494 local device=${1}
495 local state=${2}
496
497 assert device_exists ${device}
498 assert isset state
499 assert isoneof state on off
500
501 ip link set ${device} promisc ${state}
502 }
503
504 # Check if the device is free
505 device_is_free() {
506 ! device_is_used "$@"
507 }
508
509 # Check if the device is used
510 device_is_used() {
511 local device=${1}
512
513 device_has_vlans ${device} && \
514 return ${EXIT_OK}
515 device_is_bonded ${device} && \
516 return ${EXIT_OK}
517 device_is_bridge_attached ${device} && \
518 return ${EXIT_OK}
519
520 return ${EXIT_ERROR}
521 }
522
523 # Give the device a new name
524 device_set_name() {
525 local source=$1
526 local destination=${2}
527
528 # Check if devices exists
529 if ! device_exists ${source} || device_exists ${destination}; then
530 return 4
531 fi
532
533 local up
534 if device_is_up ${source}; then
535 ip link set ${source} down
536 up=1
537 fi
538
539 ip link set ${source} name ${destination}
540
541 if [ "${up}" = "1" ]; then
542 ip link set ${destination} up
543 fi
544 }
545
546 device_set_master() {
547 local device="${1}"
548 assert isset device
549
550 local master="${2}"
551 assert isset master
552
553 if ! cmd ip link set "${device}" master "${master}"; then
554 log ERROR "Could not set master ${master} for device ${device}"
555 return ${EXIT_ERROR}
556 fi
557
558 return ${EXIT_OK}
559 }
560
561 device_remove_master() {
562 local device="${1}"
563 assert isset device
564
565 if ! cmd ip link set "${device}" nomaster; then
566 log ERROR "Could not remove master for device ${device}"
567 return ${EXIT_ERROR}
568 fi
569
570 return ${EXIT_OK}
571 }
572
573 # Set device up
574 device_set_up() {
575 assert [ $# -eq 1 ]
576
577 local device=${1}
578
579 # Do nothing if device is already up
580 device_is_up ${device} && return ${EXIT_OK}
581
582 log INFO "Bringing up ${device}"
583
584 device_set_parent_up ${device}
585 if ! cmd ip link set ${device} up; then
586 return ${EXIT_ERROR}
587 fi
588
589 # Set SMP affinity
590 if interrupt_use_smp_affinity; then
591 device_auto_configure_smp_affinity ${device}
592 fi
593
594 return ${EXIT_OK}
595 }
596
597 device_set_parent_up() {
598 local device=${1}
599 local parent
600
601 if device_is_vlan ${device}; then
602 parent=$(vlan_get_parent ${device})
603
604 device_is_up ${parent} && return ${EXIT_OK}
605
606 log DEBUG "Setting up parent device '${parent}' of '${device}'"
607
608 device_set_up ${parent}
609 return $?
610 fi
611
612 return ${EXIT_OK}
613 }
614
615 # Set device down
616 device_set_down() {
617 assert [ $# -eq 1 ]
618
619 local device=${1}
620 local ret=${EXIT_OK}
621
622 if device_is_up ${device}; then
623 log INFO "Bringing down ${device}"
624
625 cmd ip link set ${device} down
626 ret=$?
627 fi
628
629 device_set_parent_down ${device}
630
631 return ${ret}
632 }
633
634 device_set_parent_down() {
635 local device=${1}
636 local parent
637
638 if device_is_vlan ${device}; then
639 parent=$(vlan_get_parent ${device})
640
641 device_is_up ${parent} || return ${EXIT_OK}
642
643 if device_is_free ${parent}; then
644 log DEBUG "Tearing down parent device '${parent}' of '${device}'"
645
646 device_set_down ${parent}
647 fi
648 fi
649
650 return ${EXIT_OK}
651 }
652
653 device_get_mtu() {
654 local device=${1}
655
656 # Return an error if the device does not exist
657 device_exists ${device} || return ${EXIT_ERROR}
658
659 echo $(<${SYS_CLASS_NET}/${device}/mtu)
660 }
661
662 # Set mtu to a device
663 device_set_mtu() {
664 local device=${1}
665 local mtu=${2}
666
667 assert device_exists ${device}
668
669 # Handle bridges differently
670 if device_is_bridge ${device}; then
671 local port
672 for port in $(bridge_get_members ${device}); do
673 device_set_mtu ${port} ${mtu}
674 done
675 fi
676
677 log INFO "Setting MTU of ${device} to ${mtu}"
678
679 local up
680 if device_is_up ${device}; then
681 device_set_down ${device}
682 up=1
683 fi
684
685 local ret=${EXIT_OK}
686 if ! cmd ip link set ${device} mtu ${mtu}; then
687 ret=${EXIT_ERROR}
688
689 log ERROR "Could not set MTU ${mtu} on ${device}"
690 fi
691
692 if [ "${up}" = "1" ]; then
693 device_set_up ${device}
694 fi
695
696 return ${ret}
697 }
698
699 device_adjust_mtu() {
700 assert [ $# -eq 2 ]
701
702 local device="${1}"
703 local other_device="${2}"
704
705 local mtu="$(device_get_mtu "${other_device}")"
706 device_set_mtu "${device}" "${mtu}"
707 }
708
709 device_discover() {
710 local device=${1}
711
712 log INFO "Running discovery process on device '${device}'."
713
714 local hook
715 for hook in $(hook_zone_get_all); do
716 hook_zone_exec ${hook} discover ${device}
717 done
718 }
719
720 device_identify() {
721 assert [ $# -ge 1 ]
722
723 local device="${1}"
724
725 # Flash for ten seconds by default
726 local seconds="10"
727
728 # Run in background?
729 local background="false"
730
731 local arg
732 while read arg; do
733 case "${arg}" in
734 --background)
735 background="true"
736 ;;
737 --seconds=*)
738 seconds="$(cli_get_val "${arg}")"
739 ;;
740 esac
741 done <<< "$(args "$@")"
742
743 assert isinteger seconds
744
745 if ! device_exists "${device}"; then
746 log ERROR "Cannot identify device ${device}: Does not exist"
747 return ${EXIT_ERROR}
748 fi
749
750 if ! device_is_ethernet "${device}"; then
751 log DEBUG "Cannot identify device ${device}: Not an ethernet device"
752 return ${EXIT_NOT_SUPPORTED}
753 fi
754
755 log DEBUG "Identifying device ${device}"
756
757 local command="ethtool --identify ${device} ${seconds}"
758 local ret=0
759
760 if enabled background; then
761 cmd_background "${command}"
762 else
763 cmd_quiet "${command}"
764 ret=$?
765 fi
766
767 return ${ret}
768 }
769
770 device_has_ip() {
771 local device=${1}
772 local addr=${2}
773
774 assert isset addr
775 assert device_exists ${device}
776
777 # IPv6 addresses must be fully imploded
778 local protocol=$(ip_detect_protocol ${addr})
779 case "${protocol}" in
780 ipv6)
781 addr=$(ipv6_format "${addr}")
782 ;;
783 esac
784
785 list_match ${addr} $(device_get_addresses ${device})
786 }
787
788 device_get_addresses() {
789 local device=${1}
790
791 assert device_exists ${device}
792
793 local prot
794 local addr
795 local line
796 ip addr show ${device} | \
797 while read prot addr line; do
798 [ "${prot:0:4}" = "inet" ] && echo "${addr}"
799 done
800 }
801
802 __device_get_file() {
803 local device=${1}
804 local file=${2}
805
806 fread "${SYS_CLASS_NET}/${device}/${file}"
807 }
808
809 __device_set_file() {
810 assert [ $# -eq 3 ]
811
812 local device="${1}"
813 local file="${2}"
814 local value="${3}"
815
816 fappend "${SYS_CLASS_NET}/${device}/${file}" "${value}"
817 }
818
819 device_get_rx_bytes() {
820 local device=${1}
821
822 __device_get_file ${device} statistics/rx_bytes
823 }
824
825 device_get_tx_bytes() {
826 local device=${1}
827
828 __device_get_file ${device} statistics/tx_bytes
829 }
830
831 device_get_rx_packets() {
832 local device=${1}
833
834 __device_get_file ${device} statistics/rx_packets
835 }
836
837 device_get_tx_packets() {
838 local device=${1}
839
840 __device_get_file ${device} statistics/tx_packets
841 }
842
843 device_get_rx_errors() {
844 local device=${1}
845
846 __device_get_file ${device} statistics/rx_errors
847 }
848
849 device_get_tx_errors() {
850 local device=${1}
851
852 __device_get_file ${device} statistics/tx_errors
853 }
854
855 device_get_speed() {
856 local device=${1}
857
858 local speed=$(__device_get_file ${device} speed)
859
860 # Exit for no output (i.e. no link detected)
861 isset speed || return ${EXIT_ERROR}
862
863 # Don't return anything for negative values
864 [ ${speed} -lt 0 ] && return ${EXIT_ERROR}
865
866 print "${speed}"
867 }
868
869 device_get_duplex() {
870 local device=${1}
871
872 local duplex=$(__device_get_file ${device} duplex)
873
874 case "${duplex}" in
875 unknown)
876 return ${EXIT_ERROR}
877 ;;
878 *)
879 print "${duplex}"
880 ;;
881 esac
882 }
883
884 device_get_link_string() {
885 local device="${1}"
886 assert isset device
887
888 local s
889
890 local speed="$(device_get_speed "${device}")"
891 if isset speed; then
892 list_append s "${speed} MBit/s"
893 fi
894
895 local duplex="$(device_get_duplex "${device}")"
896 if isset duplex; then
897 list_append s "${duplex} duplex"
898 fi
899
900 print "${s}"
901 }
902
903 device_auto_configure_smp_affinity() {
904 assert [ $# -eq 1 ]
905
906 local device=${1}
907
908 if lock_acquire "smp-affinity" 60; then
909 device_set_smp_affinity ${device} auto
910
911 lock_release "smp-affinity"
912 fi
913 }
914
915 device_set_smp_affinity() {
916 assert [ $# -eq 2 ]
917
918 local device=${1}
919 local mode=${2}
920
921 # mode can be auto which will automatically try to find
922 # the least busy processor, or an integer for the desired
923 # processor that should handle this device
924
925 local num_processors=$(system_get_processors)
926
927 if [ "${mode}" = "auto" ]; then
928 local processor=$(interrupt_choose_least_busy_processor)
929 else
930 assert isinteger mode
931 local processor=${mode}
932
933 if [ ${processor} -gt ${num_processors} ]; then
934 log ERROR "Processor ${processor} does not exist"
935 return ${EXIT_ERROR}
936 fi
937 fi
938
939 local interrupts=$(interrupts_for_device ${device})
940 if ! isset interrupts; then
941 log DEBUG "${device} has no interrupts. Not changing SMP affinity"
942 return ${EXIT_OK}
943 fi
944
945 # Set SMP affinity
946 local interrupt
947 for interrupt in ${interrupts}; do
948 interrupt_set_smp_affinity ${interrupt} ${processor}
949 done
950
951 # Find all queues and assign them to the next processor
952 local queue
953 for queue in $(device_get_queues ${device}); do
954 case "${queue}" in
955 # Only handle receive queues
956 rx-*)
957 for interrupt in $(interrupts_for_device_queue ${device} ${queue}); do
958 interrupt_set_smp_affinity ${interrupt} ${processor}
959 done
960
961 device_queue_set_smp_affinity ${device} ${queue} ${processor}
962 ;;
963
964 # Ignore the rest
965 *)
966 continue
967 ;;
968 esac
969
970 # Get the next available processor if in auto mode
971 [ "${mode}" = "auto" ] && processor=$(system_get_next_processor ${processor})
972 done
973
974 return ${EXIT_OK}
975 }
976
977 device_get_queues() {
978 assert [ $# -eq 1 ]
979
980 local device=${1}
981
982 list_directory "${SYS_CLASS_NET}/${device}/queues"
983 }
984
985 device_supports_multiqueue() {
986 local device=${1}
987
988 local num_queues=$(device_num_queues ${device})
989
990 if isset num_queues && [ ${num_queues} -gt 2 ]; then
991 return ${EXIT_TRUE}
992 fi
993
994 return ${EXIT_FALSE}
995 }
996
997 device_num_queues() {
998 local device=${1}
999 local type=${2}
1000
1001 isset type && assert isoneof type rx tx
1002
1003 local i=0
1004
1005 local q
1006 for q in $(device_get_queues ${device}); do
1007 case "${type},${q}" in
1008 rx,rx-*)
1009 (( i++ ))
1010 ;;
1011 tx,tx-*)
1012 (( i++ ))
1013 ;;
1014 *,*)
1015 (( i++ ))
1016 ;;
1017 esac
1018 done
1019
1020 print ${i}
1021 }
1022
1023 device_queue_get_smp_affinity() {
1024 assert [ $# -eq 2 ]
1025
1026 local device=${1}
1027 local queue=${2}
1028
1029 local path="${SYS_CLASS_NET}/${device}/queues/${queue}"
1030
1031 case "${queue}" in
1032 rx-*)
1033 path="${path}/rps_cpus"
1034 ;;
1035 tx-*)
1036 path="${path}/xps_cpus"
1037 ;;
1038 esac
1039 assert [ -r "${path}" ]
1040
1041 __bitmap_to_processor_ids $(<${path})
1042 }
1043
1044 device_queue_set_smp_affinity() {
1045 assert [ $# -eq 3 ]
1046
1047 local device=${1}
1048 local queue=${2}
1049 local processor=${3}
1050
1051 local path="${SYS_CLASS_NET}/${device}/queues/${queue}/rps_cpus"
1052 assert [ -w "${path}" ]
1053
1054 log DEBUG "Setting SMP affinity of ${device} (${queue}) to processor ${processor}"
1055
1056 __processor_id_to_bitmap ${processor} > ${path}
1057 }