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