OSPF Basics
OSPF Basics
OSPF is a link-state IGP: routers flood topology information within an area, run SPF, and install routes. This chapter builds a single-area triangle on FRR in Containerlab—the highest-ROI dynamic routing lab in the book.
Learning goals
By the end of this chapter you can:
- Contrast link-state vs distance-vector at a model level
- Bring up OSPF adjacencies on FRR and read neighbor states
- Advertise loopbacks and LANs into OSPF
- Predict reconvergence when a link costs out or dies
- Verify RIB/FIB and traceroute paths
Concepts
Distance-vector vs link-state
| Distance-vector (idea) | Link-state (OSPF) | |
|---|---|---|
| What is shared | Vectors to prefixes | Topology (LSAs) |
| Loop risk | Needs careful rules | SPF on common map |
| Visibility | Partial | Area-wide topology view |
| Example | Classic RIP | OSPF, IS-IS |
OSPF adjacency state machine (short)
Down → Init → 2-Way → ExStart → Exchange → Loading → Full
For learning: Full with expected neighbors on each transit link. Stuck states often mean MTU mismatch, authentication, layer-2, or network type mismatch.
Areas
Single-area (0) is enough here. Multi-area adds ABR summarization later in your journey; do not rush.
Cost
OSPF picks lowest cost path. Cost often derives from reference bandwidth / interface bandwidth. In FRR you can set ip ospf cost on interfaces for drills.
Network types (awareness)
Point-to-point vs broadcast affects adjacency count and DR/BDR. P2P links in labs are simple; Ethernet multipoint may elect DR.
Addressing plan
| Node | lo | eth1 (to peer) | eth2 | LAN eth3 |
|---|---|---|---|---|
| r1 | 1.1.1.1/32 | 10.0.12.1/24 (r2) | 10.0.13.1/24 (r3) | 192.168.1.1/24 |
| r2 | 2.2.2.2/32 | 10.0.12.2/24 | 10.0.23.1/24 | 192.168.2.1/24 |
| r3 | 3.3.3.3/32 | 10.0.23.2/24 | 10.0.13.2/24 | optional |
Hosts: 192.168.1.10, 192.168.2.10 with defaults to local r.
Topology YAML
name: ospf-tri
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
r3:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/r3:/etc/frr
h1:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 192.168.1.10/24 dev eth1 && ip link set eth1 up
- ip route add default via 192.168.1.1
h2:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 192.168.2.10/24 dev eth1 && ip link set eth1 up
- ip route add default via 192.168.2.1
links:
- endpoints: ["r1:eth1", "r2:eth1"]
- endpoints: ["r2:eth2", "r3:eth1"]
- endpoints: ["r3:eth2", "r1:eth2"]
- endpoints: ["h1:eth1", "r1:eth3"]
- endpoints: ["h2:eth1", "r2:eth3"]FRR daemons
daemons file must enable:
zebra=yes
ospfd=yes
FRR OSPF config (r1 example)
frr version 10.2.1
frr defaults traditional
hostname r1
!
interface lo
ip address 1.1.1.1/32
ip ospf area 0
!
interface eth1
ip address 10.0.12.1/24
ip ospf area 0
!
interface eth2
ip address 10.0.13.1/24
ip ospf area 0
!
interface eth3
ip address 192.168.1.1/24
ip ospf area 0
!
router ospf
ospf router-id 1.1.1.1
!
line vty
Advertise by putting interfaces in area 0 (common FRR style). Equivalent network statements exist; be consistent across nodes.
r2/r3: unique router-ids 2.2.2.2, 3.3.3.3; matching interface IPs; LANs in OSPF so remote LANs appear in RIB.
Deploy and verify
sudo containerlab deploy -t ospf-tri.clab.yml
docker exec clab-ospf-tri-r1 vtysh -c 'show ip ospf neighbor'
docker exec clab-ospf-tri-r1 vtysh -c 'show ip ospf route'
docker exec clab-ospf-tri-r1 vtysh -c 'show ip route'
docker exec clab-ospf-tri-r1 vtysh -c 'show ip ospf database'
docker exec clab-ospf-tri-h1 ping -c 3 192.168.2.10
docker exec clab-ospf-tri-h1 traceroute -n 192.168.2.10Predict
- Each router: 2 neighbors Full (triangle)
- RIB contains remote LAN and loopbacks via OSPF
- Path prefers lower cost sides
Neighbor not Full?
Check:
ip link
ip addr
# MTU match
vtysh -c 'show ip ospf interface'
# timers, area mismatch, passive interfaces accidentalCost change drill
# on r1 eth1 increase cost so traffic prefers other way
docker exec -it clab-ospf-tri-r1 vtysh
configure terminal
interface eth1
ip ospf cost 1000
end
write
# promote back to frr.conf in git after experimentdocker exec clab-ospf-tri-r1 vtysh -c 'show ip route 192.168.2.0/24'
docker exec clab-ospf-tri-h1 traceroute -n 192.168.2.10Predict: path shifts if alternate exists with lower total cost.
Link failure drill
docker exec clab-ospf-tri-r1 ip link set eth1 down
sleep 5
docker exec clab-ospf-tri-r1 vtysh -c 'show ip ospf neighbor'
docker exec clab-ospf-tri-r1 vtysh -c 'show ip route 192.168.2.0'
docker exec clab-ospf-tri-h1 ping -c 20 192.168.2.10
docker exec clab-ospf-tri-r1 ip link set eth1 upJournal reconvergence behavior and whether ping loss matches expectations.
Passive interfaces / LAN notes
Sometimes you put a LAN in OSPF for advertisement but want no adjacency on user ports:
router ospf
passive-interface eth3
Loopbacks are often passive. Transit links remain non-passive.
Verification checklist
| Check | Command |
|---|---|
| Neighbors | show ip ospf neighbor |
| Database | show ip ospf database |
| OSPF RIB | show ip ospf route |
| Kernel/FIB | show ip route / ip route |
| Data plane | ping / traceroute |
verify.sh
#!/usr/bin/env bash
set -euo pipefail
fail() { echo "FAIL: $*" >&2; exit 1; }
docker exec clab-ospf-tri-r1 vtysh -c 'show ip ospf neighbor' | grep -q Full \
|| fail "no Full neighbor on r1"
docker exec clab-ospf-tri-h1 ping -c 2 -W 1 192.168.2.10 || fail "h1->h2"
docker exec clab-ospf-tri-h2 ping -c 2 -W 1 192.168.1.10 || fail "h2->h1"
echo OKCommon mistakes
| Mistake | Symptom |
|---|---|
| ospfd not enabled | no neighbors |
| Mismatched areas | stuck |
| Different IP subnets on link | no adjacency |
| MTU mismatch | ExStart/Exchange issues |
| router-id collisions | confusing DB |
| Forgetting LAN in OSPF | hosts missing remote routes |
Beyond this chapter
- Multi-area + summarization at ABR
- Stub/NSSA ideas
- OSPFv3 for IPv6
- Authentication
Master single-area Full adjacencies and failover first.
Summary
- OSPF floods link state, computes SPF, installs routes
- FRR triangle lab is the default IGP workout
- Always verify neighbors Full and FIB and ping
- Cost and link-down drills teach reconvergence
- Keep configs in binds; promote experimental vtysh changes to git
Next: BGP basics—sessions, path selection process, and a dual-router lab without vendor exam noise.