Crmgo Blog

Combining the bandwidth of two internet channels and simple failover

Combining the bandwidth of two internet channels and simple failover

First, let's define the variables: $ cat /etc/balance/vars #!/bin/bash # LAN interface IF0= "eth1" # WAN interface 1 IF1= "eth0" # WAN interface 2 IF2= "ppp0" IP1= "194.9.xx.xx" IP2= "`ip addr show $IF2 | grep inet | awk '{print $2}'`" #…

Combining the bandwidth of two internet channels and simple failover

First, let's define the variables:
$ cat /etc/balance/vars

  1. #!/bin/bash
  2. # LAN interface
  3. IF0="eth1"
  4. # WAN interface 1
  5. IF1="eth0"
  6. # WAN interface 2
  7. IF2="ppp0"
  8. IP1="194.9.xx.xx"
  9. IP2="`ip addr show $IF2 | grep inet | awk '{print $2}'`"
  10. # gateway 1
  11. P1="194.9.xx.xx"
  12. # gateway 2
  13. P2="195.5.xx.xx"
  14. # LAN netmask
  15. P0_NET="192.168.0.0/24"
  16. # WAN1 netmask
  17. P1_NET="194.9.xx.xx/xx"
  18. # WAN2 netmask
  19. P2_NET="195.5.xx.xx/xx"
  20. TBL1="provider1"
  21. TBL2="provider2"
  22. # Relative weight of channels bandwidth
  23. W1="2"
  24. W2="1"


Add two additional routing tables to the /etc/iproute2/rt_tables file:
echo "1 provider1" >> /etc/iproute2/rt_tables
echo "2 provider2" >> /etc/iproute2/rt_tables

Now, let's write a script that will set up all the necessary routes and firewall rules:

cat /etc/balance/routing.sh

  1. #!/bin/bash
  2. . /etc/balance/vars
  3. echo "1" > /proc/sys/net/ipv4/ip_forward
  4. ip route add $P1_NET dev $IF1 src $IP1 table $TBL1 > /dev/null 2>&1
  5. ip route add default via $P1 table $TBL1 > /dev/null 2>&1
  6. ip route add $P2_NET dev $IF2 src $IP2 table $TBL2 > /dev/null 2>&1
  7. ip route add default via $P2 table $TBL2 > /dev/null 2>&1
  8. ip route add $P1_NET dev $IF1 src $IP1 > /dev/null 2>&1
  9. ip route add $P2_NET dev $IF2 src $IP2
  10. ip route add default via $P1 > /dev/null 2>&1
  11. ip rule add from $IP1 table $TBL1 > /dev/null 2>&1
  12. ip rule add from $IP2 table $TBL2 > /dev/null 2>&1
  13. ip route add $P0_NET   dev $IF0 table $TBL1 > /dev/null 2>&1
  14. ip route add $P2_NET   dev $IF2 table $TBL1 > /dev/null 2>&1
  15. ip route add 127.0.0.0/8 dev lo  table $TBL1 > /dev/null 2>&1
  16. ip route add $P0_NET   dev $IF0 table $TBL2 > /dev/null 2>&1
  17. ip route add $P1_NET   dev $IF1 table $TBL2 > /dev/null 2>&1
  18. ip route add 127.0.0.0/8 dev lo  table $TBL2 > /dev/null 2>&1
  19. iptables -t nat -F POSTROUTING
  20. iptables -t nat -A POSTROUTING -s $P0_NET -o $IF1 -j MASQUERADE
  21. iptables -t nat -A POSTROUTING -s $P0_NET -o $IF2 -j MASQUERADE

This set of commands ensures that response packets are routed through the interface on which the request was received, as well as performing masquerading on both interfaces.

Now let's write a script that will determine whether a particular channel is operational and, accordingly, change the default gateway records.

$ cat /etc/balance/check.sh

  1. #!/bin/bash
  2. . /etc/balance/vars
  3. OLDIF1=0
  4. OLDIF2=0
  5. . /etc/balance/routing.sh
  6. while true; do
  7. ping -c 3 -s 100 $P1 -I $IF1 > /dev/null
  8. if [ $? -ne 0 ]; then
  9. echo "Failed IF1!"
  10. NEWIF1=0
  11. else
  12. NEWIF1=1
  13. fi
  14. ping -c 3 -s 100 $P2 -I $IF2 > /dev/null
  15. if [ $? -ne 0 ]; then
  16. echo "Failed IF2!"
  17. NEWIF2=0
  18. else
  19. NEWIF2=1
  20. fi
  21. if (( ($NEWIF1!=$OLDIF1) || ($NEWIF2!=$OLDIF2) )); then
  22. echo "Changing routes"
  23. if (( ($NEWIF1==1) && ($NEWIF2==1) )); then
  24. echo "Both channels"
  25. ip route delete default
  26. ip route add default scope global nexthop via $P1 dev $IF1 weight $W1 \
  27. nexthop via $P2 dev $IF2 weight $W2
  28. elif (( ($NEWIF1==1) && ($NEWIF2==0) )); then
  29. echo "First channel"
  30. ip route delete default
  31. ip route add default via $P1 dev $IF1
  32. elif (( ($NEWIF1==0) && ($NEWIF2==1) )); then
  33. echo "Second channel"
  34. ip route delete default
  35. ip route add default via $P2 dev $IF2
  36. fi
  37. else
  38. echo "Not changed"
  39. fi
  40. OLDIF1=$NEWIF1
  41. OLDIF2=$NEWIF2
  42. sleep 3
  43. done

We check the channel status by pinging the gateway, and if there is no response to 3 consecutive pings, we consider the channel to be down and accordingly exclude it from the routing table.

Thus, if both channels are working:

$ ip route
195.5.xx.xx dev ppp0 proto kernel scope link src 95.133.xx.xx
194.9.xx.xx/xx dev eth0 proto kernel scope link src 194.9.xx.xx
192.168.0.0/24 dev eth1 proto kernel scope link src 192.168.0.75
default
nexthop via 194.9.xx.xx dev eth0 weight 2
nexthop via 195.5.xx.xx dev ppp0 weight 1

In total, we have two default gateways, the first with a weight of 2 and the second with a weight of 1. That is, twice as much traffic will go through the first channel compared to the second.

To customize these scripts for your needs, you need to configure the values in the vars file; the other scripts practically do not require configuration.

Note: This post may be AI-assisted and then human-edited. Editorial responsibility: Dmytro Lomaka, Kaltenkirchen.