Skip to main content
RunBook Academy

VyOSII · Routing FundamentalsRouting primitives

Connected routes — the free routes the interface gives you

Foundation⏱ ~12 minipvyos

What you'll learn

  • Describe how the kernel automatically installs connected routes for every interface IP
  • Explain why connected routes have administrative distance 0 and cannot be overridden
  • Diagnose connectivity issues caused by a connected route that should not exist
  • Recognise the failure modes that arise when interfaces are added, removed, or reconfigured

Prerequisites

Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling) · 2026-08-15

Not yet marked complete on this device.

When an interface on a VyOS router comes up with an IP address, the kernel automatically installs a connected route for the subnet the IP belongs to. The connected route has administrative distance 0 — the most trusted source — and cannot be overridden by any static or dynamic route.

The operator who understands connected routes plans their network with them in mind. The operator who does not spends hours debugging why a “should work” static route is silently ignored.

This lesson is the operator’s foundation in connected routes: how they are installed, why they have AD 0, and the production failure modes that arise from them.

How connected routes are installed

When an interface is brought up with an IP address, the kernel adds three entries to the local routing table:

flowchart TB
  subgraph "eth0 with 192.0.2.50/24"
    A["Connected route\n192.0.2.0/24 dev eth0\nproto kernel scope link src 192.0.2.50"]
    B["Local route\n192.0.2.50/32 dev eth0\nproto kernel scope host src 192.0.2.50"]
    C["Broadcast route\n192.0.2.255/32 dev eth0\nproto kernel scope link src 192.0.2.50"]
  end

  A -->|"packet to 192.0.2.X"| F["Forwarded on eth0"]
  B -->|"packet to 192.0.2.50"| L["Delivered locally"]
  C -->|"packet to 192.0.2.255"| BRO["Broadcast on eth0"]

The three entries are:

  • Connected route (192.0.2.0/24) — matches any destination within the subnet. Forwards the packet out the interface.
  • Local route (192.0.2.50/32) — matches the router’s own IP. Delivers the packet locally (the kernel passes it up the stack).
  • Broadcast route (192.0.2.255/32) — matches the subnet broadcast. Broadcasts the packet on the interface.

These three entries are part of the local routing table (table 255). They exist as long as the interface has the IP address. When the IP is removed or the interface goes down, the kernel removes them.

Why connected routes have AD 0

The Linux kernel assigns administrative distance 0 to connected routes because the kernel itself installed them. The kernel is the most trusted source of routing information — it knows the interface is up, it knows the IP is configured. No static route, no dynamic protocol, no human operator is more trustworthy than the kernel’s own view of the interface.

The consequence: a static route to the same prefix is silently ignored. The kernel installs the connected route; the static route is not installed; the operator sees no error message.

configure
# These are both set:
set interfaces ethernet eth0 address 192.0.2.50/24
set protocols static route 192.0.2.0/24 next-hop 198.51.100.1
commit
save
exit
show ip route 192.0.2.0/24

The output:

S   > 192.0.2.0/24 [1/0] via 198.51.100.1, eth1
C        192.0.2.0/24 is directly connected, eth0

Wait — both routes are shown, with > marking the static as selected. But the static and the connected cover the same prefix. Which one wins?

The kernel installs both, but the lookup uses longest-prefix match first. With identical prefixes, AD is consulted. The connected route has AD 0; the static has AD 1. The connected route wins for traffic to 192.0.2.50 (the router’s own IP, caught by the local table) but the static can still be the forwarding path for traffic to other IPs in 192.0.2.0/24 — no, wait, that’s wrong too. Let me check the kernel behaviour precisely.

Actually, the Linux kernel installs the connected route in table local (255) and the static in table main (254). The kernel’s lookup walks the tables in numeric order. The local table is consulted first. For any destination within 192.0.2.0/24 other than the router’s own IP, the local table does not have a match (the local entry is /32 for the router’s own IP). The lookup falls through to the main table. Both routes are in the main table. AD comparison: connected (0) wins over static (1).

So the connected route wins for every destination in 192.0.2.0/24, not just 192.0.2.50. The static route is installed but never used. The operator’s static route was a configuration error — they thought they were configuring a route to 198.51.100.0/24, not 192.0.2.0/24, but the typo went undetected.

Secondary IP addresses and connected routes

A single interface can have multiple IP addresses. Each IP address generates its own set of connected, local, and broadcast routes.

configure
set interfaces ethernet eth0 address 192.0.2.50/24
set interfaces ethernet eth0 address 198.51.100.65/27
commit
save

The kernel installs:

ip route show
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.50
192.0.2.50/32 dev eth0 proto kernel scope host src 192.0.2.50
198.51.100.64/27 dev eth0 proto kernel scope link src 198.51.100.65
198.51.100.65/32 dev eth0 proto kernel scope host src 198.51.100.65

The router can now send and receive traffic on either IP. The connected routes are independent. There is no “primary” address.

The operator who removes a secondary IP must remove the connected route automatically — the kernel does this when the IP is removed. The operator who adds a secondary IP must remember that any other router sending traffic to the new IP must have a route to it. The connected route on R1 does not propagate to R2 — R2 needs its own route to the new IP.

Connected routes in IPv6

IPv6 connected routes follow the same pattern, with a wrinkle. IPv6 has no broadcast, so there is no broadcast route. The link-local address (fe80::/10) is added as a connected route automatically and is the source of every IPv6 routing-protocol session on the segment.

