summaryrefslogtreecommitdiffstats
path: root/modules.d/35network-legacy/dhcp-multi.sh
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:54:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:54:25 +0000
commit9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a (patch)
tree2efb72864cc69e174c9c5ee33efb88a5f1553b48 /modules.d/35network-legacy/dhcp-multi.sh
parentInitial commit. (diff)
downloaddracut-9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a.tar.xz
dracut-9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a.zip
Adding upstream version 060+5.upstream/060+5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules.d/35network-legacy/dhcp-multi.sh')
-rwxr-xr-xmodules.d/35network-legacy/dhcp-multi.sh133
1 files changed, 133 insertions, 0 deletions
diff --git a/modules.d/35network-legacy/dhcp-multi.sh b/modules.d/35network-legacy/dhcp-multi.sh
new file mode 100755
index 0000000..60e0374
--- /dev/null
+++ b/modules.d/35network-legacy/dhcp-multi.sh
@@ -0,0 +1,133 @@
+#!/bin/sh
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+#
+PATH=/usr/sbin:/usr/bin:/sbin:/bin
+
+# File to start dhclient requests on different interfaces in parallel
+
+. /lib/dracut-lib.sh
+. /lib/net-lib.sh
+
+netif=$1
+do_vlan=$2
+arg=$3
+
+# Run dhclient in parallel
+do_dhclient() {
+ local _COUNT=0
+ local _timeout
+ local _DHCPRETRY
+ _timeout=$(getarg rd.net.timeout.dhcp=)
+ _DHCPRETRY=$(getargnum 1 1 1000000000 rd.net.dhcp.retry=)
+
+ if [ -n "$_timeout" ]; then
+ if ! (dhclient --help 2>&1 | grep -q -F -- '--timeout' 2> /dev/null); then
+ warn "rd.net.timeout.dhcp has no effect because dhclient does not implement the --timeout option"
+ unset _timeout
+ fi
+ fi
+
+ while [ $_COUNT -lt "$_DHCPRETRY" ]; do
+ info "Starting dhcp for interface $netif"
+ dhclient "$arg" \
+ ${_timeout:+--timeout "$_timeout"} \
+ -q \
+ -1 \
+ -cf /etc/dhclient.conf \
+ -pf /tmp/dhclient."$netif".pid \
+ -lf /tmp/dhclient."$netif".lease \
+ "$netif" &
+ wait $! 2> /dev/null
+
+ # wait will return the return value of dhclient
+ retv=$?
+
+ # dhclient and hence wait returned success, 0.
+ if [ $retv -eq 0 ]; then
+ return 0
+ fi
+
+ # If dhclient exited before wait was called, or it was killed by
+ # another thread for interface whose DHCP succeeded, then it will not
+ # find the process with that pid and return error code 127. In that
+ # case we need to check if /tmp/dhclient.$netif.lease exists. If it
+ # does, it means dhclient finished executing before wait was called,
+ # and it was successful (return 0). If /tmp/dhclient.$netif.lease
+ # does not exist, then it means dhclient was killed by another thread
+ # or it finished execution but failed dhcp on that interface.
+
+ if [ $retv -eq 127 ]; then
+ read -r pid < /tmp/dhclient."$netif".pid
+ info "PID $pid was not found by wait for $netif"
+ if [ -e /tmp/dhclient."$netif".lease ]; then
+ info "PID $pid not found but DHCP successful on $netif"
+ return 0
+ fi
+ fi
+
+ _COUNT=$((_COUNT + 1))
+ [ $_COUNT -lt "$_DHCPRETRY" ] && sleep 1
+ done
+ warn "dhcp for interface $netif failed"
+ # nuke those files since we failed; we might retry dhcp again if it's e.g.
+ # `ip=dhcp,dhcp6` and we check for the PID file earlier
+ rm -f /tmp/dhclient."$netif".pid /tmp/dhclient."$netif".lease
+ return 1
+}
+
+do_dhclient
+ret=$?
+
+# setup nameserver
+for s in "$dns1" "$dns2" $(getargs nameserver); do
+ [ -n "$s" ] || continue
+ echo nameserver "$s" >> /tmp/net."$netif".resolv.conf
+done
+
+if [ $ret -eq 0 ]; then
+ : > /tmp/net."${netif}".up
+
+ if [ -z "$do_vlan" ] && [ -e /sys/class/net/"${netif}"/address ]; then
+ : > "/tmp/net.$(cat /sys/class/net/"${netif}"/address).up"
+ fi
+
+ # Check if DHCP also succeeded on another interface before this one.
+ # We will always use the first one on which DHCP succeeded, by using
+ # a common file $IFNETFILE, to synchronize between threads.
+ # Consider the race condition in which multiple threads
+ # corresponding to different interfaces may try to read $IFNETFILE
+ # and find it does not exist; they may all end up thinking they are the
+ # first to succeed (hence more than one thread may end up writing to
+ # $IFNETFILE). To take care of this, instead of checking if $IFNETFILE
+ # exists to determine if we are the first, we create a symbolic link
+ # in $IFNETFILE, pointing to the interface name ($netif), thus storing
+ # the interface name in the link pointer.
+ # Creating a link will fail, if the link already exists, hence kernel
+ # will take care of allowing only first thread to create link, which
+ # takes care of the race condition for us. Subsequent threads will fail.
+ # Also, the link points to the interface name, which will tell us which
+ # interface succeeded.
+
+ if ln -s "$netif" "$IFNETFILE" 2> /dev/null; then
+ intf=$(readlink "$IFNETFILE")
+ if [ -e /tmp/dhclient."$intf".lease ]; then
+ info "DHCP successful on interface $intf"
+ # Kill all existing dhclient calls for other interfaces, since we
+ # already got one successful interface
+
+ read -r npid < /tmp/dhclient."$netif".pid
+ pidlist=$(pgrep dhclient)
+ for pid in $pidlist; do
+ [ "$pid" -eq "$npid" ] && continue
+ kill -9 "$pid" > /dev/null 2>&1
+ done
+ else
+ echo "ERROR! $IFNETFILE exists but /tmp/dhclient.$intf.lease does not exist!!!"
+ fi
+ else
+ info "DHCP success on $netif, and also on $intf"
+ exit 0
+ fi
+ exit $ret
+fi