This lab example consists of five FRR routers connected in a spine-leaf topology (two spine and three leaf). Each leaf router is connected to two hosts.
To use this lab, you need to install containerlab. You also need to have basic familiarity with Docker.
This lab uses the following Docker images:
- Click the button above → GitHub Codespaces will open a full VS Code environment in your browser.
- Wait 1–2 minutes for the container to start (first time only).
- Follow the steps in the next sectiion.
Use the following command to start the lab:
sudo clab deploy -t bgp-frr.clab.yml
For convenience, use the following script to test connectivity between leaf routers and hosts:
./router_connect_test.sh
and to test connectivity between hosts:
./host_connect_test.sh
To end the lab:
sudo clab destroy -t bgp-frr.clab.yml --cleanup
-
Confirm that BGP sessions are established among all peers.
docker exec clab-fdc-spine01 vtysh -c "show bgp summary" -
Show the routes learned from BGP in the routing table. Notices there are two paths to each host.
docker exec clab-fdc-leaf01 vtysh -c "show ip route bgp" -
Ping from any one host to another to verify connectivity.
docker exec clab-fdc-host11 ping 192.168.31.2 -
Use MTR/traceroute tools to observe the traffic path. Use MTR between several host pairs to confirm that paths are split between the two spine routers.
docker exec -it clab-fdc-host11 mtr 192.168.31.2 -
There are two paths between any pair of servers. To observe how the network reacts in case of a link failure: a) use MTR to observe the traffic route between two servers, then b) disable one of the links in the route and observe the traffic resume over another route.
docker exec -it clab-fdc-spine01 vtysh -
To force traffic to avoid one spine router (e.g. before shutting it down for repairs), prepend the path advertised by the router using a route-map. Add the following lines to the configuration:
route-map SERVICE permit 10 set as-path prepend 65000 65000 router bgp 65000 neighbor LEAF route-map SERVICE outRepeat (2) to confirm there only one route to each destination.
-
Use iperf3 to send TCP traffic between hosts (requires wbitt/network-multitool:alpine-extra): a) Run iperf3 as a server in one host
docker exec -d clab-fdc-host11 iperf3 -sb) Run iperf as a client from another host
docker exec -it clab-fdc-host31 iperf3 -c 192.168.11.2
docker exec clab-fdc-spine01 vtysh -c "show bgp summary"IPv4 Unicast Summary:
BGP router identifier 10.10.10.11, local AS number 65000 VRF default vrf-id 0
BGP table version 30
RIB entries 11, using 1408 bytes of memory
Peers 3, using 50 KiB of memory
Peer groups 1, using 64 bytes of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
eth1 4 65001 32 35 30 0 0 00:00:03 2 6 N/A
eth2 4 65002 32 36 30 0 0 00:00:03 2 6 N/A
eth3 4 65003 32 36 30 0 0 00:00:03 2 6 N/A
Total number of neighbors 3
docker exec clab-fdc-leaf01 vtysh -c "show ip route bgp"Codes: K - kernel route, C - connected, L - local, S - static,
R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
f - OpenFabric, t - Table-Direct,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
t - trapped, o - offload failure
B>* 192.168.21.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:00:36
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:00:36
B>* 192.168.22.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:00:36
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:00:36
B>* 192.168.31.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:00:36
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:00:36
B>* 192.168.32.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:00:36
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:00:36
docker exec clab-fdc-host11 ping 192.168.31.2PING 192.168.31.2 (192.168.31.2) 56(84) bytes of data.
64 bytes from 192.168.31.2: icmp_seq=1 ttl=61 time=0.275 ms
64 bytes from 192.168.31.2: icmp_seq=2 ttl=61 time=0.105 ms
64 bytes from 192.168.31.2: icmp_seq=3 ttl=61 time=0.424 ms
64 bytes from 192.168.31.2: icmp_seq=4 ttl=61 time=0.112 ms
64 bytes from 192.168.31.2: icmp_seq=5 ttl=61 time=0.105 ms
docker exec -it clab-fdc-host11 mtr 192.168.31.2 My traceroute [v0.95]
host11 (192.168.11.2) -> 192.168.31.2 (192.168.31.2) 2026-03-12T01:20:14+0000
Keys: Help Display mode Restart statistics Order of fields quit
Packets Pings
Host Loss% Snt Last Avg Best Wrst StDev
1. 192.168.11.1 0.0% 20 0.1 0.2 0.1 0.7 0.2
2. spine01 0.0% 19 0.1 0.1 0.1 0.5 0.1
3. 10.10.10.23 0.0% 19 0.1 0.1 0.1 0.4 0.1
4. 192.168.31.2 0.0% 19 0.1 0.1 0.1 0.2 0.0
docker exec clab-fdc-leaf01 vtysh -c "show ip route bgp"Codes: K - kernel route, C - connected, L - local, S - static,
R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
f - OpenFabric, t - Table-Direct,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
t - trapped, o - offload failure
B>* 192.168.21.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:01:58
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:01:58
B>* 192.168.22.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:01:58
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:01:58
B>* 192.168.31.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:01:58
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:01:58
B>* 192.168.32.0/24 [20/0] via fe80::a8c1:abff:fe1e:3ec1, eth1, weight 1, 00:01:58
* via fe80::a8c1:abff:fe24:a1b5, eth2, weight 1, 00:01:58
docker exec -d clab-fdc-host11 iperf3 -sdocker exec -it clab-bgp_frr-host32 iperf3 -c 192.168.11.2Connecting to host 192.168.11.2, port 5201
[ 5] local 192.168.32.2 port 49164 connected to 192.168.11.2 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 229 MBytes 1.92 Gbits/sec 0 258 KBytes
[ 5] 1.00-2.01 sec 231 MBytes 1.93 Gbits/sec 0 286 KBytes
[ 5] 2.01-3.00 sec 214 MBytes 1.80 Gbits/sec 6 332 KBytes
[ 5] 3.00-4.00 sec 216 MBytes 1.81 Gbits/sec 0 434 KBytes
[ 5] 4.00-5.00 sec 220 MBytes 1.85 Gbits/sec 6 434 KBytes
[ 5] 5.00-6.00 sec 221 MBytes 1.85 Gbits/sec 27 434 KBytes
[ 5] 6.00-7.00 sec 222 MBytes 1.87 Gbits/sec 13 434 KBytes
[ 5] 7.00-8.01 sec 222 MBytes 1.86 Gbits/sec 0 434 KBytes
[ 5] 8.01-9.00 sec 238 MBytes 2.00 Gbits/sec 13 434 KBytes
[ 5] 9.00-10.01 sec 225 MBytes 1.88 Gbits/sec 0 434 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.01 sec 2.19 GBytes 1.88 Gbits/sec 65 sender
[ 5] 0.00-10.01 sec 2.19 GBytes 1.88 Gbits/sec receiver
iperf Done.
Created by Maen Artimy - Personal Blog
