Bonding wifi and ethernet interfaces

January 10, 2018

How to aggregate multiple network interfaces into a single logical interface?

If you haven’t heard about network bonding - it’s a network setup that allows you to use two or more network devices to act as one interface, giving you expanded bandwidth and some redundancy. Basically you can turn a 1 GiB link into a 2 GiB link for the one virtual interface.

Usually it’s used to bond ethernet devices, but let’s try to mix wifi and ethernet.

As long as the network cable is connected, its interface (e.g. eth0) is used for the network traffic.


The goal is to switch over to the wireless interface transparently, without any loss of network packages when you pull the RJ45-plug. After reconnecting the network cable, it switches back to ethernet.


These steps were tested on Linux Mint 18.3 which is a Ubuntu based distribution.

I assume you have at least two network devices (one wifi, one eth), let’s list them:

ip -br addr show

The result on my laptop is:

lo               UNKNOWN        127.0.0.1/8 ::1/128 
enp3s0           DOWN           
wlp2s0           UP             192.168.1.19/24 ff70::957f:4ecd:d256:43c1/64 
docker0          DOWN           172.17.0.1/16 

As you can see I’m on my wifi at the moment as wlp2s0 is UP end I’m not using my ethernet ensp3s0 (it’s unplugged) connection right now.

If you don’t know which interface represents which device you can also use NetworkManager:

sudo nmcli device status
DEVICE   TYPE      STATE        CONNECTION 
docker0  bridge    connected    docker0    
wlp2s0   wifi      connected    xxxxxxxxxxxx  
enp3s0   ethernet  unavailable  --         
lo       loopback  unmanaged    --   

I replaced my real wifi name with “xxxxxxxxxxxx”, so you will see there a wifi network name you’re currently connected.

Tell the kernel to load the bonding module

If you want to check to see if your bonding module is already loaded in the kernel just run:

lsmod |grep bonding

and you should see something like this:

bonding   163840  0

If not, install neccecary packages:

sudo apt install ifenslave

And insert the module to the kernel:

sudo modprobe bonding

A default content of this file should be similar to:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

This is a standard loopback interface configuration which informs the kernel to bring the adapter up automatically on start-up. iface lo inet loopback tells the system that this interface is the system’s loop-back interface or more commonly referenced as 127.0.0.1.

Let’s start by adding two existing interfaces to the list:

auto enp3s0
iface enp3s0 inet manual
    bond-master bond0
    bond-primary enp3s0 wlp2s0

auto wlp2s0
iface wlp2s0 inet manual
    bond-master bond0
    bond-primary enp3s0 wlp2s0
    wpa-ssid xxxxxxxxxxxx
    wpa-bssid XX:XX:XX:XX:XX:XX
    wpa-psk  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • bond-master bond0 is fairly straightforward, it indicates which interface is master (we will create bond0 interface further)

  • bond-primary enp3s0 wlp2s0 is specifying which slave is the primary device. The specified device will always be the active slave while it is available. Only when the primary is off-line will alternate devices be used.

wpa-ssid is your wifi network broadcasted name, wpa-bssid is a mac of your wifi router, wpa-psk is your wifi password (don’t keep it as a plain text, use wpa_passphrase [passphrase]).

New interface (bond0)

The interface bond0 can be set a static one or as dhcp:

auto bond0
iface bond0 inet static
    address 192.168.1.10
    netmask 255.255.255.0
    network 192.168.1.0
    gateway 192.168.1.1

These settings are down to individual congiguration settings of your network but very likely these will work for you as well but you may prefer dhcp, in this replace inet static with inet dhcp and remove everything below.

Time for bonding settings:

