Bonding eth0 and wlan0 on Arch Linux
Yesterday at work, a couple of my coworkers were trying to bond two ethernet ports on a Synology NAS. For whatever reason, this made me want to play with bonding network interfaces on my own computers. So I began trying to come up with a good reason to use valuable time to play with interface bonding.
One thing that has always driven me nuts about laptops is that connections are severed when I have to unplug my ethernet cable and take the laptop elsewhere. It never seemed to matter if I was using NetworkManager or anything else--connections were dropped, and the resulting annoyances ranged from minor to much rage. Having Pidgin drop connections and reconnect was a minor annoyance. Downloading a 4.2GB linux ISO and having the connection cut at 96% caused much rage.
Anyway, I decided to see if I could use bonding to reduce the frustration with such situations. Since my laptop is usually plugged into the ethernet, I wanted to use eth0 as my primary interface. It's faster and more reliable than wireless. When my ethernet connection fails, for whatever reason, I wanted it to fall back to wlan0. Ideally, things like downloads or streaming music/movies would continue uninterrupted.
Furthermore, I wanted my KVM to be able to use the bonded interfaces inside of my virtual machines. This called for a bridge.
To quickly see this in action, check the videos below!
I configured this on a relatively new Arch Linux installation. Here's the software I used:
- linux: 3.4.8-1
- initscripts: 2012.08.2-1
- netcfg: 2.8.9-1
- netcfg-bonding: 1.5.1-1
- ifenslave: 1.1.0-7
- bridge-utils: 1.5-1
The first thing you need to do to get this working, after installing all of the above packages, is load the bonding kernel module. In my particular case, as I mentioned earlier, I wanted to use eth0 when available and use wlan0 otherwise. As such, I used the active-backup bonding mode. If you're interested in the other bonding modes, I would suggest reading up on bonding. I'm pretty new to all of this bonding magic, so I can't guarantee that I'll be of any use if you don't follow my instructions :)
Back to configuration. I placed my bonding configuration in /etc/modprobe.d/bonding.conf. The only thing that may not be self-explanatory is the miimon setting. I learned from this bonding article that this option "specifies the MII link monitoring frequency in milliseconds." In other words, this is how often the system will check to see if a failover is necessary.
options bonding mode=active-backup options bonding miimon=100 options bonding primary=eth0
After creating that file, you simply insert the module into the kernel:
To get bonding to work when you reboot your machine, you should either add bonding to your MODULES array in /etc/rc.conf or, if you're using more recent initscripts stuff, place a file in /etc/modules-load.d. I chose the latter solution.
Next, you must create some network profiles for netcfg. Prior to this bonding project, I had been using wicd or networkmanager to handle most of my networking needs. It seems like a bad idea to try using either of these, or the standard network daemon even, if you plan to use a configuration similar to what follows. Just FYI.
I created a network profile for the bonded interfaces as such:
CONNECTION="bonding" INTERFACE="bond0" SLAVES="eth0" IP="dhcp" DHCP_TIMEOUT=10 SLAVE_TIMEOUT=5
Notice that wlan0 isn't in the SLAVES list. This is because I also have a network profile for my home wireless connection to handle the authentication and whatnot:
CONNECTION="wireless" DESCRIPTION="Home connection" INTERFACE="wlan0" SECURITY="wpa" ESSID="wouldntyouliketoknow" KEY="derpies" IP="static" IFOPTS="0.0.0.0" PRE_UP="ifenslave bond0 wlan0" PRE_DOWN="ifenslave -d bond0 wlan0"
I have one more network profile for the bridged interface that allows my KVM guests to live on the same network as everything else. If you're not using KVM or don't want a bridged interface, you don't need this one.
INTERFACE="br0" CONNECTION="bridge" DESCRIPTION="KVM Bridge Connection" BRIDGE_INTERFACES="bond0" IP="dhcp" POST_UP="brctl setfd br0 0"
Finally, I added these profiles to my /etc/conf.d/netcfg:
NETWORKS=(bonded home br0)
Again, if you don't need a bridged interface, you don't need to include the br0 profile in there.
You may or may not want to test your individual network profiles by doing something like:
netcfg -u home # try to bring the profile up netcfg -d home # bring the profile down
If you have problems connecting to your wireless access point, I suggest tweaking and testing your profile until it works. If you use MAC address filtering for wireless security on your router, you might want to make sure that the MAC of your ethernet interface is in the list of permitted MAC addresses. When you setup bonding, all of the bonded interfaces seem to share the same MAC.
Try It Out
Pretty much all that's left is starting up the new network configuration! To do this, first make sure your previous networking daemon is turned off. For example, you might run one of the following commands:
rc.d stop network rc.d stop wicd rc.d stop networkmanager
Once you've done that, you simply run:
rc.d start net-profiles
If your setup is anything like mine, you might see ifconfig output similar to this (notice that my MAC addresses have been changed, but that they're identical for bond0, br0, eth0, and wlan0):
bond0: flags=5443<UP,BROADCAST,RUNNING,PROMISC,MASTER,MULTICAST> mtu 1500 ether 00:24:be:00:24:be txqueuelen 0 (Ethernet) RX packets 7318719 bytes 8578112000 (7.9 GiB) RX errors 0 dropped 33241 overruns 0 frame 0 TX packets 3404477 bytes 3562828808 (3.3 GiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.128.55 netmask 255.255.255.128 broadcast 192.168.128.127 inet6 fe80::224:beff:fec7:9895 prefixlen 64 scopeid 0x20<link> ether 00:24:be:00:24:be txqueuelen 0 (Ethernet) RX packets 4759641 bytes 4771378631 (4.4 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2119926 bytes 3491247232 (3.2 GiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth0: flags=6211<UP,BROADCAST,RUNNING,SLAVE,MULTICAST> mtu 1500 ether 00:24:be:00:24:be txqueuelen 1000 (Ethernet) RX packets 7243938 bytes 8512402737 (7.9 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3388055 bytes 3561344335 (3.3 GiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 18 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 16436 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 338869 bytes 263959385 (251.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 338869 bytes 263959385 (251.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255 ether 36:11:59:de:92:73 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 wlan0: flags=6211<UP,BROADCAST,RUNNING,SLAVE,MULTICAST> mtu 1500 ether 00:24:be:00:24:be txqueuelen 1000 (Ethernet) RX packets 74781 bytes 65709263 (62.6 MiB) RX errors 0 dropped 33241 overruns 0 frame 0 TX packets 16422 bytes 1484473 (1.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Also, if you haven't been using netcfg already, you will probably want to update your DAEMONS array in /etc/rc.conf. Again, be sure you disable your previous networking daemon (if necessary) by placing a ! before the daemon's name (or just remove it from the array). Then add net-profiles into the array somewhere, probably closer to the beginning of the array.
Hopefully that works for you! Please share your experiences (both good and bad) in the comments! If you run into troubles, I will try to be of use, and hopefully others will chime in too.
Here are a couple of videos for those of you who are interested. The first is a lower-quality, but maybe easier-to-read-on-small-screens video. The second is just shy of 1080p size-wise.