summaryrefslogtreecommitdiffstats
path: root/builder/modules.d/slx-network
diff options
context:
space:
mode:
authorJonathan Bauer2019-07-24 11:37:31 +0200
committerJonathan Bauer2019-07-24 11:37:31 +0200
commit5caba65f11cb8d890d90da4709dc488e7f2ad47c (patch)
tree45b8123908031e466a4b482c18935beb1936ad1b /builder/modules.d/slx-network
parent[patches] remove dnbd3 hacky patch (diff)
downloadsystemd-init-5caba65f11cb8d890d90da4709dc488e7f2ad47c.tar.gz
systemd-init-5caba65f11cb8d890d90da4709dc488e7f2ad47c.tar.xz
systemd-init-5caba65f11cb8d890d90da4709dc488e7f2ad47c.zip
[slx-network] introduce static network module
Diffstat (limited to 'builder/modules.d/slx-network')
-rw-r--r--builder/modules.d/slx-network/copy-network-config.sh6
-rwxr-xr-xbuilder/modules.d/slx-network/module-setup.sh31
-rw-r--r--builder/modules.d/slx-network/parse-ipxe-network-kcl.sh102
-rw-r--r--builder/modules.d/slx-network/setup-network.sh110
-rwxr-xr-xbuilder/modules.d/slx-network/udhcpc-trigger114
5 files changed, 363 insertions, 0 deletions
diff --git a/builder/modules.d/slx-network/copy-network-config.sh b/builder/modules.d/slx-network/copy-network-config.sh
new file mode 100644
index 00000000..6a8fd835
--- /dev/null
+++ b/builder/modules.d/slx-network/copy-network-config.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+if [ -n "$NEWROOT" ]; then
+ cp -f /etc/{hostname,resolv.conf} "${NEWROOT}/etc"
+fi
+true
diff --git a/builder/modules.d/slx-network/module-setup.sh b/builder/modules.d/slx-network/module-setup.sh
new file mode 100755
index 00000000..45b91877
--- /dev/null
+++ b/builder/modules.d/slx-network/module-setup.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+check() {
+ [[ $mount_needs ]] && return 1
+
+ if dracut_module_included "network" || dracut_module_included "systemd-networkd" ; then
+ derror "This module conflicts with 'network' and 'systemd-networkd'!"
+ return 1
+ fi
+ return 255
+}
+
+# called by dracut
+depends() {
+ echo "busybox kernel-network-modules"
+}
+
+# called by dracut
+install() {
+ # need initqueue to get a clean network start
+ dracut_need_initqueue
+
+ # install basic dns libs
+ _arch=$(uname -m)
+ inst_libdir_file {"tls/$_arch/",tls/,"$_arch/",}"libnss_dns.so.*"
+
+ inst "$moddir/udhcpc-trigger" "/usr/local/bin/udhcpc-trigger"
+ inst_hook cmdline 10 "$moddir/parse-ipxe-network-kcl.sh"
+ inst_hook pre-mount 00 "$moddir/setup-network.sh"
+ inst_hook pre-pivot 50 "$moddir/copy-network-config.sh"
+}
+
diff --git a/builder/modules.d/slx-network/parse-ipxe-network-kcl.sh b/builder/modules.d/slx-network/parse-ipxe-network-kcl.sh
new file mode 100644
index 00000000..c99a6465
--- /dev/null
+++ b/builder/modules.d/slx-network/parse-ipxe-network-kcl.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+#
+# TODO VLAN support
+
+command -v getarg >/dev/null || . /lib/dracut-lib.sh
+
+# static names for the boot interface and its bridge
+declare -rg BOOTIF_NAME="boot0"
+declare -rg BRIDGE_NAME="br0"
+declare -rg RUNTIME_CONF="/run/openslx/network.conf"
+mkdir -p "${RUNTIME_CONF%/*}"
+# Get all the ip-related arguments from the KCL
+parse_kernel_command_line() {
+ ## KCL "BOOTIF": MAC address of the interface that DHCP'ed during PXE
+ declare -g BOOTIF="$(getarg BOOTIF=)"
+ # Remove the hardware type prefix of BOOTIF if it has 20 chars to get
+ # the plain MAC address. The hardware type prefix has length 3, e.g. "01-".
+ if [ -n "${BOOTIF}" ] && [ ${#BOOTIF} -eq 20 ]; then
+ BOOTIF="${BOOTIF#???}"
+ BOOTIF="${BOOTIF//-/:}"
+ fi
+ readonly BOOTIF
+
+ ## KCL "ip": is expected in following format (syslinux IPAPPEND3):
+ declare -rg IPCONF="$(getarg ip=)"
+ # <CLIENT_IP>:<PXE_SERVER_IP>:<GATEWAY_IP>:<NETMASK>
+ declare -g CLIENT_IP=
+ declare -g SERVER_IP=
+ declare -g GATEWAY_IP=
+ declare -g NETMASK=
+ read -r CLIENT_IP SERVER_IP GATEWAY_IP NETMASK \
+ <<< $( awk -F: '{print $1" "$2" "$3" "$4}' <<< "${IPCONF}" )
+ readonly CLIENT_IP SERVER_IP GATEWAY_IP NETMASK
+
+ # Calculate routing prefix from netmask
+ declare -rg ROUTING_PREFIX="$(ipcalc -s -p "$CLIENT_IP" "$NETMASK")"
+
+ # KCL "hostname"
+ declare -rg HOSTNAME="$(getarg hostname=)"
+ [ -n "$HOSTNAME" ] && echo "$HOSTNAME" > /proc/sys/kernel/hostname
+
+ # KCL "dns"
+ declare -rg DNS="$(getarg dns=)"
+
+ # KCL "domain"
+ declare -rg DOMAIN="$(getarg domain=)"
+
+ # VLAN tag
+ declare -rg VLAN="$(getarg vlan=)"
+ if [ -n "$VLAN" ]; then
+ modprobe 8021q || warn "VLAN mode detected but failed to load 8021q!"
+ fi
+
+ # Bridged mode?
+ grep -wqE 'bridged' /proc/cmdline && declare -rg BRIDGED="y"
+}
+
+save_network_config() {
+ cat <<-EOF > "${RUNTIME_CONF}"
+ SLX_PXE_CLIENT_IP=${CLIENT_IP}
+ SLX_PXE_SERVER_IP=${SERVER_IP}
+ SLX_PXE_GATEWAY=${GATEWAY_IP}
+ SLX_PXE_NETMASK=${NETMASK}
+ SLX_PXE_MAC=${BOOTIF}
+ SLX_PXE_NETIF=${BOOTIF_NAME}
+ SLX_PXE_DNS=${DNS}
+ SLX_PXE_HOSTNAME=${HOSTNAME}
+ SLX_PXE_DOMAIN=${DOMAIN}
+ SLX_BRIDGE=${BRIDGED:+${BRIDGE_NAME}}
+ SLX_VLAN_ID=${VLAN}
+ EOF
+}
+
+# Create udev rule to rename the PXE boot interface to BOOTIF_NAME
+create_udev_bootif_name_rule() {
+ if [ -z "${BOOTIF}" ]; then
+ echo "No BOOTIF set, was it present in the kernel command line?"
+ return 1
+ fi
+ # priority 70 < 80-net-name-slot.rules.
+ echo 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="'${BOOTIF}'", NAME="'${BOOTIF_NAME}'"' > /etc/udev/rules.d/70-pxe-boot-interface.rules
+}
+
+## MAIN ##
+# Get IP config from KCL
+parse_kernel_command_line
+
+# Save network config for later use
+save_network_config &
+
+# Create the udev rule to rename the boot interface to the declared BOOTIF_NAME
+create_udev_bootif_name_rule &
+
+## Make dracut wait for network during the udev loop (initqueue) to make
+## sure we have network access in the pre-mount hook as it is needed
+## to get configurations and the root filesystem
+NETIF=
+[ -n "${BOOTIF_NAME}" ] && NETIF="${BOOTIF_NAME}"
+[ -n "${BRIDGED}" ] && [ -n "${BRIDGE_NAME}" ] && NETIF="${BRIDGE_NAME}"
+[ -n "${VLAN}" ] && NETIF="${BOOTIF_NAME}.${VLAN}"
+
+/sbin/initqueue --finished [ -e "/sys/class/net/${BOOTIF_NAME}" ]
diff --git a/builder/modules.d/slx-network/setup-network.sh b/builder/modules.d/slx-network/setup-network.sh
new file mode 100644
index 00000000..a983c05a
--- /dev/null
+++ b/builder/modules.d/slx-network/setup-network.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+type emergency_shell || . /lib/dracut-lib.sh
+
+. /run/openslx/network.conf
+
+_logfile="/run/openslx/network.log"
+
+wait_for_iface() {
+ local _iface="$1"
+ local _timeout="${2:-50}"
+ while [ "$_timeout" -ne 0 ]; do
+ [ "$(cat /sys/class/net/${_iface}/operstate)" = "up" ] && break
+ (( _timeout -- ))
+ usleep 100000
+ done
+ [ "$_timeout" -ne 0 ]
+}
+
+# For debugging...
+{
+set -x
+
+addtional_nic=1
+# loop over all physical interface
+for nic in "/sys/class/net/"*; do
+ [ -e "$nic/device" ] || continue
+ nic_iface="${nic##*/}"
+ nic_mac="$(cat ${nic}/address)"
+ if [ "$nic_mac" = "$SLX_PXE_MAC" ]; then
+ # found the boot interface, configure it
+ ip link set dev "$nic_iface" up
+ if ! wait_for_iface "$nic_iface" 100; then
+ # TODO handle?
+ :
+ fi
+
+ if [ -n "$SLX_BRIDGE" ]; then
+ for try in 1 2 3 fail; 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" "$nic_iface"
+ ip link set dev "$SLX_BRIDGE" up
+ wait_for_iface "$SLX_BRIDGE"
+ )
+ # success?
+ [ "$?" -eq 0 ] && break
+
+ # nope, handle
+ if [ "$try" = "fail" ]; 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"
+ try=$(( try + 1 ))
+ usleep 100000
+ done
+ fi
+ # add the IP address on the bridge/boot if
+ ip addr add \
+ "$SLX_PXE_CLIENT_IP/$(ipcalc -s -p "$SLX_PXE_CLIENT_IP" "$SLX_PXE_NETMASK" | sed "s/.*=//")" \
+ broadcast "$(ipcalc -s -b "$SLX_PXE_CLIENT_IP" "$SLX_PXE_NETMASK" | sed "s/.*=//")" \
+ dev "${SLX_BRIDGE:-${nic_iface}}"
+ continue
+ fi
+ # additional network interfaces, create additional bridges
+ addtional_bridge="br-nic-${addtional_nic}"
+ (
+ set -e
+ brctl addbr "$addtional_bridge"
+ brctl stp "$addtional_bridge" 0
+ ip link set addr "$nic_mac" "$addtional_bridge"
+ ip link set dev "$nic_iface" up
+ brctl addif "$addtional_bridge" "$nic_iface"
+ ip link set dev "$addtional_bridge" up
+ )
+ if [ "$?" -ne 0 ]; then
+ warn "Failed to setup additional bridge for '$nic_mac'."
+ else
+ additional_nic=$(( additional_nic + 1 ))
+ fi
+done
+
+if [ "$USE_DHCP_UUID" = "yes" ] && [ -s "/run/system-uuid" ]; then
+ UUID="$(cat /run/system-uuid)"
+fi
+
+# udhcpc
+for i in 1 1 1 fail; do
+ udhcpc -t 4 -T 3 -f -n -q \
+ -i "$SLX_BRIDGE" \
+ "${SLX_PXE_CLIENT_IP:+-r $SLX_PXE_CLIENT_IP}" \
+ "${UUID:+-x 0x3d:$UUID}" \
+ -O ntpsrv -O domain -O wpad -O search -O nisdomain \
+ -s "/usr/local/bin/udhcpc-trigger"
+ # success?
+ [ "$?" -eq 0 ] && break
+ # nope, handle
+ [ "$i" = "fail" ] && emergency_shell "DHCP failed 3 times... cannot continue."
+ warn "DHCP failed, retrying in 1sec..."
+ sleep $i
+done
+
+set +x
+} &> "$_logfile"
diff --git a/builder/modules.d/slx-network/udhcpc-trigger b/builder/modules.d/slx-network/udhcpc-trigger
new file mode 100755
index 00000000..0e531957
--- /dev/null
+++ b/builder/modules.d/slx-network/udhcpc-trigger
@@ -0,0 +1,114 @@
+#!/bin/ash
+
+exec >> /run/openslx/udhcpc-trigger.log
+exec 2>> /run/openslx/udhcpc-trigger.log
+set -x
+
+if [ "x$1" != "xbound" -a "x$1" != "xrenew" ] || [ "x$interface" != "xbr0" ] || [ -z "$ip" ]; then
+ exit 0
+fi
+
+NETWORK_CONF="/run/openslx/network.conf"
+
+. "$NETWORK_CONF"
+
+# If we already got an IP from KCL, see if it differs, and remove first if so
+# We just try to prevent everything from breaking if the DHCP server doesn't
+# objey the renew request by the client and hands out a new address
+if [ -n "$SLX_PXE_CLIENT_IP" ]; then
+ #...some address is already configured...
+ if [ "x${SLX_PXE_CLIENT_IP}" != "x${ip}" ]; then
+ #...it's a different one, reconfigure...
+ echo "..reconfiguring ${SLX_PXE_CLIENT_IP} to ${ip}.."
+ # remove default route and let it be added again below, as it might get lost when changing the primary address on the interface
+ ip route del default 2>/dev/null
+ ip addr del "$SLX_PXE_CLIENT_IP" dev "${interface}" 2>/dev/null
+ ip addr add "${ip}/$(ipcalc -s -p "${ip}" "${subnet}" | sed s/.*=//)" dev "${interface}"
+ fi
+else
+ #...no address configured yet, just add...
+ echo "..adding ${ip}.."
+ ip addr add "${ip}/$(ipcalc -s -p "${ip}" "${subnet}" | sed s/.*=//)" dev "${interface}"
+fi
+echo "SLX_DHCP_CLIENT_IP=$ip" >> "$NETWORK_CONF"
+
+# Same procedure for default gateway
+if [ -n "${router}" ]; then
+ if [ -s "$SLX_PXE_GATEWAY" ]; then
+ if [ "x${SLX_PXE_GATEWAY}" != "x${router}" ]; then
+ echo "..reconfiguring default gw from ${SLX_PXE_GATEWAY} to ${router}.."
+ ip route del default 2>/dev/null
+ ip route add default via "$router"
+ fi
+ else
+ ip route add default via "$router"
+ fi
+ echo "SLX_DHCP_GATEWAY=$router" >> "$NETWORK_CONF"
+fi
+
+rm -f -- "/etc/resolv.conf"
+
+# DNS/domain?
+if [ -n "$dns" ]; then
+ echo "..got DNS.."
+ echo "# From DHCP in stage 3.1" >> "$NETWORK_CONF"
+ echo "SLX_DNS=$dns" >> "$NETWORK_CONF"
+fi
+for serv in $dns; do
+ echo "nameserver $serv" >> "/etc/resolv.conf"
+done
+if [ -z "$domain" ]; then
+ # try to get domain via reverse lookup if empty
+ echo "..trying to get domain via DNS, as DHCP didn't supply one.."
+ fqdn=$(timeout -t 3 nslookup "$ip" | grep -E "^Address +[0-9]+: +$ip " | head -n 1 | awk '{print $4}')
+ domain="${fqdn#*.}"
+fi
+# Add domain to list of search domains if not in there yet
+if [ -n "$domain" ] && [ -n "$search" ]; then
+ FOUND=no
+ for sd in $search; do
+ [ "x$sd" = "x$domain" ] && FOUND=yes
+ done
+ [ "$FOUND" = "no" ] && search="$domain $search"
+elif [ -n "$domain" ]; then
+ search="$domain"
+fi
+# Write out
+if [ -n "$domain" ]; then
+ echo "domain $domain" >> "/etc/resolv.conf"
+ echo "SLX_NET_DOMAIN='$domain'" >> "/run/openslx/network.conf"
+fi
+if [ -n "$search" ]; then
+ echo "search $search" >> "/etc/resolv.conf"
+ echo "SLX_NET_SEARCH='$search'" >> "/run/openslx/network.conf"
+fi
+
+if [ -n "$ntpsrv" ]; then
+ echo "SLX_DHCP_NTP='$ntpsrv'" >> "/run/openslx/network.conf"
+fi
+
+# Hostname
+if [ -z "$hostname" ]; then
+ # as with domain, if there's no hostname, try to get via DNS
+ echo "..trying to get hostname via DNS, as DHCP didn't supply one.."
+ [ -z "$fqdn" ] && fqdn=$(timeout -t 3 nslookup "$ip" | grep -E "^Address +[0-9]+: +$ip " | head -n 1 | awk '{print $4}')
+ hostname="${fqdn%%.*}"
+elif [ -n "$domain" ]; then
+ fqdn="${hostname}.${domain%% *}" # in case domain is a list
+fi
+
+if [ -z "$hostname" ]; then
+ # no fallback hostname from DNS, use IP address
+ hostname="${ip//./-}"
+fi
+
+if [ -n "$hostname" ]; then
+ [ -z "$fqdn" ] && fqdn="$hostname"
+ echo "..setting hostname $hostname (fqdn: $fqdn).."
+ echo "$hostname" > "/proc/sys/kernel/hostname"
+ echo "$hostname" > "/etc/hostname"
+ echo "127.0.0.1 localhost" > "/etc/hosts"
+ echo "127.0.1.1 $fqdn $hostname" >> "/etc/hosts"
+ echo "SLX_HOSTNAME='$hostname'" >> "/run/openslx/network.conf"
+fi
+