Double your Internet speed: Load Balancing made easy

Ever wanted to combine two WAN connections for faster* internet? I do, for torrenting. And I scripted it.

On the Web, you’ll easily find “tutorials” that just give you some bash script you have to painstakingly modify for it to run. This is as simple as it gets! But see for yourself! (code at the end of this post)

Since I get a dynamic (external) IP right into my PC, that would mean, I’d have to modify that every time. So I made this small script, that only depends on iproute2, which you’ll need anyways, and awk and grep, that should already be on your system.

Just run the script as root and give the network interfaces you want to balance as parameters.

~$ sudo ./load-balance.sh eth0 eth1 wlan0

In a future version, I’d like to add support for dynamically setting the weight (currently, all interfaces get the same priority).

My setup looks like this:

  • eth0 goes to my Uni’s Interweb (they are my ISP)
  • eth1 is connected via a USB-Ethernet-adapter to a router with a UMTS-modem
  • wlan0 is my Android phone in tethering mode

As you can see, it is of course necessary, that you have multiple entry points into the Internet. If you connect your PC with multiple connections to the same WAN, you won’t get any speed increase.

* Load balancing won’t work in all use cases. If you for example just stream a single video (or download a single file), only one of the balanced interfaces will be in use, and no speed increase is visible. But when you download multiple things, like the chunks of a torrent, half of the files/chunks are downloaded over the first IF, and half over the other.

See on GitHub Gist

#!/bin/bash

# Load balance multiple internet connections. Requires iproute2, awk and grep.
# (C) 2016 Tobias Girstmair, isticktoit.net, GPLv2
# Also useful: speedometer -l  -r eth1 -t eth1 -m $(( 1024 * 1024 * 3 / 2 ))
# Not much user error checking is done - only pass working network connections

# script needs root to work and at least two connections to be useful
[ $EUID -eq 0 -a $# -ge 2 ] || {
	echo "Usage (as root): $0 iface1 iface2 ..." >&2
	exit 1
}

get_free_tblnum() { # http://stackoverflow.com/a/28702075
	awk -v RS='\\s+' '{ a[$1] } END { for(i = 10; i in a; ++i); print i }'</etc/iproute2/rt_tables
}

loadbal() {
	IFACE=$1
	TABLE="${IFACE}loadbalance"
	if ! grep -q -w "$TABLE" /etc/iproute2/rt_tables ; then
		echo "$(get_free_tblnum) $TABLE" >> /etc/iproute2/rt_tables
	fi
	MY_IP=$(ip -o -4 addr show $IFACE |awk -F'(\\s|/)+' '{print $4}')
	GW_IP=$(ip route show dev $IFACE | awk '/default/ {print $3}')
	SUBNT=$(ip route show dev $IFACE | awk '/proto kernel/ {print $1}')

	ip route add $SUBNT dev $IFACE src $MY_IP table $TABLE
	ip route add default via $GW_IP table $TABLE
	ip rule add from $MY_IP table $TABLE
	echo nexthop via $GW_IP dev $IFACE weight 1
}

ip route add default scope global $(for IF in "$@"; do loadbal $IF; done)

Changelog:
v1.01: HTML-escaped the code