From ceca74ccc397795db68ca6ffbe49d65af2178a50 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Sat, 11 Jul 2020 00:15:34 +0200 Subject: [PATCH] dracut-functions: add ip_params_for_remote_addr() helper This helper function takes a remote IP address, and tries to determine the dracut command line arguments ip= and ifname= that will make this remote address reachable during boot. Functionality was taken from the module-setup.sh scripts of 95iscsi and 95nfs, cleaned up and fixed some issues in particular with statically configured networks, where the old code would print the unsupported string "$ifname:static". --- dracut-functions.sh | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/dracut-functions.sh b/dracut-functions.sh index b5c28248..07ae88c0 100755 --- a/dracut-functions.sh +++ b/dracut-functions.sh @@ -728,3 +728,117 @@ btrfs_devs() { printf -- "%s\n" "$_dev" done } + +iface_for_remote_addr() { + set -- $(ip -o route get to "$1") + echo $3 +} + +local_addr_for_remote_addr() { + set -- $(ip -o route get to "$1") + echo $5 +} + +peer_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show | \ + sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' +} + +netmask_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' +} + +gateway_for_iface() { + local ifname=$1 addr=$2 + + case $addr in + *.*) proto=4;; + *:*) proto=6;; + *) return;; + esac + ip -o -$proto route show | \ + sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" +} + +# This works only for ifcfg-style network configuration! +bootproto_for_iface() { + local ifname=$1 + local dir + + # follow ifcfg settings for boot protocol + for dir in network-scripts network; do + [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { + sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ + "/etc/sysconfig/$dir/ifcfg-$ifname" + return + } + done +} + +is_unbracketed_ipv6_address() { + strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' +} + +# Create an ip= string to set up networking such that the given +# remote address can be reached +ip_params_for_remote_addr() { + local remote_addr=$1 + local ifname local_addr peer netmask= gateway ifmac + + [[ $remote_addr ]] || return 1 + ifname=$(iface_for_remote_addr "$remote_addr") + [[ $ifname ]] || { + berror "failed to determine interface to connect to $remote_addr" + return 1 + } + + # ifname clause to bind the interface name to a MAC address + if [ -d "/sys/class/net/$ifname/bonding" ]; then + dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." + elif [ -e "/sys/class/net/$ifname/address" ] ; then + ifmac=$(cat "/sys/class/net/$ifname/address") + [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" + fi + + bootproto=$(bootproto_for_iface "$ifname") + case $bootproto in + dhcp|dhcp6|auto6) ;; + dhcp4) + bootproto=dhcp;; + static*|"") + bootproto=;; + *) + derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" + bootproto=;; + esac + if [[ $bootproto ]]; then + printf 'ip=%s:%s ' "${ifname}" "${bootproto}" + else + local_addr=$(local_addr_for_remote_addr "$remote_addr") + [[ $local_addr ]] || { + berror "failed to determine local address to connect to $remote_addr" + return 1 + } + peer=$(peer_for_addr "$local_addr") + # Set peer or netmask, but not both + [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") + gateway=$(gateway_for_iface "$ifname" "$local_addr") + # Quote IPv6 addresses with brackets + is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" + is_unbracketed_ipv6_address "$peer" && peer="[$peer]" + is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" + printf 'ip=%s:%s:%s:%s::%s:none ' \ + "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" + fi + +}