network: prepare network configuration engine for udev-based nfsroot
authorDavid Dillow <dave@thedillows.org>
Sat, 23 May 2009 02:43:32 +0000 (22:43 -0400)
committerHarald Hoyer <harald@redhat.com>
Mon, 25 May 2009 10:19:25 +0000 (12:19 +0200)
This changes the network config to run dhclient from within udev, and
allows multiple dhclients to run at once. It also sets the hostname and
adds a kernel command line option 'netdebug' to help debug network issues.

modules.d/40network/dhclient-script
modules.d/40network/ifup
modules.d/40network/install
modules.d/40network/kill-dhclient.sh
modules.d/40network/run-dhclient.sh [deleted file]

index 895ed1b..7689e04 100755 (executable)
@@ -1,27 +1,85 @@
-#!/bin/sh
+#!/bin/sh -e
 # very simple dhclient-script.  All it cares about is bringing the interface
 # up, and it does not even try to do anything else.
 
-case $reason in
-    PREINIT) /sbin/ip link set "$interface" up ;;
-    BOUND) ipopts="$new_ip_address"
-       [ "$new_interface_mtu" ] && ip link set $interface mtu $new_interface_mtu
-       [ "$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
+LOG=/dhclient.$$.log
+ERR=/network.$$.err
+PATH=$PATH:/sbin:/usr/sbin
+
+. /lib/dracut-lib
+
+getarg netdebug && {
+    exec >/dhclient.$interface.$$.out
+    exec 2>>/dhclient.$interface.$$.out
+    set -x
+}
+
+log_err() {
+    # avoid the need for cat on the image
+    echo "On $netif, the following command:" > $ERR
+    echo "    " "$CMD" >> $ERR
+    echo "had errors:" >> $ERR
+    while read line; do echo "     $line"; done < $LOG >> $ERR
+}
+
+# Catch unlikely initial errors
+trap 'echo Errors preparing to configure $netif > $ERR; exit 0' EXIT
+
+netif=$interface
+ip=$new_ip_address
+mtu=$new_interface_mtu
+mask=$new_subnet_mask
+bcast=$new_broadcast_address
+gw=${new_routers%%,*}
+domain=$new_domain_name
+search=$new_domain_search
+namesrv=$new_domain_name_servers
+hostname=$new_host_name
+
+[ -f /net.$interface.override ] && . /net.$interface.override
+
+# save the offending command and let udev move on if we have an error
+trap 'log_err; exit 0' EXIT
+
+run() {
+    CMD="$@"
+    "$@" >> $LOG 2>&1
+}
+
+setup_interface() {
+    [ -n "$mtu" ] && {
+       run ip link set $netif down
+       run ip link set $netif mtu $mtu
+       run ip link set $netif up
+    }
+
+    run ip addr add $ip${mask:+/$mask} ${bcast:+broadcast $bcast} dev $netif
+    [ -n "$gw" ] && run ip route add default via $gw
+    [ -n "${search}${domain}" -a -n "$namesrv" ] && {
+       echo search $search $domain > /etc/resolv.conf
+       for s in $namesrv; do
+           echo nameserver $s >> /etc/resolv.conf
        done
-       set |grep -E '^new_[a-z_]+=' |while read line; do
-           echo "${line%%=*}='${line#*=}'">>/net.$interface.dhcpopts
+    }
+    [ -e /hostname.set ] || {
+       [ -n "$hostname" ] && mknod /hostname.set p && run hostname $hostname
+    }
+}
+
+case $reason in
+    PREINIT)
+       run /sbin/ip link set $netif up
+       ;;
+    BOUND)
+       setup_interface 
+       set | while read line; do
+           [ "${line#new_}" = "$line" ] && continue
+           echo "$line" >>/net.$netif.dhcpopts
        done
-       >/net.$interface.up ;;
+       >/net.$netif.up
+       echo online > /sys/class/net/$netif/uevent ;;
     *) ;;
 esac
+
+trap - EXIT
+exit 0
index 744a2ae..284c9df 100755 (executable)
 #!/bin/sh
 
+PATH=$PATH:/sbin:/usr/sbin
+
+. /lib/dracut-lib
+
+getarg netdebug && {
+    exec >/ifup.$1.$$.out
+    exec 2>>/ifup.$1.$$.out
+    set -x
+}
+
+netif=$1
+
 # bail immediatly if the interface is already up
