network configuration
PATCH 1/2 network configuration
Add udev based, asynchronous network configuration.
Before udevd starts, ip= and BOOTIF= are checked, parsed and if necessary the current udev networking rule overwriten to fire events only for the selected device.
Actual network configurations from ip= or dhcp are written to tempfiles instead of directly applied to the interface. These tempfiles are executed later by mininm.sh after reading the interface-name through the fifo. This way we can sequentially test wich interface works for mounting the root-fs, without going through all interfaces when we do dhcp.
---
dracut | 2 +- modules.d/40network/check | 5 ++ modules.d/40network/dhclient-script | 33 ++++++-------- modules.d/40network/ifup | 76 ++++++++++++++++++++++------------ modules.d/40network/initnet.sh | 37 ++++++++++++++++ modules.d/40network/install | 8 ++- modules.d/40network/kill-dhclient.sh | 5 ++- modules.d/40network/mininm.sh | 21 +++++++++ modules.d/40network/run-dhclient.sh | 8 ---- 9 files changed, 136 insertions(+), 59 deletions(-)
dracut +0 -0
@@ -63,7 +63,7 @@ trap 'rm -rf "$initdir"' 0 # clean up after ourselves no matter how we die.
export initdir hookdirs dsrc dracutmodules modules
# Create some directory structure first
-for d in bin sbin usr/bin usr/sbin usr/lib etc proc sys sysroot dev/pts; do +for d in bin sbin usr/bin usr/sbin usr/lib etc proc sys sysroot dev/pts tmp; do
mkdir -p "$initdir/$d";
done
modules.d/40network/check new file +4 -0
@@ -0,0 +1,5 @@ +#!/bin/sh +# +# This is not a module that should be selected when we try to +# autoconfigure the initrd +exit 1
modules.d/40network/dhclient-script +0 -0
@@ -1,27 +1,22 @@
#!/bin/sh
-# very simple dhclient-script. All it cares about is bringing the interface -# up, and it does not even try to do anything else.
+#
+# Does not actually configure the interface. Instead we just write the +# the necessary steps into an up-script, telling mininm.sh through the +# FIFO that the interface can be used.
case $reason in
- PREINIT) /sbin/ip link set "$interface" up ;;
+ PREINIT) ip link set "$interface" up ;;
BOUND) ipopts="$new_ip_address"
- [ "$new_interface_mtu" ] && ip link set $interface mtu $new_interface_mtu
+ [ "$new_interface_mtu" ] && echo ip link set $interface mtu $new_interface_mtu > /tmp/net.$interface.up
[ "$new_subnet_mask" ] && ipopts="$ipopts/$new_subnet_mask" [ "$new_broadcast_address" ] && ipopts="$ipopts broadcast $new_broadcast_address"
- /sbin/ip addr add $ipopts dev $interface
- [ "$new_routers" ] && /sbin/ip route add default via ${new_routers%%,*} dev $interface
- [ "$new_domain_name" ] && echo "domain $new_domain_name" > /etc/resolv.conf
- if [ "$new_domain_search" ]; then
- echo "search $new_domain_search" |sed 's/,//g' >> /etc/resolv.conf
- elif [ "$new_domain_name" ]; then
- echo "search $new_domain_name" >> /etc/resolv.conf
- fi
- for s in $new_domain_name_servers; do
- echo "nameserver $s" >> /etc/resolv.conf
- done
- set |grep -e '^new_[a-z_]=' |while read line; do
- echo "${line%%=*}=\'${line#*=}\'">>/net.$interface.dhcpopts
- done
- >/net.$interface.up ;;
+
+ echo ip addr add $ipopts dev $interface >> /tmp/net.$interface.up
+
+ [ "$new_routers" ] && echo ip route add default via ${new_routers%%,*} dev $interface >> /tmp/net.$interface.up
+
+ exec 3<>/tmp/iface.fifo
+ echo $interface > /tmp/iface.fifo
+ ;;
*) ;;esac
modules.d/40network/ifup +0 -0
@@ -1,36 +1,58 @@
#!/bin/sh
+#
+# Simple ifup script called through udev when a new network interface +# is discovered. Either forks away dhclient or writes the necessary +# up-script for mininm.sh later on. We can do dhcp asynchronously +# because the necessary event and configuration for mininm.sh are +# generated inside dhclient-script. This is a speedup optimization. +# We assume here that if there's network drivers inside the initrd, +# the user wants something. So a missing ip= option is treated as +# ip=dhcp.
+# Warning: Implementations bootp and arp do not exist yet.
-# bail immediatly if the interface is already up -[ -f "/net.$1.up" ] && exit 0
+ifup_static() {
+ local IFS=':'
+ read client server gw netmask hostname device autoconf
+
+ [ -z "$device" ] || [ "$device" = "$1" ] || return 0;
+
+ [ "$client" ] || return 0;
+ [ "$netmask" ] && client="$client/$netmask"
+
+ echo ip link set $1 up > /tmp/net.$1.up
+ echo ip addr add $client dev $1 >> /tmp/net.$1.up
+
+ [ "$gw" ] && echo ip route add default via $gw dev $1 >> /tmp/net.$1.up
+
+ exec 3<>/tmp/iface.fifo
+ echo $1 > /tmp/iface.fifo
+}
+
+# bail immediatly if the interface is already configured +[ -f "/tmp/net.$1.up" ] && exit 0
# loopback is always handled the same way
[ "$1" = "lo" ] && {
- /sbin/ip link set lo up
- /sbin/ip addr add 127.0.0.1/8 dev lo
+ ip link set lo up
+ ip addr add 127.0.0.1/8 dev lo
exit 0
}-# spin through the kernel command line, looking for ip= lines -for p in $(cat /proc/cmdline); do
- [ "${p%ip=*}" ] || continue
- p=${p#ip=}
- case $p in- none|off) exit 0;; # we were told to not configure anything
- dhcp|on|any) >/net.$1.dhcp; exit 0;; - bootp|rarp|both) exit 0;; #dunno how to do this
- *) echo ${ip#ip=} | \
- (IFS=':' read client server gw netmask hostname device autoconf
- if [ -z "$device" -o "$device" = "$1" ]; then
- case $autoconf in
- dhcp|on|any) >/net.$1.dhcp ;; - none|off|'') # do some basic configuration - /sbin/ip link set $1 up - /sbin/ip addr add $client/$netmask dev $1 - [ "$gw" ] && /sbin/ip route add default via $gw dev $1 - >/net.$1.up ;;
- esac
- fi
- ) ;;
- *) continue;;
- esac
+# get ip= option
+for p in $(cat /tmp/cmdline); do
+ [ "${p%%=*}" = "ip" ] || continue
+ IP=${p#*=} + break;
done
+
+
+# set autoconf to dhcp if empty, or no ip= is provided +autoconf=${IP##*:*:*:*:*:*:}
+[ "$autoconf" ] || autoconf="dhcp"
+
+# Let's do something
+case $autoconf in + bootp|rarp|both) exit 0;;
+ on|any|dhcp) dhclient -q $1 &;;
+ *) echo $IP | ifup_static $1 ;;
+esac
modules.d/40network/initnet.sh new file +37 -0
@@ -0,0 +1,37 @@ +#!/bin/sh +# +# Makes sure the network fifo is there and creates special udev rules +# to fire only for network devices we need or want. This is an +# optimization, it is not strictly necessary. + +fix_bootif() { + local macaddr=${1##??-} + local IFS='-' + macaddr=$(for i in ${macaddr} ; do echo -n $i:; done) + macaddr=${macaddr%:} + echo $macaddr +} + +dst="/lib/udev/rules.d" +[ -d /etc/udev/rules.d ] && dst="/etc/udev/rules.d" + +#Assume the user knows what he's doing when providing a devicename +BOOTDEV=$(getarg 'ip=') +[ "$BOOTDEV" ] && [ ! "$BOOTDEV" = "${BOOTDEV#*:}" ] && { +echo $BOOTDEV + BOOTDEV=${BOOTDEV#*:*:*:*:} + BOOTDEV=${BOOTDEV%:*} + + [ "$BOOTDEV" ] && printf 'ACTION=="add", SUBSYSTEM=="net", INTERFACE_NAME=="%s", RUN+="/sbin/ifup $env{INTERFACE}"\n' "$BOOTDEV" > $dst/60-net.rules +} + +#Prefer mac-address to bootdev, overwrite if provided +BOOTIF=$(getarg 'BOOTIF=') +[ "$BOOTIF" ] && { + BOOTIF=$(fix_bootif "$BOOTIF") + + printf 'ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="%s", RUN+="/sbin/ifup $env{INTERFACE}"\n' "$BOOTIF" > $dst/60-net.rules +} + +#Syncronization FIFO for mininm.sh +mkfifo /tmp/iface.fifo
modules.d/40network/install +0 -0
@@ -1,8 +1,10 @@
#!/bin/bash
-dracut_install ip dhclient
+dracut_install ip dhclient mkfifo
inst "$moddir/ifup" "/sbin/ifup"
inst "$moddir/dhclient-script" "/sbin/dhclient-script" -instmods =networking ecb arc4
+instmods =net ecb arc4 af_packetinst_rules "$moddir/60-net.rules"
+
+inst_hook pre-udev 10 "$moddir/initnet.sh" inst_hook pre-pivot 10 "$moddir/kill-dhclient.sh" -inst_hook pre-mount 70 "$moddir/run-dhclient.sh" +inst_hook mount 40 "$moddir/mininm.sh"
modules.d/40network/kill-dhclient.sh +0 -0
@@ -1,4 +1,7 @@
#!/bin/sh
+#
+# Dracut initrd should be free of side effects. Kill any runaway +# dhclients.
pid=$(pidof dhclient)
-[[ $pid ]] && kill $pid
+[[ $pid ]] && kill $pid
\ No newline at end of file
modules.d/40network/mininm.sh new file +20 -0
@@ -0,0 +1,21 @@ +#!/bin/sh +# +# Mini network manager: Should be called before trying to mount +# something. Receives names of ready interfaces through a blocking +# FIFO, configures that interface and hopes mount will +# succeed. Otherwise we return here from the init loop and try the +# next interface. + +#No Netboot? bail out +[ $NETBOOT ] || continue; + +#Deconfigure running interface. Means we've tried one and +#failed. Ensures that the default route is cleared as well. +[ $NETIF ] && ip link set $NETIF down + +#Read or wait for next ready interface +read NETIF < /tmp/iface.fifo; + +#Configure interface +[ -e /tmp/net.$NETIF.up ] && . /tmp/net.$NETIF.up +
modules.d/40network/run-dhclient.sh deleted +0 -8
@@ -1,8 +0,0 @@ -#!/bin/sh -for i in /net.*.dhcp; do - dev=${i#net.}; dev=${i%.dhcp} - [ -f "/net.$dev.up" ] && continue - dhclient -1 -q $dev & -done -wait - \ No newline at end of file
--
To unsubscribe from this list: send the line "unsubscribe initramfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html