summaryrefslogtreecommitdiffstats
path: root/modules.d/slx-network/hooks/s3-setup-bootif-network.sh
diff options
context:
space:
mode:
Diffstat (limited to 'modules.d/slx-network/hooks/s3-setup-bootif-network.sh')
-rwxr-xr-xmodules.d/slx-network/hooks/s3-setup-bootif-network.sh186
1 files changed, 186 insertions, 0 deletions
diff --git a/modules.d/slx-network/hooks/s3-setup-bootif-network.sh b/modules.d/slx-network/hooks/s3-setup-bootif-network.sh
new file mode 100755
index 00000000..1ae58464
--- /dev/null
+++ b/modules.d/slx-network/hooks/s3-setup-bootif-network.sh
@@ -0,0 +1,186 @@
+#!/bin/bash
+#
+# This script sets up the main network interface we booted from,
+# as designated by SLX_PXE_NETIF (parsed from the PXE KCL in the
+# cmdline dracut hook).
+# It is run inside dracut's initqueue, on settles to detect the
+# physical network interface as fast as possible.
+
+type emergency_shell >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+. /run/openslx/network.conf
+
+# do not run until the physical interface exists (driver loaded)
+_fails=0
+while ! [ -e "/sys/class/net/${SLX_PXE_NETIF}/device" ]; do
+ if (( ++_fails > 20 )); then
+ emergency_shell "Boot interface '${SLX_PXE_NETIF}' did not appear"
+ exit 1
+ fi
+ (( (_fails % 5) == 0 )) && udevadm trigger
+ usleep 500000
+done
+
+# wrapper around splashtool to disable it if its not present
+_splashtool() {
+ :
+}
+if grep -wq splash /proc/cmdline && hash splashtool &> /dev/null; then
+ _splashtool() {
+ splashtool "$@"
+ }
+fi
+
+wait_for_iface() {
+ local _iface="$1"
+ local _timeout="${2:-50}"
+ local _fails=0
+ local _state
+ if [ "$_iface" = "$SLX_PXE_NETIF" ]; then
+ img="??-nic"
+ elif [ "$_iface" = "$SLX_BRIDGE" ]; then
+ img="??-bridge"
+ fi
+ while (( _timeout-- > 0 )); do
+ _state="$(cat "/sys/class/net/${_iface}/operstate" 2> /dev/null)"
+ [ "$_state" = "up" ] && break
+ if (( ++_fails > 5 )) && [[ "$_state" = "unknown" || "$_state" = "" ]]; then
+ if (( _fails > 10 )) || [ "$(cat "/sys/class/net/${_iface}/carrier" 2> /dev/null)" = "1" ]; then
+ break
+ fi
+ fi
+ # every 500ms
+ usleep 500000
+ in=
+ (( (_timeout % 2) == 0 )) && in=in
+ _splashtool --icon "/opt/openslx/icons/${in}active/${img}.ppm" &
+ done
+ if (( _timeout > 0 )); then
+ _splashtool --icon "/opt/openslx/icons/active/${img}.ppm" &
+ return 0
+ else
+ _splashtool --icon "/opt/openslx/icons/inactive/${img}.ppm" &
+ return 1
+ fi
+}
+
+# For debugging...
+{
+set -x
+
+ip link set dev "$SLX_PXE_NETIF" up
+if ! wait_for_iface "$SLX_PXE_NETIF" 60; then
+ warn "'$SLX_PXE_NETIF' still not up after 30sec ... trying anyway."
+ # TODO handle case where we waited for 30sec and it is still not up
+fi
+
+# now determine whether we are in bridged/vlan/plain mode
+MAIN_NETIF="$SLX_PXE_NETIF"
+if [ -n "$SLX_VLAN_ID" ]; then
+ # create VLAN interface
+ modprobe 8021q || warn "Loading '8021q' failed - missing module?"
+ ip link add link "$SLX_PXE_NETIF" name "${SLX_PXE_NETIF}.${SLX_VLAN_ID}" \
+ type vlan id "$SLX_VLAN_ID"
+ ip link set dev "${SLX_PXE_NETIF}.${SLX_VLAN_ID}" up
+ if wait_for_iface "${SLX_PXE_NETIF}.${SLX_VLAN_ID}"; then
+ MAIN_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+ else
+ warn "Setting up VLAN '$SLX_VLAN_ID' failed, trying plain..."
+ fi
+fi
+
+if [ -n "$SLX_BRIDGE" ]; then
+ for try in {1..10} ""; do
+ if (
+ set -e
+ brctl addbr "$SLX_BRIDGE"
+ brctl stp "$SLX_BRIDGE" 0
+ brctl setfd "$SLX_BRIDGE" 0.000000000001
+ ip link set addr "$SLX_PXE_MAC" "$SLX_BRIDGE"
+ brctl addif "$SLX_BRIDGE" "$MAIN_NETIF"
+ ip link set dev "$SLX_BRIDGE" up
+ wait_for_iface "$SLX_BRIDGE"
+ ); then
+ MAIN_NETIF="$SLX_BRIDGE"
+ break
+ fi
+
+ # nope, handle
+ if [ -z "$try" ]; then
+ emergency_shell "Failed to setup main network bridge, giving up!"
+ exit 1
+ fi
+ warn "Failed to setup main network bridge on try $try. Retrying ..."
+ # delete bridge, inc try and sleep 100ms before trying again
+ [ -e "/sys/class/net/${SLX_BRIDGE}" ] && brctl delbr "$SLX_BRIDGE"
+ usleep 100000
+ done
+fi
+
+# Finally add the IP address on the main NIC.
+# Note: we should never have ip & netmask without the other.
+if [ -n "$SLX_PXE_CLIENT_IP" ] && [ -n "$SLX_PXE_NETMASK" ]; then
+ ip addr add "${SLX_PXE_CLIENT_IP}/${SLX_PXE_NETMASK}" dev "$MAIN_NETIF"
+
+ # now if we got everything from the KCL and skip dhcp if so
+ if [ -n "$SLX_PXE_GATEWAY" ] && [ -n "$SLX_PXE_DNS" ]; then
+ info "Got network configuration from KCL, skipping DHCP."
+ if ! interface="$MAIN_NETIF" \
+ ip="$SLX_PXE_CLIENT_IP" \
+ router="$SLX_PXE_GATEWAY" \
+ dns="$SLX_PXE_DNS" \
+ hostname="$SLX_PXE_HOSTNAME" \
+ /usr/local/bin/udhcpc-trigger bound; then
+ warn "Failed to launch DHCP trigger with KCL configuration - will DHCP."
+ fi
+ exit 0
+ fi
+fi
+
+## DHCP
+# Try to work around some buggy e1000e variants by waiting a bit
+sleep 1
+additional_opts=()
+
+# we need to send the same UID (without '-') as the PXE firmware did, so use the plain
+# one read with dmidecode (and not the one by s3-get-system-uuid).
+if [ "$USE_DHCP_UUID" = "yes" ]; then
+ UID="$(dmidecode -s system-uuid | sed -r 's/^(..)(..)(..)(..)-(..)(..)-(..)(..)-(....)-/00\4\3\2\1\6\5\8\7\9/')"
+ if [ "${#UID}" = 34 ]; then
+ echo "Using SMBIOS UID for DHCP"
+ additional_opts+=("-x" "0x3d:$UID")
+ fi
+fi
+
+if [ -n "$SLX_PXE_CLIENT_IP" ]; then
+ additional_opts+=("-r" "$SLX_PXE_CLIENT_IP")
+fi
+
+# DHCP options to request
+request_opts=("-O" "hostname")
+request_opts+=("-O" "dns")
+request_opts+=("-O" "ntpsrv")
+request_opts+=("-O" "domain")
+request_opts+=("-O" "wpad")
+request_opts+=("-O" "search")
+request_opts+=("-O" "nisdomain")
+
+# udhcpc
+for i in 1 1 1 fail; do
+ if [ "$i" = "fail" ]; then
+ emergency_shell "DHCP failed 3 times... cannot continue."
+ exit 1
+ fi
+ udhcpc -t 4 -T 3 -f -n -q \
+ -i "${MAIN_NETIF}" \
+ "${request_opts[@]}" \
+ "${additional_opts[@]}" \
+ -s "/usr/local/bin/udhcpc-trigger" \
+ && break
+ # failed, keep trying...
+ warn "DHCP failed, retrying in $i sec..."
+ sleep $i
+done
+
+set +x
+} {BASH_XTRACEFD}> "/run/openslx/initramfs-network.log.$$"