a0a3b4
From 7a90c8b3434a27a347f6a963d0e673e04feb485a Mon Sep 17 00:00:00 2001
a0a3b4
From: Harald Hoyer <harald@redhat.com>
a0a3b4
Date: Mon, 4 Jul 2016 11:31:49 +0200
a0a3b4
Subject: [PATCH] network: support multiple vlan, team, bridge and bond
a0a3b4
a0a3b4
---
49e6a8
 modules.d/40network/ifup.sh         | 386 ++++++++++++++--------------
49e6a8
 modules.d/40network/net-genrules.sh |  27 +-
a0a3b4
 modules.d/40network/net-lib.sh      |   9 +-
a0a3b4
 modules.d/40network/parse-bridge.sh |  30 +--
49e6a8
 modules.d/40network/parse-team.sh   |  47 +---
49e6a8
 modules.d/40network/parse-vlan.sh   |  27 +-
49e6a8
 modules.d/45ifcfg/write-ifcfg.sh    |  26 +-
a0a3b4
 7 files changed, 254 insertions(+), 298 deletions(-)
a0a3b4
a0a3b4
diff --git a/modules.d/40network/ifup.sh b/modules.d/40network/ifup.sh
1755ca
index cedf9a77..d7503c7f 100755
a0a3b4
--- a/modules.d/40network/ifup.sh
a0a3b4
+++ b/modules.d/40network/ifup.sh
a0a3b4
@@ -17,79 +17,12 @@ type ip_to_var >/dev/null 2>&1 || . /lib/net-lib.sh
a0a3b4
 
a0a3b4
 # $netif reads easier than $1
a0a3b4
 netif=$1
a0a3b4
-use_bridge='false'
a0a3b4
-use_vlan='false'
a0a3b4
 
a0a3b4
-# enslave this interface to bond?
a0a3b4
-for i in /tmp/bond.*.info; do
a0a3b4
-    [ -e "$i" ] || continue
a0a3b4
-    unset bondslaves
a0a3b4
-    unset bondname
a0a3b4
-    . "$i"
a0a3b4
-    for slave in $bondslaves ; do
a0a3b4
-        if [ "$netif" = "$slave" ] ; then
a0a3b4
-            netif=$bondname
a0a3b4
-            break 2
a0a3b4
-        fi
a0a3b4
-    done
a0a3b4
-done
a0a3b4
-
a0a3b4
-for i in /tmp/team.*.info; do
a0a3b4
-    [ -e "$i" ] || continue
a0a3b4
-    unset teamslaves
a0a3b4
-    unset teammaster
a0a3b4
-    . "$i"
a0a3b4
-    for slave in $teamslaves ; do
a0a3b4
-        if [ "$netif" = "$slave" ] ; then
a0a3b4
-            netif=$teammaster
a0a3b4
-        fi
a0a3b4
-    done
a0a3b4
-done
a0a3b4
-
a0a3b4
-if [ -e /tmp/vlan.info ]; then
a0a3b4
-    . /tmp/vlan.info
a0a3b4
-    if [ "$netif" = "$phydevice" ]; then
a0a3b4
-        if [ "$netif" = "$bondname" ] && [ -n "$DO_BOND_SETUP" ] ; then
a0a3b4
-            : # We need to really setup bond (recursive call)
a0a3b4
-        elif [ "$netif" = "$teammaster" ] && [ -n "$DO_TEAM_SETUP" ] ; then
a0a3b4
-            : # We need to really setup team (recursive call)
a0a3b4
-        else
a0a3b4
-            netif="$vlanname"
a0a3b4
-            use_vlan='true'
a0a3b4
-        fi
a0a3b4
-    fi
a0a3b4
-fi
a0a3b4
-
a0a3b4
-# bridge this interface?
a0a3b4
-if [ -e /tmp/bridge.info ]; then
a0a3b4
-    . /tmp/bridge.info
a0a3b4
-    for ethname in $bridgeslaves ; do
a0a3b4
-        if [ "$netif" = "$ethname" ]; then
a0a3b4
-            if [ "$netif" = "$bondname" ] && [ -n "$DO_BOND_SETUP" ] ; then
a0a3b4
-                : # We need to really setup bond (recursive call)
a0a3b4
-            elif [ "$netif" = "$teammaster" ] && [ -n "$DO_TEAM_SETUP" ] ; then
a0a3b4
-                : # We need to really setup team (recursive call)
a0a3b4
-            elif [ "$netif" = "$vlanname" ] && [ -n "$DO_VLAN_SETUP" ]; then
a0a3b4
-                : # We need to really setup vlan (recursive call)
a0a3b4
-            else
a0a3b4
-                netif="$bridgename"
a0a3b4
-                use_bridge='true'
a0a3b4
-            fi
a0a3b4
-        fi
a0a3b4
-    done
a0a3b4
-fi
a0a3b4
-
a0a3b4
-# disable manual ifup while netroot is set for simplifying our logic
a0a3b4
-# in netroot case we prefer netroot to bringup $netif automaticlly
a0a3b4
-[ -n "$2" -a "$2" = "-m" ] && [ -z "$netroot" ] && manualup="$2"
a0a3b4
-
a0a3b4
-if [ -n "$manualup" ]; then
a0a3b4
-    >/tmp/net.$netif.manualup
a0a3b4
-    rm -f /tmp/net.${netif}.did-setup
a0a3b4
-else
a0a3b4
-    [ -e /tmp/net.${netif}.did-setup ] && exit 0
a0a3b4
-    [ -e /sys/class/net/$netif/address ] && \
a0a3b4
-        [ -e /tmp/net.$(cat /sys/class/net/$netif/address).did-setup ] && exit 0
a0a3b4
+# loopback is always handled the same way
a0a3b4
+if [ "$netif" = "lo" ] ; then
a0a3b4
+    ip link set lo up
a0a3b4
+    ip addr add 127.0.0.1/8 dev lo
a0a3b4
+    exit 0
a0a3b4
 fi