show ipv6 route
fe80::/64 dev eth0 proto kernel metric 256
2001:db8:abcd:1::/64 dev eth0 proto kernel metric 256

The link-local is critical. Without it, IPv6 routing protocols cannot establish sessions (BGP, OSPFv3, etc.) because they expect to source their packets from a link-local address. The operator who disables IPv6 link-local on a routing interface breaks every IPv6 routing protocol on that interface.

Connected routes and the firewall

The firewall on VyOS operates at Layer 3 and above. The connected route tells the kernel which packets are destined for the router itself (the local route) versus which are destined for transit (the connected route). The firewall’s input chain handles packets destined for the router; the forward chain handles transit packets.

flowchart LR
  P["Packet to 192.0.2.50"] --> L1{"Local table\nlookup"}
  L1 -->|"/32 match"|L1a["Input chain\n(terminate locally)"]
  L1 -->|"no match"|L1b{"Main table\nlookup"}
  L1b -->|"192.0.2.0/24 connected"|L1c["Forward chain\n(transit)"]
  L1b -->|other|L1d["Other route\n(forward via next-hop)"]

The firewall rules are applied to the appropriate chain based on the route lookup. A rule in the input chain never affects transit traffic; a rule in the forward chain never affects local traffic. The operator who writes “allow all inbound” in the input chain thinking it covers everything has misread the firewall semantics.

Failure modes

Connected route wins over a more-specific static

The connected route has AD 0. A static route to the same prefix has AD 1. The static is silently ignored.

Diagnostic: ip route get <dst> returns the connected route. ip route show <prefix> shows both, but the connected is selected.

Connected route still active after the IP was “removed”

The operator removes the IP from the configuration but the connected route persists. This happens when the operator removes the address via set interfaces ethernet eth0 address but does not commit — the old configuration is still active.

Diagnostic: show configuration | match "address" shows the new configuration; ip addr show dev eth0 shows the old IP.

Connected route on a sub-interface when the parent is down

A sub-interface (VLAN) has a connected route even when the parent interface is administratively down. The connected route is bound to the sub-interface’s existence, not the parent.

Diagnostic: ip link show dev eth0 shows parent down; ip link show dev eth0.10 shows sub-interface still up; ip route show <subnet> shows the connected route.

Connected route collides with a redistribution

The operator redistributes connected routes into BGP. The connected route on a transient interface (e.g. a dial-up backup) flaps the BGP advertisement. The fix is redistribution filters that match only the intended connected prefixes.

Diagnostic: vtysh show ip bgp shows the prefix; the BGP update history shows the prefix flapping.

Operational commands

The operator verifies connected routes with:

show ip route
show ip route 192.0.2.0/24
ip route show type local
ip route show table local
ip -br addr
show interfaces ethernet eth0

The ip route show type local filter shows only local entries. The ip route show table local shows only the local table. Both are useful for confirming that the connected routes exist and have the right addresses.

Validation

The validation sequence for “the connected route is wrong”:

  1. The IP exists: ip addr show dev eth0 lists the IPs configured on the interface.
  2. The connected route exists: ip route show <subnet> shows the connected entry.
  3. The connected route wins: ip route get <dst> returns the connected route.
  4. The interface is up: ip link show dev eth0 returns state UP.
  5. The static / dynamic route exists: show configuration | match "<prefix>" shows the configured route; vtysh show ip route <prefix> shows what FRRouting knows.

If the connected route wins when it should not, either the IP should be removed from the interface or the more-specific prefix should be different.

Cross-course references

  • The Linux course’s V-Linux-NetConfig covers the same kernel behaviour from the host perspective.
  • The lesson on administrative distance in Part II covers AD in depth.
  • The lesson on routing tables in Part II covers the field semantics.

Quiz

Knowledge check · 4 questions

  1. Q1. You configure a static route to 192.0.2.0/24 via 198.51.100.1. The interface eth0 has IP 192.0.2.50/24. After commit, `ip route show 192.0.2.0/24` shows both routes. `ip route get 192.0.2.50` returns the connected route. What is the most likely cause and the fix?

    R1 has eth0 with 192.0.2.50/24. The operator adds a static route to 192.0.2.0/24 via 198.51.100.1 with the intent of routing 192.0.2.0/24 traffic to a different upstream. After commit, the operator checks the routing table and sees both routes. The static is not selected for traffic to 192.0.2.50.

  2. Q2. A packet arrives at R1 with destination 192.0.2.50 (the router's own IP). Which routing table does the kernel consult first?

  3. Q3. Adding a secondary IP address to R1 creates a connected route on R1 only; R2 still needs a route of its own to reach the new subnet.

  4. Q4. R1 redistributes connected routes into BGP. R1 has a transient backup interface (dial-on-demand) that flaps every 5 minutes. What is the most likely production consequence?

    R1 has a backup interface `ppp0` that dials on demand. When connected, R1 redistributes the connected route into BGP. The connected route advertises a small prefix (e.g. 203.0.113.0/24) to the upstream BGP peer. Every time the interface flaps, the BGP advertisement appears or disappears, causing the upstream to install or withdraw the route.

Passing score: 75%. Answers are checked in this browser.

Production discipline

Connected routes are automatic and cannot be overridden. Plan the interface addressing once. Plan the redistribution filters once. Plan the IPv6 link-local once. Then the connected routes either work the way the operator expects, or the operator finds the configuration error before the production incident does.