Edge Dual-Home Lab
Edge Dual-Home Lab
This chapter is a full edge workout: one customer site, two uplinks to two providers, first-hop redundancy on the LAN, filtered eBGP, and failure drills. Stack: Containerlab + FRR + Alpine (mid-2026 free path). Optional SR Linux as a PE substitute for CLI diversity.
Learning goals
By the end of this chapter you can:
- Design dual-homed CE addressing and AS layout
- Prefer one uplink with local-preference; backup with AS-path prepend
- Combine VRRP VIP for hosts with dual CE or single CE dual-uplink patterns
- Prove failover with ping bursts, BGP tables, and traceroute
- Ship a lab folder that meets the book’s definition of done
Design choices (pick one primary)
Pattern A — Single CE, two eBGP uplinks (simpler)
pe1 (AS65010)
/
ce (AS65001) ---- LAN ---- hosts (GW = ce LAN IP or VIP if HA pair)
\
pe2 (AS65020)
Pattern B — Dual CE + VRRP (more realistic campus edge)
pe1
/
ce1 === VRRP VIP === LAN --- hosts
\ /
ce2
\
pe2
This chapter implements Pattern B as the main lab and notes how to simplify to A.
Addressing plan
| Object | Value |
|---|---|
| Site LAN | 192.168.50.0/24 |
| VIP gateway | 192.168.50.254 |
| ce1 LAN | 192.168.50.2/24 |
| ce2 LAN | 192.168.50.3/24 |
| host | 192.168.50.10/24 via VIP |
| ce1–pe1 | 172.16.10.0/30 (ce1 .1, pe1 .2) |
| ce2–pe2 | 172.16.20.0/30 (ce2 .1, pe2 .2) |
| Site prefix | 192.168.50.0/24 (advertise) |
| pe1 lo | 1.1.1.1/32 (AS65010) |
| pe2 lo | 2.2.2.2/32 (AS65020) |
| Hijack test | 203.0.113.0/24 must not be accepted from CE |
Topology YAML
name: dualhome
topology:
nodes:
ce1:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/ce1:/etc/frr
ce2:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/ce2:/etc/frr
pe1:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/pe1:/etc/frr
pe2:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/pe2:/etc/frr
h1:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 192.168.50.10/24 dev eth1
- ip link set eth1 up
- ip route add default via 192.168.50.254
lan:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2
- ip link add br0 type bridge
- ip link set br0 up
links:
- endpoints: ["h1:eth1", "lan:eth1"]
- endpoints: ["ce1:eth1", "lan:eth2"]
- endpoints: ["ce2:eth1", "lan:eth3"]
- endpoints: ["ce1:eth2", "pe1:eth1"]
- endpoints: ["ce2:eth2", "pe2:eth1"]Enslave LAN ports to br0 in a deploy hook:
for n in eth1 eth2 eth3; do
docker exec clab-dualhome-lan ip link set $n master br0
docker exec clab-dualhome-lan ip link set $n up
doneFRR daemons
zebra=yes
bgpd=yes
staticd=yes
vrrpd=yes
CE1 config sketch
frr version 10.2.1
frr defaults traditional
hostname ce1
!
interface lo
ip address 10.0.0.1/32
!
interface eth1
ip address 192.168.50.2/24
vrrp 1 ip 192.168.50.254
vrrp 1 priority 200
!
interface eth2
ip address 172.16.10.1/30
!
router bgp 65001
bgp router-id 10.0.0.1
no bgp ebgp-requires-policy
neighbor 172.16.10.2 remote-as 65010
!
address-family ipv4 unicast
network 192.168.50.0/24
neighbor 172.16.10.2 route-map FROM-PE in
neighbor 172.16.10.2 route-map TO-PE out
exit-address-family
!
ip prefix-list SITE seq 5 permit 192.168.50.0/24
ip prefix-list SITE seq 10 deny any
!
ip prefix-list DEFAULT-OK seq 5 permit 0.0.0.0/0
ip prefix-list DEFAULT-OK seq 10 deny any
!
route-map TO-PE permit 10
match ip address prefix-list SITE
route-map TO-PE deny 20
!
route-map FROM-PE permit 10
match ip address prefix-list DEFAULT-OK
set local-preference 200
route-map FROM-PE deny 20
!
line vty
no bgp ebgp-requires-policy is a lab convenience on some FRR versions—prefer explicit policies always in “production-shaped” labs.
CE2 config differences
- LAN IP
.3, VRRP priority100
- Uplink
172.16.20.1/30to pe2
- Outbound prepend so pe2 is less preferred by others if both advertise:
route-map TO-PE permit 10
match ip address prefix-list SITE
set as-path prepend 65001 65001
- Inbound local-pref
100(lower than ce1’s 200) if both learn default:
route-map FROM-PE permit 10
match ip address prefix-list DEFAULT-OK
set local-preference 100
For dual-CE, each CE may only have one uplink—VRRP chooses which CE hosts use; each CE’s BGP prefers its own default. Advanced: iBGP between ce1/ce2—optional stretch goal.
PE1 / PE2 sketch
hostname pe1
!
interface lo
ip address 1.1.1.1/32
!
interface eth1
ip address 172.16.10.2/30
!
router bgp 65010
bgp router-id 1.1.1.1
neighbor 172.16.10.1 remote-as 65001
!
address-family ipv4 unicast
network 0.0.0.0/0
network 1.1.1.1/32
neighbor 172.16.10.1 route-map FROM-CE in
neighbor 172.16.10.1 route-map TO-CE out
exit-address-family
!
ip prefix-list CE-ALLOW seq 5 permit 192.168.50.0/24
ip prefix-list CE-ALLOW seq 10 deny any
!
route-map FROM-CE permit 10
match ip address prefix-list CE-ALLOW
route-map FROM-CE deny 20
!
ip prefix-list ORIGINATE seq 5 permit 0.0.0.0/0
ip prefix-list ORIGINATE seq 10 permit 1.1.1.1/32
route-map TO-CE permit 10
match ip address prefix-list ORIGINATE
!
line vty
pe2 mirrors with AS 65020, 2.2.2.2, 172.16.20.2.
Hijack drill: temporarily add network 203.0.113.0/24 on CE—PE must not install it.
Deploy and baseline verify
sudo containerlab deploy -t dualhome.clab.yml
# bridge hook as above
docker exec clab-dualhome-ce1 vtysh -c 'show vrrp'
docker exec clab-dualhome-ce2 vtysh -c 'show vrrp'
docker exec clab-dualhome-ce1 vtysh -c 'show bgp summary'
docker exec clab-dualhome-ce1 vtysh -c 'show ip route'
docker exec clab-dualhome-pe1 vtysh -c 'show bgp ipv4 uni'
docker exec clab-dualhome-h1 ping -c 3 192.168.50.254
docker exec clab-dualhome-h1 ping -c 3 1.1.1.1
docker exec clab-dualhome-h1 traceroute -n 1.1.1.1Predict (baseline)
- ce1 VRRP Master
- h1 reaches VIP and pe1 loopback via ce1
- pe1 has 192.168.50.0/24 only from CE
- pe2 may also have site prefix if ce2 session up
Drill 1 — Primary PE session loss
docker exec clab-dualhome-ce1 ip link set eth2 down
sleep 2
docker exec clab-dualhome-ce1 vtysh -c 'show bgp summary'
docker exec clab-dualhome-h1 ping -c 20 2.2.2.2
docker exec clab-dualhome-h1 traceroute -n 2.2.2.2Predict → observe → fix
| Predict | If false |
|---|---|
| Host still uses ce1 VIP (VRRP unchanged) | — |
| ce1 loses default → traffic blackholes unless ce2 takes VIP or ce1 has alternate | Add static floating / iBGP / kill VRRP master |
Important teaching moment: if only ce1 is master and its uplink dies, VRRP does not care unless you track the uplink (BFD/link tracking) or lower priority. Options:
- Shut ce1 LAN to force VRRP failover (crude).
- Configure track/priority decrement when eth2 down (if supported).
- Run dual default via both CEs with host-side multipath (rare).
Document which design you chose. Professional edges tie FHRP priority to uplink health.
Drill 2 — Force VRRP failover
docker exec clab-dualhome-ce1 ip link set eth1 down
sleep 3
docker exec clab-dualhome-ce2 vtysh -c 'show vrrp'
docker exec clab-dualhome-h1 ip neigh flush dev eth1
docker exec clab-dualhome-h1 ping -c 10 2.2.2.2
docker exec clab-dualhome-h1 traceroute -n 2.2.2.2Predict
ce2 Master; path via pe2; short disruption.
Drill 3 — Policy rejection
# on ce1 temporarily
docker exec -it clab-dualhome-ce1 vtysh
# network 203.0.113.0/24 under bgp + dummy interface address if neededdocker exec clab-dualhome-pe1 vtysh -c 'show bgp ipv4 uni 203.0.113.0/24'Predict
Empty / not best—filter works. If accepted, fix FROM-CE prefix-list.
Drill 4 — Name/time smoke (hygiene)
Optional: add dnsmasq A record vip.site.lab → 192.168.50.254 and dig from h1; confirm date -u roughly matches host.
verify.sh
#!/usr/bin/env bash
set -euo pipefail
fail() { echo "FAIL: $*" >&2; exit 1; }
docker exec clab-dualhome-h1 ping -c 2 -W 1 192.168.50.254 || fail "vip"
docker exec clab-dualhome-pe1 vtysh -c 'show bgp ipv4 uni' | grep -q '192.168.50.0' \
|| fail "pe1 missing site"
# hijack should be absent
if docker exec clab-dualhome-pe1 vtysh -c 'show bgp ipv4 uni' | grep -q '203.0.113.0'; then
fail "hijack accepted"
fi
echo OKDefinition of done (this lab)
- Topology + configs in git
- Addressing plan + diagram
- VRRP master/backup documented
- eBGP policies on CE and PE
- Three drills with notes (PE loss, VRRP fail, hijack)
verify.shgreen on clean deploy
- Written note: how uplink loss interacts with VRRP
Optional SR Linux PE
Replace pe1 with community SR Linux kind in Containerlab; keep CE on FRR. Same BGP objects: neighbor, import prefix allow-list, export default. Compare show bgp dialects in your journal—models stay identical.
Common mistakes
| Mistake | Symptom |
|---|---|
| No bridge on LAN | VRRP never forms |
| Host uses .2 not VIP | No HA |
| PE accepts any prefix | Hijack succeeds |
| Uplink down but VRRP stays on blind CE | Blackhole |
| Asymmetric return without pe routes | One-way |
Summary
- Dual-home labs combine multihoming policy and first-hop HA—design their interaction
- FRR eBGP + prefix-lists + VRRP are enough for a portfolio-quality edge
- Always test policy negatives (hijack) and uplink vs VIP failures separately
- Prefer link tracking or clear runbooks when master loses upstream
- This lab maps to capstone C2 in the ops part
Next part: policy, QoS vocabulary, and hardening—filters beyond BGP, control-plane protection, and checklists.