Sunday, February 15, 2015

Linux Bonding Channel Driver, on Slackware P3

Basically, the bonding driver included in the stock 14.1 Slackware kernel (3.10.17), still supports using the ifenslave tool.

Unfortunately, there isn't a current slackbuild in either's Slackware official package repo nor the slackbuilds repository which has a Slackbuild for ifenslave.

So, you're left building it from scratch as described in the source file ifenslave.c (/usr/src/linux/Documentation/networking/ifenslave.c):

compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"

When I was initially attempting to use the bonding driver, it was on my Poweredge 750 (arch: i686). For whatever reason, I could never get this source file to actually compile the binary ifenslave w/o encountering a build error.

This prompted me to look for an alternative. All the documentation I've seen in setting up bonding in Slackware walk you through this step first. In the major distros, ifenslave is either already included in the official repository, or bonding is integrated into the init script.

After some searching I finally came across an alternative: Vincent Batts posted a Slackbuild for ifenslave! It was hidden in the discarded directory, I believe it was for Slackware 12. It built just fine on my system!

(I later discovered what Vincent employed in his Slackbuild that actually allowed me to build ifenslave properly on my 14.1 x86 poweredge: the arch variable wasn't set via a case statement tied to uname--as is normally done-- it was hardcoded to 386.)

I was able to load the binary, initialize a bonded interface w/ ifconfig, and successfully utilized ifenslave to set the slave interfaces under the bond.

I've received Vincents permission to become the maintainer of the Slackbuild for the current release. I've modified it w/ enough core functionality to enable a Slackware installation to easily configure bonding. My difficulties in my journey to enable bonding in Slackware compelled me to create a solution that would bring this much needed functionality into Slackware into a simple installable package.

However, there is a caveat. Mainly, the current version of the Linux Bonding Driver (in the current stable kernel), no longer officially supports ifenslave--its use is now considered obsolete. This is sad, because the dev's reasoning is that a) most distro's include bonding functionality in the init scripts (a la RHEL), or b) in lack of such support you can always rely on creating a bond via the sysfs interface (/sys/class/net/bondX).

That being said, Slackware 14.1's kernel (3.10.17), still uses the older bonding driver, which supports ifenslave.

In fact--the current bonding driver doc mentions ifenslave will still function w/ the bonding driver and can be utilized. They just no longer support it and are in favor of the sysfs interface instead (which actually does provide more functionality in the bond initialization process).

So, I realize there is a need for this Slackbuild, although it will only be useful to a small audience (14.1). I'm not sure which kernel current is using, or if the bonding driver in that release still supports ifenslave or not.

Edit: I just checked kernel 3.14.29 (utilized at the moment in current); this kernel utilizes the updated bonding driver which does not officially support ifenslave.

To continue on though, ifenslave isn't the only thing we need to overcome in slackware. Sure, you could create a bond manually by simply:

 - initializing the bond via ifconfig
 - designating the slave interfaces via ifenslave
 - adding the route for the bonded interface into kernel routing table manualy

However, if you want a bonded interface to be created during the boot/startup process--because rc.inet1 includes no functionality for bonded interfaces--you will need to either add the bond initialization commands into rc.local, or the better solution in my opinion, create another rc.d init script. (Note: this will require executable permissions, i.e. chmod 775.)

#!/bin/sh
# rc.bond

        case "$1" in
          'start')
            echo "start bond0"
            #modprobe bonding mode=balance-alb miimon=100
            modprobe bonding mode=0 miimon=50
            modprobe tg3
            ifconfig bond0 up
            ifconfig bond0 192.168.0.210 netmask 255.255.255.0
            ifenslave bond0 eth0
            ifenslave bond0 eth1
            #TODO need to be changed
            ifconfig bond0 hw ether 00:16:3e:aa:aa:aa
        route add default gw 192.168.0.1 metric 1 bond0
          ;;
          'stop')
            ifconfig bond0 down
            rmmod bonding
            rmmod tg3
          ;;
          *)
            echo "Usage: $0 {start|stop}"
          ;;
        esac
#EOF


Credit for the original rc.bond script goes to Mehdi Sadighian.

The bonds' IP & Netmask, and the gateway IP, will need to be changed to reflect your network.

My only modifications were adding the route command to add the default gw.

Also: make sure you modify the HW mac address if you intend to:
 - make multiple bonds on the same system w/ this script
 - utilize this rc.bond script on multiple systems in the same LAN (or VLAN).

When I first tested this out, I had just initialized a bonded interface on both of my servers in my lan, however I was stumped when my attempt to ssh into either system would time out. After digging I realized the HW mac address was the same for both systems in each LAN. Once I ensured each system had a unique MAC, ssh returned to normal and everything was right once again in the LAN.

Apparently, 00:16:3e:aa:aa:aa is the XenSource MAC prefix. Xen recommends its use because it will not conflict w/ any known hardware mac address. I feel this reason merits leaving the prefix here.

I've experimented w/ modifying rc.inet1.conf to include a bonding statement but... it doesn't quite work right. For one, that isn't the proper file to modify, since its sourced by rc.inet1 (which is the rc script that should be modified). 2, every time you run the rc.inet1 script--to start, stop, restart, doesn't matter--because rc.inet1 always sources rc.inet1.conf, it will call rc.bond regardless of the subcommand you pass to it. So when I shutdown my network the rc.bond script would initiate.

I suppose a work around would be to modify the case statement to only source rc.inet1.conf during network initialization.. this may be something to consider, still its really only a hack. 

Honestly, even if the network stack stops, it isn't a problem if the rc.bond script initializes.. This can be seen as a good thing, you'll know none of the slave interfaces will accidentally be initialized w/ a ip address and route attached. (BTW--the documentation does list that as a known problem to watch for.)

However, as you've seen from my previous modifications to rc.inet1.conf, I've added sections for dns and hosts file settings, which now makes rc.inet1.conf more valuable to me. Valuable enough to not want initialize a bond w/o these settings being enabled.

So for now, if you want your system to startup w/ a bonded interface, the simplest solution is to create the rc.bond script I showed above, modify the bond to reflect your network (or add additional bonds), and finally add the following to rc.local:

/etc/rc.d/rc.bond start

In the slackbuild, I plan to include ifenslave tool, a sample rc.bond script to modify (like the one above), and a readme explaining the above.

In the future I will create a slackbuild that will actually utilize the sysfs interface instead, and thus be a supported method of bond creation, which will hopefully bring some cool features too.


3 comments:

  1. Hi,

    Could share your binary package of the ifenslave. I got some errors in compiling the source. Google around but only found your blog for the 14.1.

    Regards,
    Budiarno

    ReplyDelete
  2. Hi,

    I got the some errors to, at this moment the bonding module don't work for me.
    On older version, works fine.

    Att,
    João Paulo

    ReplyDelete