#!/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 > 30 )); then emergency_shell "Boot interface '${SLX_PXE_NETIF}' did not appear" exit 1 fi (( (_fails % 7) == 0 )) && udevadm trigger --subsystem-match=net usleep 333333 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} * 3 ))" 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 ip link set dev "$_iface" up _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 333ms usleep 333333 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 if ! wait_for_iface "$SLX_PXE_NETIF" 30; 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 if [ -e "/sys/class/net/${SLX_BRIDGE}" ]; then ip link set dev "$SLX_BRIDGE" down brctl delif "$SLX_BRIDGE" "$MAIN_NETIF" brctl delbr "$SLX_BRIDGE" fi 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.$$"