Static routes#
Network → Static routes, at /routes, titled Routes on the screen. It owns the
protocols static subtree. The page puts two things side by side: the router's
forwarding table exactly as FRR prints it, and the static routes the configuration
declares — so a route that was configured and never installed is visible as such rather
than being assumed to work.
Everything here is IPv4. The table comes from show ip route; there is no IPv6
forwarding view in the product.
Where the data comes from#
GET /api/routes, polled every 15 seconds, returns three things in one response:
{
"routes": [ { "prefix": "0.0.0.0/0", "protocol": "static", "selected": true, "fib": true, "…": "" } ],
"static": { "route": { "0.0.0.0/0": { "next-hop": { "203.0.113.1": {} } } } },
"raw": "S>* 0.0.0.0/0 [1/0] via 203.0.113.1, eth1, weight 1, 2d16h22m"
}routes is show ip route parsed line by line; static is the protocols static
configuration subtree; raw is the untouched output, which the side panel shows.
A separate GET /api/config/commands?path=protocols static feeds the CLI view —
agent/opmode.go (handleRoutes),
agent/parse.go (parseRoutes).
The four tiles#
| Tile | Value | Sub-line |
|---|---|---|
| Routes | rows in the forwarding table | how many are installed in the FIB |
| Static | rows whose protocol is static | how many static routes the configuration declares |
| Connected | rows whose protocol is connected | — |
| Default route | the next hop of 0.0.0.0/0, or none | the interface it leaves by |
The Static tile is the one to read twice. When the two numbers differ — three declared, two in the table — a route is not doing what the configuration says it should.
The forwarding table#
| Column | Meaning |
|---|---|
| Prefix | the destination |
| Source | which protocol put the route there, as a coloured badge |
| Next hop | the gateway, or directly connected |
| Interface | the interface the route leaves by |
| Distance/metric | FRR's [distance/metric] pair |
| In FIB | installed when the kernel is really using it, no otherwise |
| Age | how long the route has been there |
Source, and the letter it came from#
FRR prefixes each line with a one-letter protocol code. The agent maps seventeen of them; a line whose first letter is not in the table is skipped rather than guessed at.
| Code | Source | Code | Source |
|---|---|---|---|
K | kernel | B | bgp |
C | connected | E | eigrp |
L | local | N | nhrp |
S | static | T | table |
R | rip | v | vnc |
O | ospf | V | vnc-direct |
I | isis | A | babel |
F | pbr | f | openfabric |
t | table-direct |
Four of these are coloured on the page: connected green, static blue, bgp and
ospf amber, local and kernel grey, everything else grey.
kernel is the one that surprises people. A route the failover daemon installs appears
as a kernel route at distance 0, which is why it outranks every static and DHCP default
route while it is there — see Uplinks.
Selected and In FIB#
FRR prints two flags after the code: > for the selected route to a prefix, and * for
a route that is in the forwarding table. The parser reads them as separate columns
rather than as one word, because a route that is installed but not selected — every
multi-WAN backup — has a space where the > would be, and reading the flags as a single
token dropped those lines entirely.
- In FIB — installed: the kernel is using this route.
- In FIB — no: FRR knows about the route and is not using it. Usually because a better one exists for the same prefix.
- The side panel shows Selected and Installed in FIB separately, which is the distinction the table's single column compresses.
Interface, and what the parser will not call one#
The interface is taken from the comma-separated remainder of the line, skipping anything
that is plainly not an interface name: a via … clause, a weight … clause, the
distance in brackets, a parenthesised reason like unreachable (blackhole), and the
uptime. A token followed by onlink or inactive is still an interface. This is why a
blackhole route shows no interface rather than showing its uptime in that column —
agent/parse.go (parseRoutes).
Declared static routes#
Below the table, one row per prefix under protocols static route, present only when
the configuration declares at least one. Each row shows the prefix, its next hops, and a
badge:
- in FIB — a route for this prefix is in the forwarding table.
- declared, not installed — it is not. The commonest causes are a next hop that is not on any connected subnet, an interface that is down, and a better route from another protocol for the same prefix.
The badge compares the prefix against the forwarding table, not the prefix and the next hop together. A prefix reached through a different gateway than the one declared still shows in FIB.
Delete on a row stages, without confirmation:
delete protocols static route 172.16.0.0/12That removes the prefix and every next hop under it.
The route detail panel#
Clicking a row in the forwarding table opens a panel with the parsed fields — prefix, protocol, next hop, interface, distance/metric, selected, installed in FIB, age — and below them the line exactly as FRR printed it, under the heading As FRR printed it. When the parsed view and the raw line disagree, the raw line is the truth and the parse is the bug.
There is no editor in this panel. A route that came from BGP, OSPF or a DHCP client is not something this page can change; delete the static route that produced it, or change the protocol that did.
Adding a static route#
+ Add static route opens a panel with four fields. The prefix and the next hop are required; nothing is staged until both are filled.
| Field | Written as | Notes |
|---|---|---|
| Destination prefix | protocols static route <prefix> | CIDR. 0.0.0.0/0 is a default route |
| Next hop | … next-hop <address> | must be reachable on a connected subnet |
| Administrative distance | … next-hop <address> distance <n> | optional; lower wins, and 1 is the static default |
| Description | protocols static route <prefix> description <text> | optional |
set protocols static route 172.20.0.0/16 next-hop 10.0.3.1
set protocols static route 172.20.0.0/16 next-hop 10.0.3.1 distance 20
set protocols static route 172.20.0.0/16 description 'lab network'Note where distance hangs: under the next hop, not under the route. Two next hops for
one prefix can carry different distances, which is how a backup path is expressed.
The page does not offer an interface-based route (next-hop-interface), a blackhole
route, or a route in an alternate table. The first two are CLI; alternate tables are
written by the policy-routing editor on Uplinks.
What this page will not do#
- No IPv6.
show ip routeis IPv4. A dual-stack router's v6 table has to be read on the CLI. - No VRF or namespace view. Not built —
PLAN.md§7. - No editing of a route that is not static. Connected, kernel, BGP and OSPF routes are read-only here by construction.
- No reordering or renumbering. There is nothing to order; distance is the only ranking, and you set it per next hop.
Worked example: reach a lab network behind a jump router#
10.0.3.1 is a second router on the LAN, and 172.20.0.0/16 lives behind it.
- Network → Static routes → + Add static route.
- Destination prefix
172.20.0.0/16, next hop10.0.3.1, descriptionlab. The Commands block reads:
set protocols static route 172.20.0.0/16 next-hop 10.0.3.1 set protocols static route 172.20.0.0/16 description lab- Stage route, then commit.
Now check the result on this same page, not on the router. The Declared static routes
panel should show 172.20.0.0/16 with an in FIB badge, and a row should appear in
the forwarding table with source static, next hop 10.0.3.1 and installed. If the
badge says declared, not installed, the next hop is not on a connected subnet — check
that some interface holds an address in 10.0.3.0/24 on Interfaces.
App integrations#
The page renders any integration offers installed apps make for it — the hint block sits
between the header and the tiles, and is present only when an installed app declares a
hint for the routes page. See Apps.
See also#
- Interfaces — where the connected routes come from.
- Addressing — the distances a DHCP or PPPoE client gives its own default route.
- Uplinks (multi-WAN) — everything about the default route, ranked and health-checked.
- BGP / OSPF — the dynamic sources of the routes in this table.
- Diagnostics → Tools — traceroute from the router, for when the table looks right and the traffic still does not arrive.
Checked against ui/src/pages/Routes.tsx,
agent/opmode.go (handleRoutes),
agent/parse.go (parseRoutes, routeCodes),
ui/src/lib/format.ts (isDangerousPath),
ui/src/lib/api.ts.