20100112

Hack to allow automatic wired/wireless failover with lagg on FreeBSD

For years I've had a love/hate relationship with my wireless card. On the one hand, it allows me to roam. On the other I like being able to plug into the wired Ethernet when I'm sitting at my desk since I get better throughput and lower latency. So for years, I just loaded and unloaded kernel modules to make dhclient (and/or wpa_supplicant) do its thing. This changed the IP address of my box, which messed up NFS mounts until I went back to the old way.

Recently, Josh Paetzel came up with a way to use lagg to do automatic failover. Inspired by the lagg man page, he created a number of rc.conf lines that would do this automatically. Xin Li and I refined the trick a bit. To completely integrate this into FreeBSD, I suppose that the rc.d scripts would need to be enhanced to automatically generate these lines when appropriate. However, the hack is so easy to do now, I'm going to share it with you here. Xin Li is writing up a longer description of how to set this up for the handbook. Let's say you have a ath0 wireless interface, and a re0 wired interface, just add the following to your /etc/rc.conf file:

  • ifconfig_re0="up"

  • ifconfig_ath0=`ifconfig re0 ether`

  • ifconfig_ath0="ether ${ifconfig_ath0##*ether }"

  • wlans_ath0="wlan0"

  • ifconfig_wlan0="WPA"

  • cloned_interfaces="lagg0"

  • ifconfig_lagg0="laggproto failover laggport re0 laggport wlan0 DHCP"



This bit of code brings up re0, programs ath0 with the ethernet MAC address of re0 (so your MAC doesn't change when you switch over), creates a wlan0 interface from ath0, causes lagg0 to be created and configured to do the fail over.

Hope this tip is useful...

Revision at Wed Jan 13 16:00:00 UTC 2010:

Note: "ifconfig re0 ether" doesn't work in versions prior to 8.0. The following should fix it, but I don't have a system to test it on:
  • ifconfig_ath0=`ifconfig re0 ether`

  • ifconfig_ath0="${ifconfig_ath0##*ether}"

  • ifconfig_ath0="ether ${ifconfig_ath0%%inet*}"

  • This sequence avoids using grep, awk and/or sed to accomplish this (and thus touch /usr too early for systems where / and /usr are on different partitions).

    Also corrected the bwi0 reference in the feedback...

    Revision at Mon Jan 18 23:00:00 UTC 2010:
    Corrected () vs {} confusion in the above...

    5 comments:

    Warner Losh said...

    Changes all instances of bwi0 to ath0 in post... I changed my mind on which wireless card to use part way though the post and didn't cleanup them all :(

    Unknown said...

    You managed to miss one instance of bwi0 (ifconfig_bwi0)

    Very useful indeed! I knew it existed, but this is definitely a trivial but useful example of its use. I like the trick with changing the MAC address.

    The trick with 'ifconfig re0 ether' however does not seem to work with FreeBSD 7. You would need to use

    ifconfig re0 | awk '/ether / {print $2}'

    Anonymous said...

    I've tried on FreeBSD 8.0-STABLE (weekly synced and upgraded) with re and ath and it looks like ath is unable to connect to the AP

    Connecting manualy only with ath (without lagg) works fine.

    Did you tried with other wifi cards ?

    Warner Losh said...

    I tried bwi on an early version of these patches, but not extensively. I'm posting this from my netbook that has Atheros wireless and wired (ath0 and ale0). And it seems to work fine.

    Josh updated his original example to me to include a devd.conf entry that helps fail over to wlan0. As soon as I've tested it I'll update this post...

    Warner Losh said...

    Looks like the following in devd.conf will help. Thanks to Serge Semenenko for posting this to mobile@.

    notify 0 {

    match "system" "IFNET";

    match "subsystem" "wlan0";

    match "type" "LINK_UP";

    media-type "802.11";

    action "ifconfig lagg0 laggport wlan0";

    };