Bridged network boot
authorWarren Togami <wtogami@redhat.com>
Thu, 16 Jul 2009 20:58:19 +0000 (16:58 -0400)
committerWarren Togami <wtogami@redhat.com>
Thu, 16 Jul 2009 20:58:19 +0000 (16:58 -0400)
* SYNTAX
bridge=<bridgename>:<ethname>
If bridge without parameters, assume bridge=br0:eth0
* When <ethname> would be configured by network scripts, instead create a bridge named <bridgename> then add <ethname> to that bridge.
* Then $netif becomes <bridgename> instead of <ethname> and all existing scripts process netroot mount via this new $netif instead of <ethname>.
* Include a few test cases in NFS and NBD

modules.d/40network/check
modules.d/40network/ifup
modules.d/40network/install
modules.d/40network/net-genrules.sh
modules.d/40network/parse-bridge.sh [new file with mode: 0644]
modules.d/40network/write-ifcfg.sh
test/TEST-20-NFS/test.sh
test/TEST-40-NBD/test.sh

index 79a6d97..3d45030 100755 (executable)
@@ -1,4 +1,4 @@
 #!/bin/sh
-which ip dhclient hostname >/dev/null 2>&1 || exit 1
+which ip dhclient hostname brctl >/dev/null 2>&1 || exit 1
 exit 255
 
index 89017bb..0450855 100755 (executable)
@@ -60,6 +60,14 @@ fi
 # $netif reads easier than $1
 netif=$1
 
+# bridge this interface?
+if [ -e /tmp/bridge.info ]; then
+    . /tmp/bridge.info
+    if [ "$netif" = "$ethname" ]; then
+        netif="$bridgename"
+    fi
+fi
+
 # bail immediately if the interface is already up
 # or we don't need the network
 [ -f "/tmp/net.$netif.up" ] && exit 0
@@ -77,6 +85,15 @@ fi
 
 # XXX need error handling like dhclient-script
 
+# start bridge if necessary
+if [ "$netif" = "$bridgename" ] && [ ! -e /tmp/net.$bridgename.up ]; then
+    ip link set $ethname up
+    # Create bridge and add eth to bridge
+    brctl addbr $bridgename
+    brctl setfd $bridgename 0
+    brctl addif $bridgename $ethname
+fi
+
 # No ip lines default to dhcp
 ip=$(getarg ip)
 [ -z "$ip" ] && do_dhcp;
index 0b76cbd..729f1f1 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/bash
-dracut_install ip dhclient hostname
+dracut_install ip dhclient hostname brctl
 # Include wired net drivers, excluding wireless
 for modname in $(find "/lib/modules/$kernel/kernel/drivers" -name '*.ko'); do
   if nm -uPA $modname | grep -q eth_type_trans; then
@@ -15,9 +15,12 @@ inst "$moddir/netroot" "/sbin/netroot"
 inst "$moddir/dhclient-script" "/sbin/dhclient-script"
 inst "$moddir/dhclient.conf" "/etc/dhclient.conf" 
 instmods ecb arc4
+# bridge modules
+instmods bridge stp llc
 inst_hook pre-udev 60 "$moddir/net-genrules.sh"
 inst_hook cmdline 91 "$moddir/dhcp-root.sh"
 inst_hook cmdline 99 "$moddir/parse-ip-opts.sh"
+inst_hook cmdline 98 "$moddir/parse-bridge.sh"
 inst_hook pre-pivot 10 "$moddir/kill-dhclient.sh"
 
 # TODO ifcfg config style is redhat specific, this should probably
index dbd0474..04e0528 100755 (executable)
@@ -14,6 +14,11 @@ fix_bootif() {
 
 # Write udev rules
 {
+    # bridge: attempt only the defined interface
+    if [ -e /tmp/bridge.info ]; then
+        . /tmp/bridge.info
+        IFACES=$ethname
+    fi
 
     # BOOTIF says everything, use only that one
     BOOTIF=$(getarg 'BOOTIF=')
diff --git a/modules.d/40network/parse-bridge.sh b/modules.d/40network/parse-bridge.sh
new file mode 100644 (file)
index 0000000..494da2d
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Format:
+#      bridge=<bridgename>:<ethname>
+#
+#      bridge without parameters assumes bridge=br0:eth0
+#
+
+# return if bridge already parsed
+[ -n "$bridgename" ] && return
+
+# Check if bridge parameter is valid 
+if getarg ip= >/dev/null ; then
+    if [ -z "$netroot" ] ; then
+       die "No netboot configured, bridge is invalid"
+    fi
+fi
+
+parsebridge() {
+    local v=${1}:
+    set --
+    while [ -n "$v" ]; do
+        set -- "$@" "${v%%:*}"
+        v=${v#*:}
+    done
+
+    unset bridgename ethname
+    case $# in
+    0)  bridgename=br0; ethname=eth0 ;;
+    1)  die "bridge= requires two parameters" ;;
+    2)  bridgename=$1; ethname=$2 ;;
+    *)  die "bridge= requires two parameters" ;;
+    esac
+}
+
+unset bridgename ethname
+
+# Parse bridge for bridgename and ethname
+if getarg bridge >/dev/null; then
+    # Read bridge= parameters if they exist
+    bridge="$(getarg bridge=)"
+    if [ ! "$bridge" = "bridge" ]; then 
+        parsebridge "$(getarg bridge=)"
+    fi
+    # Simple default bridge
+    if [ -z "$bridgename" ]; then
+        bridgename=br0
+        ethname=eth0
+    fi
+    echo "bridgename=$bridgename" > /tmp/bridge.info
+    echo "ethname=$ethname" >> /tmp/bridge.info
+    return
+fi
index c408076..4fa59e0 100755 (executable)
@@ -6,11 +6,14 @@
 read IFACES < /tmp/net.ifaces
 
 for netif in $IFACES ; do
