After rebuilding my Arista SR-MPLS lab on Containerlab, I wanted to keep that same workflow and move into Cumulus EVPN-VXLAN. This time the goal was not just to recreate a fabric, but to get hands-on quickly with a repeatable topology, fast verification, and a workflow that fits naturally with automation and AI.
Why I built this lab
My earlier Containerlab work focused on Arista SR-MPLS. That exercise proved something important: once the topology, startup configs, and validation flow are written as code, the time from idea to working lab drops dramatically.
So the next logical step was to build a compact Cumulus EVPN-VXLAN fabric and observe how the Linux bridge, FRR, and EVPN control plane all line up.
On this lab, I wanted a few things immediately:
- A reproducible spine-leaf topology in YAML
- Fast deployment with Containerlab
- Direct access to FRR via
vtysh - A realistic way to validate EVPN behavior from both BGP and Linux bridge views
This is exactly the kind of workflow I want for short, focused infrastructure experiments in 2026.
Architecture Summary
The lab focuses on a small spine-leaf EVPN-VXLAN fabric running on Cumulus Linux containers. The underlay uses BGP between leaf and spine nodes, while EVPN distributes MAC/IP reachability for L2 VNIs across the fabric.
Key design points
- Two spines in AS 65100
- Leaf1 in AS 65111
- Remote leaf visible as VTEP 10.255.255.13
- Leaf1 router ID / VTEP loopback 10.255.255.11
- VNI 10010 mapped to VLAN 10
- VNI 10020 mapped to VLAN 20
- MLAG-style peerlink between the leaf nodes
Topology image:
Topology YAML
Like the Arista lab, everything starts from one topology file:
containerlab deploy -t cumulus-evpn-vxlan.yaml
The YAML defines:
- Nodes
- Management IPs
- Spine-leaf links
- Startup configs
- EVPN-VXLAN structure
That is the real advantage of Containerlab. The topology is not just documented — it is executable.
Why Cumulus is interesting here
What makes Cumulus useful in a lab like this is the combination of Linux visibility and networking abstraction.
I can validate the same behavior from multiple angles:
net showfor high-level operational checksvtyshfor FRR internals- Linux bridge state for data-plane confirmation
That makes it ideal for learning EVPN-VXLAN properly rather than treating it like a black box.
Validation approach (Architect mindset)
This lab is not a config copy-paste article. I wanted to validate whether the design was behaving coherently at every layer.
These were the main questions:
- Are both EVPN sessions from leaf1 to the spines established?
- Are VNIs present and associated with a remote VTEP?
- Are local and remote MACs reflected correctly in the bridge table?
- Do EVPN Type-2 and Type-3 routes match what the data plane is learning?
When those answers line up, the fabric becomes predictable — and troubleshooting becomes much easier.
EVPN BGP summary on leaf1
The first sanity check is:
net show bgp l2vpn evpn summary
From leaf1:
BGP router identifier 10.255.255.11, local AS number 65111 vrf-id 0
BGP table version 0
RIB entries 7, using 1344 bytes of memory
Peers 2, using 43 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt
spine1(swp1) 4 65100 1580 1589 0 0 0 01:16:19 4 9
spine2(swp2) 4 65100 1580 1592 0 0 0 01:16:08 4 9
What this tells me:
- Both spines are up and exchanging EVPN routes
- The sessions are stable
State/PfxRcd = 4confirms routes are actually being receivedPfxSnt = 9suggests leaf1 is advertising its local EVPN state correctly
This is the fastest way to rule out basic adjacency or EVPN activation problems.
VNI state on leaf1
Next check:
net show evpn vni
Output:
VNI Type VxLAN IF # MACs # ARPs # Remote VTEPs Tenant VRF
10010 L2 vni10 2 8 1 default
10020 L2 vni20 0 0 1 default
This is a very clean summary:
- VNI 10010 is active and already populated with MAC and ARP state
- VNI 10020 is present even though there is no active local endpoint in this snapshot
- Both VNIs already see 1 remote VTEP
For a small two-leaf EVPN fabric, that is exactly what I want to see.
MAC learning through the Linux bridge
This is where Cumulus becomes especially useful from a learning perspective.
net show bridge macs
Relevant excerpts:
10 bridge swp10 aa:c1:ab:c1:79:a2
10 bridge vni10 aa:c1:ab:1b:76:8c extern_learn
...
untagged vni10 aa:c1:ab:1b:76:8c 10.255.255.13 self, extern_learn
untagged vni20 00:00:00:00:00:00 10.255.255.13 permanent self
This tells me:
- Local MACs are learned on the access-facing interface (
swp10) - Remote MACs are learned on the VXLAN interface (
vni10) withextern_learn - The remote VTEP for that learned state is 10.255.255.13, which matches the other leaf
This is the exact kind of visibility I like in Cumulus. The Linux bridge is not hidden from you — it becomes part of the validation workflow.
EVPN route inspection with vtysh
To tie the control plane back to the MAC table, I inspect FRR directly:
vtysh -c "show bgp l2vpn evpn route"
Relevant portions:
Route Distinguisher: 10.255.255.11:10010
*> [2]:[0]:[48]:[aa:c1:ab:c1:79:a2]:[32]:[10.1.10.101]
10.255.255.11 32768 i
ET:8 RT:65111:10010
*> [3]:[0]:[32]:[10.255.255.11]
10.255.255.11 32768 i
ET:8 RT:65111:10010
Route Distinguisher: 10.255.255.13:10010
*> [2]:[0]:[48]:[aa:c1:ab:1b:76:8c]:[32]:[10.1.10.102]
10.255.255.13 0 65100 65113 i
RT:65113:10010 ET:8
*> [3]:[0]:[32]:[10.255.255.13]
10.255.255.13 0 65100 65113 i
RT:65113:10010 ET:8
What this shows:
- Leaf1 originates a local Type-2 MAC/IP route for host
10.1.10.101 - Leaf1 also originates a Type-3 IMET route for its own VTEP participation
- Remote host
10.1.10.102is learned from VTEP 10.255.255.13 - The EVPN routes match the MAC learning seen in the Linux bridge
That cross-check is the whole point. BGP, VNI state, and bridge learning all tell the same story.
Useful show commands
These are the main commands I used to validate the fabric:
net show bgp l2vpn evpn summary
net show evpn vni
net show bridge macs
vtysh -c "show bgp l2vpn evpn route"
ip -br a
For a compact EVPN-VXLAN lab, this is enough to validate most of the important behavior quickly.
Lessons learned during build
- Running the topology as code makes EVPN-VXLAN experiments very fast
- Cumulus + FRR is excellent for understanding how EVPN control plane state maps into Linux bridge behavior
vtyshgives the clearest view when I want to see exactly what EVPN is advertising and receiving- AI-assisted workflows make it easier to move from raw CLI output into structured validation notes
The biggest change is not speed alone. It is that I spend less time transcribing commands and more time validating design intent.
EVE-NG vs Containerlab (one architect’s perspective)
| Feature | EVE-NG | Containerlab |
|---|---|---|
| Topology definition | UI | YAML |
| Config version control | Manual | Git |
| Reproducibility | Medium | High |
| Build speed | Slower | Fast |
| Linux-level visibility | Limited | Excellent |
| Automation / AI workflow | Awkward | Natural |
Verdict: For compact EVPN-VXLAN and control-plane labs, Containerlab is now my default starting point.
What’s next
I plan to expand this into multiple follow-up posts:
- Part 2 — EVPN route-type interpretation on Cumulus
- Part 3 — MLAG behavior in a dual-leaf fabric
- Part 4 — Failure testing during spine or peerlink loss
- Part 5 — Parsing and validating outputs with automation
Contact
If you’re a network architect, SE, data centre engineer, or working on EVPN fabrics, connect with me:
- LinkedIn: https://www.linkedin.com/in/gary-wong-0503a837/
- GitHub: https://github.com/svenuscf
- Blog: https://garywong.pro
Meta
This post continues the direction I wanted after moving onto Hugo and code-driven labs. I do not just want to publish CLI output. I want technical posts to reflect how I validate systems as an architect.
Build fast. Validate deeper. Keep the lab in code.