Edge Dual-Home Lab

Updated

September 4, 2026

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 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
done

FRR 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 priority 100
  • Uplink 172.16.20.1/30 to 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.1

Predict (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.2

Predict → 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:

  1. Shut ce1 LAN to force VRRP failover (crude).
  2. Configure track/priority decrement when eth2 down (if supported).
  3. 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.2

Predict

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 needed
docker 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 OK

Definition 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.sh green 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.