DEV Community

Subnetica
Subnetica

Posted on Originally published at subnetica.xyz

FRRouting and the Linux Routing Table: How Routes Reach the Kernel

FRRouting does not forward packets by itself. Its protocol daemons learn and evaluate routes; Zebra coordinates the selected result with the Linux kernel, whose forwarding tables ultimately decide what happens to a packet.

The route's journey

A useful mental model is to separate learning a route from forwarding a packet. OSPF, BGP, or a static configuration produces routing information inside FRR. The protocol daemon sends candidates to Zebra. Zebra applies FRR's selection rules, resolves next hops, and asks the kernel to install the winners. Linux then performs the lookup when a packet arrives.

A protocol database is upstream of forwarding; the Linux kernel is the final packet-forwarding authority.

What each FRR daemon does

FRR is a suite of cooperating daemons. ospfd maintains OSPF adjacencies and its link-state database, then calculates OSPF paths. bgpd exchanges routes with BGP peers and applies BGP policy. staticd manages static routes when that daemon is enabled. These daemons know their own protocol state; they are not independent kernel forwarding planes.

zebra is the routing manager and the bridge to the operating system. It receives route candidates, keeps FRR's main routing view, chooses the routes that should win across protocols, and communicates interface, address, and route state to the Linux kernel. The command syntax may look familiar to Cisco users, but FRR's architecture and implementation are not Cisco IOS.

Protocol information, the RIB, and the FIB

There are several layers of "the route exists." A protocol database may contain an OSPF learned path. FRR's RIB may select that path as the best route for a prefix. The kernel's FIB may then contain an installed route. Only the last layer is directly used by Linux for ordinary packet forwarding.

That is why "OSPF learned it" does not prove that the host will forward traffic through it. A better administrative distance or preference can win. The next hop may not resolve recursively. An interface can be down, a route can be filtered by policy, or the kernel can reject an installation. A newer route can also replace the one you were inspecting.

RIB vs FIB: why the distinction matters

In practical troubleshooting, think of the RIB as the selected control-plane answer and the FIB as the installed forwarding answer. On Linux, the operational view is exposed through commands such as ip route; FRR's view is exposed through show ip route. They should agree for routes that FRR successfully installed, but they are not guaranteed to be identical snapshots.

Inspect both sides

Start with FRR's selected view, then inspect the Linux interfaces, neighbors, and routes. The comparison is more valuable than either command alone.

# FRR: selected routes and protocol-specific evidence
show ip route
show ip ospf route
show bgp ipv4 unicast

# Linux: addresses, neighbors, and the forwarding table
ip -br addr
ip neigh
ip route

# Ask Linux which route it would use for a destination
ip route get 10.44.8.10
Enter fullscreen mode Exit fullscreen mode

show ip route can show a route selected by FRR while ip route tells you whether that route reached the kernel. ip route get is especially useful because it performs a lookup for a concrete destination and displays the chosen interface, source address, and next hop.

Watch the installation boundary

If the state changes while you are troubleshooting, watch both views instead of repeatedly taking screenshots. Linux can report route changes as they happen, while FRR can show whether a route was replaced or withdrawn. This is useful when an interface flaps or a protocol reconverges:

ip monitor route

# In another terminal, watch the selected FRR view
show ip route 10.44.8.0/24
Enter fullscreen mode Exit fullscreen mode

A route disappearing from the kernel immediately after FRR selects it points toward installation, interface, or next-hop problems. A route that never reaches FRR's selected view points earlier in the chain: adjacency, policy, preference, or recursive resolution. The timing often tells you more than a single static table.

This distinction between FRR's view of the network and the Linux kernel's forwarding state is one of the reasons I built Subnetica's labs around FRRouting and Linux rather than hiding the underlying networking stack.

Scenario: OSPF learned the route, but forwarding fails

Suppose Router R1 reports an OSPF route to 10.44.8.0/24, but a host behind R1 cannot reach 10.44.8.10. Work from the control plane toward the data plane:

  1. Check show ip ospf neighbor and confirm the expected adjacency is actually Full. A stale or partial adjacency may leave the protocol database incomplete.
  2. Use show ip ospf route to verify the prefix and next hop are present in OSPF's view.
  3. Use show ip route 10.44.8.0/24 or show ip route to see whether FRR selected an OSPF path, or whether another protocol won.
  4. Run ip route and ip route get 10.44.8.10. If Linux has no matching route, the problem is between FRR selection and kernel installation, or the route was never selected.
  5. Check ip -br addr for interface state and addressing, then ip neigh for a missing or failed next-hop resolution.
  6. If both tables contain the route, test the next hop and the return path. A correct local FIB entry cannot repair a missing reverse route, filtering rule, or disabled forwarding on another hop.

This method avoids a common category error: treating a protocol's knowledge as proof of end-to-end connectivity. Route installation, neighbor resolution, interface state, and return traffic all still matter.

Do not confuse route presence with forwarding success

Even a matching FIB entry is only one part of packet delivery. Linux still needs an operational output interface and a usable neighbor entry for the next hop. The receiving host needs a route back, and local firewall or forwarding policy may reject the packet. For a router namespace, also check that IPv4 forwarding is enabled; a namespace with two addresses is not automatically a router.

That layered model scales beyond FRR. It is the same reason a Kubernetes node can have a route in one namespace while an application namespace has a different view, or why a container route can be correct while the host-side veth or bridge is misconfigured.

Where namespaces make this easier to see

Linux network namespaces make it possible to inspect several independent routing tables on one host. Put FRR in a router namespace, connect it with veth pairs, and the same protocol-to-Zebra-to-kernel pipeline becomes visible without physical hardware. The companion guide explains that topology in detail.

If you want to practice this kind of troubleshooting interactively, Subnetica has browser-based networking labs where you can inspect FRR state, routing tables, and connectivity and have the resulting network automatically graded.

Further reading

FRRouting Zebra documentation
FRRouting basic commands and daemons
FRRouting OSPFv2 documentation
FRRouting BGP documentation
Linux ip-route(8) manual page

Top comments (0)