Changzao Heka Fei avatar

Linux Networking Mastery Series Part 3: Routing, Gateways, and Advanced Addressing

x9ed1732b

Published: 13 Feb 2026 › Updated: 13 Feb 2026Linux Networking Mastery Series Part 3: Routing, Gateways, and Advanced Addressing

Linux Networking Mastery Series Part 3: Routing, Gateways, and Advanced Addressing

Welcome back to Linux Networking Mastery! In Part 1 we explored the fundamentals of the Linux network stack and basic inspection commands. In Part 2 we took control of interfaces—bringing them up/down, assigning temporary and persistent IP addresses (via Netplan, NetworkManager/nmcli, systemd-networkd, etc.), and handling IPv4/IPv6 differences.

Now we move to one of the most powerful (and sometimes confusing) parts of Linux networking: routing. We'll examine how the kernel decides where to send packets, how to add and manipulate routes, introduce policy-based routing for complex scenarios, and finish with network namespaces—a foundational technology for isolation in containers and advanced setups.

By the end of this post, you'll understand the routing table deeply, be able to configure static routes and multiple gateways, and set up a basic multi-interface router.

Understanding the Routing Table

The Linux kernel uses a routing table to decide the next hop for every outgoing packet. View it with:

ip route show
# or more verbose
ip route list

Typical output on a single-interface system:

default via 192.168.1.1 dev enp0s3 proto dhcp src 192.168.1.100 metric 100 
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.100 metric 100 
  • default via ... → default gateway (your router)
  • 192.168.1.0/24 dev enp0s3 ... → directly connected local subnet (added automatically by kernel when IP is assigned)
  • proto kernel → route added by kernel
  • proto dhcp → added by DHCP client
  • metric → preference (lower = better; used when multiple routes match)

For IPv6:

ip -6 route show

You'll see link-local routes, possibly a default via router advertisement, etc.

Adding and Removing Static Routes (Temporary)

Add a route to a specific network:

sudo ip route add 10.10.0.0/24 via 192.168.1.50 dev enp0s3

Add/change default gateway:

sudo ip route add default via 192.168.1.254 dev enp0s3
# or replace existing default
sudo ip route replace default via 192.168.1.254 dev enp0s3

Remove a route:

sudo ip route del 10.10.0.0/24
sudo ip route del default

Note: ip route change works only for some fields (e.g., metric); often safer to del then add/replace.

Making Routes Persistent

Use the same configuration systems from Part 2:

  • Netplan (Ubuntu/Debian):

    network:
      version: 2
      ethernets:
        enp0s3:
          addresses: [192.168.1.100/24]
          routes:
            - to: 10.10.0.0/24
              via: 192.168.1.50
            - to: default
              via: 192.168.1.1
    
  • nmcli (RHEL/Fedora):

    sudo nmcli con mod "System enp0s3" +ipv4.routes "10.10.0.0/24 192.168.1.50"
    sudo nmcli con up "System enp0s3"
    
  • systemd-networkd:

    Add to .network file:

    [Route]
    Destination=10.10.0.0/24
    Gateway=192.168.1.50
    

Policy-Based Routing (Multiple Routing Tables)

Standard routing looks only at destination IP. Policy routing lets you route based on source IP, protocol, fwmark, etc., using multiple tables.

  1. Define custom tables in /etc/iproute2/rt_tables:

    100 isp1
    200 isp2
    
  2. Add routes to those tables:

    sudo ip route add default via 203.0.113.1 dev enp1s0 table isp1
    sudo ip route add default via 198.51.100.1 dev enp2s0 table isp2
    
  3. Add rules to select table:

    # Route traffic from source 192.168.10.0/24 via isp1
    sudo ip rule add from 192.168.10.0/24 table isp1
    
    # Route marked packets (e.g., via iptables/nftables) via isp2
    sudo ip rule add fwmark 2 table isp2
    
  4. View rules:

    ip rule show
    

    Lower pref number = higher priority.

Flush cache after changes (older kernels):

sudo ip route flush cache

(Note: Routing cache was removed in kernel 3.6 for IPv4 and later for IPv6; modern kernels usually don't need this.)

Network Namespaces: Isolated Routing Environments

Network namespaces give each namespace its own interfaces, addresses, routes, etc.—perfect for testing, containers, or isolating routing domains.

Create and enter a namespace:

sudo ip netns add blue
sudo ip netns exec blue bash

Inside namespace:

ip link show          # only lo exists by default
ip addr add 10.0.0.1/24 dev lo
ip link set lo up

Create virtual Ethernet pair to connect namespaces/host:

sudo ip link add veth-blue type veth peer name veth-host
sudo ip link set veth-blue netns blue
sudo ip netns exec blue ip addr add 172.16.0.2/24 dev veth-blue
sudo ip netns exec blue ip link set veth-blue up

sudo ip addr add 172.16.0.1/24 dev veth-host
sudo ip link set veth-host up

Now add routes:

# In host
sudo ip route add 10.0.0.0/24 via 172.16.0.2

# In blue namespace
ip route add default via 172.16.0.1

Ping between them to test.

Practical Example: Configuring a Simple Linux Router

Scenario: Two interfaces — enp1s0 (WAN, 203.0.113.10/24, gateway 203.0.113.1), enp2s0 (LAN, 192.168.100.1/24).

Steps:

  1. Enable IP forwarding:

    sudo sysctl -w net.ipv4.ip_forward=1
    # Persistent: echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-ip-forward.conf
    
  2. Assign IPs (persistent via your config method).

  3. Add NAT for LAN clients (using nftables or iptables):

    sudo nft add table nat
    sudo nft add chain nat postrouting { type nat hook postrouting priority 100 \; }
    sudo nft add rule nat postrouting oifname "enp1s0" masquerade
    
  4. LAN clients use 192.168.100.1 as gateway.

Hands-On Exercises

  1. Add a static route to a private network (e.g., 172.20.0.0/16 via your current gateway). Verify with traceroute.
  2. Create a second routing table with a dummy default route; add a rule based on source IP from a secondary address on your interface.
  3. Create two namespaces, connect them with veth pair, assign IPs, add routes, and ping between them.
  4. (Advanced) Set up basic forwarding between two physical interfaces (disable if on production machine!).

Warning: Changing default routes or enabling forwarding can disrupt connectivity—use a VM or have console access.

What's Next?

In Part 4, we'll focus on name resolution: how Linux finds hostnames, configuring /etc/resolv.conf, using systemd-resolved, setting up local caching, and troubleshooting DNS problems.

Leave Linux Networking Mastery Series Part 3: Routing, Gateways, and Advanced Addressing to:

Written by

Wire: u9ed1732b

Read more #computernetworks posts


Best Posts From Changzao Heka Fei

We have not curated any of x9ed1732b's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From Changzao Heka Fei