# Bonding
    bond-slaves none
    bond-mode active-backup
    bond-miimon 100
    bond-downdelay 200
    bond-updelay 200
  • bond-slaves none this one is very hard to find in any documentation but based on my understanding it instructs to not proceed with slaves interfaces before bond0 is started. Ping me if you find a better explaination.

  • bond-mode active-backup means that when the active interface fails, the other takes over. There are different options available here like broadcast which transmits everything to all slave devices, or balance-tld (adaptive load balancing), or balance-xor (selectable hashing algorithm) and a few more

  • bond-miimon 100 determines how often the link state of each slave is inspected for link failures. A value of zero disables MII link monitoring

  • bond-downdelay 200 means that the system will wait 200 ms before concluding that the currently active interface is indeed down.

  • bond-updelay 200 is used to tell the system to wait on using the new active interface until 200 ms after the link is brought up.

updelay and downdelay - both of these values must be multiples of the miimon value otherwise the system will round down

The completed setup should look like this:

auto enp3s0
iface enp3s0 inet manual
    bond-master bond0
    bond-primary enp3s0 wlp2s0

auto wlp2s0
iface wlp2s0 inet manual
    bond-master bond0
    bond-primary enp3s0 wlp2s0
    wpa-scan-ssid 1
    wpa-ssid xxxxxxxxxxxx
    wpa-bssid XX:XX:XX:XX:XX:XX
    wpa-psk  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

auto bond0
iface bond0 inet dhcp
    bond-slaves none
    bond-mode active-backup
    bond-miimon 100
    bond-downdelay 200
    bond-updelay 200

Testing the Bond Configuration

Enslave interfaces and restart network:

sudo ifenslave bond0 enp3s0 wlp2s0
sudo /etc/init.d/networking restart

Checkout the output:

cat /proc/net/bonding/bond0

Output:

Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: enp3s0 (primary_reselect always)
Currently Active Slave: enp3s0
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 200
Down Delay (ms): 200

Slave Interface: enp3s0
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: XX:XX:XX:XX:XX:XX
Slave queue ID: 0

Slave Interface: wlp2s0
MII Status: up
Speed: Unknown
Duplex: Unknown
Link Failure Count: 0
Permanent HW addr: XX:XX:XX:XX:XX:XX
Slave queue ID: 0

You can also check:

dmesg | grep -i bond0

[ 1708.596284] IPv6: ADDRCONF(NETDEV_CHANGE): bond0: link becomes ready
[ 1708.714483] bond0: Enslaving wlp2s0 as a backup interface with a down link
[ 1712.352020] bond0: link status up for interface wlp2s0, enabling it in 200 ms
[ 1712.560172] bond0: link status definitely up for interface wlp2s0, 0 Mbps full duplex
[ 1823.200935] bond0: link status down for active interface enp3s0, disabling it in 200 ms
[ 1823.409140] bond0: link status definitely down for interface enp3s0, disabling it
[ 1823.409146] bond0: making interface wlp2s0 the new active one
[ 1855.865317] bond0: link status up for interface enp3s0, enabling it in 200 ms
[ 1856.073355] bond0: link status definitely up for interface enp3s0, 100 Mbps full duplex
[ 1856.073358] bond0: making interface enp3s0 the new active one
[ 3032.576211] bond0: link status down for active interface enp3s0, disabling it in 200 ms
[ 3032.784299] bond0: link status definitely down for interface enp3s0, disabling it
[ 3032.784304] bond0: making interface wlp2s0 the new active one

If you run sudo nmcli device status you probably notice that NetworkManager didn’t pick up bond0, you can safely disable it:

sudo systemctl stop NetworkManager.service
sudo systemctl disable NetworkManager.service

Use ip -br addr show instead:

ip -br addr show
lo               UNKNOWN        127.0.0.1/8 ::1/128 
enp3s0           UP             
wlp2s0           UP             
docker0          DOWN           172.17.0.1/16 
bond0            UP             192.168.1.29/24 ff50::4fdd:6aff:fedc:fddc/64 

Now you should enjoy packetless switching between network devices, which in practice means your video streaming or VPN connection won’t be frozen when unplugging RJ45 cable :)


Source:

[1] Kernel Docs