I have two ISP connections and need automatic load balancing between them. I also need to handle failed connections (not use one that does not work).

First link is a PPTP connection (ppp0), second is usual Ethernet. The system is Gentoo Linux.

Currently, I achieved basic balancing with ip route, but looks like it is not working very well. Here's what I've used:

ip rule $ADD from $IP1 table rt_link1
ip rule $ADD fwmark 1 lookup rt_link1
ip rule $ADD from $IP2 table rt_link2
ip rule $ADD fwmark 2 lookup rt_link2
$NET2 dev eth2 src $IP2 table rt_link2
default via GW2 table rt_link2
$NET2 dev eth2 src $IP2
$NET1 dev ppp0 src $IP1 table rt_link1
default via GW1 table rt_link1
$NET1 dev ppp0 src $IP1
default scope global nexthop via $GW1 weight 1 nexthop via $GW2 dev eth2 weight 1

As a former core team member of the LVS project, I would strongly advise against using this technology for balancing multiple internet connections; in fact I can almost guarantee you that it won't work as expected.

Now, the handling of failed provider links is often referred to as dead gateway detection (DGD), and sometimes referred to as neighbour unreachability detection (NUD). According to RFC816 and RFC1122 there are multiple ways to perform DGD, however I've only seen about 3 of those in the wild (from an old post of mine to the LVS mailing-list):

  • Link-layer information that reliably detects and reports host failures (e.g., ARPANET Destination Dead messages) should be used as negative advice.
  • An ICMP Redirect message from a particular gateway should be used as positive advice about that gateway.
  • Packets arriving from a particular link-layer address are evidence that the system at this address is alive. However, turning this information into advice about gateways requires mapping the link-layer address into an IP address, and then checking that IP address against the gateways pointed to by the route cache. This is probably prohibitively inefficient.

When I left active linux kernel networking development in 2006, there was still no definite decision about how to implement NUD state changes. A friend of mine and core developer of LVS, Julian Anastasov, needed to solve your challenge back in 2002. So, one evening he sat down and wrote a working version of the DGD for static routing by adding NUD state to the FIB (forward information base). You can find his patch here and the documentation here, here and here. This should give you plenty of information on your further quest in addressing this non-trivial task. I see that the patches are still wildly used and therefore kept up to date with recent kernels. You might want to start with a script like the following (written by Robert Kurjata):

# This script is done by : Robert Kurjata Sep, 2003.
# feel free to use it in any useful way


#--------------- LINK PART -----------------
# EXTIFn - interface name
# EXTIPn - outgoing IP
# EXTMn  - netmask length (bits)
# EXTGWn - outgoing gateway

# LINK 1

# LINK 2

# removing old rules and routes

echo "removing old rules"
${IP} rule del prio 50 table main
${IP} rule del prio 201 from ${EXTIP1}/${EXTM1} table 201
${IP} rule del prio 202 from ${EXTIP2}/${EXTM2} table 202
${IP} rule del prio 221 table 221
echo "flushing tables"
${IP} route flush table 201
${IP} route flush table 202
${IP} route flush table 221
echo "removing tables"
${IP} route del table 201
${IP} route del table 202
${IP} route del table 221

# setting new rules
echo "Setting new routing rules"

# main table w/o default gateway here
${IP} rule add prio 50 table main
${IP} route del default table main

# identified routes here
${IP} rule add prio 201 from ${EXTIP1}/${EXTM1} table 201
${IP} rule add prio 202 from ${EXTIP2}/${EXTM2} table 202

${IP} route add default via ${EXTGW1} dev ${EXTIF1} src ${EXTIP1} proto static table 201
${IP} route append prohibit default table 201 metric 1 proto static

${IP} route add default via ${EXTGW2} dev ${EXTIF2} src ${EXTIP2} proto static table 202
${IP} route append prohibit default table 202 metric 1 proto static

# mutipath
${IP} rule add prio 221 table 221

${IP} route add default table 221 proto static \
            nexthop via ${EXTGW1} dev ${EXTIF1} weight 2\
            nexthop via ${EXTGW2} dev ${EXTIF2} weight 3

${IP} route flush cache

while : ; do
  ${PING} -c 1 ${EXTGW1}
  ${PING} -c 1 ${EXTGW2}
  sleep 60

Besides that, you could check out the option of running dynamic routing protocols.

  • probably this script is too old. it does not work on latest ubuntu. – Zibri Mar 31 '18 at 23:35
  • @Zibri: I don't understand the "too old" part in conjunction with the script, but what exactly does not work and what constitutes "latest ubuntu"? – Moreaki Apr 7 '18 at 19:14

Use LVS in conjunction with lvs-kiss. Or something similar.

LVS is basically the ìpvsadm command. The only drawback of that load-balancer is that it does not monitor. So you need a program that does that for you and removes the dead link from your configuration (and adds it back one alive again).

ldirectord from the heartbeat-stack might be another lvs-addition (instead of lvs-kiss).

  • thx, i will check – sss123next Apr 20 '12 at 21:45
  • sorry, i not understanding how to use lvs for use two uplinks, as i know lvs is for balance incoming traffic between many phisical nodes, but i need to use many internet connection on one phisical machine and share it for network transparently – sss123next Apr 20 '12 at 22:11
  • So in this case your server is director and two real servers in the same box. One real server is serving ppp0, the other eth2. Incoming LAN-traffic comes from eth0 and/or eth1? – Nils Apr 21 '12 at 19:46
  • incomming lan traffic comming from br1, but i still do not understand how to use lvs for NAT – sss123next Apr 22 '12 at 2:43
  • @sss123next instead of using NAT I would recommend to use a proper proxy - e.g. SQUID. – Nils Apr 22 '12 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.