From 114aadff326cb6ac63d2b3926fafe944b1670a62 Mon Sep 17 00:00:00 2001
From: Julian Wolf <juwolf@suse.com>
Date: Thu, 31 Jul 2014 17:11:16 +0200
Subject: Allow multiple configurations per network interface bnc#887906

Signed-off-by: Julian Wolf <juwolf@suse.com>
---
 modules.d/40network/ifup.sh          |   91 ++++++++++++++++++++++------------
 modules.d/40network/net-genrules.sh  |    2 +-
 modules.d/40network/net-lib.sh       |    4 +-
 modules.d/40network/parse-ibft.sh    |    4 +-
 modules.d/40network/parse-ip-opts.sh |   14 ++---
 5 files changed, 70 insertions(+), 45 deletions(-)

diff --git a/modules.d/40network/ifup.sh b/modules.d/40network/ifup.sh
index 84dc530..0362287 100755
--- a/modules.d/40network/ifup.sh
+++ b/modules.d/40network/ifup.sh
@@ -91,6 +91,7 @@ else
 fi
 
 dhcp_apply() {
+    unset IPADDR INTERFACE BROADCAST NETWORK PREFIXLEN ROUTES GATEWAYS HOSTNAME DNSDOMAIN DNSSEARCH DNSSERVERS
     if [ -f /tmp/leaseinfo.${netif}.dhcp.ipv${1:1:1} ]; then
         . /tmp/leaseinfo.${netif}.dhcp.ipv${1:1:1}
     else
@@ -132,24 +133,37 @@ dhcp_apply() {
     [ -n "${HOSTNAME}" ] && hostname "$HOSTNAME"
 
     # If nameserver= has not been specified, use what dhcp provides
-    if [ ! -s /tmp/net.$netif.resolv.conf ]; then
+    if [ ! -s /tmp/net.$netif.resolv.conf.ipv${1:1:1} ]; then
         if [ -n "${DNSDOMAIN}" ]; then
             echo domain "${DNSDOMAIN}"
-        fi >> /tmp/net.$netif.resolv.conf
+        fi >> /tmp/net.$netif.resolv.conf.ipv${1:1:1}
 
         if [ -n "${DNSSEARCH}" ]; then
             echo search "${DNSSEARCH}"
-        fi >> /tmp/net.$netif.resolv.conf
+        fi >> /tmp/net.$netif.resolv.conf.ipv${1:1:1}
 
         if  [ -n "${DNSSERVERS}" ] ; then
             for s in ${DNSSERVERS}; do
                 echo nameserver "$s"
             done
-        fi >> /tmp/net.$netif.resolv.conf
+        fi >> /tmp/net.$netif.resolv.conf.ipv${1:1:1}
     fi
-    [ -e /tmp/net.$netif.resolv.conf ] && \
-        cp -f /tmp/net.$netif.resolv.conf /etc/resolv.conf
-
+    # copy resolv.conf if it doesn't exist yet, modify otherwise
+    if [ -e /tmp/net.$netif.resolv.conf.ipv${1:1:1} ] && [ ! -e /etc/resolv.conf ]; then
+        cp -f /tmp/net.$netif.resolv.conf.ipv${1:1:1} /etc/resolv.conf
+    else
+        if [ -n "$(sed -n '/^search .*$/p' /etc/resolv.conf)" ]; then
+            sed -i "s/\(^search .*\)$/\1 ${DNSSEARCH}/" /etc/resolv.conf
+        else
+            echo search ${DNSSEARCH} >> /etc/resolv.conf
+        fi
+        if  [ -n "${DNSSERVERS}" ] ; then
+            for s in ${DNSSERVERS}; do
+                echo nameserver "$s"
+            done
+        fi >> /etc/resolv.conf
+    fi
+        
     info "DHCP is finished successfully"
     return 0
 }
@@ -171,9 +185,6 @@ do_dhcp() {
         dhclient="wickedd-dhcp6"
     fi
 
-    # Address changed
-    ip $1 addr flush dev "$netif"
-
     if ! iface_has_link $netif; then
         warn "No carrier detected"
         warn "Trying to set $netif up..."
@@ -188,7 +199,6 @@ do_dhcp() {
     $dhclient --test $netif > /tmp/leaseinfo.${netif}.dhcp.ipv${1:1:1}
     dhcp_apply $1 || return $?
 
-    echo $netif > /tmp/net.${netif}.did-setup
     echo $netif > /tmp/setup_net_${netif}.ok
     return 0
 }
@@ -218,6 +228,31 @@ do_ipv6auto() {
 
 # Handle static ip configuration
 do_static() {
+    if [ "$autoconf" = "static" ] &&
+        [ -e /etc/sysconfig/network/ifcfg-${netif} ] ; then
+        # Pull in existing static configuration
+        . /etc/sysconfig/network/ifcfg-${netif}
+
+        # loop over all configurations in ifcfg-$netif (IPADDR*) and apply
+        for conf in ${!IPADDR@}; do
+            ip=${!conf}
+            [ -z "$ip" ] && continue
+            ext=${conf#IPADDR}
+            concat="PREFIXLEN$ext" && [ -n "${!concat}" ] && mtu=${!concat}
+            concat="MTU$ext" && [ -n "${!concat}" ] && mtu=${!concat}
+            concat="REMOTE_IPADDR$ext" && [ -n "${!concat}" ] && server=${!concat}
+            concat="GATEWAY$ext" && [ -n "${!concat}" ] && gw=${!concat}
+            concat="BOOTPROTO$ext" && [ -n "${!concat}" ] && autoconf=${!concat}
+            do_static_setup
+        done
+    else
+        do_static_setup
+    fi
+
+    return 0
+}
+
+do_static_setup() {
     strglobin $ip '*:*:*' && load_ipv6
 
     linkup $netif
@@ -237,7 +272,6 @@ do_static() {
     else
         # Assume /24 prefix for IPv4
         [ -z "$prefix" ] && prefix=24
-        ip addr flush dev $netif
         ip addr add $ip/$prefix ${srv:+peer $srv} brd + dev $netif
     fi
 
@@ -256,8 +290,6 @@ do_static() {
     done
 
     [ -n "$hostname" ] && echo "echo $hostname > /proc/sys/kernel/hostname" > /tmp/net.$netif.hostname
-
-    return 0
 }
 
 # loopback is always handled the same way
@@ -404,6 +436,14 @@ for p in $(getargs ip=); do
     ip_to_var $p
     # skip ibft
     [ "$autoconf" = "ibft" ] && continue
+    
+    # skip if same configuration appears twice
+    while read line
+    do
+      [ "$line" = "$p" ] && continue 2
+    done < /tmp/net.${netif}.conf
+
+    echo $p >> /tmp/net.${netif}.conf
 
     case "$dev" in
         ??:??:??:??:??:??)  # MAC address
@@ -421,29 +461,12 @@ for p in $(getargs ip=); do
     [ "$use_bridge" != 'true' ] && \
     [ "$use_vlan" != 'true' ] && continue
 
-    if [ "$autoconf" = "static" ] &&
-        [ -e /etc/sysconfig/network/ifcfg-${netif} ] ; then
-        # Pull in existing static configuration
-        . /etc/sysconfig/network/ifcfg-${netif}
-        ip=${IPADDR}
-        prefix=${PREFIXLEN}
-        mtu=${MTU}
-        server=${REMOTE_IPADDR}
-        gw=${GATEWAY}
-        autoconf=${BOOTPROTO}
-    fi
-
     # setup nameserver
     namesrv="$dns1 $dns2 $(getargs nameserver)"
     for s in $namesrv; do
         echo nameserver $s >> /tmp/net.$netif.resolv.conf
     done
 
-    # Store config for later use
-    for i in ip srv gw mask prefix hostname macaddr dns1 dns2; do
-        eval '[ "$'$i'" ] && echo '$i'="$'$i'"'
-    done > /tmp/net.$netif.override
-
     case $autoconf in
         dhcp4|dhcp|on|any)
             do_dhcp -4 ;;
@@ -466,7 +489,6 @@ for p in $(getargs ip=); do
         fi
     fi
 
-    exit 0
 done
 
 # netif isn't the top stack? Then we should exit here.
@@ -486,4 +508,9 @@ if [ ! -e /tmp/net.${netif}.up ]; then
     fi
 fi
 
+if [ -e /tmp/net.${netif}.up ]; then
+    > /tmp/net.$netif.did-setup
+    [ -e /sys/class/net/$netif/address ] && \
+        > /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
+fi
 exit 0
diff --git a/modules.d/40network/net-genrules.sh b/modules.d/40network/net-genrules.sh
index 2fd8c6b..9d0ed20 100755
--- a/modules.d/40network/net-genrules.sh
+++ b/modules.d/40network/net-genrules.sh
@@ -99,7 +99,7 @@ command -v fix_bootif >/dev/null || . /lib/net-lib.sh
         # if you change the name of "91-default-net.rules", also change modules.d/80cms/cmssetup.sh
         if [ "$NEEDNET" = "1" ]; then
             echo "$cond, $runcmd" > /etc/udev/rules.d/91-default-net.rules
-            echo "[ -f /tmp/net.*.did-setup ]" >$hookdir/initqueue/finished/wait-network.sh
+            echo "ls -1 /tmp/net.*.did-setup >/dev/null 2>&1" >$hookdir/initqueue/finished/wait-network.sh
         fi
     fi
 
diff --git a/modules.d/40network/net-lib.sh b/modules.d/40network/net-lib.sh
index fce845a..e8d898a 100755
--- a/modules.d/40network/net-lib.sh
+++ b/modules.d/40network/net-lib.sh
@@ -111,6 +111,7 @@ ifdown() {
     ip addr flush dev $netif
     echo "#empty" > /etc/resolv.conf
     rm -f -- /tmp/net.$netif.did-setup
+    rm -f -- /tmp/net.$netif.conf
     [ -e /sys/class/net/$netif/address ] && \
         rm -f -- /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
     # TODO: send "offline" uevent?
@@ -165,9 +166,6 @@ setup_net() {
     fi
     unset layer2
 
-    > /tmp/net.$netif.did-setup
-    [ -e /sys/class/net/$netif/address ] && \
-        > /tmp/net.$(cat /sys/class/net/$netif/address).did-setup
 }
 
 save_netinfo() {
diff --git a/modules.d/40network/parse-ibft.sh b/modules.d/40network/parse-ibft.sh
index 9776c75..b81ddb1 100755
--- a/modules.d/40network/parse-ibft.sh
+++ b/modules.d/40network/parse-ibft.sh
@@ -6,5 +6,7 @@ command -v getarg >/dev/null          || . /lib/dracut-lib.sh
 command -v ibft_to_cmdline >/dev/null || . /lib/net-lib.sh
 
 # If ibft is requested, read ibft vals and write ip=XXX cmdline args
-[ "ibft" = "$(getarg ip=)" ] && ibft_to_cmdline
+for i in $(getargs ip=); do
+    [ "ibft" = "$i" ] && ibft_to_cmdline && break
+done
 
diff --git a/modules.d/40network/parse-ip-opts.sh b/modules.d/40network/parse-ip-opts.sh
index 52a1923..13bc45c 100755
--- a/modules.d/40network/parse-ip-opts.sh
+++ b/modules.d/40network/parse-ip-opts.sh
@@ -78,24 +78,22 @@ for p in $(getargs ip=); do
                 die "Sorry, automatic calculation of netmask is not yet supported"
             ;;
         auto6);;
-        dhcp|dhcp6|on|any) \
-            [ -n "$NEEDBOOTDEV" ] && [ -z "$dev" ] && \
-            die "Sorry, 'ip=$p' does not make sense for multiple interface configurations"
-            [ -n "$ip" ] && \
-                die "For argument 'ip=$p'\nSorry, setting client-ip does not make sense for '$autoconf'"
-            ;;
+        dhcp|dhcp6|on|any) ;;
         *) die "For argument 'ip=$p'\nSorry, unknown value '$autoconf'";;
     esac
 
+    dup=0
     if [ -n "$dev" ] ; then
         # We don't like duplicate device configs
         if [ -n "$IFACES" ] ; then
             for i in $IFACES ; do
-                [ "$dev" = "$i" ] && die "For argument 'ip=$p'\nDuplication configurations for '$dev'"
+                [ "$dev" = "$i" ] && dup=1 && break
             done
         fi
         # IFACES list for later use
-        IFACES="$IFACES $dev"
+        if [ $dup -eq 0 ]; then
+             IFACES="$IFACES $dev"
+        fi
     fi
 
     # Do we need to check for specific options?
-- 
1.7.6.1

