DHCP management of bonded eths with ifupdown

Posted by nferrier on Tue 14 Jun 2005 at 15:43

When you're using bonded ethernet interfaces (2 or more cards bound to a single IP address) it can be difficult to manage addresses. Multiple sites might have different IP networks and that means different interfaces files for each site.

This is a scheme that allows you to use DHCP to allow ifupdown to automatically work out which interfaces it should add to a bond.

The idea is that you configure 2 interfaces from the same machine into the local DHCP (each interface will have a different IP address as normal) and then use the script included here to setup the bond.

.

Here is an example interfaces file. This should go into /etc/network/interfaces

#### Setup and standard stuff.
auto lo bond0

#### Iface specifications
iface lo inet loopback

iface bond0 inet dhcp
        pre-up /etc/network/scripts/bond-init bond0 10.1 10.2 10.3 192.168.1

#### End

This interface file is designed to bring up a bonded interface with any interfaces it finds attached to a network beginning:

Here's how bond-init works.

And here's the source

#!/bin/sh

# Initialize bonding for at most 2 eths connected to one of a range of
# networks.

# Copyright (C) 2005 Tapsell-Ferrier Limited
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.


# Arg1 is the interface name to bond
# Other args are net patterns.

# What's a net pattern?  
# A net pattern is a string pattern that identifies the beginning
# fragment of a network address that is to be bonded.

# Example of using bond-init
# You can't really use bond-init from the command line because it will
# trash your existing interfaces (unless they are already bonded).
#
# You can choose to do this:
#
#   DEBUG=1 bond-init bond0 192.168.1 10.18
#
# That just outputs the bonding statements to stderr.
#
# The normal way to use bond-init though is in the pre-up of the
# interfaces file:
#
# iface bond0 inet dhcp
#   pre-up bond-init bond0 192.168.1 10.18
#   up route add -net 172.25.0.0 netmask 255.255.0.0 dev bond0


DEBUG=${DEBUG:-0}


function list_eths
{
    ifconfig -a | awk '/^eth[0-9]/ { print $1 }'
}

function make_dhscript
{
    # This script is so small we may as well create it ourselves
    cat < /tmp/ethselect-dhscript
#!/bin/sh
echo \$new_ip_address
EOF
    chmod u+x /tmp/ethselect-dhscript
}

function get_dhcp_address
{
    # Uses DHCP to get the address which is written to stdout.
    IF=$1

    # Record the current "up or down" status of the interface
    ifconfig | grep -qs -e "^$IF"
    ifstate=$?

    # Bring up the interface if it isn't already
    [ $ifstate -eq 0 ] || ifconfig $IF up

    # Make the DHCP script if it's not available
    [ -f /tmp/ethselect-dhscript ] || make_dhscript

    # Get the address from DHCP
    dhclient3 -n -sf /tmp/ethselect-dhscript \
	-lf /var/lib/dhcp3/ethselect.${IF}.leases \
	-pf /var/run/ethselect.${IF}.pid  ${IF} 2> /dev/null

    # Belt and braces
    DHCP_PID=$!

    if [ $? -eq 0 ]
    then
        if [ -f /var/run/ethselect.${IF}.pid ]
        then
            kill -QUIT `cat /var/run/ethselect.${IF}.pid`
            rm /var/run/ethselect.${IF}.pid
        else
            kill -QUIT $DHCP_PID
        fi
    fi

    # Don't want to do this if the card was already up...
    [ $ifstate -eq 0 ] || ifconfig $IF down
}


function bond_up
{
    # Bring up the bonded interface
    # Arg 1 is the bond interface, other args are the eths we need to bond
    to_bond=$1
    shift

    ifconfig $to_bond up

    for eth in $* 
    do
      ifconfig $eth up
    done

    ifenslave $to_bond $*
    exit $?
}



### Main program

# First arg is the bonding iface name
iface=$1
shift

# The list of cards that match the netpattern
matching_cards=""

# DHCP for the addresses
for card in `list_eths`
do
  addr=`get_dhcp_address $card`
  # addr will be something like 10.18.0.22
  for netpattern in $*
  do
    echo $addr | grep -qs $netpattern
    if [ $? -eq 0 ]
    then
        # If the card matches then add it to the list
        matching_cards="$matching_cards $card"
        break
    fi
  done

  # If we have two matching cards that's enough
  echo $matching_cards | grep -qs ' '
  [ $? -eq 0 ] && bond_up $iface $matching_cards

done

# We might have just one card in which case bring it up with just one
[ "$matching_cards" == "" ] || bond_up $iface $matching_cards

# End
Important Caveats

If you mix bonded and normal interfaces, eg:

auto lo eth1 eth4 bond0

the bonded interface should always be referenced last otherwise other interface ups might trash the bonding.


This article can be found online at the Debian Administration website at the following bookmarkable URL (along with associated comments):

This article is copyright 2005 nferrier - please ask for permission to republish or translate.