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