Configuring Policy-Based Routing on Linux for Multi-Homed Networks

Introduction to Policy Routing

In environments with multiple network interfaces (NICs) and public IP addresses, standard routing often fails to handle outgoing traffic correctly. By default, the Linux kernel routes traffic based solely on the destination address, which can cause packets sent from a secondary interface to be routed through the default gateway of the primary interface. Policy-based routing (PBR) solves this by allowing routing decisions to be based on source addresses or other criteria.

1. Defining Custom Routing Tables

The first step is to assign identifiers to custom routing tables. These entries must be added to the /etc/iproute2/rt_tables file.

Install the necessary tools if they are missing:

apt update && apt install iproute2

Edit the routing tables configuration file:

# /etc/iproute2/rt_tables
#
# reserved values
255     local
254     main
253     default
0       unspec
# local tables
#
100     wan1_table
101     wan2_table

2. Persistent Configuration with Netplan

For modern Ubuntu systems using Netplan, policy routing can be configured directly in the YAML configuration files. This ensures settings persist after a reboot.

Create or edit the configuration file, for example /etc/netplan/01-netcfg.yaml:

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      addresses:
        - 192.168.1.10/24
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 1.1.1.1]
      routes:
        - to: 0.0.0.0/0
          via: 192.168.1.1
          table: 100
      routing-policy:
        - from: 192.168.1.10
          table: 100
          priority: 100
    eth1:
      addresses:
        - 10.0.0.10/24
      routes:
        - to: 0.0.0.0/0
          via: 10.0.0.1
          table: 101
      routing-policy:
        - from: 10.0.0.10
          table: 101
          priority: 200

Apply the changes:

netplan apply

In this configuration, each interface has a dedicated routing table. The routing-policy directive ensures that traffic originating from a specific IP looks up the corresponding table.

3. Runtime Configuration Using iproute2

For immediate, non-persistent changes, or for scripts, use the ip command suite.

Setup for the Primary Interface (eth0)

Clear existing entries in the custom table, add the default gateway, ensure local subnet reachability, and add the policy rule.

# Flush the custom table
ip route flush table 100

# Add default route to the custom table
ip route add default via 192.168.1.1 dev eth0 table 100

# Add local subnet route to the custom table (crucial for local switching)
ip route add 192.168.1.0/24 dev eth0 table 100

# Add the policy rule
ip rule add from 192.168.1.10 table 100

Setup for the Secondary Interface (eth1)

ip route flush table 101
ip route add default via 10.0.0.1 dev eth1 table 101
ip route add 10.0.0.0/24 dev eth1 table 101
ip rule add from 10.0.0.10 table 101

Verification

To verify the configuration, inspect the policy rules and the specific routing tables:

# List policy rules
ip rule list

# Show routes for a specific table
ip route show table 100
ip route show table 101

4. Connectivity Testing

To confirm that traffic leaves the correct interface, use curl with the --interface flag or ping with the -I flag.

# Test using source IP of eth0
curl --interface 192.168.1.10 https://ifconfig.me
ping -I 192.168.1.10 8.8.8.8

# Test using source IP of eth1
curl --interface 10.0.0.10 https://ifconfig.me
ping -I 10.0.0.10 8.8.8.8

5. Windows Configuration

On Windows systems, policy routing is typically handled by setting interface metrics or adding specific routes. To prioritize a specific intreface, you can add a persistent route with a lower metric value (lower metric = higher priority).

# Add a persistent route for the secondary network
route -p add 0.0.0.0 mask 0.0.0.0 10.0.0.1 metric 10

# Test connectivity specifying the source address
ping -S 10.0.0.10 8.8.8.8

6. Handling DHCP Interfaces

When using DHCP, you can control the routing priority using metrics or override the routing behavior. Below is a Netplan example where a secondary DHCP interface is configured with a higher metric (lower priority) and forced into a specific routing table.

network:
  version: 2
  ethernets:
    ens5:
      dhcp4: true
      dhcp4-overrides:
        route-metric: 100
    ens6:
      dhcp4: true
      dhcp4-overrides:
        route-metric: 200
      routes:
        - to: 0.0.0.0/0
          via: 10.10.10.1
          table: 102
        - to: 10.10.10.0/24
          table: 102
      routing-policy:
        - from: 10.10.10.50
          table: 102

7. Service Management

In some cases, NetworkManager might conflict with manual network configurations or systemd-networkd. It can be disabled in favor of systemd-networkd.

# Stop and mask NetworkManager
systemctl stop NetworkManager
systemctl disable NetworkManager
systemctl mask NetworkManager

# Enable and start systemd-networkd
systemctl unmask systemd-networkd.service
systemctl enable systemd-networkd.service
systemctl start systemd-networkd.service

Tags: Linux Policy Routing netplan iproute2 networking

Posted on Sat, 08 Aug 2026 16:52:43 +0000 by labmixz