Start with the VLANs, Bonding, Bridging. This is part 1 of 3 in the Advanced Networking in Linux series (4 posts in total). Also in this series: VLANs, Bonding, Bridging, Namespaces and Virtual Links, Overlays and CNI.
In VLANs, Bonding, and Bridging, the host stayed inside one or more Layer 2 domains: bonds for uplinks, VLANs for separation, bridges for VMs. That stack answers “who shares this Ethernet segment?”
This post answers a different question: how does a Linux box move packets between IP networks? That is routing — forwarding, policy routing when you have more than one path, and nftables rules that decide what is allowed to cross.
The audience is the same as part 1: people who already run servers or lab hosts and need a clear mental model, not a vendor certification dump.
The Mental Model
A bridge forwards Ethernet frames inside one Layer 2 network. Hosts on the same bridge share a broadcast domain. The host IP usually sits on the bridge.
A router forwards IP packets between Layer 3 networks. It has an address in each network, looks at the destination IP, and chooses a next hop or an egress interface. Broadcasts do not cross routers.
| |
You can still build the LAN side with part 1’s bond/VLAN/bridge stack. Routing starts when packets must leave that domain for another subnet or the internet.
When to Route vs Bridge
Route when:
- Two subnets need to talk and should not share a broadcast domain (LAN vs DMZ, lab vs home).
- The host is a NAT gateway for a private network.
- Traffic should leave through different uplinks depending on source or destination (management vs internet, dual WAN).
Bridge when guests or containers must appear on the same Layer 2 network as the physical NIC (classic KVM bridge, DHCP from the same switch as the host).
Do not bridge two different ISPs or two independent Layer 2 domains “for redundancy.” That creates loops and broken ARP. Bond for redundant links into the same L2 fabric; route (or use policy routing) when the uplinks are different networks.
IP Forwarding
Linux does not forward packets between interfaces until you ask it to.
Temporary:
| |
Persistent (distribution paths vary; /etc/sysctl.d/99-router.conf is common):
| |
Also know reverse path filtering. Strict rp_filter drops packets that would not be accepted on the return path through the same interface. That breaks asymmetric routing and some dual-uplink designs:
| |
For a lab with deliberate asymmetry, use loose mode (2) or turn filtering off on the affected interfaces. Prefer fixing the routing design when you can.
Temporary Two-NIC Router
Assume lan0 faces a private network and wan0 faces an upstream router:
| |
Hosts on 192.168.10.0/24 use 192.168.10.1 as their gateway. Until you add NAT or upstream routes for that prefix, the internet will not know how to reply — that is where masquerading comes in later.
Verify:
| |
Policy Routing
The main routing table is enough when every packet uses the same default gateway. Two uplinks usually need policy routing: match on source address, ingress interface, or mark, then look up a different table.
Example: LAN clients should exit via the ISP on wan0. Management traffic sourced from 192.168.99.10 on mgmt0 should use a second uplink.
| |
Check the decision path:
| |
When ip rule tables multiply and you need interface-scoped routing that looks more like separate routers on one box, VRF (Virtual Routing and Forwarding) is the next step. It is worth knowing the name; it is not required for a two-uplink lab. Prefer one or two policy tables first.
nftables: Input vs Forward vs Output
Filtering a router is not the same as filtering a workstation.
| Chain | What it covers |
|---|---|
| input | Packets destined to the host itself (SSH to the router, DNS on the router) |
| forward | Packets the host is routing between interfaces |
| output | Packets the host originates |
A common mistake: locking down input until SSH works, then wondering why LAN clients cannot reach the internet. That traffic never hits input. It hits forward.
Lab masquerade (SNAT for a private LAN):
| |
Inspect:
| |
This is routed filtering. If you still use part 1’s bridges and guest traffic mysteriously hits filter rules, check br_netfilter from that post: bridged frames can be forced through the IP filter path. That is a bridge problem, not a reason to put VM traffic in forward by default.
Distributions often wrap nftables with firewalld or ufw. The hooks are still the same: know whether you are opening a service on the host (input) or allowing a path through the host (forward).
A Practical Design
A small lab router or edge host:
| |
With NetworkManager for addresses and a small nftables file for policy:
| |
Enable forwarding in sysctl, install the nftables rules above, and verify from a LAN client.
Netplan variant for static WAN:
| |
Keep the habit from part 1: configure carefully over console or with a rollback path (netplan try, or a timed nft flush ruleset if you are experimenting).
Verification Workflow
Bottom-up still works; the layers are different.
| |
From the router:
| |
From a LAN client:
| |
When replies vanish, tcpdump on each side of the forward path:
| |
If packets enter lan0 and never leave wan0, check forwarding, routes, and forward chain policy. If they leave but never return, check NAT, upstream routing, and rp_filter.
Common Mistakes
- Forgetting
ip_forward: Interfaces and routes look fine; nothing crosses. - Filtering
inputinstead offorward: SSH to the router works; clients cannot reach upstream. - Wrong routing table: Policy rules send traffic into an empty or incomplete table.
- Strict
rp_filteron asymmetric paths: Return packets are dropped before your firewall rules matter. - No masquerade for private sources: Upstream has no route back to
192.168.10.0/24. - Bridging two WANs: Use routing or policy routing; do not merge ISP Layer 2 domains on a Linux bridge.
- Blaming nftables for bridge problems: Guest traffic on a pure L2 bridge is not
forwardunlessbr_netfilter(or an explicit router) is involved.
Tooling Notes
Use iproute2 for addresses, routes, and rules: ip addr, ip route, ip rule, ip route get.
Use nftables as the modern packet filter. Learn the three hooks before memorizing every expression. On RHEL-family systems you may edit firewalld zones that compile down to nftables; the mental model stays the same.
Avoid designing new routers around iptables-legacy or route from net-tools. They still appear on old hosts; they are not the interface to learn first in 2026.
Further Reading
- Linux kernel networking documentation
ip-rule(8)andip-route(8)- nftables wiki
- systemd-networkd for persistent interface config
Conclusion
Bridges keep hosts in a Layer 2 conversation. Routers move IP packets between conversations. Enable forwarding deliberately, put filters in the chain that matches the traffic (forward for transit, input for the host), and use policy routing when one default route is not enough.
The next step is not a bigger router. It is isolating whole network stacks on the same machine — namespaces, veth pairs, and the bridge versus macvlan versus ipvlan choices that containers reuse. That is Linux Network Namespaces and Virtual Links.