Combining the bandwidth of two Internet channels and simple fault tolerance

    I have my own home network, with a linux server, and it is connected to the Internet using a wireless connection - on the roof there is an antenna and a router, and a twisted pair cable is connected to the server. All in general, it’s not bad, a channel with a guaranteed band in both directions, a constant IP address, quite reliable, rarely falls. But here he has one minus - the price bites.
    The provider’s pricing policy is designed in such a way that in order to double the speed, you also have to pay twice as much. And I want more speed! And reliability too - like during severe frosts, the router became “cold” and there was no Internet in the evening and at night.
    Therefore, I decided to bring home a second Internet channel, the choice fell on one well-known provider in Ukraine, providing access via ADSL. It has inexpensive tariffs and an ADSL modem is inexpensive. So I did, connected, stuck the ADLS modem in the switch - everything works. But I didn’t want to refuse the good old wireless channel, so I decided to make sure that Internet traffic went through both channels at once, so that I could take advantage of the total bandwidth. Yes, and so that with the fall of one channel, the whole load would be borne by the other.



    After searching the Internet, I found that there are at least two solutions:

    - At the firewall level, scatter TCP sessions on different interfaces. Disadvantages - sites that have sessions bound to an IP address will stop working, as consecutive requests from one user can come on different channels and from different IPs.
    - At the routing level, scatter routes through different interfaces. There will be no problems with the first solution, since routes are cached and subsequent calls to the same address will go through the same interface. But the balancing will not be so accurate, and downloading from one server even in several streams will not be able to achieve the total speed of two channels.

    I chose for myself balancing using routing, since the stable operation of all sites was very important to me, well, this functionality was already in my core, and the firewall would have to be patched.

    So let's get started!

    First, define the variables:
    $ cat / etc / balance / vars Add two additional routing tables to the / etc / iproute2 / rt_tables file: Now we will write a script that will record all the necessary routes and firewall rules: cat /etc/balance/routing.sh This set of commands provides the routing of responses through the interface on which the request was received, as well as masquerading on both interfaces. Now we’ll write a script that will determine whether a particular channel will work and change the default gateway entries accordingly. $ cat /etc/balance/check.sh

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




    echo "1 provider1" >> /etc/iproute2/rt_tables
    echo "2 provider2" >> /etc/iproute2/rt_tables






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








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


    We check the operation of the channel by the ping gateway, and if there is no answer to 3 pings in a row, we consider that the channel has fallen, and accordingly exclude it from the routing table.

    Thus, if both channels work:

    $ ip route In total, we have two default gw, 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 than through the second. In order to customize these scripts to your needs, you need to configure the values ​​in the vars file, the rest of the scripts practically do not require configuration.
    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





    Also popular now: