diff options
Diffstat (limited to 'modules.d/slx-network/hooks/s3-setup-bootif-network.sh')
-rwxr-xr-x | modules.d/slx-network/hooks/s3-setup-bootif-network.sh | 186 |
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.$$" |