-[ -f "/net.$1.up" ] && exit 0
+[ -f "/net.$netif.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
+[ "$netif" = "lo" ] && {
+    ip link set lo up
+    ip addr add 127.0.0.1/8 dev lo
+    >/net.$netif.up
     exit 0
 }
 
+# XXX need error handling like dhclient-script
+
+die() {
+    echo $netif: "$@" 1>&2
+    exit 1
+}
+
+do_static() {
+    [ -n "$ip" ] || die "static: need IP address"
+    [ -n "$mask" ] || {
+       net=${ip%%.*}
+       mask=255.0.0.0
+       [ $net -ge 128 ] && mask=255.255.0.0
+       [ $net -ge 192 ] && mask=255.255.255.0
+    }
+    ip addr add $ip/$mask dev $netif || die "static: setting IP $ip/$mask"
+    [ -n "$gw" ] && {
+       ip route add default via $gw dev $netif ||
+           die "static: setting default route via $gw"
+    }
+    ip link set $netif up 
+    [ -e /hostname.set ] || {
+       [ -n "$hostname" ] && mknod /hostname.set p 2>/dev/null &&
+           hostname $hostname
+    }
+    [ -n "$srv" ] &&
+       echo "new_dhcp_server_identifier=$srv" > /net.$netif.dhcpopts
+
+    >/net.$netif.up
+    echo online > /sys/class/net/$netif/uevent
+}
+
+do_dhcp() {
+    reqs=subnet-mask,broadcast-address,routers,domain-name
+    reqs=${reqs},domain-name-servers,domain-search
+    reqs=${reqs},host-name,root-path,interface-mtu
+
+    for i in ip srv gw mask hostname; do
+       eval '[ "$'$i'" ] && echo '$i'="$'$i'"'
+    done > /net.$netif.override
+    [ -n "$ip" ] && echo bcast= >> /net.$netif.override
+
+    # /sbin/dhclient-script will mark the netif up and generate the online
+    # event for nfsroot
+    # XXX add -V vendor class and option parsing per kernel
+    dhclient -1 -q -R ${reqs} -pf /dhclient.$netif.pid $netif
+}
+
+ip_to_var() {
+    local v=${1}:
+    set --
+    while [ -n "$v" ]; do
+       set -- "$@" "${v%%:*}"
+       v=${v#*:}
+    done
+
+    unset ip srv gw mask hostname dev autoconf
+    case $# in
+    0) autoconf=off ;;
+    1) autoconf=$1 ;;
+    2) dev=$1; autoconf=$2 ;;
+    *) ip=$1; srv=$2; gw=$3; mask=$4; hostname=$5; dev=$6; autoconf=$7
+       case $autoconf in
+           ''|none|off) [ -n "$ip" ] && autoconf=static ;;
+       esac
+    esac
+    [ -n "$dev" ] || dev=$netif
+    [ -n "$autoconf" ] || autoconf=off
+}
+
 # spin through the kernel command line, looking for ip= lines
 for p in $(cat /proc/cmdline); do
-    [ "${p%%=*}" = "ip" ] || continue
-    ip=${p#ip=}
-    case $ip 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} | \
-           (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;;
+    [ -n "${p%ip=*}" ] && continue
+    ip_to_var ${p#ip=}
+
+    # If this option isn't directed at our interface, skip it
+    [ "$dev" = "$netif" ] || continue
+
+    case $autoconf in
+       static)          do_static ;;
+       dhcp|on|any)     do_dhcp ;;
+       bootp|rarp|both) die "autoconfig type $autoconf is not supported" ;;
+       ''|none|off)     ;;
     esac
+    break
 done
+exit 0
index c0c13fc..7a13348 100755 (executable)
@@ -1,10 +1,9 @@
 #!/bin/bash
-dracut_install ip dhclient grep
+dracut_install ip dhclient hostname
 instmods ${modules:-=net}
 inst "$moddir/ifup" "/sbin/ifup"
 inst "$moddir/dhclient-script" "/sbin/dhclient-script"
 instmods =networking ecb arc4
 inst_rules "$moddir/60-net.rules"
 inst_hook pre-pivot 10 "$moddir/kill-dhclient.sh"
-inst_hook pre-mount 70 "$moddir/run-dhclient.sh"
 mkdir -p "${initdir}/var/run"
index 70deda6..d1d15f4 100755 (executable)
@@ -1,4 +1,5 @@
 #!/bin/sh
 
-pid=$(pidof dhclient)
-[ -n "$pid" ] && kill $pid
+for f in /dhclient.*.pid; do
+    [ "$f" != "/dhclient.*.pid" ] && kill $(cat $f)
+done
diff --git a/modules.d/40network/run-dhclient.sh b/modules.d/40network/run-dhclient.sh
deleted file mode 100755 (executable)
index bc32883..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-for i in /net.*.dhcp; do
-    [ "$i" = '/net.*.dhcp' ] && break
-    dev=${i#/net.}; dev=${dev%.dhcp}
-    [ -f "/net.$dev.up" ] && continue
-    dhclient  -R 'subnet-mask,broadcast-address,time-offset,routers,domain-name,domain-name-servers,host-name,nis-domain,nis-servers,ntp-servers,root-path' -1 -q $dev &
-done
-wait
-