LinuxXXI · Advanced Linux NetworkingRouting tables
Multiple routing tables on Linux
What you'll learn
- Explain why multiple routing tables exist
- Read and modify ip rule and ip route show table
- Add a custom routing table and route traffic into it
- Recognise when multiple tables are the right tool
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
A Linux host can have many routing tables, not just the “main” one. Each table holds routes; the kernel picks a table for each packet using rules. This is the foundation of policy routing - choosing routes based on source address, mark, interface, or other criteria.
The default tables
| Table | Number | Contents |
|---|---|---|
| local | 255 | Routes for local and broadcast addresses |
| main | 254 | The “main” routing table (the default) |
| default | 253 | Empty by default; used as a fallback |
ip route show table local
ip route show table main
ip route show table all # every table
The local table holds entries for 127.0.0.0/8, broadcast
addresses, and anycast addresses. The kernel creates these
automatically and you should not modify them.
The main table is where most user configuration goes.
Custom tables
Add a new table by name and number:
echo "100 mgmt" >> /etc/iproute2/rt_tables
Then add routes to it:
ip route add 10.0.0.0/24 dev eth0 table mgmt
ip route add default via 10.0.0.1 dev eth0 table mgmt
Tables are isolated: a route in table mgmt is not visible
to traffic in table main. The kernel only looks at table mgmt when a rule sends traffic there.
ip rule - selecting a table
ip rule show
Output:
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
Each rule has:
- Priority: lower is consulted first.
- Selector:
from,to,iif,oif,mark, etc. - action:
lookup <table>,blackhole,prohibit.
The default rules consult local, then main, then
default. To send traffic from a specific source to a
specific table, add a rule with higher priority:
ip rule add from 10.0.0.0/24 lookup mgmt priority 100
ip rule show
Now traffic from 10.0.0.0/24 first consults table mgmt.
If table mgmt has no route for the destination, the next
rule applies (eventually table main).
A worked example
A host has two interfaces: eth0 (production, 10.0.0.0/24)
and eth1 (backup, 192.168.1.0/24). You want:
- Traffic from 10.0.0.0/24 uses eth0.
- Traffic from 192.168.1.0/24 uses eth1.
- Traffic from any other source uses eth0’s default route.
echo "100 backup" >> /etc/iproute2/rt_tables
ip route add 192.168.1.0/24 dev eth1 table backup src 192.168.1.10
ip route add default via 192.168.1.1 dev eth1 table backup
ip rule add from 192.168.1.0/24 lookup backup priority 100
Verify:
ip route get 8.8.8.8 from 10.0.0.10
ip route get 8.8.8.8 from 192.168.1.10
The kernel should pick different routes for the two source addresses.
Persistent configuration
The /etc/iproute2/rt_tables file makes table names stable. Rules and routes in custom tables are made persistent via the network manager:
With Netplan:
network:
version: 2
renderer: networkd
ethernets:
eth0:
addresses: [10.0.0.10/24]
routes:
- to: default
via: 10.0.0.1
eth1:
addresses: [192.168.1.10/24]
routes:
- to: default
via: 192.168.1.1
table: 100
routing-policy:
- from: 192.168.1.0/24
table: 100
priority: 100
Netplan has no top-level routing: key, and no policy: or
tables: children. Both the routes and the rules belong to
the interface they apply to: routes: entries take an
optional table:, and routing-policy: holds the ip rule
equivalents. Netplan wants the table number, not a name
from /etc/iproute2/rt_tables - that file names tables for
the ip command only, and systemd-networkd never reads it.
The snippet above renders to exactly the systemd-networkd units you would write by hand:
# /run/systemd/network/10-netplan-eth1.network
[Route]
Destination=0.0.0.0/0
Gateway=192.168.1.1
Table=100
[RoutingPolicyRule]
From=192.168.1.0/24
Table=100
Priority=100
With systemd-networkd directly, the same configuration is a
[Route] section with Table= and a [RoutingPolicyRule]
section, as shown above. Hand-written ip commands in a boot
service are a third option, but they are invisible to the
network manager and are lost on the next netplan apply.
When to use multiple tables
- Two uplinks, different source ranges (like the example above).
- VRF-like isolation for sensitive workloads.
- Tenant isolation in a multi-tenant host (when namespaces are overkill).
- Routing in containers (CNI uses tables internally).
For most single-purpose hosts, the main table is enough.
Knowledge check
Knowledge check · 5 questions
Q1. What command lists all routing tables?
Q2. Rules are consulted in priority order - lower priority numbers first.
Q3. Which of the following are real Linux routing tables? Select all that apply.
Q4. Where does a policy routing rule belong in a Netplan file?
Q5. One unrecognised key anywhere in a Netplan file makes netplan apply abort without applying any part of it.
Passing score: 75%. Answers are checked in this browser.