Linux as a Router

A Linux bridge connects devices within the same Layer 2 network. But real networks are rarely limited to a single subnet. Sooner or later, packets must travel between different networks. That's the job of a router. In this chapter, we'll transform a Linux host into a fully functional IP router and see exactly how packets move between independent networks.


Learning Objectives

By the end of this chapter, you will be able to:

  • Understand the difference between switching and routing
  • Configure Linux to forward packets
  • Build multiple isolated IP networks
  • Route packets between subnets
  • Observe routing decisions in action
  • Understand the role of the default gateway
  • Troubleshoot routing problems
  • Recognize how Kubernetes nodes, cloud VMs, and physical routers perform the same function

The Problem

In the previous chapter, we built a virtual Ethernet network.

                br0

      +---------+---------+

    Host1     Host2     Host3

192.168.50.11
192.168.50.12
192.168.50.13

All hosts belonged to the same subnet.

192.168.50.0/24

Communication was simple.

Every host could reach every other host directly using ARP.

But what happens when hosts belong to different networks?

Host A

192.168.10.10/24

-------------

Host B

192.168.20.10/24

Host A cannot send Ethernet frames directly to Host B because they are in different IP networks.

Something must connect those networks.

That something is a router.


What Is a Router?

A router is a device that forwards IP packets between different networks.

Unlike a bridge:

  • it operates at Layer 3
  • it makes decisions using IP addresses
  • it maintains a routing table
  • it rewrites Ethernet headers for every hop

Every packet that crosses between IP networks passes through a router.

Linux can perform exactly the same job.


The Network We'll Build

We'll create two independent Ethernet networks connected by one Linux router.

                    Linux Router

             left-br          right-br
                |                 |
         +------+                 +------+
         |                               |
      router-l                      router-r
         |                               |
===================             ===================
        |                               |
      hostA                          hostB
        |                               |
 Namespace A                     Namespace B

Network A

192.168.10.0/24

Network B

192.168.20.0/24

The Linux host will connect both networks together.


Step 1 — Create the Namespaces

Create two namespaces.

sudo ip netns add hostA
sudo ip netns add hostB

Enable loopback.

sudo ip netns exec hostA ip link set lo up

sudo ip netns exec hostB ip link set lo up

Step 2 — Create Two Linux Bridges

Each bridge represents an independent Ethernet network.

sudo ip link add left-br type bridge

sudo ip link add right-br type bridge

Bring them up.

sudo ip link set left-br up

sudo ip link set right-br up

Step 3 — Create the veth Pairs

Each namespace needs one Ethernet connection.

sudo ip link add hostA-veth type veth peer name hostA-host

sudo ip link add hostB-veth type veth peer name hostB-host

Move one side into the namespaces.

sudo ip link set hostA-veth netns hostA

sudo ip link set hostB-veth netns hostB

Step 4 — Connect the Hosts to Their Bridges

Attach the host-side interfaces.

sudo ip link set hostA-host master left-br

sudo ip link set hostB-host master right-br

Bring them up.

sudo ip link set hostA-host up

sudo ip link set hostB-host up

Step 5 — Configure the Host Interfaces

Namespace A

sudo ip netns exec hostA ip addr add 192.168.10.10/24 dev hostA-veth

sudo ip netns exec hostA ip link set hostA-veth up

Namespace B

sudo ip netns exec hostB ip addr add 192.168.20.10/24 dev hostB-veth

sudo ip netns exec hostB ip link set hostB-veth up

Current topology

Host A

192.168.10.10

        |

     left-br


right-br

        |

192.168.20.10

Host B

There is still no connection between the two bridges.


Step 6 — Give the Router an Interface on Each Network

Remember that a Linux bridge is itself a network interface.

Assign an IP address to each bridge.

sudo ip addr add 192.168.10.1/24 dev left-br

sudo ip addr add 192.168.20.1/24 dev right-br

The Linux host now belongs to both networks.

                Linux Router

left-br                  right-br

192.168.10.1          192.168.20.1

At this point, Linux has two interfaces connected to two different IP networks.


Step 7 — Test Local Connectivity

Namespace A should reach its local gateway.

sudo ip netns exec hostA ping 192.168.10.1

Namespace B should also reach its gateway.

sudo ip netns exec hostB ping 192.168.20.1

These pings stay inside their local Ethernet networks.


Step 8 — Try to Reach the Other Network

From Namespace A:

sudo ip netns exec hostA ping 192.168.20.10

The result:

Network is unreachable

Why?

Because Namespace A only knows about:

192.168.10.0/24

It has no route for:

192.168.20.0/24

The packet never leaves the namespace.


Step 9 — Configure the Default Gateway

Tell each namespace where to send packets destined for other networks.

Namespace A:

sudo ip netns exec hostA ip route add default via 192.168.10.1

Namespace B:

sudo ip netns exec hostB ip route add default via 192.168.20.1

Verify.

sudo ip netns exec hostA ip route

