From 9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Mon, 3 Jun 2024 15:54:25 +0200
Subject: Adding upstream version 060+5.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 modules.d/35network-legacy/dhcp-multi.sh | 133 +++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100755 modules.d/35network-legacy/dhcp-multi.sh

(limited to 'modules.d/35network-legacy/dhcp-multi.sh')

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
-- 
cgit v1.2.3