Using multitable routing for backup connections

example nettopology

In this example the router has three interfaces:

  • eth0 for the local network, rfc1918
  • eth1 is a broadband connection (default gateway) with a volatile ip address
  • ppp0 is a narrow band connection (e.g. gprs, umts, ..) with a volatile ip address

All interfaces are always-on.

For accessing the router and/or the local network from outside, the router connects to a vpn server which distributes the routes to other vpn clients.

In case of losing eth1 we still want to be able to connect to the router and/or the local network. That's what ppp0 is for.

You can define up to 252 custom routing tables in Linux (three tables are pre-defined). These can be referred either by a number or their corresponding mapping:

$ grep '^[^#]' /etc/iproute2/rt_tables
255 local
254 main
253 default
0   unspec

See also linux routing tables.

The default routing table Linux uses is main (not default, as one would suspect). The local table is usually not for fscking around with, it is handled by the kernel and contains loopback addresses, broadcasts, etc. Lower priority tables (up to 253) can be used (almost) for whatever you like. When Linux looks for a route to a specific address, it walks through all tables beginning with 255 and stops at the first match.

Routes to more specific targets override routes to less specific ones, e.g. 192.168.255.0/24 overrides 192.168.0.0/16. So setting a route to 93.184.216.34/32 via ppp0 would override the default route and the vpn connection would be established using the narrow band upstream. We don't want that.

Overriding only works within a single table. And that's what multitable routing is about: we set up a specific route in table 253, in this case a route to the vpn server via ppp0 without overriding the default gateway in table 254:

$ ip route add 93.184.216.34/32 dev ppp0 table default

That's it. As simple as that. Check it:

$ ip route ls
default via 10.255.255.1 dev eth1
10.64.64.64 dev ppp0  proto kernel  scope link  src 10.123.123.123
10.255.255.0/30 dev eth1  proto kernel  scope link  src 10.255.255.2
10.2.2.0/24 dev eth0  proto kernel  scope link  src 10.2.2.1
$ ip route ls table default
93.184.216.34 dev ppp0  scope link
$ ip route get 93.184.216.34
93.184.216.34 via 10.255.255.1 dev eth1  src 10.255.255.2
    cache

Now when eth1 goes down, the main routing table entries regarding eth1 get cleared and the default route vanishes. When trying to connect to the vpn server Linux finds a matching routing entry in table 253 (default).