How to Configure Policy-Based Routing and Custom Routing Tables in Linux Using ip rule

Traditional IP routing in Linux selects the next-hop gateway based solely on the packet’s destination IP address using the main kernel routing table. However, multi-homed servers, dual-WAN gateways, and VPN tunnel endpoints often require granular traffic control based on source IP address, network interface, or firewall packet marks. Linux implements this capability through Policy-Based Routing (PBR) and the Routing Policy Database (RPDB), managed via the ip rule and ip route commands from the iproute2 suite.

Understanding the Routing Policy Database (RPDB)

When the Linux kernel prepares to route an outbound or forwarded packet, it consults the RPDB in ascending numerical priority (from priority 0 up to 32767). Each rule specifies matching criteria and designates which routing table evaluates the packet. By default, Linux includes three core rules:

  • Priority 0 (local table): Handles local loopback and broadcast addresses. This rule cannot be deleted.
  • Priority 32766 (main table): Evaluates standard static and DHCP routes configured on the machine.
  • Priority 32767 (default table): Evaluates fallback post-processing routes; typically empty unless specifically populated.

Policy-based routing allows administrators to insert custom rules between priority 1 and 32765 that direct packets to independent, isolated routing tables before the main table is evaluated.

Inspecting Active Routing Rules

To inspect your server’s current RPDB configuration:

  1. Open your Linux terminal session.
  2. Run the rule listing command:
    ip rule show
  3. The terminal displays the priority number, selector criteria (such as from all or specific subnets), and the target table name or integer ID.

Defining Custom Routing Table Names

While routing tables can be referenced by numeric IDs (1 to 252), naming your tables prevents configuration errors and simplifies auditing:

  1. Open the routing table definition file in a text editor with root privileges:
    sudo nano /etc/iproute2/rt_tables
  2. Scroll to the bottom of the file and add your custom table ID and identifier name (for example, table ID 100 for a secondary ISP or VPN):
    100    custom_isp
  3. Save and close the file. The Linux kernel and iproute2 utilities will now recognise custom_isp as a valid table identifier.

Populating Routes in the Custom Table

Before adding policy rules that point traffic to the custom table, configure the appropriate gateway routes inside that table:

  1. Add the network subnet route for the secondary interface (e.g., eth1):
    sudo ip route add 192.168.2.0/24 dev eth1 src 192.168.2.50 table custom_isp
  2. Add the dedicated default gateway for the secondary uplink:
    sudo ip route add default via 192.168.2.1 dev eth1 table custom_isp
  3. Verify the contents of the custom table:
    ip route show table custom_isp

Adding Policy Rules Using ip rule

Once the custom routing table contains valid routes, attach policy rules in the RPDB to route matching traffic through it:

1. Route by Source IP Address

To force all traffic originating from a secondary IP address (such as 192.168.2.50) to exit through its corresponding gateway:

sudo ip rule add from 192.168.2.50/32 table custom_isp priority 1000

2. Route by Incoming Network Interface

To route traffic received on a specific interface through the custom table:

sudo ip rule add iif eth1 table custom_isp priority 1010

3. Route by Firewall Mark (fwmark)

For advanced traffic shaping, combine iptables or nftables packet marking with policy routing. If firewall rules mark specific packets with hex value 0x1:

sudo ip rule add fwmark 1 table custom_isp priority 1020

Testing and Deleting Policy Rules

To test how the Linux kernel resolves a simulated route for a specific source and destination IP:

ip route get 8.8.8.8 from 192.168.2.50

The output indicates the chosen gateway, outbound interface, and matching routing table (e.g., table custom_isp).

If you need to remove a rule:

sudo ip rule del from 192.168.2.50/32 table custom_isp

Alternatively, delete the rule directly by priority:

sudo ip rule del priority 1000

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.