]> git.ipfire.org Git - thirdparty/dracut.git/blob - modules.d/40network/net-lib.sh
Merge branch 'fix_ipv2_for_busybox' of https://github.com/nolange/dracut into nolange...
[thirdparty/dracut.git] / modules.d / 40network / net-lib.sh
1 #!/bin/sh
2
3 is_ip() {
4 echo "$1" | {
5 IFS=. read a b c d
6 test "$a" -ge 0 -a "$a" -le 255 \
7 -a "$b" -ge 0 -a "$b" -le 255 \
8 -a "$c" -ge 0 -a "$c" -le 255 \
9 -a "$d" -ge 0 -a "$d" -le 255 \
10 2> /dev/null
11 } && return 0
12 return 1
13 }
14
15 get_ip() {
16 local iface="$1" ip=""
17 ip=$(ip -f inet addr show $iface)
18 ip=${ip%%/*}
19 ip=${ip##* }
20 echo $ip
21 }
22
23 iface_for_remote_addr() {
24 set -- $(ip route get to $1 | sed 's/.*\bdev\b//p;q')
25 echo $1
26 }
27
28 iface_for_ip() {
29 set -- $(ip addr show to $1)
30 echo ${2%:}
31 }
32
33 iface_for_mac() {
34 local interface="" mac="$(echo $1 | sed 'y/ABCDEF/abcdef/')"
35 for interface in /sys/class/net/*; do
36 if [ $(cat $interface/address) = "$mac" ]; then
37 echo ${interface##*/}
38 fi
39 done
40 }
41
42 # get the iface name for the given identifier - either a MAC, IP, or iface name
43 iface_name() {
44 case $1 in
45 ??:??:??:??:??:??|??-??-??-??-??-??) iface_for_mac $1 ;;
46 *:*:*|*.*.*.*) iface_for_ip $1 ;;
47 *) echo $1 ;;
48 esac
49 }
50
51 # list the configured interfaces
52 configured_ifaces() {
53 local IFACES="" iface_id="" rv=1
54 [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
55 if { pidof udevd || pidof systemd-udevd; } > /dev/null; then
56 for iface_id in $IFACES; do
57 echo $(iface_name $iface_id)
58 rv=0
59 done
60 else
61 warn "configured_ifaces called before udev is running"
62 echo $IFACES
63 [ -n "$IFACES" ] && rv=0
64 fi
65 return $rv
66 }
67
68 all_ifaces_up() {
69 local iface="" IFACES=""
70 [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
71 for iface in $IFACES; do
72 [ -e /tmp/net.$iface.up ] || return 1
73 done
74 }
75
76 all_ifaces_setup() {
77 local iface="" IFACES=""
78 [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
79 for iface in $IFACES; do
80 [ -e /tmp/net.$iface.did-setup ] || return 1
81 done
82 }
83
84 get_netroot_ip() {
85 local prefix="" server="" rest=""
86 splitsep "$1" ":" prefix server rest
87 case $server in
88 [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*) echo "$server"; return 0 ;;
89 esac
90 return 1
91 }
92
93 ip_is_local() {
94 strstr "$(ip route get $1 2>/dev/null)" " via "
95 }
96
97 ifdown() {
98 local netif="$1"
99 # ip down/flush ensures that routing info goes away as well
100 ip link set $netif down
101 ip addr flush dev $netif
102 echo "#empty" > /etc/resolv.conf
103 rm -f -- /tmp/net.$netif.did-setup
104 [ -z "$DO_VLAN" ] && \
105 [ -e /sys/class/net/$netif/address ] && \
106 rm -f -- /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
107 # TODO: send "offline" uevent?
108 }
109
110 setup_net() {
111 local netif="$1" f="" gw_ip="" netroot_ip="" iface="" IFACES=""
112 local _p
113 [ -e /tmp/net.$netif.did-setup ] && return
114 [ -z "$DO_VLAN" ] && \
115 [ -e /sys/class/net/$netif/address ] && \
116 [ -e /tmp/net.$(cat /sys/class/net/$netif/address).did-setup ] && return
117 [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
118 [ -z "$IFACES" ] && IFACES="$netif"
119 # run the scripts written by ifup
120 [ -e /tmp/net.$netif.hostname ] && . /tmp/net.$netif.hostname
121 [ -e /tmp/net.$netif.override ] && . /tmp/net.$netif.override
122 [ -e /tmp/dhclient.$netif.dhcpopts ] && . /tmp/dhclient.$netif.dhcpopts
123 # set up resolv.conf
124 [ -e /tmp/net.$netif.resolv.conf ] && \
125 awk '!array[$0]++' /tmp/net.$netif.resolv.conf > /etc/resolv.conf
126 [ -e /tmp/net.$netif.gw ] && . /tmp/net.$netif.gw
127
128 # add static route
129 for _p in $(getargs rd.route); do
130 route_to_var "$_p" || continue
131 [ -n "$route_dev" ] && [ "$route_dev" != "$netif" ] && continue
132 ip route add "$route_mask" ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev}
133 if strstr "$route_mask" ":"; then
134 printf -- "%s\n" "$route_mask ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev}" \
135 > /tmp/net.route6."$netif"
136 else
137 printf -- "%s\n" "$route_mask ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev}" \
138 > /tmp/net.route."$netif"
139 fi
140 done
141
142 # If a static route was necessary to reach the gateway, the
143 # first gateway setup call will have failed with
144 # RTNETLINK answers: Network is unreachable
145 # Replace the default route again after static routes to cover
146 # this scenario.
147 [ -e /tmp/net.$netif.gw ] && . /tmp/net.$netif.gw
148
149 # Handle STP Timeout: arping the default gateway.
150 # (or the root server, if a) it's local or b) there's no gateway.)
151 # Note: This assumes that if no router is present the
152 # root server is on the same subnet.
153
154 # Get DHCP-provided router IP, or the cmdline-provided "gw=" argument
155 [ -n "$new_routers" ] && gw_ip=${new_routers%%,*}
156 [ -n "$gw" ] && gw_ip=$gw
157
158 # Get the "netroot" IP (if there's an IP address in there)
159 netroot_ip=$(get_netroot_ip $netroot)
160
161 # try netroot if it's local (or there's no gateway)
162 if ip_is_local $netroot_ip || [ -z "$gw_ip" ]; then
163 dest="$netroot_ip"
164 else
165 dest="$gw_ip"
166 fi
167
168 unset layer2
169 if [ -f /sys/class/net/$netif/device/layer2 ]; then
170 read layer2 < /sys/class/net/$netif/device/layer2
171 fi
172
173 if [ "$layer2" != "0" ] && [ -n "$dest" ] && ! strstr "$dest" ":"; then
174 if command -v arping2 >/dev/null; then
175 arping2 -q -C 1 -c 60 -I $netif $dest || info "Resolving $dest via ARP on $netif failed"
176 else
177 arping -q -f -w 60 -I $netif $dest || info "Resolving $dest via ARP on $netif failed"
178 fi
179 fi
180 unset layer2
181
182 > /tmp/net.$netif.did-setup
183 [ -z "$DO_VLAN" ] && \
184 [ -e /sys/class/net/$netif/address ] && \
185 > /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
186 }
187
188 save_netinfo() {
189 local netif="$1" IFACES="" f="" i=""
190 [ -e /tmp/net.ifaces ] && read IFACES < /tmp/net.ifaces
191 # Add $netif to the front of IFACES (if it's not there already).
192 set -- "$netif"
193 for i in $IFACES; do [ "$i" != "$netif" ] && set -- "$@" "$i"; done
194 IFACES="$*"
195 for i in $IFACES; do
196 for f in /tmp/dhclient.$i.*; do
197 [ -f $f ] && cp -f $f /tmp/net.${f#/tmp/dhclient.}
198 done
199 done
200 echo $IFACES > /tmp/.net.ifaces.new
201 mv /tmp/.net.ifaces.new /tmp/net.ifaces
202 }
203
204 set_ifname() {
205 local name="$1" mac="$2" num=-1 n=""
206 # if it's already set, return the existing name
207 for n in $(getargs ifname=); do
208 strstr "$n" "$mac" && echo ${n%%:*} && return
209 done
210 # otherwise, pick a new name and use that
211 while :; do
212 num=$(($num+1));
213 [ -e /sys/class/net/$name$num ] && continue
214 for n in $(getargs ifname=); do
215 [ "$name$num" = "${n%%:*}" ] && continue 2
216 done
217 break
218 done
219 echo "ifname=$name$num:$mac" >> /etc/cmdline.d/45-ifname.conf
220 echo "$name$num"
221 }
222
223 # pxelinux provides macaddr '-' separated, but we need ':'
224 fix_bootif() {
225 local macaddr=${1}
226 local IFS='-'
227 macaddr=$(printf '%s:' ${macaddr})
228 macaddr=${macaddr%:}
229 # strip hardware type field from pxelinux
230 [ -n "${macaddr%??:??:??:??:??:??}" ] && macaddr=${macaddr#??:}
231 # return macaddr with lowercase alpha characters expected by udev
232 echo $macaddr | sed 'y/ABCDEF/abcdef/'
233 }
234
235 ibft_to_cmdline() {
236 local iface=""
237 modprobe -q iscsi_ibft
238 (
239 for iface in /sys/firmware/ibft/ethernet*; do
240 local mac="" dev=""
241 local dhcp="" ip="" gw="" mask="" hostname=""
242 local dns1 dns2
243
244 [ -e ${iface}/mac ] || continue
245 mac=$(read a < ${iface}/mac; echo $a)
246 [ -z "$mac" ] && continue
247 dev=$(set_ifname ibft $mac)
248
249 [ -e /tmp/net.${dev}.has_ibft_config ] && continue
250
251 [ -e ${iface}/flags ] && flags=$(read a < ${iface}/flags; echo $a)
252 # Skip invalid interfaces
253 (( $flags & 1 )) || continue
254 # Skip interfaces not used for booting
255 (( $flags & 2 )) || continue
256 [ -e ${iface}/dhcp ] && dhcp=$(read a < ${iface}/dhcp; echo $a)
257 [ -e ${iface}/origin ] && origin=$(read a < ${iface}/origin; echo $a)
258 [ -e ${iface}/ip-addr ] && ip=$(read a < ${iface}/ip-addr; echo $a)
259
260 if [ -n "$ip" ] ; then
261 case "$ip" in
262 *.*.*.*)
263 family=ipv4
264 ;;
265 *:*)
266 family=ipv6
267 ;;
268 esac
269 fi
270 if [ -n "$dhcp" ] || [ "$origin" -eq 3 ]; then
271 if [ "$family" = "ipv6" ] ; then
272 echo "ip=$dev:dhcp6"
273 else
274 echo "ip=$dev:dhcp"
275 fi
276 elif [ -e ${iface}/ip-addr ]; then
277 # skip not assigned ip adresses
278 [ "$ip" = "0.0.0.0" ] && continue
279 [ -e ${iface}/gateway ] && gw=$(read a < ${iface}/gateway; echo $a)
280 [ "$gateway" = "0.0.0.0" ] && unset $gateway
281 [ -e ${iface}/subnet-mask ] && mask=$(read a < ${iface}/subnet-mask; echo $a)
282 [ -e ${iface}/prefix-len ] && prefix=$(read a < ${iface}/prefix-len; echo $a)
283 [ -e ${iface}/primary-dns ] && dns1=$(read a < ${iface}/primary-dns; echo $a)
284 [ "$dns1" = "0.0.0.0" ] && unset $dns1
285 [ -e ${iface}/secondary-dns ] && dns2=$(read a < ${iface}/secondary-dns; echo $a)
286 [ "$dns2" = "0.0.0.0" ] && unset $dns2
287 [ -e ${iface}/hostname ] && hostname=$(read a < ${iface}/hostname; echo $a)
288 if [ "$family" = "ipv6" ] ; then
289 if [ -n "$ip" ] ; then
290 ip="[$ip]"
291 [ -n "$prefix" ] || prefix=64
292 ip="[${ip}/${prefix}]"
293 mask=
294 fi
295 if [ -n "$gw" ] ; then
296 gw="[${gw}]"
297 fi
298 fi
299 if [ -n "$ip" ] && [ -n "$mask" -o -n "$prefix" ]; then
300 echo "ip=$ip::$gw:$mask:$hostname:$dev:none${dns1:+:$dns1}${dns2:+:$dns2}"
301 else
302 warn "${iface} does not contain a valid iBFT configuration"
303 warn "ip-addr=$ip"
304 warn "gateway=$gw"
305 warn "subnet-mask=$mask"
306 warn "hostname=$hostname"
307 fi
308 else
309 info "${iface} does not contain a valid iBFT configuration"
310 ls -l ${iface} | vinfo
311 fi
312
313 if [ -e ${iface}/vlan ]; then
314 vlan=$(read a < ${iface}/vlan; echo $a)
315 if [ "$vlan" -ne "0" ]; then
316 case "$vlan" in
317 [0-9]*)
318 echo "vlan=$dev.$vlan:$dev"
319 echo $mac > /tmp/net.${dev}.${vlan}.has_ibft_config
320 ;;
321 *)
322 echo "vlan=$vlan:$dev"
323 echo $mac > /tmp/net.${vlan}.has_ibft_config
324 ;;
325 esac
326 else
327 echo $mac > /tmp/net.${dev}.has_ibft_config
328 fi
329 else
330 echo $mac > /tmp/net.${dev}.has_ibft_config
331 fi
332
333 done
334 ) >> /etc/cmdline.d/40-ibft.conf
335 }
336
337 parse_iscsi_root()
338 {
339 local v
340 v=${1#iscsi:}
341
342 # extract authentication info
343 case "$v" in
344 *@*:*:*:*:*)
345 authinfo=${v%%@*}
346 v=${v#*@}
347 # allow empty authinfo to allow having an @ in iscsi_target_name like this:
348 # netroot=iscsi:@192.168.1.100::3260::iqn.2009-01.com.example:testdi@sk
349 if [ -n "$authinfo" ]; then
350 OLDIFS="$IFS"
351 IFS=:
352 set $authinfo
353 IFS="$OLDIFS"
354 if [ $# -gt 4 ]; then
355 warn "Wrong authentication info in iscsi: parameter!"
356 return 1
357 fi
358 iscsi_username=$1
359 iscsi_password=$2
360 if [ $# -gt 2 ]; then
361 iscsi_in_username=$3
362 iscsi_in_password=$4
363 fi
364 fi
365 ;;
366 esac
367
368 # extract target ip
369 case "$v" in
370 [[]*[]]:*)
371 iscsi_target_ip=${v#[[]}
372 iscsi_target_ip=${iscsi_target_ip%%[]]*}
373 v=${v#[[]$iscsi_target_ip[]]:}
374 ;;
375 *)
376 iscsi_target_ip=${v%%[:]*}
377 v=${v#$iscsi_target_ip:}
378 ;;
379 esac
380
381 unset iscsi_target_name
382 # extract target name
383 case "$v" in
384 *:iqn.*)
385 iscsi_target_name=iqn.${v##*:iqn.}
386 v=${v%:iqn.*}:
387 ;;
388 *:eui.*)
389 iscsi_target_name=eui.${v##*:eui.}
390 v=${v%:eui.*}:
391 ;;
392 *:naa.*)
393 iscsi_target_name=naa.${v##*:naa.}
394 v=${v%:naa.*}:
395 ;;
396 esac
397
398 # parse the rest
399 OLDIFS="$IFS"
400 IFS=:
401 set $v
402 IFS="$OLDIFS"
403
404 iscsi_protocol=$1; shift # ignored
405 iscsi_target_port=$1; shift
406
407 if [ -n "$iscsi_target_name" ]; then
408 if [ $# -eq 3 ]; then
409 iscsi_iface_name=$1; shift
410 fi
411 if [ $# -eq 2 ]; then
412 iscsi_netdev_name=$1; shift
413 fi
414 iscsi_lun=$1; shift
415 if [ $# -ne 0 ]; then
416 warn "Invalid parameter in iscsi: parameter!"
417 return 1
418 fi
419 return 0
420 fi
421
422
423 if [ $# -gt 3 ] && [ -n "$1$2" ]; then
424 if [ -z "$3" ] || [ "$3" -ge 0 ] 2>/dev/null ; then
425 iscsi_iface_name=$1; shift
426 iscsi_netdev_name=$1; shift
427 fi
428 fi
429
430 iscsi_lun=$1; shift
431
432 iscsi_target_name=$(printf "%s:" "$@")
433 iscsi_target_name=${iscsi_target_name%:}
434 }
435
436 ip_to_var() {
437 local v=${1}:
438 local i
439 set --
440 while [ -n "$v" ]; do
441 if [ "${v#\[*:*:*\]:}" != "$v" ]; then
442 # handle IPv6 address
443 i="${v%%\]:*}"
444 i="${i##\[}"
445 set -- "$@" "$i"
446 v=${v#\[$i\]:}
447 else
448 set -- "$@" "${v%%:*}"
449 v=${v#*:}
450 fi
451 done
452
453 unset ip srv gw mask hostname dev autoconf macaddr mtu dns1 dns2
454
455 if [ $# -eq 0 ]; then
456 autoconf="error"
457 return 0
458 fi
459
460 if [ $# -eq 1 ]; then
461 # format: ip={dhcp|on|any|dhcp6|auto6|either6}
462 # or
463 # ip=<ipv4-address> means anaconda-style static config argument cluster
464 autoconf="$1"
465
466 if strglob "$autoconf" "*.*.*.*"; then
467 # ip=<ipv4-address> means anaconda-style static config argument cluster:
468 # ip=<ip> gateway=<gw> netmask=<nm> hostname=<host> mtu=<mtu>
469 # ksdevice={link|bootif|ibft|<MAC>|<ifname>}
470 ip="$autoconf"
471 gw=$(getarg gateway=)
472 mask=$(getarg netmask=)
473 hostname=$(getarg hostname=)
474 dev=$(getarg ksdevice=)
475 autoconf="none"
476 mtu=$(getarg mtu=)
477
478 # handle special values for ksdevice
479 case "$dev" in
480 bootif|BOOTIF) dev=$(fix_bootif $(getarg BOOTIF=)) ;;
481 link) dev="" ;; # FIXME: do something useful with this
482 ibft) dev="" ;; # ignore - ibft is handled elsewhere
483 esac
484 fi
485 return 0
486 fi
487
488 if [ "$2" = "dhcp" -o "$2" = "on" -o "$2" = "any" -o "$2" = "dhcp6" -o "$2" = "auto6" -o "$2" = "either6" ]; then
489 # format: ip=<interface>:{dhcp|on|any|dhcp6|auto6}[:[<mtu>][:<macaddr>]]
490 [ -n "$1" ] && dev="$1"
491 [ -n "$2" ] && autoconf="$2"
492 [ -n "$3" ] && mtu=$3
493 if [ -z "$5" ]; then
494 macaddr="$4"
495 else
496 macaddr="${4}:${5}:${6}:${7}:${8}:${9}"
497 fi
498 return 0
499 fi
500
501 # format: ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}:[:[<mtu>][:<macaddr>]]
502
503 [ -n "$1" ] && ip=$1
504 [ -n "$2" ] && srv=$2
505 [ -n "$3" ] && gw=$3
506 [ -n "$4" ] && mask=$4
507 [ -n "$5" ] && hostname=$5
508 [ -n "$6" ] && dev=$6
509 [ -n "$7" ] && autoconf=$7
510 case "$8" in
511 [0-9]*:*|[0-9]*.[0-9]*.[0-9]*.[0-9]*)
512 dns1="$8"
513 [ -n "$9" ] && dns2="$9"
514 ;;
515 [0-9]*)
516 mtu="$8"
517 if [ -n "${9}" -a -z "${10}" ]; then
518 macaddr="${9}"
519 elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then
520 macaddr="${9}:${10}:${11}:${12}:${13}:${14}"
521 fi
522 ;;
523 *)
524 if [ -n "${9}" -a -z "${10}" ]; then
525 macaddr="${9}"
526 elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then
527 macaddr="${9}:${10}:${11}:${12}:${13}:${14}"
528 fi
529 ;;
530 esac
531 return 0
532 }
533
534 route_to_var() {
535 local v=${1}:
536 local i
537 set --
538 while [ -n "$v" ]; do
539 if [ "${v#\[*:*:*\]:}" != "$v" ]; then
540 # handle IPv6 address
541 i="${v%%\]:*}"
542 i="${i##\[}"
543 set -- "$@" "$i"
544 v=${v#\[$i\]:}
545 else
546 set -- "$@" "${v%%:*}"
547 v=${v#*:}
548 fi
549 done
550
551 unset route_mask route_gw route_dev
552 case $# in
553 2) [ -n "$1" ] && route_mask="$1"; [ -n "$2" ] && route_gw="$2"
554 return 0;;
555 3) [ -n "$1" ] && route_mask="$1"; [ -n "$2" ] && route_gw="$2"; [ -n "$3" ] && route_dev="$3"
556 return 0;;
557 *) return 1;;
558 esac
559 }
560
561 parse_ifname_opts() {
562 local IFS=:
563 set $1
564
565 case $# in
566 7)
567 ifname_if=$1
568 # udev requires MAC addresses to be lower case
569 ifname_mac=$(echo $2:$3:$4:$5:$6:$7 | sed 'y/ABCDEF/abcdef/')
570 ;;
571 *)
572 die "Invalid arguments for ifname="
573 ;;
574 esac
575
576 case $ifname_if in
577 eth[0-9]|eth[0-9][0-9]|eth[0-9][0-9][0-9]|eth[0-9][0-9][0-9][0-9])
578 warn "ifname=$ifname_if uses the kernel name space for interfaces"
579 warn "This can fail for multiple network interfaces and is discouraged!"
580 warn "Please use a custom name like \"netboot\" or \"bluesocket\""
581 warn "or use biosdevname and no ifname= at all."
582 ;;
583 esac
584
585 }
586
587 # some network driver need long time to initialize, wait before it's ready.
588 wait_for_if_link() {
589 local cnt=0
590 local li
591 local timeout="$(getargs rd.net.timeout.iflink=)"
592 timeout=${timeout:-60}
593 timeout=$(($timeout*10))
594
595 while [ $cnt -lt $timeout ]; do
596 li=$(ip link show dev $1 2>/dev/null)
597 [ -n "$li" ] && return 0
598 sleep 0.1
599 cnt=$(($cnt+1))
600 done
601 return 1
602 }
603
604 wait_for_if_up() {
605 local cnt=0
606 local li
607 local timeout="$(getargs rd.net.timeout.ifup=)"
608 timeout=${timeout:-20}
609 timeout=$(($timeout*10))
610
611 while [ $cnt -lt $timeout ]; do
612 li=$(ip link show up dev $1)
613 if [ -n "$li" ]; then
614 case "$li" in
615 *\<UP*)
616 return 0;;
617 *\<*,UP\>*)
618 return 0;;
619 *\<*,UP,*\>*)
620 return 0;;
621 esac
622 fi
623 if strstr "$li" "LOWER_UP" \
624 && strstr "$li" "state UNKNOWN" \
625 && ! strstr "$li" "DORMANT"; then
626 return 0
627 fi
628 sleep 0.1
629 cnt=$(($cnt+1))
630 done
631 return 1
632 }
633
634 wait_for_route_ok() {
635 local cnt=0
636 local timeout="$(getargs rd.net.timeout.route=)"
637 timeout=${timeout:-20}
638 timeout=$(($timeout*10))
639
640 while [ $cnt -lt $timeout ]; do
641 li=$(ip route show)
642 [ -n "$li" ] && [ -z "${li##*$1*}" ] && return 0
643 sleep 0.1
644 cnt=$(($cnt+1))
645 done
646 return 1
647 }
648
649 wait_for_ipv6_dad_link() {
650 local cnt=0
651 local timeout="$(getargs rd.net.timeout.ipv6dad=)"
652 timeout=${timeout:-50}
653 timeout=$(($timeout*10))
654
655 while [ $cnt -lt $timeout ]; do
656 [ -z "$(ip -6 addr show dev "$1" scope link tentative)" ] \
657 && [ -n "$(ip -6 route list proto ra dev "$1" | grep ^default)" ] \
658 && return 0
659 [ -n "$(ip -6 addr show dev "$1" scope link dadfailed)" ] \
660 && return 1
661 sleep 0.1
662 cnt=$(($cnt+1))
663 done
664 return 1
665 }
666
667 wait_for_ipv6_dad() {
668 local cnt=0
669 local timeout="$(getargs rd.net.timeout.ipv6dad=)"
670 timeout=${timeout:-50}
671 timeout=$(($timeout*10))
672
673 while [ $cnt -lt $timeout ]; do
674 [ -z "$(ip -6 addr show dev "$1" tentative)" ] \
675 && [ -n "$(ip -6 route list proto ra dev "$1" | grep ^default)" ] \
676 && return 0
677 [ -n "$(ip -6 addr show dev "$1" dadfailed)" ] \
678 && return 1
679 sleep 0.1
680 cnt=$(($cnt+1))
681 done
682 return 1
683 }
684
685 wait_for_ipv6_auto() {
686 local cnt=0
687 local timeout="$(getargs rd.net.timeout.ipv6auto=)"
688 timeout=${timeout:-40}
689 timeout=$(($timeout*10))
690
691 while [ $cnt -lt $timeout ]; do
692 [ -z "$(ip -6 addr show dev "$1" tentative)" ] \
693 && [ -n "$(ip -6 route list proto ra dev "$1" | grep ^default)" ] \
694 && return 0
695 sleep 0.1
696 cnt=$(($cnt+1))
697 done
698 return 1
699 }
700
701 linkup() {
702 wait_for_if_link $1 2>/dev/null\
703 && ip link set $1 up 2>/dev/null\
704 && wait_for_if_up $1 2>/dev/null
705 }
706
707 type hostname >/dev/null 2>&1 || \
708 hostname() {
709 cat /proc/sys/kernel/hostname
710 }
711
712 iface_has_carrier() {
713 local cnt=0
714 local interface="$1" flags=""
715 [ -n "$interface" ] || return 2
716 interface="/sys/class/net/$interface"
717 [ -d "$interface" ] || return 2
718 local timeout="$(getargs rd.net.timeout.carrier=)"
719 timeout=${timeout:-5}
720 timeout=$(($timeout*10))
721
722 linkup "$1"
723
724 li=$(ip link show up dev $1)
725 strstr "$li" "NO-CARRIER" && _no_carrier_flag=1
726
727 while [ $cnt -lt $timeout ]; do
728 if [ -n "$_no_carrier_flag" ]; then
729 li=$(ip link show up dev $1)
730 # NO-CARRIER flag was cleared
731 strstr "$li" "NO-CARRIER" || return 0
732 elif ! [ -e "$interface/carrier" ]; then
733 # sysfs not available and "NO-CARRIER" not displayed
734 return 0
735 fi
736 # double check the syscfs carrier flag
737 [ -e "$interface/carrier" ] && [ "$(cat $interface/carrier)" = 1 ] && return 0
738 sleep 0.1
739 cnt=$(($cnt+1))
740 done
741 return 1
742 }
743
744 iface_has_link() {
745 iface_has_carrier "$@"
746 }
747
748 iface_is_enslaved() {
749 local _li
750 _li=$(ip link show dev $1)
751 strstr "$_li" " master " || return 1
752 return 0
753 }
754
755 find_iface_with_link() {
756 local iface_path="" iface=""
757 for iface_path in /sys/class/net/*; do
758 iface=${iface_path##*/}
759 str_starts "$iface" "lo" && continue
760 if iface_has_link $iface; then
761 echo "$iface"
762 return 0
763 fi
764 done
765 return 1
766 }
767
768 is_persistent_ethernet_name() {
769 local _netif="$1"
770 local _name_assign_type="0"
771
772 [ -f "/sys/class/net/$_netif/name_assign_type" ] \
773 && _name_assign_type=$(cat "/sys/class/net/$_netif/name_assign_type")
774
775 # NET_NAME_ENUM 1
776 [ "$_name_assign_type" = "1" ] && return 1
777
778 # NET_NAME_PREDICTABLE 2
779 [ "$_name_assign_type" = "2" ] && return 0
780
781 case "$_netif" in
782 # udev persistent interface names
783 eno[0-9]|eno[0-9][0-9]|eno[0-9][0-9][0-9]*)
784 ;;
785 ens[0-9]|ens[0-9][0-9]|ens[0-9][0-9][0-9]*)
786 ;;
787 enp[0-9]s[0-9]*|enp[0-9][0-9]s[0-9]*|enp[0-9][0-9][0-9]*s[0-9]*)
788 ;;
789 enP*p[0-9]s[0-9]*|enP*p[0-9][0-9]s[0-9]*|enP*p[0-9][0-9][0-9]*s[0-9]*)
790 ;;
791 # biosdevname
792 em[0-9]|em[0-9][0-9]|em[0-9][0-9][0-9]*)
793 ;;
794 p[0-9]p[0-9]*|p[0-9][0-9]p[0-9]*|p[0-9][0-9][0-9]*p[0-9]*)
795 ;;
796 *)
797 return 1
798 esac
799 return 0
800 }
801
802 is_kernel_ethernet_name() {
803 local _netif="$1"
804 local _name_assign_type="1"
805
806 if [ -e "/sys/class/net/$_netif/name_assign_type" ]; then
807 _name_assign_type=$(cat "/sys/class/net/$_netif/name_assign_type")
808
809 case "$_name_assign_type" in
810 2|3|4)
811 # NET_NAME_PREDICTABLE 2
812 # NET_NAME_USER 3
813 # NET_NAME_RENAMED 4
814 return 1
815 ;;
816 1|*)
817 # NET_NAME_ENUM 1
818 return 0
819 ;;
820 esac
821 fi
822
823 # fallback to error prone manual name check
824 case "$_netif" in
825 eth[0-9]|eth[0-9][0-9]|eth[0-9][0-9][0-9]*)
826 return 0
827 ;;
828 *)
829 return 1
830 esac
831
832 }
833
834 iface_get_subchannels() {
835 local _netif
836 local _subchannels
837
838 _netif="$1"
839
840 _subchannels=$({
841 for i in /sys/class/net/$_netif/device/cdev[0-9]*; do
842 [ -e $i ] || continue
843 channel=$(readlink -f $i)
844 printf -- "%s" "${channel##*/},"
845 done
846 })
847 [ -n "$_subchannels" ] || return 1
848
849 printf -- "%s" ${_subchannels%,}
850 }