Chapter: 11 (Cloud Networking)
Duration: 90 minutes
Tools: Containerlab, FRRouting (EVPN), tcpdump, Wireshark
Points: 10
Objectives
- Deploy a 2-spine, 3-leaf Containerlab fabric with eBGP underlay
- Configure VXLAN VNI 100 overlay on leaf1 and leaf2
- Enable EVPN address-family to advertise MAC/IP routes
- Verify MAC learning without flooding via BGP EVPN Type 2 routes
- Capture VXLAN-encapsulated traffic on spine links
Topology
spine1 (AS 65100) spine2 (AS 65100)
/ \ / \
leaf1 leaf2 leaf1 leaf2
(65001) (65002) (65001) (65002)
| |
host1 host2
leaf1 and leaf2 are in the overlay; leaf3 is connected to spines but not configured for EVPN in this lab.
Setup
# topo-evpn.clab.yml
name: evpn
topology:
nodes:
spine1:
kind: linux
image: frrouting/frr:latest
spine2:
kind: linux
image: frrouting/frr:latest
leaf1:
kind: linux
image: frrouting/frr:latest
leaf2:
kind: linux
image: frrouting/frr:latest
leaf3:
kind: linux
image: frrouting/frr:latest
host1:
kind: linux
image: alpine:latest
host2:
kind: linux
image: alpine:latest
links:
- endpoints: ["leaf1:eth1", "spine1:eth1"]
- endpoints: ["leaf1:eth2", "spine2:eth1"]
- endpoints: ["leaf2:eth1", "spine1:eth2"]
- endpoints: ["leaf2:eth2", "spine2:eth2"]
- endpoints: ["leaf3:eth1", "spine1:eth3"]
- endpoints: ["leaf3:eth2", "spine2:eth3"]
- endpoints: ["host1:eth1", "leaf1:eth3"]
- endpoints: ["host2:eth1", "leaf2:eth3"]
containerlab deploy -t topo-evpn.clab.yml
Part 1: eBGP Underlay Configuration (25 min)
Configure eBGP underlay on all leaf-spine links (each leaf has its own AS; spines share AS 65100):
# Spine1 (AS 65100)
docker exec -it clab-evpn-spine1 vtysh <<'EOF'
configure terminal
interface eth1
ip address 10.0.11.0/31
interface eth2
ip address 10.0.21.0/31
interface eth3
ip address 10.0.31.0/31
interface lo
ip address 10.255.255.100/32
router bgp 65100
bgp router-id 10.255.255.100
no bgp ebgp-requires-policy
neighbor LEAVES peer-group
neighbor LEAVES send-community both
neighbor 10.0.11.1 peer-group LEAVES
neighbor 10.0.11.1 remote-as 65001
neighbor 10.0.21.1 peer-group LEAVES
neighbor 10.0.21.1 remote-as 65002
neighbor 10.0.31.1 peer-group LEAVES
neighbor 10.0.31.1 remote-as 65003
address-family ipv4 unicast
redistribute connected
exit-address-family
EOF
Configure spine2 analogously (AS 65100, different IP block: 10.0.12.0/31, 10.0.22.0/31, 10.0.32.0/31).
# Leaf1 (AS 65001)
docker exec -it clab-evpn-leaf1 vtysh <<'EOF'
configure terminal
interface eth1
ip address 10.0.11.1/31
interface eth2
ip address 10.0.12.1/31
interface lo
ip address 10.255.255.1/32
router bgp 65001
bgp router-id 10.255.255.1
no bgp ebgp-requires-policy
neighbor SPINES peer-group
neighbor SPINES remote-as 65100
neighbor SPINES send-community both
neighbor 10.0.11.0 peer-group SPINES
neighbor 10.0.12.0 peer-group SPINES
address-family ipv4 unicast
redistribute connected
maximum-paths 2
exit-address-family
EOF
Verify underlay routing:
docker exec clab-evpn-leaf1 vtysh -c "show ip bgp summary"
docker exec clab-evpn-leaf1 vtysh -c "show ip route"
# Should see routes to leaf2 loopback via both spines (ECMP)
Record:
- Are all BGP sessions in leaf1's
show ip bgp summaryEstablished? - How many paths does leaf1 have to leaf2's loopback (10.255.255.2/32)?
Part 2: VXLAN Overlay and EVPN Configuration (25 min)
# Leaf1: configure VXLAN and EVPN
docker exec -it clab-evpn-leaf1 vtysh <<'EOF'
configure terminal
interface vxlan100
vxlan id 100
vxlan local-tunnelip 10.255.255.1
vxlan remoteip 10.255.255.2
vxlan dstport 4789
router bgp 65001
address-family l2vpn evpn
neighbor SPINES activate
advertise-all-vni
exit-address-family
EOF
Create the VXLAN interface in the kernel and add it to a bridge with the host-facing port:
docker exec clab-evpn-leaf1 bash -c "
ip link add vxlan100 type vxlan id 100 dstport 4789 local 10.255.255.1
ip link set vxlan100 up
ip link add br100 type bridge
ip link set vxlan100 master br100
ip link set eth3 master br100
ip link set br100 up"
Repeat on leaf2 (local tunnelip 10.255.255.2; remoteip 10.255.255.1).
Configure hosts:
docker exec clab-evpn-host1 ip addr add 10.100.0.1/24 dev eth1
docker exec clab-evpn-host2 ip addr add 10.100.0.2/24 dev eth1
Part 3: EVPN Route Verification (15 min)
# Check EVPN routes on leaf1 after host1 has sent some traffic
docker exec clab-evpn-host1 arping -c 3 10.100.0.2
# On leaf1: check EVPN MAC/IP routes (Type 2)
docker exec clab-evpn-leaf1 vtysh -c "show bgp l2vpn evpn"
docker exec clab-evpn-leaf1 vtysh -c "show bgp l2vpn evpn route type 2"
docker exec clab-evpn-leaf1 vtysh -c "show evpn vni"
docker exec clab-evpn-leaf1 vtysh -c "show evpn mac vni 100"
Record:
- What BGP EVPN route type(s) appear after the arping?
- Does leaf1 see host2's MAC address via a Type 2 EVPN route from leaf2?
- What is the next-hop for the EVPN routes? (Should be leaf2's VTEP IP: 10.255.255.2)
Part 4: VXLAN Capture and Encapsulation Analysis (15 min)
# Capture on spine1's eth1 (leaf1 uplink) during host-to-host ping
docker exec clab-evpn-spine1 tcpdump -i eth1 -n \
"udp port 4789" -w /tmp/vxlan_capture.pcap &
docker exec clab-evpn-host1 ping -c 5 10.100.0.2
docker exec clab-evpn-spine1 killall tcpdump 2>/dev/null
docker cp clab-evpn-spine1:/tmp/vxlan_capture.pcap /tmp/
Open in Wireshark. Display filter: vxlan
Examine the VXLAN frame structure:
- Outer Ethernet frame: src/dst MAC (should be leaf1 and spine1 MACs)
- Outer IP header: src 10.255.255.1 (leaf1 VTEP), dst 10.255.255.2 (leaf2 VTEP)
- UDP header: src port (random), dst port 4789
- VXLAN header: VNI field should show 100
- Inner Ethernet frame: src/dst MAC of host1 and host2
Record:
- What is the VNI value in the VXLAN header?
- What are the outer IP source and destination addresses?
- What are the inner Ethernet source and destination MAC addresses?
- How many bytes of overhead does VXLAN encapsulation add to the original Ethernet frame?
Part 5: ECMP Verification (10 min)
# Generate traffic and observe both spines are used
# (ECMP hash will distribute flows across spine1 and spine2)
docker exec clab-evpn-spine1 tcpdump -i eth1 -n -c 20 "udp port 4789" &
docker exec clab-evpn-spine2 tcpdump -i eth1 -n -c 20 "udp port 4789" &
for i in $(seq 1 50); do
docker exec clab-evpn-host1 ping -c 1 -s $((i * 10)) 10.100.0.2 &
done
wait
docker exec clab-evpn-spine1 killall tcpdump 2>/dev/null
docker exec clab-evpn-spine2 killall tcpdump 2>/dev/null
Record:
- Did both spine1 and spine2 capture VXLAN traffic?
- What determines which flows go via spine1 vs. spine2? (Hint: ECMP hash inputs)
- What happens to existing VXLAN sessions if spine1 goes down?
# Simulate spine1 failure
docker exec clab-evpn-leaf1 ip link set eth1 down
docker exec clab-evpn-host1 ping -c 10 10.100.0.2
docker exec clab-evpn-leaf1 ip link set eth1 up
Lab Report
- Explain how EVPN eliminates the need for BUM (Broadcast/Unknown unicast/Multicast) flooding in a VXLAN fabric. What BGP EVPN route type is responsible?
- In the VXLAN capture, the inner Ethernet frame (host1's original packet) is completely unchanged by the encapsulation process. What property of VXLAN makes it transparent to the hosts?
- The leaf-spine fabric uses eBGP with a separate AS per leaf. Why is this preferred over running iBGP or OSPF as the underlay? (Hint: think about failure isolation and ECMP.)
Cleanup
containerlab destroy -t topo-evpn.clab.yml
Grading (10 points)
| Item | Points |
|---|---|
| eBGP underlay: all sessions Established; ECMP routes to leaf2 verified | 2 |
| EVPN: Type 2 MAC/IP routes propagated between leaf1 and leaf2 | 3 |
| VXLAN capture: VNI, outer/inner headers correctly identified | 3 |
| Lab report: BUM elimination; transparency; eBGP underlay rationale | 2 |