a0a3b4
 
a0a3b4
 # Run dhclient
a0a3b4
@@ -199,158 +132,213 @@ do_static() {
a0a3b4
     return 0
a0a3b4
 }
a0a3b4
 
a0a3b4
-# loopback is always handled the same way
a0a3b4
-if [ "$netif" = "lo" ] ; then
a0a3b4
-    ip link set lo up
a0a3b4
-    ip addr add 127.0.0.1/8 dev lo
a0a3b4
+get_vid() {
a0a3b4
+    case "$1" in
a0a3b4
+    vlan*)
a0a3b4
+        echo ${1#vlan}
a0a3b4
+        ;;
a0a3b4
+    *.*)
a0a3b4
+        echo ${1##*.}
a0a3b4
+        ;;
a0a3b4
+    esac
a0a3b4
+}
a0a3b4
+
a0a3b4
+# check, if we need VLAN's for this interface
a0a3b4
+if [ -z "$DO_VLAN_PHY" ] && [ -e /tmp/vlan.${netif}.phy ]; then
a0a3b4
+    unset DO_VLAN
a0a3b4
+    NO_AUTO_DHCP=yes DO_VLAN_PHY=yes ifup "$netif"
a0a3b4
+    modprobe -b -q 8021q
a0a3b4
+
a0a3b4
+    for i in /tmp/vlan.*.${netif}; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        read vlanname < "$i"
a0a3b4
+        if [ -n "$vlanname" ]; then
a0a3b4
+            linkup "$netif"
a0a3b4
+            ip link add dev "$vlanname" link "$netif" type vlan id "$(get_vid $vlanname)"
a0a3b4
+            ifup "$vlanname"
a0a3b4
+        fi
a0a3b4
+    done
a0a3b4
     exit 0
a0a3b4
 fi
a0a3b4
 
a0a3b4
-# start bond if needed
a0a3b4
-if [ -e /tmp/bond.${netif}.info ]; then
a0a3b4
-    . /tmp/bond.${netif}.info
a0a3b4
+# Check, if interface is VLAN interface
a0a3b4
+if ! [ -e /tmp/vlan.${netif}.phy ]; then
a0a3b4
+    for i in /tmp/vlan.${netif}.*; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        export DO_VLAN=yes
a0a3b4
+        break
a0a3b4
+    done
a0a3b4
+fi
a0a3b4
 
