#!/bin/sh # shellcheck disable=SC2034 IFNETFILE="/tmp/bootnetif" is_ip() { echo "$1" | { IFS=. read -r a b c d test "$a" -ge 0 -a "$a" -le 255 \ -a "$b" -ge 0 -a "$b" -le 255 \ -a "$c" -ge 0 -a "$c" -le 255 \ -a "$d" -ge 0 -a "$d" -le 255 \ 2> /dev/null } && return 0 return 1 } get_ip() { local iface="$1" ip="" ip=$(ip -f inet addr show "$iface") ip=${ip%%/*} ip=${ip##* } echo "$ip" } iface_for_remote_addr() { # shellcheck disable=SC2046 set -- $(ip route get to "$@" | sed 's/.*\bdev\b//p;q') echo "$1" } iface_for_ip() { # shellcheck disable=SC2046 set -- $(ip addr show to "$@") echo "${2%:}" } iface_for_mac() { local interface="" local mac mac="$(echo "$@" | sed 'y/ABCDEF/abcdef/')" for interface in /sys/class/net/*; do if [ "$(cat "$interface"/address)" = "$mac" ]; then echo "${interface##*/}" fi done } # get the iface name for the given identifier - either a MAC, IP, or iface name iface_name() { case "$1" in ??:??:??:??:??:?? | ??-??-??-??-??-??) iface_for_mac "$1" ;; *:*:* | *.*.*.*) iface_for_ip "$1" ;; *) echo "$1" ;; esac } # list the configured interfaces configured_ifaces() { local IFACES="" iface_id="" rv=1 [ -e "/tmp/net.ifaces" ] && read -r IFACES < /tmp/net.ifaces if { pidof udevd || pidof systemd-udevd; } > /dev/null; then for iface_id in $IFACES; do printf "%s\n" "$(iface_name "$iface_id")" rv=0 done else warn "configured_ifaces called before udev is running" echo "$IFACES" [ -n "$IFACES" ] && rv=0 fi return $rv } all_ifaces_up() { local iface="" IFACES="" [ -e "/tmp/net.ifaces" ] && read -r IFACES < /tmp/net.ifaces for iface in $IFACES; do [ -e /tmp/net."$iface".up ] || return 1 done } all_ifaces_setup() { local iface="" IFACES="" [ -e "/tmp/net.ifaces" ] && read -r IFACES < /tmp/net.ifaces for iface in $IFACES; do [ -e /tmp/net."$iface".did-setup ] || return 1 done } get_netroot_ip() { local prefix="" server="" rest="" splitsep ":" "$1" prefix server rest case $server in [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*) echo "$server" return 0 ;; esac return 1 } ip_is_local() { li=$(ip route get "$@" 2> /dev/null) if [ -n "$li" ]; then strstr "$li" " via " || return 0 fi return 1 } ifdown() { local netif="$1" # ip down/flush ensures that routing info goes away as well ip link set "$netif" down ip addr flush dev "$netif" echo "#empty" > /etc/resolv.conf rm -f -- /tmp/net."$netif".did-setup [ -z "$DO_VLAN" ] \ && [ -e /sys/class/net/"$netif"/address ] \ && rm -f -- "/tmp/net.$(cat /sys/class/net/"$netif"/address).did-setup" # TODO: send "offline" uevent? } setup_net() { local netif="$1" f="" gw_ip="" netroot_ip="" iface="" IFACES="" local _p [ -e /tmp/net."$netif".did-setup ] && return [ -z "$DO_VLAN" ] \ && [ -e /sys/class/net/"$netif"/address ] \ && [ -e "/tmp/net.$(cat /sys/class/net/"$netif"/address).did-setup" ] && return [ -e "/tmp/net.ifaces" ] && read -r IFACES < /tmp/net.ifaces [ -z "$IFACES" ] && IFACES="$netif" # run the scripts written by ifup # shellcheck disable=SC1090 [ -e /tmp/net."$netif".hostname ] && . /tmp/net."$netif".hostname # shellcheck disable=SC1090 [ -e /tmp/net."$netif".override ] && . /tmp/net."$netif".override # shellcheck disable=SC1090 [ -e /tmp/dhclient."$netif".dhcpopts ] && . /tmp/dhclient."$netif".dhcpopts # set up resolv.conf [ -e /tmp/net."$netif".resolv.conf ] \ && awk '!array[$0]++' /tmp/net."$netif".resolv.conf > /etc/resolv.conf # shellcheck disable=SC1090 [ -e /tmp/net."$netif".gw ] && . /tmp/net."$netif".gw # add static route for _p in $(getargs rd.route); do route_to_var "$_p" || continue [ -n "$route_dev" ] && [ "$route_dev" != "$netif" ] && continue ip route add "$route_mask" ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev} if strstr "$route_mask" ":"; then printf -- "%s\n" "$route_mask ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev}" \ > /tmp/net.route6."$netif" else printf -- "%s\n" "$route_mask ${route_gw:+via $route_gw} ${route_dev:+dev $route_dev}" \ > /tmp/net.route."$netif" fi done # If a static route was necessary to reach the gateway, the # first gateway setup call will have failed with # RTNETLINK answers: Network is unreachable # Replace the default route again after static routes to cover # this scenario. # shellcheck disable=SC1090 [ -e /tmp/net."$netif".gw ] && . /tmp/net."$netif".gw # Handle STP Timeout: arping the default gateway. # (or the root server, if a) it's local or b) there's no gateway.) # Note: This assumes that if no router is present the # root server is on the same subnet. # Get DHCP-provided router IP, or the cmdline-provided "gw=" argument [ -n "$new_routers" ] && gw_ip=${new_routers%%,*} [ -n "$gw" ] && gw_ip=$gw # Get the "netroot" IP (if there's an IP address in there) netroot_ip=$(get_netroot_ip "$netroot") # try netroot if it's local (or there's no gateway) if ip_is_local "$netroot_ip" || [ -z "$gw_ip" ]; then dest="$netroot_ip" else dest="$gw_ip" fi unset layer2 if [ -f /sys/class/net/"$netif"/device/layer2 ]; then read -r layer2 < /sys/class/net/"$netif"/device/layer2 fi if [ "$layer2" != "0" ] && [ -n "$dest" ] && ! strstr "$dest" ":"; then if command -v arping2 > /dev/null; then arping2 -q -C 1 -c 60 -I "$netif" "$dest" || info "Resolving $dest via ARP on $netif failed" else arping -q -f -w 60 -I "$netif" "$dest" || info "Resolving $dest via ARP on $netif failed" fi fi unset layer2 : > /tmp/net."$netif".did-setup [ -z "$DO_VLAN" ] \ && [ -e /sys/class/net/"$netif"/address ] \ && : > "/tmp/net.$(cat /sys/class/net/"$netif"/address).did-setup" } save_netinfo() { local netif="$1" IFACES="" f="" i="" [ -e /tmp/net.ifaces ] && read -r IFACES < /tmp/net.ifaces # Add $netif to the front of IFACES (if it's not there already). set -- "$netif" for i in $IFACES; do [ "$i" != "$netif" ] && set -- "$@" "$i"; done IFACES="$*" for i in $IFACES; do for f in "/tmp/dhclient.$i."*; do [ -f "$f" ] && cp -f "$f" /tmp/net."${f#/tmp/dhclient.}" done done echo "$IFACES" > /tmp/.net.ifaces.new mv /tmp/.net.ifaces.new /tmp/net.ifaces } set_ifname() { local name="$1" mac="$2" num=-1 n="" # if it's already set, return the existing name for n in $(getargs ifname=); do strstr "$n" "$mac" && echo "${n%%:*}" && return done [ ! -f "/tmp/set_ifname_$name" ] || read -r num < "/tmp/set_ifname_$name" # otherwise, pick a new name and use that while :; do num=$((num + 1)) [ -e /sys/class/net/"$name"$num ] && continue for n in $(getargs ifname=); do [ "$name$num" = "${n%%:*}" ] && continue 2 done break done echo "ifname=$name$num:$mac" >> /etc/cmdline.d/45-ifname.conf echo "$num" > "/tmp/set_ifname_$name" echo "$name$num" } # pxelinux provides macaddr '-' separated, but we need ':' fix_bootif() { local macaddr="${1}" local IFS='-' # shellcheck disable=SC2086 macaddr=$(printf '%s:' ${macaddr}) macaddr=${macaddr%:} # strip hardware type field from pxelinux [ -n "${macaddr%??:??:??:??:??:??}" ] && macaddr=${macaddr#??:} # return macaddr with lowercase alpha characters expected by udev echo "$macaddr" | sed 'y/ABCDEF/abcdef/' } ibft_to_cmdline() { local iface="" modprobe -q iscsi_ibft ( for iface in /sys/firmware/ibft/ethernet*; do local mac="" dev="" local dhcp="" ip="" gw="" mask="" hostname="" local dns1 dns2 [ -e "${iface}"/mac ] || continue read -r mac < "${iface}"/mac [ -z "$mac" ] && continue dev=$(set_ifname ibft "$mac") [ -e /tmp/net."${dev}".has_ibft_config ] && continue [ -e "${iface}"/flags ] && read -r flags < "${iface}"/flags # Skip invalid interfaces awk -- 'BEGIN { exit (!and('"$flags"',1)) }' || continue # Skip interfaces not used for booting unless using multipath if ! getargbool 0 rd.iscsi.mp; then awk -- 'BEGIN { exit (!and('"$flags"',2)) }' || continue fi [ -e "${iface}"/dhcp ] && read -r dhcp < "${iface}"/dhcp [ -e "${iface}"/origin ] && read -r origin < "${iface}"/origin [ -e "${iface}"/ip-addr ] && read -r ip < "${iface}"/ip-addr if [ -n "$ip" ]; then case "$ip" in *.*.*.*) family=ipv4 ;; *:*) family=ipv6 ;; esac fi if [ -n "$dhcp" ] || [ "$origin" -eq 3 ]; then if [ "$family" = "ipv6" ]; then echo "ip=$dev:dhcp6" else echo "ip=$dev:dhcp" fi elif [ -e "${iface}"/ip-addr ]; then # skip not assigned ip addresses [ "$ip" = "0.0.0.0" ] && continue [ -e "${iface}"/gateway ] && read -r gw < "${iface}"/gateway [ "$gw" = "0.0.0.0" ] && unset gw [ -e "${iface}"/subnet-mask ] && read -r mask < "${iface}"/subnet-mask [ -e "${iface}"/prefix-len ] && read -r prefix < "${iface}"/prefix-len [ -e "${iface}"/primary-dns ] && read -r dns1 < "${iface}"/primary-dns [ "$dns1" = "0.0.0.0" ] && unset dns1 [ -e "${iface}"/secondary-dns ] && read -r dns2 < "${iface}"/secondary-dns [ "$dns2" = "0.0.0.0" ] && unset dns [ -e "${iface}"/hostname ] && read -r hostname < "${iface}"/hostname if [ "$family" = "ipv6" ]; then if [ -n "$ip" ]; then [ -n "$prefix" ] || prefix=128 ip="[${ip}]" mask=$prefix fi if [ -n "$gw" ]; then gw="[${gw}]" fi fi if [ -n "$ip" ] && [ -n "$mask" -o -n "$prefix" ]; then echo "ip=$ip::$gw:$mask:$hostname:$dev:none${dns1:+:$dns1}${dns2:+:$dns2}" else warn "${iface} does not contain a valid iBFT configuration" warn "ip-addr=$ip" warn "gateway=$gw" warn "subnet-mask=$mask" warn "hostname=$hostname" fi else info "${iface} does not contain a valid iBFT configuration" # shellcheck disable=SC2012 ls -l "${iface}" | vinfo fi if [ -e "${iface}"/vlan ]; then read -r vlan < "${iface}"/vlan if [ "$vlan" -ne "0" ]; then case "$vlan" in [0-9]*) echo "vlan=$dev.$vlan:$dev" echo "$mac" > /tmp/net."${dev}"."${vlan}".has_ibft_config ;; *) echo "vlan=$vlan:$dev" echo "$mac" > /tmp/net."${vlan}".has_ibft_config ;; esac else echo "$mac" > /tmp/net."${dev}".has_ibft_config fi else echo "$mac" > /tmp/net."${dev}".has_ibft_config fi done ) >> /etc/cmdline.d/40-ibft.conf } parse_iscsi_root() { local v v=${1#iscsi:} # extract authentication info case "$v" in *@*:*:*:*:*) authinfo=${v%%@*} v=${v#*@} # allow empty authinfo to allow having an @ in iscsi_target_name like this: # netroot=iscsi:@192.168.1.100::3260::iqn.2009-01.com.example:testdi@sk if [ -n "$authinfo" ]; then OLDIFS="$IFS" IFS=: # shellcheck disable=SC2086 set $authinfo IFS="$OLDIFS" if [ $# -gt 4 ]; then warn "Wrong authentication info in iscsi: parameter!" return 1 fi iscsi_username=$1 iscsi_password=$2 if [ $# -gt 2 ]; then iscsi_in_username=$3 iscsi_in_password=$4 fi fi ;; esac # extract target ip case "$v" in [[]*[]]:*) iscsi_target_ip=${v#[[]} iscsi_target_ip=${iscsi_target_ip%%[]]*} v=${v#[[]"$iscsi_target_ip"[]]:} ;; *) iscsi_target_ip=${v%%[:]*} v=${v#"$iscsi_target_ip":} ;; esac unset iscsi_target_name # extract target name case "$v" in *:iqn.*) iscsi_target_name=iqn.${v##*:iqn.} v=${v%:iqn.*}: ;; *:eui.*) iscsi_target_name=eui.${v##*:eui.} v=${v%:eui.*}: ;; *:naa.*) iscsi_target_name=naa.${v##*:naa.} v=${v%:naa.*}: ;; esac # parse the rest OLDIFS="$IFS" IFS=: # shellcheck disable=SC2086 set $v IFS="$OLDIFS" iscsi_protocol=$1 shift # ignored iscsi_target_port=$1 shift if [ -n "$iscsi_target_name" ]; then if [ $# -eq 3 ]; then iscsi_iface_name=$1 shift fi if [ $# -eq 2 ]; then iscsi_netdev_name=$1 shift fi iscsi_lun=$1 shift if [ $# -ne 0 ]; then warn "Invalid parameter in iscsi: parameter!" return 1 fi return 0 fi if [ $# -gt 3 ] && [ -n "$1$2" ]; then if [ -z "$3" ] || [ "$3" -ge 0 ] 2> /dev/null; then iscsi_iface_name=$1 shift iscsi_netdev_name=$1 shift fi fi iscsi_lun=$1 shift iscsi_target_name=$(printf "%s:" "$@") iscsi_target_name=${iscsi_target_name%:} } ip_to_var() { local v="${1}": local i set -- while [ -n "$v" ]; do if [ "${v#\[*:*:*\]:}" != "$v" ]; then # handle IPv6 address i="${v%%\]:*}" i="${i##\[}" set -- "$@" "$i" v=${v#\["$i"\]:} else set -- "$@" "${v%%:*}" v=${v#*:} fi done unset ip srv gw mask hostname dev autoconf macaddr mtu dns1 dns2 if [ $# -eq 0 ]; then autoconf="error" return 0 fi if [ $# -eq 1 ]; then # format: ip={dhcp|on|any|dhcp6|auto6|either6|single-dhcp} # or # ip= means anaconda-style static config argument cluster autoconf="$1" if strglob "$autoconf" "*.*.*.*"; then # ip= means anaconda-style static config argument cluster: # ip= gateway= netmask= hostname= mtu= # ksdevice={link|bootif|ibft||} ip="$autoconf" gw=$(getarg gateway=) mask=$(getarg netmask=) hostname=$(getarg hostname=) dev=$(getarg ksdevice=) autoconf="none" mtu=$(getarg mtu=) # handle special values for ksdevice case "$dev" in bootif | BOOTIF) dev=$(fix_bootif "$(getarg BOOTIF=)") ;; link) dev="" ;; # FIXME: do something useful with this ibft) dev="" ;; # ignore - ibft is handled elsewhere esac fi return 0 fi if [ "$2" = "dhcp" -o "$2" = "on" -o "$2" = "any" -o "$2" = "dhcp6" -o "$2" = "auto6" -o "$2" = "either6" ]; then # format: ip=:{dhcp|on|any|dhcp6|auto6}[:[][:]] [ -n "$1" ] && dev="$1" [ -n "$2" ] && autoconf="$2" [ -n "$3" ] && mtu=$3 if [ -z "$5" ]; then macaddr="$4" else macaddr="${4}:${5}:${6}:${7}:${8}:${9}" fi return 0 fi # format: ip=:[]:::::{none|off|dhcp|on|any|dhcp6|auto6|ibft}:[:[][:]] [ -n "$1" ] && ip=$1 [ -n "$2" ] && srv=$2 [ -n "$3" ] && gw=$3 [ -n "$4" ] && mask=$4 [ -n "$5" ] && hostname=$5 [ -n "$6" ] && dev=$6 [ -n "$7" ] && autoconf=$7 case "$8" in [0-9a-fA-F]*:* | [0-9]*.[0-9]*.[0-9]*.[0-9]*) dns1="$8" [ -n "$9" ] && dns2="$9" ;; [0-9]*) mtu="$8" if [ -n "${9}" -a -z "${10}" ]; then macaddr="${9}" elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then macaddr="${9}:${10}:${11}:${12}:${13}:${14}" fi ;; *) if [ -n "${9}" -a -z "${10}" ]; then macaddr="${9}" elif [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then macaddr="${9}:${10}:${11}:${12}:${13}:${14}" fi ;; esac return 0 } route_to_var() { local v="${1}": local i set -- while [ -n "$v" ]; do if [ "${v#\[*:*:*\]:}" != "$v" ]; then # handle IPv6 address i="${v%%\]:*}" i="${i##\[}" set -- "$@" "$i" v=${v#\["$i"\]:} else set -- "$@" "${v%%:*}" v=${v#*:} fi done unset route_mask route_gw route_dev case $# in 2) [ -n "$1" ] && route_mask="$1" [ -n "$2" ] && route_gw="$2" return 0 ;; 3) [ -n "$1" ] && route_mask="$1" [ -n "$2" ] && route_gw="$2" [ -n "$3" ] && route_dev="$3" return 0 ;; *) return 1 ;; esac } parse_ifname_opts() { local IFS=: # shellcheck disable=SC2086 set -- $1 case $# in 7) ifname_if=$1 # udev requires MAC addresses to be lower case ifname_mac=$(echo "$2:$3:$4:$5:$6:$7" | sed 'y/ABCDEF/abcdef/') ;; 21) ifname_if=$1 # udev requires MAC addresses to be lower case 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/') ;; *) die "Invalid arguments for ifname=" ;; esac case $ifname_if in eth[0-9] | eth[0-9][0-9] | eth[0-9][0-9][0-9] | eth[0-9][0-9][0-9][0-9]) warn "ifname=$ifname_if uses the kernel name space for interfaces" warn "This can fail for multiple network interfaces and is discouraged!" warn 'Please use a custom name like "netboot" or "bluesocket"' warn "or use biosdevname and no ifname= at all." ;; esac } # some network driver need long time to initialize, wait before it's ready. wait_for_if_link() { local cnt=0 local li local timeout timeout=$(getargs rd.net.timeout.iflink=) timeout=${timeout:-60} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do li=$(ip link show dev "$@" 2> /dev/null) [ -n "$li" ] && return 0 sleep 0.1 cnt=$((cnt + 1)) done return 1 } wait_for_if_up() { local cnt=0 local li local timeout timeout=$(getargs rd.net.timeout.ifup=) timeout=${timeout:-20} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do li=$(ip link show up dev "$@") if [ -n "$li" ]; then case "$li" in *\*) return 0 ;; *\<*,UP,*\>*) return 0 ;; esac fi if strstr "$li" "LOWER_UP" \ && strstr "$li" "state UNKNOWN" \ && ! strstr "$li" "DORMANT"; then return 0 fi sleep 0.1 cnt=$((cnt + 1)) done return 1 } wait_for_route_ok() { local cnt=0 local timeout timeout=$(getargs rd.net.timeout.route=) timeout=${timeout:-20} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do li=$(ip route show) [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 sleep 0.1 cnt=$((cnt + 1)) done return 1 } wait_for_ipv6_dad_link() { local cnt=0 local timeout timeout=$(getargs rd.net.timeout.ipv6dad=) timeout=${timeout:-50} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do [ -n "$(ip -6 addr show dev "$@" scope link)" ] \ && [ -z "$(ip -6 addr show dev "$@" scope link tentative)" ] \ && return 0 [ -n "$(ip -6 addr show dev "$@" scope link dadfailed)" ] \ && return 1 sleep 0.1 cnt=$((cnt + 1)) done return 1 } wait_for_ipv6_dad() { local cnt=0 local timeout timeout=$(getargs rd.net.timeout.ipv6dad=) timeout=${timeout:-50} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do [ -n "$(ip -6 addr show dev "$@")" ] \ && [ -z "$(ip -6 addr show dev "$@" tentative)" ] \ && return 0 [ -n "$(ip -6 addr show dev "$@" dadfailed)" ] \ && return 1 sleep 0.1 cnt=$((cnt + 1)) done return 1 } wait_for_ipv6_auto() { local cnt=0 local timeout timeout=$(getargs rd.net.timeout.ipv6auto=) timeout=${timeout:-40} timeout=$((timeout * 10)) while [ $cnt -lt $timeout ]; do [ -z "$(ip -6 addr show dev "$@" tentative)" ] \ && { ip -6 route list proto ra dev "$@" | grep -q ^default; } \ && return 0 sleep 0.1 cnt=$((cnt + 1)) done return 1 } linkup() { wait_for_if_link "$@" 2> /dev/null && ip link set "$@" up 2> /dev/null && wait_for_if_up "$@" 2> /dev/null } type hostname > /dev/null 2>&1 \ || hostname() { cat /proc/sys/kernel/hostname } iface_has_carrier() { local cnt=0 local iface="$1" flags="" local timeout local iface_sys_path [ -n "$iface" ] || return 2 iface_sys_path="/sys/class/net/$iface" [ -d "$iface_sys_path" ] || return 2 timeout=$(getargs rd.net.timeout.carrier=) timeout=${timeout:-10} timeout=$((timeout * 10)) linkup "$1" li=$(ip link show up dev "$iface") strstr "$li" "NO-CARRIER" && _no_carrier_flag=1 while [ $cnt -lt $timeout ]; do if [ -n "$_no_carrier_flag" ]; then li=$(ip link show up dev "$iface") # NO-CARRIER flag was cleared strstr "$li" "NO-CARRIER" || return 0 elif ! [ -e "$iface_sys_path/carrier" ]; then # sysfs not available and "NO-CARRIER" not displayed return 0 fi # double check the syscfs carrier flag [ -e "$iface_sys_path/carrier" ] && [ "$(cat "$iface_sys_path"/carrier)" = 1 ] && return 0 sleep 0.1 cnt=$((cnt + 1)) done return 1 } iface_has_link() { iface_has_carrier "$@" } iface_is_enslaved() { local _li _li=$(ip link show dev "$@") strstr "$_li" " master " || return 1 return 0 } find_iface_with_link() { local iface_path="" iface="" for iface_path in /sys/class/net/*; do iface=${iface_path##*/} str_starts "$iface" "lo" && continue if iface_has_link "$iface"; then echo "$iface" return 0 fi done return 1 } is_persistent_ethernet_name() { local _netif="$1" local _name_assign_type="0" [ -f "/sys/class/net/$_netif/name_assign_type" ] \ && read -r _name_assign_type < "/sys/class/net/$_netif/name_assign_type" 2> /dev/null # NET_NAME_ENUM 1 [ "$_name_assign_type" = "1" ] && return 1 # NET_NAME_PREDICTABLE 2 [ "$_name_assign_type" = "2" ] && return 0 case "$_netif" in # udev persistent interface names eno[0-9] | eno[0-9][0-9] | eno[0-9][0-9][0-9]*) ;; ens[0-9] | ens[0-9][0-9] | ens[0-9][0-9][0-9]*) ;; enp[0-9]s[0-9]* | enp[0-9][0-9]s[0-9]* | enp[0-9][0-9][0-9]*s[0-9]*) ;; 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]*) ;; # biosdevname em[0-9] | em[0-9][0-9] | em[0-9][0-9][0-9]*) ;; p[0-9]p[0-9]* | p[0-9][0-9]p[0-9]* | p[0-9][0-9][0-9]*p[0-9]*) ;; *) return 1 ;; esac return 0 } is_kernel_ethernet_name() { local _netif="$1" local _name_assign_type="1" if [ -e "/sys/class/net/$_netif/name_assign_type" ]; then read -r _name_assign_type < "/sys/class/net/$_netif/name_assign_type" case "$_name_assign_type" in 2 | 3 | 4) # NET_NAME_PREDICTABLE 2 # NET_NAME_USER 3 # NET_NAME_RENAMED 4 return 1 ;; 1 | *) # NET_NAME_ENUM 1 return 0 ;; esac fi # fallback to error prone manual name check case "$_netif" in eth[0-9] | eth[0-9][0-9] | eth[0-9][0-9][0-9]*) return 0 ;; *) return 1 ;; esac } iface_get_subchannels() { local _netif local _subchannels _netif="$1" _subchannels=$({ for i in /sys/class/net/"$_netif"/device/cdev[0-9]*; do [ -e "$i" ] || continue channel=$(readlink -f "$i") printf -- "%s" "${channel##*/}," done }) [ -n "$_subchannels" ] || return 1 printf -- "%s" "${_subchannels%,}" }