]> git.ipfire.org Git - thirdparty/dracut.git/blame - modules.d/40network/net-lib.sh
chore: remove unnecessary shellcheck disable for SC1087
[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 396 iscsi_target_ip=${iscsi_target_ip%%[]]*}
08b63a25 397 v=${v#[[]"$iscsi_target_ip"[]]:}
29763cb7
HH
398 ;;
399 *)
400 iscsi_target_ip=${v%%[:]*}
08b63a25 401 v=${v#"$iscsi_target_ip":}
29763cb7 402 ;;
ac3f1c6e
HH
403 esac
404
36e8ce4f
HH
405 unset iscsi_target_name
406 # extract target name
407 case "$v" in
408 *:iqn.*)
409 iscsi_target_name=iqn.${v##*:iqn.}
410 v=${v%:iqn.*}:
411 ;;
412 *:eui.*)
7cddd7b8
HH
413 iscsi_target_name=eui.${v##*:eui.}
414 v=${v%:eui.*}:
36e8ce4f
HH
415 ;;
416 *:naa.*)
7cddd7b8
HH
417 iscsi_target_name=naa.${v##*:naa.}
418 v=${v%:naa.*}:
36e8ce4f
HH
419 ;;
420 esac
421
29763cb7 422 # parse the rest
ac3f1c6e
HH
423 OLDIFS="$IFS"
424 IFS=:
e25c536c 425 # shellcheck disable=SC2086
ac3f1c6e
HH
426 set $v
427 IFS="$OLDIFS"
428
9a52c3fd
HH
429 iscsi_protocol=$1
430 shift # ignored
431 iscsi_target_port=$1
432 shift
29763cb7 433
36e8ce4f
HH
434 if [ -n "$iscsi_target_name" ]; then
435 if [ $# -eq 3 ]; then
9a52c3fd
HH
436 iscsi_iface_name=$1
437 shift
36e8ce4f
HH
438 fi
439 if [ $# -eq 2 ]; then
9a52c3fd
HH
440 iscsi_netdev_name=$1
441 shift
36e8ce4f 442 fi
9a52c3fd
HH
443 iscsi_lun=$1
444 shift
36e8ce4f
HH
445 if [ $# -ne 0 ]; then
446 warn "Invalid parameter in iscsi: parameter!"
447 return 1
448 fi
449 return 0
ac3f1c6e 450 fi
29763cb7 451
36e8ce4f 452 if [ $# -gt 3 ] && [ -n "$1$2" ]; then
9a52c3fd
HH
453 if [ -z "$3" ] || [ "$3" -ge 0 ] 2> /dev/null; then
454 iscsi_iface_name=$1
455 shift
456 iscsi_netdev_name=$1
457 shift
36e8ce4f 458 fi
ac3f1c6e 459 fi
29763cb7 460
9a52c3fd
HH
461 iscsi_lun=$1
462 shift
29763cb7 463
36e8ce4f
HH
464 iscsi_target_name=$(printf "%s:" "$@")
465 iscsi_target_name=${iscsi_target_name%:}
ac3f1c6e
HH
466}
467
990e945f 468ip_to_var() {
08b63a25 469 local v="${1}":
990e945f
HH
470 local i
471 set --
472 while [ -n "$v" ]; do
473 if [ "${v#\[*:*:*\]:}" != "$v" ]; then
474 # handle IPv6 address
475 i="${v%%\]:*}"
476 i="${i##\[}"
477 set -- "$@" "$i"
08b63a25 478 v=${v#\["$i"\]:}
990e945f
HH
479 else
480 set -- "$@" "${v%%:*}"
481 v=${v#*:}
482 fi
483 done
484
66bfe863 485 unset ip srv gw mask hostname dev autoconf macaddr mtu dns1 dns2
740c46c0
HH
486
487 if [ $# -eq 0 ]; then
488 autoconf="error"
489 return 0
490 fi
491
492 if [ $# -eq 1 ]; then
4026cd3b 493 # format: ip={dhcp|on|any|dhcp6|auto6|either6|single-dhcp}
740c46c0
HH
494 # or
495 # ip=<ipv4-address> means anaconda-style static config argument cluster
496 autoconf="$1"
497
b2616b52 498 if strglob "$autoconf" "*.*.*.*"; then
740c46c0
HH
499 # ip=<ipv4-address> means anaconda-style static config argument cluster:
500 # ip=<ip> gateway=<gw> netmask=<nm> hostname=<host> mtu=<mtu>
501 # ksdevice={link|bootif|ibft|<MAC>|<ifname>}
502 ip="$autoconf"
503 gw=$(getarg gateway=)
504 mask=$(getarg netmask=)
505 hostname=$(getarg hostname=)
506 dev=$(getarg ksdevice=)
507 autoconf="none"
508 mtu=$(getarg mtu=)
509
510 # handle special values for ksdevice
511 case "$dev" in
e25c536c 512 bootif | BOOTIF) dev=$(fix_bootif "$(getarg BOOTIF=)") ;;
740c46c0
HH
513 link) dev="" ;; # FIXME: do something useful with this
514 ibft) dev="" ;; # ignore - ibft is handled elsewhere
66bfe863 515 esac
740c46c0
HH
516 fi
517 return 0
518 fi
519
67354eeb 520 if [ "$2" = "dhcp" -o "$2" = "on" -o "$2" = "any" -o "$2" = "dhcp6" -o "$2" = "auto6" -o "$2" = "either6" ]; then
740c46c0
HH
521 # format: ip=<interface>:{dhcp|on|any|dhcp6|auto6}[:[<mtu>][:<macaddr>]]
522 [ -n "$1" ] && dev="$1"
523 [ -n "$2" ] && autoconf="$2"
524 [ -n "$3" ] && mtu=$3
525 if [ -z "$5" ]; then
526 macaddr="$4"
527 else
528 macaddr="${4}:${5}:${6}:${7}:${8}:${9}"
529 fi
530 return 0
531 fi
532
533 # format: ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}:[:[<mtu>][:<macaddr>]]
534
535 [ -n "$1" ] && ip=$1
536 [ -n "$2" ] && srv=$2
537 [ -n "$3" ] && gw=$3
538 [ -n "$4" ] && mask=$4
539 [ -n "$5" ] && hostname=$5
540 [ -n "$6" ] && dev=$6
541 [ -n "$7" ] && autoconf=$7
542 case "$8" in
9a52c3fd 543 [0-9a-fA-F]*:* | [0-9]*.[0-9]*.[0-9]*.[0-9]*)
740c46c0
HH
544 dns1="$8"
545 [ -n "$9" ] && dns2="$9"
66bfe863 546 ;;
740c46c0
HH
547 [0-9]*)
548 mtu="$8"
549 if [ -n "${9}" -a -z "${10}" ]; then
550 macaddr="${9}"
551 elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then
552 macaddr="${9}:${10}:${11}:${12}:${13}:${14}"
553 fi
c98d1756 554 ;;
740c46c0
HH
555 *)
556 if [ -n "${9}" -a -z "${10}" ]; then
557 macaddr="${9}"
558 elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then
559 macaddr="${9}:${10}:${11}:${12}:${13}:${14}"
560 fi
9a52c3fd 561 ;;
c98d1756 562 esac
740c46c0 563 return 0
990e945f 564}
e7dc1e42 565
7b46244b 566route_to_var() {
08b63a25 567 local v="${1}":
7b46244b
HH
568 local i
569 set --
570 while [ -n "$v" ]; do
571 if [ "${v#\[*:*:*\]:}" != "$v" ]; then
572 # handle IPv6 address
573 i="${v%%\]:*}"
574 i="${i##\[}"
575 set -- "$@" "$i"
08b63a25 576 v=${v#\["$i"\]:}
7b46244b
HH
577 else
578 set -- "$@" "${v%%:*}"
579 v=${v#*:}
580 fi
581 done
582
583 unset route_mask route_gw route_dev
584 case $# in
9a52c3fd
HH
585 2)
586 [ -n "$1" ] && route_mask="$1"
587 [ -n "$2" ] && route_gw="$2"
588 return 0
589 ;;
590 3)
591 [ -n "$1" ] && route_mask="$1"
592 [ -n "$2" ] && route_gw="$2"
593 [ -n "$3" ] && route_dev="$3"
594 return 0
595 ;;
596 *) return 1 ;;
7b46244b
HH
597 esac
598}
599
e7dc1e42
HH
600parse_ifname_opts() {
601 local IFS=:
e25c536c
HH
602 # shellcheck disable=SC2086
603 set -- $1
e7dc1e42
HH
604
605 case $# in
606 7)
607 ifname_if=$1
608 # udev requires MAC addresses to be lower case
e25c536c 609 ifname_mac=$(echo "$2:$3:$4:$5:$6:$7" | sed 'y/ABCDEF/abcdef/')
e7dc1e42 610 ;;
376ce851
TB
611 21)
612 ifname_if=$1
613 # udev requires MAC addresses to be lower case
e25c536c 614 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 615 ;;
e7dc1e42
HH
616 *)
617 die "Invalid arguments for ifname="
618 ;;
619 esac
1760dfc0
HH
620
621 case $ifname_if in
9a52c3fd 622 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
623 warn "ifname=$ifname_if uses the kernel name space for interfaces"
624 warn "This can fail for multiple network interfaces and is discouraged!"
75d758e8 625 warn 'Please use a custom name like "netboot" or "bluesocket"'
1760dfc0
HH
626 warn "or use biosdevname and no ifname= at all."
627 ;;
628 esac
629
e7dc1e42 630}
efa5eb42 631
90781679
DY
632# some network driver need long time to initialize, wait before it's ready.
633wait_for_if_link() {
634 local cnt=0
635 local li
e25c536c
HH
636 local timeout
637 timeout=$(getargs rd.net.timeout.iflink=)
2448fbf1 638 timeout=${timeout:-60}
75d758e8 639 timeout=$((timeout * 10))
2448fbf1
HH
640
641 while [ $cnt -lt $timeout ]; do
e25c536c 642 li=$(ip link show dev "$@" 2> /dev/null)
90781679
DY
643 [ -n "$li" ] && return 0
644 sleep 0.1
75d758e8 645 cnt=$((cnt + 1))
90781679
DY
646 done
647 return 1
648}
649
efa5eb42
DY
650wait_for_if_up() {
651 local cnt=0
652 local li
e25c536c
HH
653 local timeout
654 timeout=$(getargs rd.net.timeout.ifup=)
2448fbf1 655 timeout=${timeout:-20}
75d758e8 656 timeout=$((timeout * 10))
2448fbf1
HH
657
658 while [ $cnt -lt $timeout ]; do
e25c536c 659 li=$(ip link show up dev "$@")
df95b100
HH
660 if [ -n "$li" ]; then
661 case "$li" in
662 *\<UP*)
9a52c3fd
HH
663 return 0
664 ;;
df95b100 665 *\<*,UP\>*)
9a52c3fd
HH
666 return 0
667 ;;
df95b100 668 *\<*,UP,*\>*)
9a52c3fd
HH
669 return 0
670 ;;
df95b100
HH
671 esac
672 fi
673 if strstr "$li" "LOWER_UP" \
9a52c3fd
HH
674 && strstr "$li" "state UNKNOWN" \
675 && ! strstr "$li" "DORMANT"; then
df95b100 676 return 0
42b4fc90 677 fi
efa5eb42 678 sleep 0.1
75d758e8 679 cnt=$((cnt + 1))
efa5eb42
DY
680 done
681 return 1
682}
683
684wait_for_route_ok() {
685 local cnt=0
e25c536c
HH
686 local timeout
687 timeout=$(getargs rd.net.timeout.route=)
2448fbf1 688 timeout=${timeout:-20}
75d758e8 689 timeout=$((timeout * 10))
2448fbf1
HH
690
691 while [ $cnt -lt $timeout ]; do
efa5eb42 692 li=$(ip route show)
08b63a25 693 [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0
efa5eb42 694 sleep 0.1
75d758e8 695 cnt=$((cnt + 1))
efa5eb42
DY
696 done
697 return 1
698}
b455451f 699
811a070d
HH
700wait_for_ipv6_dad_link() {
701 local cnt=0
e25c536c
HH
702 local timeout
703 timeout=$(getargs rd.net.timeout.ipv6dad=)
811a070d 704 timeout=${timeout:-50}
75d758e8 705 timeout=$((timeout * 10))
811a070d
HH
706
707 while [ $cnt -lt $timeout ]; do
e25c536c
HH
708 [ -n "$(ip -6 addr show dev "$@" scope link)" ] \
709 && [ -z "$(ip -6 addr show dev "$@" scope link tentative)" ] \
811a070d 710 && return 0
e25c536c 711 [ -n "$(ip -6 addr show dev "$@" scope link dadfailed)" ] \
811a070d
HH
712 && return 1
713 sleep 0.1
75d758e8 714 cnt=$((cnt + 1))
811a070d
HH
715 done
716 return 1
717}
718
61b4afb4
HH
719wait_for_ipv6_dad() {
720 local cnt=0
e25c536c
HH
721 local timeout
722 timeout=$(getargs rd.net.timeout.ipv6dad=)
2448fbf1 723 timeout=${timeout:-50}
75d758e8 724 timeout=$((timeout * 10))
2448fbf1
HH
725
726 while [ $cnt -lt $timeout ]; do
e25c536c
HH
727 [ -n "$(ip -6 addr show dev "$@")" ] \
728 && [ -z "$(ip -6 addr show dev "$@" tentative)" ] \
811a070d 729 && return 0
e25c536c 730 [ -n "$(ip -6 addr show dev "$@" dadfailed)" ] \
811a070d 731 && return 1
61b4afb4 732 sleep 0.1
75d758e8 733 cnt=$((cnt + 1))
61b4afb4
HH
734 done
735 return 1
736}
737
f8b958dc
HH
738wait_for_ipv6_auto() {
739 local cnt=0
e25c536c
HH
740 local timeout
741 timeout=$(getargs rd.net.timeout.ipv6auto=)
2448fbf1 742 timeout=${timeout:-40}
75d758e8 743 timeout=$((timeout * 10))
2448fbf1
HH
744
745 while [ $cnt -lt $timeout ]; do
e25c536c
HH
746 [ -z "$(ip -6 addr show dev "$@" tentative)" ] \
747 && { ip -6 route list proto ra dev "$@" | grep -q ^default; } \
e8dc8c4d 748 && return 0
f8b958dc 749 sleep 0.1
75d758e8 750 cnt=$((cnt + 1))
f8b958dc
HH
751 done
752 return 1
753}
754
b455451f 755linkup() {
e25c536c 756 wait_for_if_link "$@" 2> /dev/null && ip link set "$@" up 2> /dev/null && wait_for_if_up "$@" 2> /dev/null
b455451f
DY
757}
758
9a52c3fd
HH
759type hostname > /dev/null 2>&1 \
760 || hostname() {
761 cat /proc/sys/kernel/hostname
762 }
7c8da72c 763
df95b100 764iface_has_carrier() {
07d9319d 765 local cnt=0
36af0518 766 local iface="$1" flags=""
e25c536c 767 local timeout
36af0518
HH
768 local iface_sys_path
769 [ -n "$iface" ] || return 2
770 iface_sys_path="/sys/class/net/$iface"
771 [ -d "$iface_sys_path" ] || return 2
e25c536c 772 timeout=$(getargs rd.net.timeout.carrier=)
579fbb9f 773 timeout=${timeout:-10}
75d758e8 774 timeout=$((timeout * 10))
2448fbf1 775
7c8da72c 776 linkup "$1"
df95b100 777
36af0518 778 li=$(ip link show up dev "$iface")
df95b100
HH
779 strstr "$li" "NO-CARRIER" && _no_carrier_flag=1
780
2448fbf1 781 while [ $cnt -lt $timeout ]; do
df95b100 782 if [ -n "$_no_carrier_flag" ]; then
36af0518 783 li=$(ip link show up dev "$iface")
df95b100
HH
784 # NO-CARRIER flag was cleared
785 strstr "$li" "NO-CARRIER" || return 0
36af0518 786 elif ! [ -e "$iface_sys_path/carrier" ]; then
efecf0a9
HH
787 # sysfs not available and "NO-CARRIER" not displayed
788 return 0
df95b100
HH
789 fi
790 # double check the syscfs carrier flag
36af0518 791 [ -e "$iface_sys_path/carrier" ] && [ "$(cat "$iface_sys_path"/carrier)" = 1 ] && return 0
07d9319d 792 sleep 0.1
75d758e8 793 cnt=$((cnt + 1))
07d9319d
HH
794 done
795 return 1
7c8da72c
HH
796}
797
df95b100
HH
798iface_has_link() {
799 iface_has_carrier "$@"
800}
801
f6e3b59e
HH
802iface_is_enslaved() {
803 local _li
e25c536c 804 _li=$(ip link show dev "$@")
8084f3f6 805 strstr "$_li" " master " || return 1
f6e3b59e
HH
806 return 0
807}
808
7c8da72c
HH
809find_iface_with_link() {
810 local iface_path="" iface=""
811 for iface_path in /sys/class/net/*; do
812 iface=${iface_path##*/}
813 str_starts "$iface" "lo" && continue
e25c536c 814 if iface_has_link "$iface"; then
7c8da72c
HH
815 echo "$iface"
816 return 0
817 fi
818 done
819 return 1
820}
fb0e5184
HH
821
822is_persistent_ethernet_name() {
3947f07d
HH
823 local _netif="$1"
824 local _name_assign_type="0"
825
826 [ -f "/sys/class/net/$_netif/name_assign_type" ] \
28f37724 827 && read -r _name_assign_type < "/sys/class/net/$_netif/name_assign_type" 2> /dev/null
3947f07d
HH
828
829 # NET_NAME_ENUM 1
830 [ "$_name_assign_type" = "1" ] && return 1
831
832 # NET_NAME_PREDICTABLE 2
833 [ "$_name_assign_type" = "2" ] && return 0
834
835 case "$_netif" in
fb0e5184 836 # udev persistent interface names
9a52c3fd
HH
837 eno[0-9] | eno[0-9][0-9] | eno[0-9][0-9][0-9]*) ;;
838
839 ens[0-9] | ens[0-9][0-9] | ens[0-9][0-9][0-9]*) ;;
840
841 enp[0-9]s[0-9]* | enp[0-9][0-9]s[0-9]* | enp[0-9][0-9][0-9]*s[0-9]*) ;;
842
843 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]*) ;;
844
845 # biosdevname
846 em[0-9] | em[0-9][0-9] | em[0-9][0-9][0-9]*) ;;
847
848 p[0-9]p[0-9]* | p[0-9][0-9]p[0-9]* | p[0-9][0-9][0-9]*p[0-9]*) ;;
849
fb0e5184
HH
850 *)
851 return 1
9a52c3fd 852 ;;
fb0e5184
HH
853 esac
854 return 0
855}
3947f07d
HH
856
857is_kernel_ethernet_name() {
858 local _netif="$1"
859 local _name_assign_type="1"
860
861 if [ -e "/sys/class/net/$_netif/name_assign_type" ]; then
28f37724 862 read -r _name_assign_type < "/sys/class/net/$_netif/name_assign_type"
3947f07d
HH
863
864 case "$_name_assign_type" in
9a52c3fd 865 2 | 3 | 4)
3947f07d
HH
866 # NET_NAME_PREDICTABLE 2
867 # NET_NAME_USER 3
868 # NET_NAME_RENAMED 4
869 return 1
870 ;;
9a52c3fd 871 1 | *)
3947f07d
HH
872 # NET_NAME_ENUM 1
873 return 0
874 ;;
875 esac
876 fi
877
878 # fallback to error prone manual name check
879 case "$_netif" in
9a52c3fd 880 eth[0-9] | eth[0-9][0-9] | eth[0-9][0-9][0-9]*)
3947f07d
HH
881 return 0
882 ;;
883 *)
884 return 1
9a52c3fd 885 ;;
3947f07d
HH
886 esac
887
888}
041e49ee
HH
889
890iface_get_subchannels() {
891 local _netif
892 local _subchannels
893
894 _netif="$1"
895
896 _subchannels=$({
e25c536c
HH
897 for i in /sys/class/net/"$_netif"/device/cdev[0-9]*; do
898 [ -e "$i" ] || continue
899 channel=$(readlink -f "$i")
9a52c3fd
HH
900 printf -- "%s" "${channel##*/},"
901 done
902 })
041e49ee
HH
903 [ -n "$_subchannels" ] || return 1
904
e25c536c 905 printf -- "%s" "${_subchannels%,}"
041e49ee 906}