First-Hop Redundancy
First-Hop Redundancy
Hosts rarely run a routing protocol. They send traffic to a default gateway. If that gateway dies, the LAN dies with it—unless you give the LAN a virtual first hop that can move between routers. This chapter builds the model and a free-stack lab: Linux + FRR + Containerlab (mid-2026 open path).
Learning goals
By the end of this chapter you can:
- Explain why a single gateway IP is a single point of failure
- Contrast VRRP-class first-hop redundancy with floating statics and ECMP
- Deploy a dual-router VRRP pair on FRR for a shared virtual IP (VIP)
- Predict host behavior when the master fails and when it recovers
- Verify with
ip neigh, pings, and FRR VRRP state—not hope
Concepts
The problem
h1 ---- [LAN] ---- gw 10.0.0.1 (one box)
|
Internet-ish
Host config: default via 10.0.0.1. When that box reboots, ARP still points at a MAC that is gone until the host relearns—or traffic blackholes forever if nothing answers.
First-hop redundancy idea
Two (or more) routers share:
| Object | Role |
|---|---|
| Virtual IP (VIP) | Address hosts use as gateway |
| Virtual MAC (often) | Stable L2 identity for the VIP |
| Master / backup roles | Who owns the VIP right now |
| Hello / advertise | “I am alive and I claim priority” |
Hosts keep one gateway IP. The active forwarder changes under them.
Protocol family (vendor-agnostic)
| Name | Notes |
|---|---|
| VRRP | Open standard idea; FRR supports VRRP |
| HSRP / GLBP | Proprietary dialects of the same problem class |
| CARP | OpenBSD-family cousin |
This book uses VRRP on FRR because it is free, documented, and works in Containerlab without licenses. Optional: Nokia SR Linux community images have their own FHRP configuration surface—same model, different CLI.
Priority, preempt, timers
- Priority: higher wins master election (within rules).
- Preempt: when a higher-priority router returns, does it take the VIP back?
- Advertisement interval: how fast backups notice silence.
- Skew / master-down interval: how long before backup promotes.
What FHRP is not
| Not this | Because |
|---|---|
| Full routing protocol | Hosts do not learn remote prefixes via VRRP |
| Load balancing of arbitrary flows (unless designed) | Classic VRRP is active/standby for a VIP |
| Multihoming policy | That is BGP/statics + dual default; separate chapter lab |
FHRP protects the LAN’s first hop. Dual-homing the site edge is complementary (see dual-home lab later in this part).
ARP and the VIP
When master changes, hosts may still have the old MAC in the neighbor cache briefly. Good implementations use a shared virtual MAC or gratuitous ARP so clients rebind quickly. In labs, clear neighbor cache deliberately when debugging:
# Linux host
ip neigh flush dev eth1
# or
ip neigh del 10.0.0.254 dev eth1Addressing plan
| Node | Role | Interface | Address |
|---|---|---|---|
| r1 | VRRP priority high | eth1 (LAN) | 10.10.10.2/24 |
| r2 | VRRP priority low | eth1 (LAN) | 10.10.10.3/24 |
| VIP | gateway for hosts | — | 10.10.10.254 |
| h1 | client | eth1 | 10.10.10.10/24 via VIP |
| r1 eth2 | uplink | eth2 | 172.16.1.1/30 |
| r2 eth2 | uplink | eth2 | 172.16.2.1/30 |
| pe | “upstream” | eth1/eth2 | 172.16.1.2, 172.16.2.2 |
Upstream pe can be a simple FRR or Linux box that advertises a sink for drills (203.0.113.1 loopback).
Topology YAML
name: vrrp-edge
topology:
nodes:
r1:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/r1:/etc/frr
r2:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/r2:/etc/frr
pe:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/pe:/etc/frr
h1:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 10.10.10.10/24 dev eth1
- ip link set eth1 up
- ip route add default via 10.10.10.254
links:
- endpoints: ["h1:eth1", "r1:eth1"]
- endpoints: ["r1:eth1", "r2:eth1"] # same LAN: use bridge or multipoint
- endpoints: ["r1:eth2", "pe:eth1"]
- endpoints: ["r2:eth2", "pe:eth2"]LAN wiring note: two point-to-point links do not make a shared segment. Prefer a Linux bridge node as “LAN switch,” or Containerlab multipoint / bridge patterns from your lab-craft notes:
lan:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 bridge-utils
- ip link add name br0 type bridge
- ip link set br0 up
# links: h1, r1, r2 all into lan with bridge enslavement in execSimpler teaching pattern: one host + two routers on a bridge so ARP and VRRP multicast behave like a campus LAN.
FRR daemons
zebra=yes
vrrpd=yes
# staticd or bgpd if you route beyond the VIP
staticd=yes
Check mid-2026 FRR image docs for exact daemon names (vrrpd may be integrated differently by version—vtysh show vrrp is the operator check).
FRR VRRP sketch (r1)
frr version 10.2.1
frr defaults traditional
hostname r1
!
interface eth1
ip address 10.10.10.2/24
!
interface eth2
ip address 172.16.1.1/30
!
interface eth1
vrrp 1 ip 10.10.10.254
vrrp 1 priority 200
vrrp 1 advertisement-interval 1000
!
ip route 0.0.0.0/0 172.16.1.2
!
line vty
r2: real IP 10.10.10.3/24, priority 100, same VIP and VRID 1, default via its own uplink.
Syntax varies slightly by FRR minor version—always validate with:
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-r1 vtysh -c 'show interface eth1'Linux alternative (keepalived)
Some operators run keepalived on Linux instead of NOS VRRP. Same objects: VIP, priority, advert. In pure Alpine labs you may:
# illustrative — package availability varies
# apk add keepalived
# configure vrrp_instance with virtual_ipaddressFor this book’s default path, FRR VRRP keeps one control-plane stack with your OSPF/BGP labs.
Deploy and baseline
sudo containerlab deploy -t vrrp-edge.clab.yml
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-h1 ip route
docker exec clab-vrrp-edge-h1 ip neigh
docker exec clab-vrrp-edge-h1 ping -c 3 10.10.10.254
docker exec clab-vrrp-edge-h1 ping -c 3 172.16.1.2Predict (baseline)
- r1 is Master, r2 is Backup (priority 200 > 100)
- h1 ARP for VIP resolves to master’s virtual/real MAC pattern for your stack
- Ping VIP succeeds; traffic to upstream uses r1’s uplink
Observe
Record: VRRP state, VIP owner interface counters, ip neigh on h1, traceroute if upstream is reachable.
Drill 1 — Master failure
# Simulate master death (stop data plane or whole node)
docker exec clab-vrrp-edge-r1 ip link set eth1 down
# or: docker stop clab-vrrp-edge-r1
sleep 3
docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-h1 ip neigh show 10.10.10.254
docker exec clab-vrrp-edge-h1 ping -c 10 10.10.10.254
docker exec clab-vrrp-edge-h1 ping -c 5 203.0.113.1 # if pe has thisPredict → observe → fix
| Predict | Observe | Fix if wrong |
|---|---|---|
| r2 becomes Master after down-timer | show vrrp |
timers, VRID mismatch, not same LAN |
| Short ping loss then recovery | count drops | ARP stuck—flush neigh; check VIP MAC |
| Upstream still works via r2 | traceroute | r2 default / pe return routes |
Restore:
docker exec clab-vrrp-edge-r1 ip link set eth1 up
# or docker start + wait FRR ready
sleep 5
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp'Preempt on: r1 reclaims Master. Preempt off: r2 may stay Master—document which you configured.
Drill 2 — Split brain / LAN partition (concept)
If both routers believe they are alone (broken LAN bridge), two masters can both answer the VIP → intermittent ARP thrash.
Predict
Duplicate VIP answers; flapping neighbor cache; odd packet loss.
Observe
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp'
# tcpdump for VRRP (IP protocol 112) on the LAN
docker exec clab-vrrp-edge-h1 sh -c 'apk add --no-cache tcpdump; tcpdump -ni eth1 proto 112 -c 10'Fix / harden
- Ensure single L2 domain for the VRID
- BFD or link tracking to uplinks (advanced) so a “master” without upstream demotes
- Monitoring on “two masters seen” is an ops smell
Drill 3 — Priority change live
docker exec -it clab-vrrp-edge-r2 vtysh
configure terminal
interface eth1
vrrp 1 priority 250
end
writePredict
If preempt allowed, r2 becomes Master; h1 may re-ARP; path to upstream shifts to r2’s uplink.
Observe
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp'
docker exec clab-vrrp-edge-h1 traceroute -n 172.16.2.2Revert priorities in git-mounted configs after the experiment.
Return path and asymmetric edges
VIP failover only moves the outbound first hop. If upstream routing always returns via r1 while r2 is master, you get asymmetric paths or blackholes. Pair FHRP with:
- Shared upstream design, or
- Dynamic routing so return traffic follows the active edge, or
- State-aware NAT only on the active path (harder—prefer avoid state at edge in labs first)
Verification checklist
| Check | Intent |
|---|---|
show vrrp |
One Master per VRID on the LAN |
| Host default route | Points at VIP only |
ping VIP |
L2/L3 ownership of first hop |
| Kill master | Backup promotes; host recovers |
| Capture proto 112 | Hellos present on LAN |
| Upstream ping during fail | Data plane + return path |
verify.sh sketch
#!/usr/bin/env bash
set -euo pipefail
fail() { echo "FAIL: $*" >&2; exit 1; }
docker exec clab-vrrp-edge-h1 ping -c 2 -W 1 10.10.10.254 || fail "VIP"
# Exactly one master is harder in shell—parse show vrrp or accept soft check:
docker exec clab-vrrp-edge-r1 vtysh -c 'show vrrp' | grep -qi master \
|| docker exec clab-vrrp-edge-r2 vtysh -c 'show vrrp' | grep -qi master \
|| fail "no master"
echo OKCommon mistakes
| Mistake | Symptom |
|---|---|
| Routers not same L2 domain | Never form master/backup correctly |
| Different VRID or VIP | Two independent groups |
| Host points at real IP not VIP | No redundancy |
| No return routes via backup | Failover pings die mid-path |
| Priority tie without tie-break awareness | Unstable election |
| Forgetting to enable vrrp daemon | Empty show vrrp |
Optional SR Linux note (community)
SR Linux community Containerlab kinds expose interface and IRP/FHRP-related configuration in a different tree (YANG/CLI). Do not memorize CLI here—map objects: VIP, group id, priority, interface, preempt. Same predict→observe drills.
Summary
- Hosts need a stable first hop; VRRP-class protocols move a VIP between routers
- FRR + Containerlab is enough to learn Master/Backup, preempt, and failure timers
- Always verify host ARP, VRRP state, and end-to-end path after failover
- FHRP is not multihoming policy—combine later with dual-home BGP/statics
- Keep configs in binds; promote live priority experiments back to git
Next: DHCP relay and NAT—how edge services attach to this LAN model without becoming mysterious middleboxes.