a0a3b4
-    if [ "$netif" = "$bondname" ] && [ ! -e /tmp/net.$bondname.setup ] ; then # We are master bond device
a0a3b4
-        modprobe bonding
a0a3b4
-        udevadm settle
a0a3b4
-        if ! [ -e /sys/class/net/${netif} ]; then
a0a3b4
-            echo "+$netif" >  /sys/class/net/bonding_masters
a0a3b4
-        fi
a0a3b4
-        ip link set $netif down
a0a3b4
-
a0a3b4
-        # Stolen from ifup-eth
a0a3b4
-        # add the bits to setup driver parameters here
a0a3b4
-        for arg in $bondoptions ; do
a0a3b4
-            key=${arg%%=*};
a0a3b4
-            value=${arg##*=};
a0a3b4
-            # %{value:0:1} is replaced with non-bash specific construct
a0a3b4
-            if [ "${key}" = "arp_ip_target" -a "${#value}" != "0" -a "+${value%%+*}" != "+" ]; then
a0a3b4
-                OLDIFS=$IFS;
a0a3b4
-                IFS=',';
a0a3b4
-                for arp_ip in $value; do
a0a3b4
-                    echo +$arp_ip > /sys/class/net/${netif}/bonding/$key
a0a3b4
-                done
a0a3b4
-                IFS=$OLDIFS;
a0a3b4
-            else
a0a3b4
-                echo $value > /sys/class/net/${netif}/bonding/$key
a0a3b4
+# bridge this interface?
a0a3b4
+if [ -z "$NO_BRIDGE_MASTER" ]; then
a0a3b4
+    for i in /tmp/bridge.*.info; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        unset bridgeslaves
a0a3b4
+        unset bridgename
a0a3b4
+        . "$i"
a0a3b4
+        for ethname in $bridgeslaves ; do
a0a3b4
+            [ "$netif" != "$ethname" ] && continue
a0a3b4
+
a0a3b4
+            NO_BRIDGE_MASTER=yes NO_AUTO_DHCP=yes ifup $ethname
a0a3b4
+            linkup $ethname
a0a3b4
+            if [ ! -e /tmp/bridge.$bridgename.up ]; then
a0a3b4
+                brctl addbr $bridgename
a0a3b4
+                brctl setfd $bridgename 0
a0a3b4
+                > /tmp/bridge.$bridgename.up
a0a3b4
             fi
a0a3b4
+            brctl addif $bridgename $ethname
a0a3b4
+            ifup $bridgename
a0a3b4
+            exit 0
a0a3b4
         done
a0a3b4
+    done
a0a3b4
+fi
a0a3b4
 
a0a3b4
-        linkup $netif
a0a3b4
-
a0a3b4
+# enslave this interface to bond?
a0a3b4
+if [ -z "$NO_BOND_MASTER" ]; then
a0a3b4
+    for i in /tmp/bond.*.info; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        unset bondslaves
a0a3b4
+        unset bondname
a0a3b4
+        . "$i"
a0a3b4
         for slave in $bondslaves ; do
a0a3b4
-            ip link set $slave down
a0a3b4
-            cat /sys/class/net/$slave/address > /tmp/net.${netif}.${slave}.hwaddr
a0a3b4
-            echo "+$slave" > /sys/class/net/$bondname/bonding/slaves
a0a3b4
-            linkup $slave
a0a3b4
-        done
a0a3b4
+            [ "$netif" != "$slave" ] && continue
a0a3b4
 
a0a3b4
-        # add the bits to setup the needed post enslavement parameters
a0a3b4
-        for arg in $BONDING_OPTS ; do
a0a3b4
-            key=${arg%%=*};
a0a3b4
-            value=${arg##*=};
a0a3b4
-            if [ "${key}" = "primary" ]; then
a0a3b4
-                echo $value > /sys/class/net/${netif}/bonding/$key
a0a3b4
-            fi
a0a3b4
+            # already setup
a0a3b4
+            [ -e /tmp/bond.$bondname.up ] && exit 0
a0a3b4
+
a0a3b4
+            # wait for all slaves to show up
a0a3b4
+            for slave in $bondslaves ; do
a0a3b4
+                # try to create the slave (maybe vlan or bridge)
a0a3b4
+                NO_BOND_MASTER=yes NO_AUTO_DHCP=yes ifup $slave
a0a3b4
+
a0a3b4
+                if ! ip link show dev $slave >/dev/null 2>&1; then
a0a3b4
+                    # wait for the last slave to show up
a0a3b4
+                    exit 0
a0a3b4
+                fi
a0a3b4
+            done
a0a3b4
+
a0a3b4
+            modprobe -q -b bonding
a0a3b4
+            echo "+$bondname" >  /sys/class/net/bonding_masters 2>/dev/null
a0a3b4
+            ip link set $bondname down
a0a3b4
+
a0a3b4
+            # Stolen from ifup-eth
a0a3b4
+            # add the bits to setup driver parameters here
a0a3b4
+            for arg in $bondoptions ; do
a0a3b4
+                key=${arg%%=*};
a0a3b4
+                value=${arg##*=};
a0a3b4
+                # %{value:0:1} is replaced with non-bash specific construct
a0a3b4
+                if [ "${key}" = "arp_ip_target" -a "${#value}" != "0" -a "+${value%%+*}" != "+" ]; then
a0a3b4
+                    OLDIFS=$IFS;
a0a3b4
+                    IFS=',';
a0a3b4
+                    for arp_ip in $value; do
a0a3b4
+                        echo +$arp_ip > /sys/class/net/${bondname}/bonding/$key
a0a3b4
+                    done
a0a3b4
+                    IFS=$OLDIFS;
a0a3b4
+                else
a0a3b4
+                    echo $value > /sys/class/net/${bondname}/bonding/$key
a0a3b4
+                fi
a0a3b4
+            done
a0a3b4
+
a0a3b4
+            linkup $bondname
a0a3b4
+
a0a3b4
+            for slave in $bondslaves ; do
a0a3b4
+                cat /sys/class/net/$slave/address > /tmp/net.${bondname}.${slave}.hwaddr
a0a3b4
+                ip link set $slave down
a0a3b4
+                echo "+$slave" > /sys/class/net/$bondname/bonding/slaves
a0a3b4
+                linkup $slave
a0a3b4
+            done
a0a3b4
+
a0a3b4
+            # add the bits to setup the needed post enslavement parameters
a0a3b4
+            for arg in $bondoptions ; do
a0a3b4
+                key=${arg%%=*};
a0a3b4
+                value=${arg##*=};
a0a3b4
+                if [ "${key}" = "primary" ]; then
a0a3b4
+                    echo $value > /sys/class/net/${bondname}/bonding/$key
a0a3b4
+                fi
a0a3b4
+            done
a0a3b4
+
a0a3b4
+            > /tmp/bond.$bondname.up
a0a3b4
+
a0a3b4
+            NO_BOND_MASTER=yes ifup $bondname
a0a3b4
+            exit $?
a0a3b4
         done
a0a3b4
-        > /tmp/net.$bondname.setup
a0a3b4
-    fi
a0a3b4
+    done
a0a3b4
 fi
a0a3b4
 
a0a3b4
-if [ -e /tmp/team.${netif}.info ]; then
a0a3b4
-    . /tmp/team.${netif}.info
a0a3b4
-    if [ "$netif" = "$teammaster" ] && [ ! -e /tmp/net.$teammaster.setup ] ; then
a0a3b4
-        # We shall only bring up those _can_ come up
a0a3b4
-        # in case of some slave is gone in active-backup mode
a0a3b4
-        working_slaves=""
a0a3b4
+if [ -z "$NO_TEAM_MASTER" ]; then
a0a3b4
+    for i in /tmp/team.*.info; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        unset teammaster
a0a3b4
+        unset teamslaves
a0a3b4
+        . "$i"
a0a3b4
         for slave in $teamslaves ; do
a0a3b4
-            teamdctl ${teammaster} port present ${slave} 2>/dev/null \
a0a3b4
-                     && continue
a0a3b4
-            ip link set dev $slave up 2>/dev/null
a0a3b4
-            if wait_for_if_up $slave; then
a0a3b4
-                working_slaves+="$slave "
a0a3b4
-            fi
a0a3b4
-        done
a0a3b4
-        # Do not add slaves now
a0a3b4
-        teamd -d -U -n -N -t $teammaster -f /etc/teamd/$teammaster.conf
a0a3b4
-        for slave in $working_slaves; do
a0a3b4
-            # team requires the slaves to be down before joining team
a0a3b4
-            ip link set dev $slave down
a0a3b4
-            (
a0a3b4
-                unset TEAM_PORT_CONFIG
a0a3b4
-                _hwaddr=$(cat /sys/class/net/$slave/address)
a0a3b4
-                _subchannels=$(iface_get_subchannels "$slave")
a0a3b4
-                if [ -n "$_hwaddr" ] && [ -e "/etc/sysconfig/network-scripts/mac-${_hwaddr}.conf" ]; then
a0a3b4
-                    . "/etc/sysconfig/network-scripts/mac-${_hwaddr}.conf"
a0a3b4
-                elif [ -n "$_subchannels" ] && [ -e "/etc/sysconfig/network-scripts/ccw-${_subchannels}.conf" ]; then
a0a3b4
-                    . "/etc/sysconfig/network-scripts/ccw-${_subchannels}.conf"
a0a3b4
-                elif [ -e "/etc/sysconfig/network-scripts/ifcfg-${slave}" ]; then
a0a3b4
-                    . "/etc/sysconfig/network-scripts/ifcfg-${slave}"
a0a3b4
-                fi
a0a3b4
+            [ "$netif" != "$slave" ] && continue
a0a3b4
+
a0a3b4
+            [ -e /tmp/team.$teammaster.up ] && exit 0
a0a3b4
 
a0a3b4
-                if [ -n "${TEAM_PORT_CONFIG}" ]; then
a0a3b4
-                    /usr/bin/teamdctl ${teammaster} port config update ${slave} "${TEAM_PORT_CONFIG}"
a0a3b4
+            # wait for all slaves to show up
a0a3b4
+            for slave in $teamslaves ; do
a0a3b4
+                # try to create the slave (maybe vlan or bridge)
a0a3b4
+                NO_BOND_MASTER=yes NO_AUTO_DHCP=yes ifup $slave
a0a3b4
+
a0a3b4
+                if ! ip link show dev $slave >/dev/null 2>&1; then
a0a3b4
+                    # wait for the last slave to show up
a0a3b4
+                    exit 0
a0a3b4
                 fi
a0a3b4
-            )
a0a3b4
-            teamdctl $teammaster port add $slave
a0a3b4
-        done
a0a3b4
-        ip link set dev $teammaster up
a0a3b4
-        > /tmp/net.$teammaster.setup
a0a3b4
-    fi
a0a3b4
-fi
a0a3b4
+            done
a0a3b4
+
a0a3b4
+            if [ ! -e /tmp/team.$teammaster.up ] ; then
a0a3b4
+                # We shall only bring up those _can_ come up
a0a3b4
+                # in case of some slave is gone in active-backup mode
a0a3b4
+                working_slaves=""
a0a3b4
+                for slave in $teamslaves ; do
a0a3b4
+                    ip link set $slave up 2>/dev/null
a0a3b4
+                    if wait_for_if_up $slave; then
a0a3b4
+                        working_slaves="$working_slaves$slave "
a0a3b4
+                    fi
a0a3b4
+                done
a0a3b4
+                # Do not add slaves now
a0a3b4
+                teamd -d -U -n -N -t $teammaster -f /etc/teamd/$teammaster.conf
a0a3b4
+                for slave in $working_slaves; do
a0a3b4
+                    # team requires the slaves to be down before joining team
a0a3b4
+                    ip link set $slave down
a0a3b4
+                    teamdctl $teammaster port add $slave
a0a3b4
+                done
a0a3b4
 
a0a3b4
-# XXX need error handling like dhclient-script
a0a3b4
+                ip link set $teammaster up
a0a3b4
 
a0a3b4
-if [ -e /tmp/bridge.info ]; then
a0a3b4
-    . /tmp/bridge.info
a0a3b4
-# start bridge if necessary
a0a3b4
-    if [ "$netif" = "$bridgename" ] && [ ! -e /tmp/net.$bridgename.setup ]; then
a0a3b4
-        brctl addbr $bridgename
a0a3b4
-        brctl setfd $bridgename 0
a0a3b4
-        for ethname in $bridgeslaves ; do
a0a3b4
-            if [ "$ethname" = "$bondname" ] ; then
a0a3b4
-                DO_BOND_SETUP=yes ifup $bondname -m
a0a3b4
-            elif [ "$ethname" = "$teammaster" ] ; then
a0a3b4
-                DO_TEAM_SETUP=yes ifup $teammaster -m
a0a3b4
-            elif [ "$ethname" = "$vlanname" ]; then
a0a3b4
-                DO_VLAN_SETUP=yes ifup $vlanname -m
a0a3b4
-            else
a0a3b4
-                linkup $ethname
a0a3b4
+                > /tmp/team.$teammaster.up
a0a3b4
+                NO_TEAM_MASTER=yes ifup $teammaster
a0a3b4
+                exit $?
a0a3b4
             fi
a0a3b4
-            brctl addif $bridgename $ethname
a0a3b4
         done
a0a3b4
-        > /tmp/net.$bridgename.setup
a0a3b4
-    fi
a0a3b4
+    done
a0a3b4
 fi
a0a3b4
 
a0a3b4
-get_vid() {
a0a3b4
-    case "$1" in
a0a3b4
-    vlan*)
a0a3b4
-        echo ${1#vlan}
a0a3b4
-        ;;
a0a3b4
-    *.*)
a0a3b4
-        echo ${1##*.}
a0a3b4
-        ;;
a0a3b4
-    esac
a0a3b4
-}
a0a3b4
+# all synthetic interfaces done.. now check if the interface is available
a0a3b4
+if ! ip link show dev $netif >/dev/null 2>&1; then
a0a3b4
+    exit 1
a0a3b4
+fi
a0a3b4
 
a0a3b4
-if [ "$netif" = "$vlanname" ] && [ ! -e /tmp/net.$vlanname.up ]; then
a0a3b4
-    modprobe 8021q
a0a3b4
-    if [ "$phydevice" = "$bondname" ] ; then
a0a3b4
-        DO_BOND_SETUP=yes ifup $phydevice -m
a0a3b4
-    elif [ "$phydevice" = "$teammaster" ] ; then
a0a3b4
-        DO_TEAM_SETUP=yes ifup $phydevice -m
a0a3b4
-    else
a0a3b4
-        linkup "$phydevice"
a0a3b4
-    fi
a0a3b4
-    ip link add dev "$vlanname" link "$phydevice" type vlan id "$(get_vid $vlanname)"
a0a3b4
-    ip link set "$vlanname" up
a0a3b4
+# disable manual ifup while netroot is set for simplifying our logic
a0a3b4
+# in netroot case we prefer netroot to bringup $netif automaticlly
a0a3b4
+[ -n "$2" -a "$2" = "-m" ] && [ -z "$netroot" ] && manualup="$2"
a0a3b4
+
a0a3b4
+if [ -n "$manualup" ]; then
a0a3b4
+    >/tmp/net.$netif.manualup
a0a3b4
+    rm -f /tmp/net.${netif}.did-setup
a0a3b4
+else
a0a3b4
+    [ -e /tmp/net.${netif}.did-setup ] && exit 0
a0a3b4
+    [ -z "$DO_VLAN" ] && \
a0a3b4
+        [ -e /sys/class/net/$netif/address ] && \
a0a3b4
+        [ -e /tmp/net.$(cat /sys/class/net/$netif/address).did-setup ] && exit 0
a0a3b4
 fi
a0a3b4
 
a0a3b4
 # No ip lines default to dhcp
a0a3b4
 ip=$(getarg ip)
a0a3b4
 
a0a3b4
-if [ -z "$ip" ]; then
a0a3b4
+if [ -z "$NO_AUTO_DHCP" ] && [ -z "$ip" ]; then
a0a3b4
     if [ "$netroot" = "dhcp6" ]; then
a0a3b4
         do_dhcp -6
a0a3b4
     else
a0a3b4
@@ -415,7 +403,7 @@ for p in $(getargs ip=); do
a0a3b4
     if [ $ret -eq 0 ]; then
a0a3b4
         > /tmp/net.${netif}.up
a0a3b4
 
a0a3b4
-        if [ -e /sys/class/net/${netif}/address ]; then
a0a3b4
+        if [ -z "$DO_VLAN" ] && [ -e /sys/class/net/${netif}/address ]; then
a0a3b4
             > /tmp/net.$(cat /sys/class/net/${netif}/address).up
a0a3b4
         fi
a0a3b4
 
a0a3b4
@@ -444,7 +432,7 @@ if [ -n "$DO_BOND_SETUP" -o -n "$DO_TEAM_SETUP" -o -n "$DO_VLAN_SETUP" ]; then
a0a3b4
 fi
a0a3b4
 
a0a3b4
 # no ip option directed at our interface?
a0a3b4
-if [ ! -e /tmp/net.${netif}.up ]; then
a0a3b4
+if  [ -z "$NO_AUTO_DHCP" ] && [ ! -e /tmp/net.${netif}.up ]; then
a0a3b4
     if [ -e /tmp/net.bootdev ]; then
a0a3b4
         BOOTDEV=$(cat /tmp/net.bootdev)
a0a3b4
         if [ "$netif" = "$BOOTDEV" ] || [ "$BOOTDEV" = "$(cat /sys/class/net/${netif}/address)" ]; then
a0a3b4
diff --git a/modules.d/40network/net-genrules.sh b/modules.d/40network/net-genrules.sh
1755ca
index 526dd5cf..08072fbe 100755
a0a3b4
--- a/modules.d/40network/net-genrules.sh
a0a3b4
+++ b/modules.d/40network/net-genrules.sh
a0a3b4
@@ -1,6 +1,4 @@
a0a3b4
 #!/bin/sh
a0a3b4
-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
a0a3b4
-# ex: ts=8 sw=4 sts=4 et filetype=sh
a0a3b4
 
a0a3b4
 getargbool 0 rd.neednet && NEEDNET=1
a0a3b4
 
a0a3b4
@@ -14,11 +12,14 @@ command -v fix_bootif >/dev/null || . /lib/net-lib.sh
a0a3b4
 # Write udev rules
a0a3b4
 {
a0a3b4
     # bridge: attempt only the defined interface
a0a3b4
-    if [ -e /tmp/bridge.info ]; then
a0a3b4
-        . /tmp/bridge.info
a0a3b4
+    for i in /tmp/bridge.*.info; do
a0a3b4
+        [ -e "$i" ] || continue
a0a3b4
+        unset bridgeslaves
a0a3b4
+        unset bridgename
a0a3b4
+        . "$i"
a0a3b4
         RAW_IFACES="$RAW_IFACES $bridgeslaves"
a0a3b4
         MASTER_IFACES="$MASTER_IFACES $bridgename"
a0a3b4
-    fi
a0a3b4
+    done
a0a3b4
 
a0a3b4
     # bond: attempt only the defined interface (override bridge defines)
a0a3b4
     for i in /tmp/bond.*.info; do
a0a3b4
@@ -40,11 +41,19 @@ command -v fix_bootif >/dev/null || . /lib/net-lib.sh
a0a3b4
         MASTER_IFACES="$MASTER_IFACES ${teammaster}"
a0a3b4
     done
a0a3b4
 
a0a3b4
-    if [ -e /tmp/vlan.info ]; then
a0a3b4
-        . /tmp/vlan.info
a0a3b4
+    for j in /tmp/vlan.*.phy; do
a0a3b4
+        [ -e "$j" ] || continue
a0a3b4
+        unset phydevice
a0a3b4
+	read phydevice < "$j"
a0a3b4
         RAW_IFACES="$RAW_IFACES $phydevice"
a0a3b4
-        MASTER_IFACES="$MASTER_IFACES ${vlanname}"
a0a3b4
-    fi
a0a3b4
+        for i in /tmp/vlan.*.${phydevice}; do
a0a3b4
+            [ -e "$i" ] || continue
a0a3b4
+            unset vlanname
a0a3b4
+	    read vlanname < "$i"
a0a3b4
+            MASTER_IFACES="$MASTER_IFACES ${vlanname}"
a0a3b4
+        done
a0a3b4
+    done
a0a3b4
+
a0a3b4
     MASTER_IFACES="$(trim "$MASTER_IFACES")"
a0a3b4
     RAW_IFACES="$(trim "$RAW_IFACES")"
a0a3b4
 
a0a3b4
diff --git a/modules.d/40network/net-lib.sh b/modules.d/40network/net-lib.sh
1755ca
index 71201938..de334d98 100755
a0a3b4
--- a/modules.d/40network/net-lib.sh
a0a3b4
+++ b/modules.d/40network/net-lib.sh
a0a3b4
@@ -102,7 +102,8 @@ ifdown() {
a0a3b4
     ip addr flush dev $netif
a0a3b4
     echo "#empty" > /etc/resolv.conf
a0a3b4
     rm -f -- /tmp/net.$netif.did-setup
a0a3b4
-    [ -e /sys/class/net/$netif/address ] && \
a0a3b4
+    [ -z "$DO_VLAN" ] && \
a0a3b4
+        [ -e /sys/class/net/$netif/address ] && \
a0a3b4
         rm -f -- /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
a0a3b4
     # TODO: send "offline" uevent?
a0a3b4
 }
a0a3b4
@@ -111,7 +112,8 @@ setup_net() {
a0a3b4
     local netif="$1" f="" gw_ip="" netroot_ip="" iface="" IFACES=""
a0a3b4
     local _p
a0a3b4
     [ -e /tmp/net.$netif.did-setup ] && return
a0a3b4
-    [ -e /sys/class/net/$netif/address ] && \
a0a3b4
+    [ -z "$DO_VLAN" ] && \
a0a3b4
+        [ -e /sys/class/net/$netif/address ] && \
a0a3b4
         [ -e /tmp/net.$(cat /sys/class/net/$netif/address).did-setup ] && return
a0a3b4
     [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
a0a3b4
     [ -z "$IFACES" ] && IFACES="$netif"
a0a3b4
@@ -168,7 +170,8 @@ setup_net() {
a0a3b4
     unset layer2
a0a3b4
 
a0a3b4
     > /tmp/net.$netif.did-setup
a0a3b4
-    [ -e /sys/class/net/$netif/address ] && \
a0a3b4
+    [ -z "$DO_VLAN" ] && \
a0a3b4
+        [ -e /sys/class/net/$netif/address ] && \
a0a3b4
         > /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
a0a3b4
 }
a0a3b4
 
a0a3b4
diff --git a/modules.d/40network/parse-bridge.sh b/modules.d/40network/parse-bridge.sh
1755ca
index a9101094..5c3af292 100755
a0a3b4
--- a/modules.d/40network/parse-bridge.sh
a0a3b4
+++ b/modules.d/40network/parse-bridge.sh
a0a3b4
@@ -1,6 +1,4 @@
a0a3b4
 #!/bin/sh
a0a3b4
-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
a0a3b4
-# ex: ts=8 sw=4 sts=4 et filetype=sh
a0a3b4
 #
a0a3b4
 # Format:
a0a3b4
 #       bridge=<bridgename>:<bridgeslaves>
a0a3b4
@@ -9,14 +7,6 @@
a0a3b4
 #       bridge without parameters assumes bridge=br0:eth0
a0a3b4
 #
a0a3b4
 
a0a3b4
-# return if bridge already parsed
a0a3b4
-[ -n "$bridgename" ] && return
a0a3b4
-
a0a3b4
-# Check if bridge parameter is valid
a0a3b4
-if getarg bridge= >/dev/null ; then
a0a3b4
-    command -v brctl >/dev/null 2>&1 || die "No 'brctl' installed" 
a0a3b4
-fi
a0a3b4
-
a0a3b4
 parsebridge() {
a0a3b4
     local v=${1}:
a0a3b4
     set --
a0a3b4
@@ -24,8 +14,6 @@ parsebridge() {
a0a3b4
         set -- "$@" "${v%%:*}"
a0a3b4
         v=${v#*:}
a0a3b4
     done
a0a3b4
-
a0a3b4
-    unset bridgename bridgeslaves
a0a3b4
     case $# in
a0a3b4
         0)  bridgename=br0; bridgeslaves=$iface ;;
a0a3b4
         1)  die "bridge= requires two parameters" ;;
a0a3b4
@@ -34,14 +22,13 @@ parsebridge() {
a0a3b4
     esac
a0a3b4
 }
a0a3b4
 
a0a3b4
-unset bridgename bridgeslaves
a0a3b4
-
a0a3b4
-iface=eth0
a0a3b4
-
a0a3b4
 # Parse bridge for bridgename and bridgeslaves
a0a3b4
-if bridge="$(getarg bridge)"; then
a0a3b4
+for bridge in $(getargs bridge=); do
a0a3b4
+    unset bridgename
a0a3b4
+    unset bridgeslaves
a0a3b4
+    iface=eth0
a0a3b4
     # Read bridge= parameters if they exist
a0a3b4
-    if [ -n "$bridge" ]; then
a0a3b4
+    if [ "$bridge" != "bridge" ]; then
a0a3b4
         parsebridge $bridge
a0a3b4
     fi
a0a3b4
     # Simple default bridge
a0a3b4
@@ -49,7 +36,6 @@ if bridge="$(getarg bridge)"; then
a0a3b4
         bridgename=br0
a0a3b4
         bridgeslaves=$iface
a0a3b4
     fi
a0a3b4
-    echo "bridgename=$bridgename" > /tmp/bridge.info
a0a3b4
-    echo "bridgeslaves=\"$bridgeslaves\"" >> /tmp/bridge.info
a0a3b4
-    return
a0a3b4
-fi
a0a3b4
+    echo "bridgename=$bridgename" > /tmp/bridge.${bridgename}.info
a0a3b4
+    echo "bridgeslaves=\"$bridgeslaves\"" >> /tmp/bridge.${bridgename}.info
a0a3b4
+done
a0a3b4
diff --git a/modules.d/40network/parse-team.sh b/modules.d/40network/parse-team.sh
1755ca
index a836d688..136c3705 100755
a0a3b4
--- a/modules.d/40network/parse-team.sh
a0a3b4
+++ b/modules.d/40network/parse-team.sh
a0a3b4
@@ -6,14 +6,6 @@
a0a3b4
 #       teamslaves is a comma-separated list of physical (ethernet) interfaces
a0a3b4
 #
a0a3b4
 
a0a3b4
-# return if team already parsed
a0a3b4
-[ -n "$teammaster" ] && return
a0a3b4
-
a0a3b4
-# Check if team parameter is valid
a0a3b4
-if getarg team= >/dev/null ; then
a0a3b4
-    :
a0a3b4
-fi
a0a3b4
-
a0a3b4
 parseteam() {
a0a3b4
     local v=${1}:
a0a3b4
     set --
a0a3b4
@@ -22,33 +14,22 @@ parseteam() {
a0a3b4
         v=${v#*:}
a0a3b4
     done
a0a3b4
 
a0a3b4
-    unset teammaster teamslaves
a0a3b4
     case $# in
a0a3b4
-        2)  teammaster=$1; teamslaves=$(str_replace "$2" "," " ") ;;
a0a3b4
-        *)  warn "team= requires two parameters"; return 1;;
a0a3b4
+    2)  teammaster=$1; teamslaves=$(str_replace "$2" "," " ") ;;
a0a3b4
+    *)  die "team= requires two parameters" ;;
a0a3b4
     esac
a0a3b4
-    return 0
a0a3b4
 }
a0a3b4
 
a0a3b4
-unset teammaster teamslaves
a0a3b4
-
a0a3b4
-if getarg team>/dev/null; then
a0a3b4
-    # Read team= parameters if they exist
a0a3b4
-    for team in $(getargs team); do
a0a3b4
-        [ "$team" = "team" ] && continue
a0a3b4
-
a0a3b4
-        unset teammaster
a0a3b4
-        unset teamslaves
a0a3b4
 
a0a3b4
-        parseteam "$team" || continue
a0a3b4
-
a0a3b4
-        echo "teammaster=$teammaster" > /tmp/team.${teammaster}.info
a0a3b4
-        echo "teamslaves=\"$teamslaves\"" >> /tmp/team.${teammaster}.info
a0a3b4
-
a0a3b4
-        if ! [ -e /etc/teamd/${teammaster}.conf ]; then
a0a3b4
-            warn "Team master $teammaster specified, but no /etc/teamd/$teammaster.conf present. Using activebackup."
a0a3b4
-            mkdir -p /etc/teamd
a0a3b4
-            printf -- "%s" '{"runner": {"name": "activebackup"}, "link_watch": {"name": "ethtool"}}' > "/etc/teamd/${teammaster}.conf"
a0a3b4
-        fi
a0a3b4
-    done
a0a3b4
-fi
a0a3b4
+for team in $(getargs team=); do
a0a3b4
+    unset teammaster teamslaves
a0a3b4
+    parseteam "$(getarg team=)"
a0a3b4
+
a0a3b4
+    echo "teammaster=$teammaster" > /tmp/team.${teammaster}.info
a0a3b4
+    echo "teamslaves=\"$teamslaves\"" >> /tmp/team.${teammaster}.info
a0a3b4
+    if ! [ -e /etc/teamd/${teammaster}.conf ]; then
a0a3b4
+        warn "Team master $teammaster specified, but no /etc/teamd/$teammaster.conf present. Using activebackup."
a0a3b4
+        mkdir -p /etc/teamd
a0a3b4
+        printf -- "%s" '{"runner": {"name": "activebackup"}, "link_watch": {"name": "ethtool"}}' > "/etc/teamd/${teammaster}.conf"
a0a3b4
+    fi
a0a3b4
+done
a0a3b4
diff --git a/modules.d/40network/parse-vlan.sh b/modules.d/40network/parse-vlan.sh
1755ca
index 3ba22892..5a747f0f 100755
a0a3b4
--- a/modules.d/40network/parse-vlan.sh
a0a3b4
+++ b/modules.d/40network/parse-vlan.sh
a0a3b4
@@ -4,14 +4,6 @@
a0a3b4
 #	vlan=<vlanname>:<phydevice>
a0a3b4
 #
a0a3b4
 
a0a3b4
-# return if vlan already parsed
a0a3b4
-[ -n "$vlanname" ] && return
a0a3b4
-
a0a3b4
-# Check if vlan parameter is valid
a0a3b4
-if getarg vlan= >/dev/null ; then
a0a3b4
-    :
a0a3b4
-fi
a0a3b4
-
a0a3b4
 parsevlan() {
a0a3b4
     local v=${1}:
a0a3b4
     set --
a0a3b4
@@ -27,16 +19,11 @@ parsevlan() {
a0a3b4
     esac
a0a3b4
 }
a0a3b4
 
a0a3b4
-unset vlanname phydevice
a0a3b4
-
a0a3b4
-if getarg vlan >/dev/null; then
a0a3b4
-    # Read vlan= parameters if they exist
a0a3b4
-    vlan="$(getarg vlan=)"
a0a3b4
-    if [ ! "$vlan" = "vlan" ]; then
a0a3b4
-        parsevlan "$(getarg vlan=)"
a0a3b4
-    fi
a0a3b4
+for vlan in $(getargs vlan=); do
a0a3b4
+    unset vlanname
a0a3b4
+    unset phydevice
a0a3b4
+    parsevlan "$vlan"
a0a3b4
 
a0a3b4
-    echo "vlanname=\"$vlanname\"" > /tmp/vlan.info
a0a3b4
-    echo "phydevice=\"$phydevice\"" >> /tmp/vlan.info
a0a3b4
-    return
a0a3b4
-fi
a0a3b4
+    echo "$phydevice" > /tmp/vlan.${phydevice}.phy
a0a3b4
+    echo "$vlanname" > /tmp/vlan.${vlanname}.${phydevice}
a0a3b4
+done
a0a3b4
diff --git a/modules.d/45ifcfg/write-ifcfg.sh b/modules.d/45ifcfg/write-ifcfg.sh
1755ca
index cab74772..a077da1c 100755
a0a3b4
--- a/modules.d/45ifcfg/write-ifcfg.sh
a0a3b4
+++ b/modules.d/45ifcfg/write-ifcfg.sh
a0a3b4
@@ -7,14 +7,6 @@ type is_persistent_ethernet_name >/dev/null 2>&1 || . /lib/net-lib.sh
a0a3b4
 
a0a3b4
 udevadm settle --timeout=30
a0a3b4
 
a0a3b4
-if [ -e /tmp/bridge.info ]; then
a0a3b4
-    . /tmp/bridge.info
a0a3b4
-fi
a0a3b4
-
a0a3b4
-if [ -e /tmp/vlan.info ]; then
a0a3b4
-    . /tmp/vlan.info
a0a3b4
-fi
a0a3b4
-
a0a3b4
 mkdir -m 0755 -p /tmp/ifcfg/
a0a3b4
 mkdir -m 0755 -p /tmp/ifcfg-leases/
a0a3b4
 
a0a3b4
@@ -24,7 +16,7 @@ get_config_line_by_subchannel()
a0a3b4
     local line
a0a3b4
 
a0a3b4
     CHANNELS="$1"
a0a3b4
-    while read line; do
a0a3b4
+    while read line || [ -n "$line" ]; do
a0a3b4
         if strstr "$line" "$CHANNELS"; then
a0a3b4
             echo $line
a0a3b4
             return 0
a0a3b4
@@ -132,6 +124,8 @@ for netup in /tmp/net.*.did-setup ; do
a0a3b4
     unset bondslaves
a0a3b4
     unset bondname
a0a3b4
     unset bondoptions
a0a3b4
+    unset bridgename
a0a3b4
+    unset bridgeslaves
a0a3b4
     unset uuid
a0a3b4
     unset ip
a0a3b4
     unset gw
a0a3b4
@@ -141,8 +135,10 @@ for netup in /tmp/net.*.did-setup ; do
a0a3b4
     unset slave
a0a3b4
     unset ethname
a0a3b4
     unset vlan
a0a3b4
+    unset phydevice
a0a3b4
 
a0a3b4
     [ -e /tmp/bond.${netif}.info ] && . /tmp/bond.${netif}.info
a0a3b4
+    [ -e /tmp/bridge.${netif}.info ] && . /tmp/bridge.${netif}.info
a0a3b4
     [ -e /tmp/team.${netif}.info ] && . /tmp/team.${netif}.info
a0a3b4
     [ -e /tmp/net.${netif}.override ] && . /tmp/net.${netif}.override
a0a3b4
 
a0a3b4
@@ -152,11 +148,17 @@ for netup in /tmp/net.*.did-setup ; do
a0a3b4
     elif [ "$netif" = "$teammaster" ]; then
a0a3b4
         team=yes
a0a3b4
     elif [ "$netif" = "$bondname" ]; then
a0a3b4
-    # $netif can't be bridge and bond at the same time
a0a3b4
+        # $netif can't be bridge and bond at the same time
a0a3b4
         bond=yes
a0a3b4
     fi
a0a3b4
-    if [ "$netif" = "$vlanname" ]; then
a0a3b4
-        vlan=yes
a0a3b4
+
a0a3b4
+    if ! [ -e /tmp/vlan.${netif}.phy ]; then
a0a3b4
+        for i in /tmp/vlan.${netif}.*; do
a0a3b4
+            [ ! -e "$i" ] && continue
a0a3b4
+            phydevice=${i##/tmp/vlan.${netif}.}
a0a3b4
+            vlan=yes
a0a3b4
+            break
a0a3b4
+        done
a0a3b4
     fi
a0a3b4
 
a0a3b4
     # skip team interfaces for now, the host config must be in sync