+    # bridge?
+    unset bridge
+    if [ "$netif" = "$bridgename" ]; then
+        bridge=yes
+    fi
     cat /sys/class/net/$netif/address > /tmp/net.$netif.hwaddr
     echo "# Generated by dracut initrd" > /tmp/net.$netif.ifcfg
     echo "DEVICE=$netif" >> /tmp/net.$netif.ifcfg
-    echo "HWADDR=$(cat /sys/class/net/$netif/address)" >> /tmp/net.$netif.ifcfg
-    echo "TYPE=Ethernet" >> /tmp/net.$netif.ifcfg
     echo "ONBOOT=yes" >> /tmp/net.$netif.ifcfg
     if [ -f /tmp/net.$netif.lease ]; then
        echo "BOOTPROTO=dhcp" >> /tmp/net.$netif.ifcfg
@@ -22,4 +25,23 @@ for netif in $IFACES ; do
        echo "NETMASK=$mask" >> /tmp/net.$netif.ifcfg
        [ -n "$gw" ] && echo "GATEWAY=$gw" >> /tmp/net.$netif.ifcfg
     fi
+
+    # bridge needs differente things written to ifcfg
+    if [ -z "$bridge" ]; then
+        # standard interface
+        echo "HWADDR=$(cat /sys/class/net/$netif/address)" >> /tmp/net.$netif.ifcfg
+        echo "TYPE=Ethernet" >> /tmp/net.$netif.ifcfg
+        echo "NAME=\"Boot Disk\"" >> /tmp/net.$netif.ifcfg
+    else
+        # bridge
+       echo "TYPE=Bridge" >> /tmp/net.$netif.ifcfg
+        echo "NAME=\"Boot Disk\"" >> /tmp/net.$netif.ifcfg
+        # write separate ifcfg file for the raw eth interface
+        echo "DEVICE=$ethname" >> /tmp/net.$ethname.ifcfg
+        echo "TYPE=Ethernet" >> /tmp/net.$ethname.ifcfg
+        echo "ONBOOT=yes" >> /tmp/net.$ethname.ifcfg
+        echo "HWADDR=$(cat /sys/class/net/$ethname/address)" >> /tmp/net.$ethname.ifcfg
+        echo "BRIDGE=$netif" >> /tmp/net.$ethname.ifcfg
+        echo "NAME=$ethname" >> /tmp/net.$ethname.ifcfg
+    fi
 done
index 1811eca..cd81424 100755 (executable)
@@ -125,6 +125,9 @@ test_nfsv3() {
     client_test "NFSv3 root=nfs:..." 52:54:00:12:34:04 \
        "root=nfs:192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1
 
+    client_test "NFSv3 Bridge root=nfs:..." 52:54:00:12:34:04 \
+       "root=nfs:192.168.50.1:/nfs/client bridge" 192.168.50.1 -wsize=4096 || return 1
+
     client_test "NFSv3 Legacy root=IP:path" 52:54:00:12:34:04 \
        "root=192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1
 
@@ -135,6 +138,9 @@ test_nfsv3() {
     client_test "NFSv3 root=dhcp DHCP path,options" \
        52:54:00:12:34:05 "root=dhcp" 192.168.50.1 wsize=4096 || return 1
 
+    client_test "NFSv3 Bridge Customized root=dhcp DHCP path,options" \
+       52:54:00:12:34:05 "root=dhcp bridge=foobr0:eth0" 192.168.50.1 wsize=4096 || return 1
+
     client_test "NFSv3 root=dhcp DHCP IP:path,options" \
        52:54:00:12:34:06 "root=dhcp" 192.168.50.2 wsize=4096 || return 1
 
index c3d8bfc..b3a580f 100755 (executable)
@@ -106,6 +106,10 @@ test_run() {
        "root=nbd:192.168.50.1:2000:ext2:errors=panic" \
        ext2 errors=panic || return 1
 
+     client_test "NBD Bridge root=nbd:IP:port:fstype:fsopts" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:ext2:errors=panic bridge" \
+       ext2 errors=panic || return 1
+
      # There doesn't seem to be a good way to validate the NBD options, so
      # just check that we don't screw up the other options
 
@@ -125,6 +129,9 @@ test_run() {
     client_test "NBD root=dhcp DHCP root-path nbd:srv:port" 52:54:00:12:34:01 \
        "root=dhcp" || return 1
 
+    client_test "NBD Bridge root=dhcp DHCP root-path nbd:srv:port" 52:54:00:12:34:01 \
+       "root=dhcp bridge" || return 1
+
     client_test "NBD root=dhcp DHCP root-path nbd:srv:port:fstype" \
        52:54:00:12:34:02 "root=dhcp" ext2 || return 1