Example:

default via 192.168.10.1

192.168.10.0/24 dev hostA-veth

Now the packet reaches the Linux router.

But communication still fails.


Why Doesn't It Work Yet?

The packet now arrives at the Linux host.

However, Linux does not forward packets between interfaces by default.

Instead, it silently drops them.

This behavior protects ordinary desktop and server systems from unintentionally acting as routers.


Step 10 — Enable IP Forwarding

Check the current setting.

cat /proc/sys/net/ipv4/ip_forward

Output:

0

Enable forwarding.

sudo sysctl -w net.ipv4.ip_forward=1

Or:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

Verify.

cat /proc/sys/net/ipv4/ip_forward

Output:

1

Linux is now acting as a router.


Step 11 — Test Again

From Namespace A:

sudo ip netns exec hostA ping 192.168.20.10

Now the ping succeeds.

Congratulations.

You have built an IP router using only the Linux kernel.


Following the Packet

Let's follow the packet step by step.

Namespace A creates an ICMP Echo Request.

Destination

192.168.20.10

Namespace A checks its routing table.

Destination not local

↓

Use default gateway

192.168.10.1

An ARP request resolves the gateway's MAC address.

The Ethernet frame is sent.

Destination MAC

Linux Router

The Linux router receives the frame.

Ethernet Header

↓

Removed

Linux now examines the IP packet.

Destination IP

192.168.20.10

Linux searches its routing table.

192.168.20.0/24

↓

right-br

A new Ethernet header is created.

Source MAC

right-br

Destination MAC

Host B

The packet leaves through the second interface.

Notice what changed.

  • Ethernet headers were replaced.
  • MAC addresses changed.
  • The IP packet stayed the same.

This is exactly how every IP router operates.


Observe the Routing Table

Display the router's routing table.

ip route

Example:

192.168.10.0/24 dev left-br

192.168.20.0/24 dev right-br

Linux automatically installed these connected routes when IP addresses were assigned.

No manual routing configuration was required.


Observe TTL Changes

Capture packets.

sudo tcpdump -i right-br icmp

Run:

sudo ip netns exec hostA ping 192.168.20.10

Notice that the packet's TTL has decreased by one.

Every router decrements the TTL before forwarding the packet.

This prevents routing loops from lasting forever.


Observe ARP

Namespace A never learns Host B's MAC address.

Check:

sudo ip netns exec hostA ip neigh

You'll only see:

192.168.10.1

The namespace only knows the MAC address of its default gateway.

Likewise, Host B only knows the router's MAC address.

This is one of the most important concepts in IP networking.

Hosts do not ARP for remote destinations.

They ARP only for the next hop.


Common Routing Problems

IP Forwarding Disabled

Check:

cat /proc/sys/net/ipv4/ip_forward

Must be:

1

Missing Default Route

Verify:

ip netns exec hostA ip route

Expected:

default via 192.168.10.1

Wrong Subnet Mask

Ensure both hosts and router interfaces use compatible prefixes.

Incorrect subnet masks often cause confusing routing behavior.


Interfaces Down

Verify:

ip link

and

ip netns exec hostA ip link

Firewall Rules

Linux may be forwarding packets correctly, but firewall rules can still block them.

Later in this book, we'll study Netfilter, iptables, and nftables in detail.


Real-World Examples

Linux routers are everywhere.

Examples include:

SystemLinux Routing
Kubernetes nodeRoutes Pod traffic
Docker hostRoutes bridge traffic
Cloud VMRoutes VPC traffic
Home router (many models)Linux kernel routing
VPN serverRoutes encrypted traffic
Virtual firewallLinux routing stack

Once IP forwarding is enabled, Linux behaves exactly like a dedicated router.


Cleaning Up

Delete the namespaces.

sudo ip netns delete hostA

sudo ip netns delete hostB

Delete the bridges.

sudo ip link delete left-br

sudo ip link delete right-br

Disable forwarding if desired.

sudo sysctl -w net.ipv4.ip_forward=0

Key Takeaways

  • A router forwards IP packets between different Layer 3 networks.
  • Linux becomes a router when it has interfaces in multiple networks and IP forwarding is enabled.
  • Hosts use their routing tables to determine whether a destination is local or remote.
  • Remote packets are sent to the default gateway, not directly to the destination host.
  • A router removes the incoming Ethernet header, makes a routing decision based on the destination IP address, and creates a new Ethernet header for the outgoing interface.
  • The router decrements the packet's TTL before forwarding it.
  • Linux automatically installs connected routes for directly attached networks.

Coming Next

So far, every virtual network we've built has used a single Layer 2 broadcast domain per bridge. In production environments, however, a single physical network is often divided into multiple logical networks using VLANs, while technologies like TUN and TAP create virtual interfaces for VPNs, virtualization, and userspace networking.

In the next chapter, we'll explore these additional Linux networking primitives and see how they extend the virtual networking toolbox beyond bridges and veth pairs.