Linux network routing table

Our computers can have multiple network devices: Ethernet, WiFi cards, virtual network devices, etc. On Linux when the network packets arrive to one of these devices, these packets are handled by device drivers and then put to networking stack. Then packets are dispatched to appropriate application to handle.

When the packets are sent, they are put to networking stack, e.g. via BSD sockets API. Then Linux networking stack uses a routing table to decide which network interface the packet will be sent to.

Routing table can be viewed with:

$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface         UG    600    0        0 wlp3s0         U     1002   0        0 enp0s25   U     0      0        0 tun0   U     600    0        0 wlp3s0


$ ip route show
default via dev wlp3s0 proto static metric 600
default dev enp0s25 scope link metric 1002 linkdown dev tun0 proto kernel scope link src dev wlp3s0 proto kernel scope link src metric 600

Although route command is deprecated [1], I still prefer it because of nicer output.


Let's take the output of route -n. Now what happens when we execute ping

Well, Linux kernel

  1. matches address with (all addresses),
  2. selects route with the lowest Metric (600) because there are multiple routes to,
  3. looks up the gateway which is,
  4. matches gateway address with,
  5. looks up that destination does not have gateway meaning that the network is directly connected somehow,
  6. does NAT (network address translation),
  7. writes packet to wlp3s0 interface,
  8. device driver sends packet to WiFi card.

Understanding routing table

Again, let's look at route -n output.

Genmask column is a mask applied (bitwise AND) to IP packet destination address. After Genmask is applied, Destination column is used to match packet destination. If the matched destination has Gateway, packet is forwarded there, otherwise it's written to network interface described by column Iface.

When packet destination address matches with multiple Destination entries, the one with the longest prefix wins. For example address matches and But prefix is 24 bits long, so this rule takes priority.

Flags column holds some metainfo about routes: U - route is up, G route has gateway.

Metric column is used to determine priority when multiple routes match packet destination address.

Ref column is not used in Linux kernel.

Manipulating routing table

We can use ip command to add, delete, modify routes. E.g. we can redirect packets to desired network interfaces:

# ip route add via

This makes all packets with destination be written to tun0 interface.

To delete route issue command:

# ip route del via

We can test which Destination entry will be matched for given address:

$ ip route get dev tun0 src

$ ip route get via dev wlp3s0 src

$ ip route get dev wlp3s0 src

The difference between the last two routes is that NAT will be executed for packets destined to, while packets with destination will remain intact.

We can change the route metric by adding new route with different metric and then deleting the old one:

# ip route add default via dev wlp3s0 proto static metric 500
# ip route del default via dev wlp3s0 proto static metric 600