03 February 2011

Static Routes in Linux

Nearly every UNIX sysadmin at some point will need to know how to manage
a host's routing table.  With that in mind, here's how to manage static
routes on a Red Hat Linux clone.  Our details for this are:
        HOST:           tux
        PROMPT:         tux [0]
        OS:             CentOS 5.4 Linux
In the following exmple, a route is added for network 10.11.18.0/24
(10.11.18.0 - 10.11.18.255).  Since the network is directly reachable
from 'eth0', we set 'eth0' as the gateway with the 'dev' parameter:
        tux [0] /sbin/route add -net 10.11.18.0/24 dev eth0
In the next example, we attempt to add a route for 10.17.4.35/27
(10.17.4.32 - 10.17.4.63), using 10.0.22.44 as the gateway:
        tux [0] /sbin/route add -net 10.17.4.35 netmask 255.255.255.224 gw 10.0.22.44
        route: netmask doesn't match route address
        <snip...>
                help output
        <snip...>
        tux [4]
The above attempt fails because the 'route' and 'ip' commands are
expecting the network to be specified on a network boundary, specifically
the network address.  Unlike other operating systems, we can't simply use
one of the IP addresses contained within the network block.  To determine
the appropriate "network address", we can use 'ipcalc' if it is installed,
or we can use 'ipcalc.pl':
    ipcalc (either 'ipcalc' example results in the same output):

        tux [0] /bin/ipcalc -npmb 10.17.4.35 255.255.255.224
        tux [0] /bin/ipcalc -nmpb 10.17.4.35/27
        NETMASK=255.255.255.224
        PREFIX=27
        BROADCAST=10.17.4.63
        NETWORK=10.17.4.32

    ipcalc.pl (either 'ipcalc.pl' example results in the same output):

        tux [0] /usr/local/bin/ipcalc.pl 10.17.4.35 255.255.255.224
        tux [0] /usr/local/bin/ipcalc.pl 10.17.4.35/27

                10.17.4.35/27; 32 IP addresses
                10.17.4.32 => 10.17.4.63 (255.255.255.224)
As an aside, the "PREFIX" value from 'ipcalc' is the CIDR notation for
the network.  Now that we have the appropriate information, let's go
back to adding the route for '10.17.4.32/27':
        tux [0] /sbin/route add -net 10.17.4.32 netmask 255.255.255.224 gw 10.0.22.44
It's noteworthy to mention that 'route' will accept either netmask values
(netmask 255.255.255.224) or CIDR notation (/27).  If you'd rather use
'ip route add', 'ip' only accepts CIDR notation.  In the last example, we
add a host route for '192.168.34.43' accessible via gateway '192.168.56.88:
        tux [0] /sbin/route add -host 192.168.34.43 gw 192.168.56.88
A review of our routing table shows the newly added routes (I've identified
them with "<====" at the end of the lines):
        tux [0] /bin/netstat -rn
        Kernel IP routing table
        Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
        192.168.34.43   192.168.56.88   255.255.255.255 UGH       0 0          0 eth1   <====
        10.17.4.32      10.0.22.44      255.255.255.224 UG        0 0          0 eth0   <====
        192.168.56.0    0.0.0.0         255.255.255.0   U         0 0          0 eth1
        10.0.22.0       0.0.0.0         255.255.254.0   U         0 0          0 eth0
        10.11.18.0      0.0.0.0         255.255.255.0   U         0 0          0 eth0   <====
        0.0.0.0         127.0.0.1       0.0.0.0         UG        0 0          0 lo
In order to retain the above routes through a reboot, we need to update
a few files.  Starting with 'static-routes', we can essentially add the
same syntax as we would via the 'route' command, though stripping the
hyphen (-) from '-net' or '-host':
        tux [0] /bin/cat /etc/sysconfig/static-routes
        any net 10.17.4.32 netmask 255.255.255.224 gw 10.0.22.44
        any host 192.168.34.43 gw 192.168.56.88
Previously, we would have added all three of our example routes here,
however, Red Hat decided to change things up.  If you want Linux
to determine the appropriate interface for an associated route, use
'static-routes' as shown above, leading each line with 'any' (see note 1).
If you need to retain routes related to a particular interface, we now
need to use 'route-INTERFACE' (see note 2):
        tux [0] /bin/cat /etc/sysconfig/network-scripts/route-eth0
        10.11.18.0/24 dev eth0
As an alternative to either 'static-routes' or 'route-INTERFACE', you
could simply add explicit 'route' commands to 'rc.local':
        tux [0] /bin/cat /etc/rc.local
        #!/bin/sh
        #
        # This script will be executed *after* all the other init scripts.
        # You can put your own initialization stuff in here if you don't
        # want to do the full Sys V style init stuff.

        touch /var/lock/subsys/local

        /sbin/route add -net 10.11.18.0/24 dev eth0
        /sbin/route add -net 10.17.4.32 netmask 255.255.255.224 gw 10.0.22.44
        /sbin/route add -host 192.168.34.43 gw 192.168.56.88
To delete a route, 'route' again accepts either netmask or CIDR notation,
whereas 'ip' only accepts CIDR notation.  In either case, you need to
specify at least the network and netmask or CIDR in order to delete the
particular route:
        tux [0] /sbin/route delete -net 10.11.18.0 netmask 255.255.255.0
        tux [0] /sbin/route delete -net 10.11.18.0/24
        tux [0] /sbin/ip route delete 10.17.4.32/27
        tux [0] /sbin/ip route delete 192.168.34.43

NOTES

note 1: Network routes in the 'static-routes' file only use netmasks
        and cannot include CIDR notation.  Also, like the 'route' command,
        networks must be specified beginning on the network boundary
        start as determined by the netmask in use.  Whereas previously
        you could enter any static routes in 'static-routes', it appears
        that since Red Hat 9 only routes beginning with 'any' are applied
        from 'static-routes'.  This means that routes specified with a
        leading interface (instead of 'any') are ignored.

note 2: In our example of a device specific route, our gateway is a
        particular network interface (eth0) on our host.  If a gateway
        isn't specified for the route in 'route-INTERFACE' (ex; 'dev
        eth0', 'via IPADDR', etc.), the route will not be added during
        a system boot.  Additionally, the syntax of this file follows
        that of command 'ip route add'.  As such, only CIDR notation
        is accepted.


see also:
    Static Routes in Solaris
    Static Routes in FreeBSD