## -*- mode: shell-script; -*- 
##
## To be able to make changes to the part of configuration created
## from this configlet you need to copy this file to the directory
## fwbuilder/configlets/linux24/ in your home directory and modify it.
## Double "##" comments are removed during processing but single "#"
## comments are be retained and appear in the generated script. Empty
## lines are removed as well.  
##
## Configlets support simple macro language with these constructs:
## {{$var}} is variable expansion
## {{if var}} is conditional operator.
##
############ bonding ###########################################
## cat /proc/net/bonding/bond0
## Ethernet Channel Bonding Driver: v3.5.0 (November 4, 2008)
##
## Bonding Mode: load balancing (round-robin)
## MII Status: up
## MII Polling Interval (ms): 0
## Up Delay (ms): 0
## Down Delay (ms): 0
##
## Slave Interface: eth2
## MII Status: up
## Link Failure Count: 0
## Permanent HW addr: 00:0c:29:f6:be:aa
##
## Slave Interface: eth3
## MII Status: up
## Link Failure Count: 0
## Permanent HW addr: 00:0c:29:f6:be:b4
##
##

missing_bond() {
    bond_intf=$1
    cmd=$2

    test "$cmd" = "down" && {
      echo "# Bring unconfigured bonding interface $bond_intf down"
      $FWBDEBUG $IP link set $bond_intf down
    }
}

missing_slave() {
    slave=$1
    cmd=$2

    oldIFS=$IFS
    IFS="@"
    set $slave
    intf=$1
    bond_interface=$2
    IFS=$oldIFS

    test "$cmd" = "-d" && {
      echo "# Delete bonding interface slave: $bond_interface $intf"
      $FWBDEBUG $IFENSLAVE -d $bond_interface $intf
    } || {
      echo "# Add bonding interface slave: $bond_interface $intf"
      $FWBDEBUG $IP link set $bond_interface up
      $FWBDEBUG $IFENSLAVE $bond_interface $intf
    }
}

## verify that bonding module is loaded with parameters that provide
## support for required number of bonding interfaces (bonding
## interfaces get created when module is loaded and if we need 2 --
## bond0 and bond1 -- then the way to get them is to load the module
## with parameter max_bonds=2).
##
## Current implementation only supports identical bonding parameters
## for all bonding interfaces. This is because in my tests command
## "modprobe bonding -obond1" always causes kernel panic. This means I
## could not find a way to load bonding module two times with
## different parameters. Call for this function is generated in 
## OSConfigurator_linux24::printBondingInterfaceConfigurationCommands()
##
## load_bonding_module "bond0 bond1" max_bonds=2 mode=balance-alb miimon=50
##
load_bonding_module() {
    bonding_interfaces=$1
    shift
    module_parameters=$*

    PROC_DIR="/proc/net/bonding/"
    test -d $PROC_DIR || {
## module is not loaded. Load it with appropriate max_bonds argument
        cmd="$MODPROBE bonding $module_parameters"
        test -n "$FWBDEBUG" && echo "# $cmd" || $cmd || {
            # Module load failed.
            cat <<EOF

Could not load bonding interface module. Try to add 
module parameters to the file /etc/modprobe.conf or
/etc/modprobe.d/bond.conf and reboot
EOF
            # do not abort in test mode
            test -z "$FWBDEBUG" && exit 1
        }
    }
    ## test that we now have bonding interfaces that we need
    for bondint in $bonding_interfaces; do
        PROD_BOND_IFACE="${PROC_DIR}/$bondint"
        test -f $PROD_BOND_IFACE || {
            echo "Bonding interface $bondint does not exist"
            test -z "$FWBDEBUG" && exit 1
        }
    done
}

## If no bonding interfaces are configured in fwbuilder, unload the module
## to kill any that might be present on the machine.
unload_bonding_module() {
    $MODPROBE -r bonding
}

## update_bonding bond0 eth2 eth3
## Quotes are essential
update_bonding() {
    bond_interface=$1
    shift

    PROC_DIR="/proc/net/bonding/"
    PROD_BOND_IFACE="${PROC_DIR}/$bond_interface"
    test -f $PROD_BOND_IFACE && {

        FWB_SLAVES=""
        CURRENT_SLAVES=""

        FWB_SLAVES=$(
            for subint in $*; do
                echo "${subint}@$bond_interface"
            done | sort
        )

        CURRENT_SLAVES=$(
            cat $PROD_BOND_IFACE | grep 'Slave Interface:' | \
                while read a b slave; do
                    echo "${slave}@$bond_interface"
                done | sort
        )

        diff_intf missing_slave "$FWB_SLAVES" "$CURRENT_SLAVES" "  "
        diff_intf missing_slave "$CURRENT_SLAVES" "$FWB_SLAVES" "-d"
    }
}

## Since we can not remove bonding interface without unloading the
## module (which kills other bonding interfaces), we'll just bridge
## bonding interfaces that exist on the machine but not in fwbuilder
## config down.
##
##  clear_bonding_except_known bond0 bond1
##
## If bond2 interface exist, it will be brought down.
## 
## Note that ifenslave fails to remove slave if bond interface is down
## with error "Illegal operation; the specified master interface 'bond1' is not up."
## Need to bring bond interface up before removing slaves. This makes
## no sense, but still. This is with bonding module v3.5.0, tested on Fedora C11.
##
clear_bonding_except_known() {
    PROC_DIR="/proc/net/bonding/"
    ls $PROC_DIR | awk -v IGNORED="$*" \
        'BEGIN {
           split(IGNORED,ignored_arr);
           for (a in ignored_arr) {ignored_dict[ignored_arr[a]]=1;}
         }
         (!($1 in ignored_dict)) {print $1;}' | \
         while read bond_intf; do
             PROD_BOND_IFACE="${PROC_DIR}/$bond_intf"
             slaves=$(cat $PROD_BOND_IFACE | awk '/[sS]lave [iI]nterface:/ { printf "%s ",$NF;}')
             test -n "$slaves" && {
                 echo "Removing slaves and bringing unconfigured bonding interface $bond_intf down"
                 $FWBDEBUG $IP link set $bond_intf up
                 $FWBDEBUG $IFENSLAVE  -d $bond_intf $slaves
                 $FWBDEBUG $IP link set $bond_intf down
             }
         done
}
