If one ISP Provider bandwidth is not enough for your needs, you can have multiple lines and load balance between them on Linux. This documentation has been done on Debian and works like a charm :-).
It contains 3 network interfaces:
Is plugged in a special DMZ VLAN (eth0)
The second is plugged on a dedicated VLANS to ISP1 Provider (eth1)
The third is plugged on a dedicated VLANS to ISP2 Provider (eth2)
Internet traffic is load balanced between the two Internet accesses. In the current configuration the weight assigned to ISP1 is 3 and ISP2 1 (it means that 3 times more traffic passes through ISP1 than ISP2).
Network configuration
To do this, we are using the following configuration:
#!/bin/bash# Enable load balancing between ISP1 & ISP2# Enable routing on eth2 uptest"${IFACE}"='eth2'||exit0functiondie(){echo"$@">&2exit1}whichip>/dev/null2>&1||die"Command not found, please install it"whichipcalc>/dev/null2>&1||die"Command not found, please install it"LAN_IFACE='eth0'LAN_IFACE_IP=$(ipas${LAN_IFACE}|awk'($1=="inet") {gsub("/.*", "", $2) ; print $2}')LAN_NET_IP=$(ipcalc-n$(ipas${LAN_IFACE}|awk'($1=="inet") {print $2}')|awk'($1=="Network:") {print $2}')INET1_IFACE='eth1'INET1_IFACE_IP=$(ipas${INET1_IFACE}|awk'($1=="inet") {gsub("/.*", "", $2) ; print $2}')INET1_NET_IP=$(ipcalc-n$(ipas${INET1_IFACE}|awk'($1=="inet") {print $2}')|awk'($1=="Network:") {print $2}')INET1_GW='192.168.1.1'INET1_WEIGHT=1INET2_IFACE=${IFACE}INET2_IFACE_IP=$(ipas${INET2_IFACE}|awk'($1=="inet") {gsub("/.*", "", $2) ; print $2}')INET2_NET_IP=$(ipcalc-n$(ipas${INET2_IFACE}|awk'($1=="inet") {print $2}')|awk'($1=="Network:") {print $2}')INET2_GW='192.168.2.1'INET2_WEIGHT=3# Create routes throught ours network in each tablesiprouteadd${LAN_NET_IP}dev${LAN_IFACE}table100iprouteadd${INET1_NET_IP}dev${INET1_IFACE}src${INET1_IFACE_IP}table100iprouteadd${INET2_NET_IP}dev${INET2_IFACE}table100iprouteadd127.0.0.0/8devlotable100iprouteadd${LAN_NET_IP}dev${LAN_IFACE}table200iprouteadd${INET1_NET_IP}dev${INET1_IFACE}table200iprouteadd${INET2_NET_IP}dev${INET2_IFACE}src${INET2_IFACE_IP}table200iprouteadd127.0.0.0/8devlotable200# Create a default route per tableiprouteadddefaultvia${INET1_GW}table100iprouteadddefaultvia${INET2_GW}table200# Assigning appropriate traffic from an interface to the corresponding tableipruleaddfrom${INET1_IFACE_IP}table100ipruleaddfrom${INET2_IFACE_IP}table200# Force some specific routes if needed# ip route add to x.x.x.x via ${INET1_GW} dev ${INET1_IFACE}# ip route add to x.x.x.x via ${INET1_GW} dev ${INET1_IFACE}# Replacing default routeiproutedeldefault
iprouteadddefaultscopeglobalnexthopvia${INET1_GW}dev${INET1_IFACE}weight${INET1_WEIGHT}nexthopvia${INET2_GW}dev${INET2_IFACE}weight${INET2_WEIGHT}iprouteflushcached
# If you're using ntop, you should restart it for new changes to take effect# /etc/init.d/ntop restart &
Now let's create the disable script (/etc/network/if-down.d/disable_balanced_routing):
Since the ISP2 Internet access is unstable, we are using a self-made script to check it, and disable traffic through this interface if needed. This script runs in the background, and is launched by this init script:
#!/bin/bash# Check that the ISP2 works fine, and, if this is not the case, suppress balanced routing# TODO : avoid multiple variable declaration between /etc/network/if-up.d/enable_balanced_routing and this script# Interval to check connectivity on ISPscheck_interval=5IFACE='eth2'HOST='www.google.fr'LOGFILE="/var/log/$(basename${0/.sh/.log})"PIDFILE="/var/run/$(basename${0/.sh/.pid})"INET1_IFACE='eth1'INET1_IFACE_IP=$(ipas${INET1_IFACE}|awk'($1=="inet") {gsub("/.*", "", $2) ; print $2}')INET1_NET_IP=$(ipcalc-n$(ipas${INET1_IFACE}|awk'($1=="inet") {print $2}')|awk'($1=="Network:") {print $2}')INET1_GW='192.168.1.1'INET1_WEIGHT=1INET2_IFACE=${IFACE}INET2_IFACE_IP=$(ipas${INET2_IFACE}|awk'($1=="inet") {gsub("/.*", "", $2) ; print $2}')INET2_NET_IP=$(ipcalc-n$(ipas${INET2_IFACE}|awk'($1=="inet") {print $2}')|awk'($1=="Network:") {print $2}')INET2_GW='192.168.2.1'INET2_WEIGHT=3DO_RUN=true# We catch SIGTERM signal to end this script properlytrapdo_stop15functiondie(){echo"${@}">&2echo"$(LANG=Cdate"+%h %d %H:%M:%S") : ${@}">>${LOGFILE}exit1}functionlog(){echo"$(LANG=Cdate"+%h %d %H:%M:%S") : ${@}">>${LOGFILE}}functiontest_interface(){localtest_ip=$(host-tA${HOST}|awk'($2=="has" && $3=="address") {print $4}'|head-n1)# if balanced routing is disabledif!$(iproshow|grep-Eq"nexthop via ${INET2_GW}");theniprouteaddto${test_ip}via${INET2_GW}dev${INET2_IFACE}if$(ping-W1-q-c3-I${IFACE}${test_ip}>/dev/null2>&1);thenenable_balanced_routing
elselog"We cannot ping ${test_ip} and balanced routing is already disabled"fiiproutedelto${test_ip}via${INET2_GW}dev${INET2_IFACE}# if balanced routing is enabled, and we cannot ping our test IPelif!$(ping-W1-q-c3-I${IFACE}${test_ip}>/dev/null2>&1);thenlog"We cannot ping ${test_ip}. Doing a second check just to be sure ..."# We double check if we cannot join our test IPif$(ping-W1-q-c3-I${IFACE}${test_ip}>/dev/null2>&1);thenlog"It's okay, I can ping ${test_ip} during the second test"elsedisable_balanced_routing
fifi}functiondisable_balanced_routing(){log"Disabling balanced routing"iproutedeldefault
iprouteadddefaultvia${INET1_GW}iprouteflushcached
}functionenable_balanced_routing(){log"Enabling balanced routing"iproutedeldefault
iprouteadddefaultscopeglobalnexthopvia${INET1_GW}dev${INET1_IFACE}weight${INET1_WEIGHT}nexthopvia${INET2_GW}dev${INET2_IFACE}weight${INET2_WEIGHT}iprouteflushcached
}functionpid_managment(){localmy_pid=$$localold_pid
if[-f${PIDFILE}];thenold_pid=$(<${PIDFILE})ps--no-headers--pid${old_pid}>/dev/null&&die"Deamon is already up and running"fiecho${my_pid}>${PIDFILE}}functiondo_stop(){log"${0} is stopping..."DO_RUN=false}log"${0} is starting..."pid_managment
# Launch check every x secondswhile${DO_RUN};doif$(iplinkshow${IFACE}|grep-qUP);thentest_interface
fisleep$check_intervaldonelog"${0} is stopped"
Then we'll set good rights and auto start on boot: