summaryrefslogtreecommitdiffstats
path: root/modules.d/slx-network/scripts/setup-bootif-network.stage3
blob: 1f8fb9ee93f744a397bf8f93c35473a881394e35 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/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 is not ready yet
if [ ! -e "/sys/class/net/${SLX_PXE_NETIF}/device" ]; then
	exit 1
fi

# 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}"
	if [ "$_iface" = "$SLX_PXE_NETIF" ]; then
		img="??-nic"
	elif [ "$_iface" = "$SLX_BRIDGE" ]; then
		img="??-bridge"
	fi
	while [ "$_timeout" -ne 0 ]; do
		[ "$(cat /sys/class/net/${_iface}/operstate)" = "up" ] && break
		(( _timeout -- ))
		# every 500ms
		usleep 500000
		in=
		[ "$(( _timeout % 2 ))" = 0 ] && in=in
		_splashtool --icon "/opt/openslx/icons/${in}active/${img}.ppm" &
	done
	if [ "$_timeout" -ne 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
		(
		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"
		)
		# success?
		if [ "$?" -eq 0 ]; then
			MAIN_NETIF="$SLX_BRIDGE"
			break
		fi

		# nope, handle
		if [ -z "$try" ]; then
			emergency_shell "Failed to setup main network bridge, giving up!"
		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 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
	[ "$i" = "fail" ] && emergency_shell "DHCP failed 3 times... cannot continue."
	udhcpc -t 4 -T 3 -f -n -q \
		-i "${MAIN_NETIF}" \
		"${request_opts[@]}" \
		"${additional_opts[@]}" \
		-s "/usr/local/bin/udhcpc-trigger"
	# success?
	[ "$?" -eq 0 ] && break
	# nope, keep trying...
	warn "DHCP failed, retrying in 1sec..."
	sleep $i
done

set +x
} {BASH_XTRACEFD}> "/run/openslx/initramfs-network.log.$$"