This article describes an experiment with Containerlab's advanced Generated topologies capability, taking the 3 stage Clos topology shown above and creating a template that can be used to generate topologies with any number of leaf and spine switches.
The clos3.yml topology file specifies the 2 leaf 2 spine topology shown above:
name: clos3
mgmt:
network: fixedips
ipv4_subnet: 172.100.100.0/24
ipv6_subnet: 2001:172:100:100::/80
topology:
defaults:
env:
COLLECTOR: 172.100.100.8
nodes:
leaf1:
kind: linux
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.2
mgmt_ipv6: 2001:172:100:100::2
env:
LOCAL_AS: 65001
NEIGHBORS: eth1 eth2
HOSTPORT: eth3
HOSTNET: "172.16.1.1/24"
HOSTNET6: "2001:172:16:1::1/64"
exec:
- touch /tmp/initialized
leaf2:
kind: linux
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.3
mgmt_ipv6: 2001:172:100:100::3
env:
LOCAL_AS: 65002
NEIGHBORS: eth1 eth2
HOSTPORT: eth3
HOSTNET: "172.16.2.1/24"
HOSTNET6: "2001:172:16:2::1/64"
exec:
- touch /tmp/initialized
spine1:
kind: linux
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.4
mgmt_ipv6: 2001:172:100:100::4
env:
LOCAL_AS: 65003
NEIGHBORS: eth1 eth2
exec:
- touch /tmp/initialized
spine2:
kind: linux
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.5
mgmt_ipv6: 2001:172:100:100::5
env:
LOCAL_AS: 65003
NEIGHBORS: eth1 eth2
exec:
- touch /tmp/initialized
h1:
kind: linux
image: sflow/clab-iperf3
mgmt_ipv4: 172.100.100.6
mgmt_ipv6: 2001:172:100:100::6
exec:
- ip addr add 172.16.1.2/24 dev eth1
- ip route add 172.16.2.0/24 via 172.16.1.1
- ip addr add 2001:172:16:1::2/64 dev eth1
- ip route add 2001:172:16:2::/64 via 2001:172:16:1::1
h2:
kind: linux
image: sflow/clab-iperf3
mgmt_ipv4: 172.100.100.7
mgmt_ipv6: 2001:172:100:100::7
exec:
- ip addr add 172.16.2.2/24 dev eth1
- ip route add 172.16.1.0/24 via 172.16.2.1
- ip addr add 2001:172:16:2::2/64 dev eth1
- ip route add 2001:172:16:1::/64 via 2001:172:16:2::1
sflow-rt:
kind: linux
image: sflow/prometheus
mgmt_ipv4: 172.100.100.8
mgmt_ipv6: 2001:172:100:100::8
ports:
- 8008:8008
links:
- endpoints: ["leaf1:eth1","spine1:eth1"]
- endpoints: ["leaf1:eth2","spine2:eth1"]
- endpoints: ["leaf2:eth1","spine1:eth2"]
- endpoints: ["leaf2:eth2","spine2:eth2"]
- endpoints: ["h1:eth1","leaf1:eth3"]
- endpoints: ["h2:eth1","leaf2:eth3"]
The new clos3.clab.gotmpl file is a templated version of the topology:
name: clos3
mgmt:
network: fixedips
ipv4_subnet: 172.100.100.0/24
ipv6_subnet: 2001:172:100:100::/80
topology:
defaults:
kind: linux
env:
COLLECTOR: 172.100.100.{{ add $.spines.num $.leaves.num $.leaves.num 2 }}
nodes:
{{- range $leafIndex := seq 1 $.leaves.num }}
leaf{{ $leafIndex }}:
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.{{ add $leafIndex 1 }}
mgmt_ipv6: 2001:172:100:100::{{ add $leafIndex 1 }}
env:
LOCAL_AS: {{ add 65000 $leafIndex }}
NEIGHBORS:{{- range $spineIndex := seq 1 $.spines.num }} eth{{ $spineIndex}}{{- end }}
HOSTPORT: eth{{ add $.spines.num 1 }}
HOSTNET: 172.16.{{ $leafIndex }}.1/24
HOSTNET6: 2001:172:16:{{ $leafIndex }}::1/64
exec:
- touch /tmp/initialized
{{- end }}
{{- range $spineIndex := seq 1 $.spines.num }}
spine{{ $spineIndex }}:
image: sflow/clab-frr
mgmt_ipv4: 172.100.100.{{ add $.leaves.num $spineIndex 1 }}
mgmt_ipv6: 2001:172:100:100::{{ add $.leaves.num $spineIndex 1 }}
env:
LOCAL_AS: {{ add 65000 $.leaves.num 1 }}
NEIGHBORS:{{- range $leafIndex := seq 1 $.leaves.num }} eth{{ $leafIndex }}{{- end }}
exec:
- touch /tmp/initialized
{{- end }}
{{- range $leafIndex := seq 1 $.leaves.num }}
h{{ $leafIndex }}:
image: sflow/clab-iperf3
mgmt_ipv4: 172.100.100.{{ add $.spines.num $.leaves.num $leafIndex 1 }}
mgmt_ipv6: 2001:172:100:100::{{ add $.spines.num $.leaves.num $leafIndex 1 }}
exec:
- ip addr add 172.16.{{ $leafIndex }}.2/24 dev eth1
- ip route add 172.16.0.0/16 via 172.16.{{ $leafIndex }}.1
- ip addr add 2001:172:16:{{ $leafIndex }}::2/64 dev eth1
- ip route add 2001:172:16::/48 via 2001:172:16:{{ $leafIndex }}::1
{{- end }}
sflow-rt:
image: sflow/prometheus
mgmt_ipv4: 172.100.100.{{ add $.spines.num $.leaves.num $.leaves.num 2 }}
mgmt_ipv6: 2001:172:100:100::{{ add $.spines.num $.leaves.num $.leaves.num 2 }}
ports:
- 8008:8008
links:
{{- range $spineIndex := seq 1 $.spines.num }}
{{- range $leafIndex := seq 1 $.leaves.num }}
- endpoints: ["spine{{ $spineIndex }}:eth{{ $leafIndex }}", "leaf{{ $leafIndex }}:eth{{ $spineIndex }}"]
{{- end }}
{{- end }}
{{- range $leafIndex := seq 1 $.leaves.num }}
- endpoints: ["leaf{{ $leafIndex }}:eth{{ add $.spines.num 1 }}", "h{{ $leafIndex }}:eth1"]
{{- end }}
The template makes uses of settings in the corresponsing clos3.clab_vars.yml file:
spines: num: 2 leaves: num: 2While creating a template involves some work, the result is a more compact representation of the configuration since repetative leaf and spine configurations are captures in iterative blocks. The advantage becomes clear with larger topologies since a 4 leaf 4 spine explicit configuration would be twice as large, but the tempate remains unchanged.
docker run --rm -it --privileged --network host --pid="host" \ -v /var/run/docker.sock:/var/run/docker.sock -v /run/netns:/run/netns \ -v $(pwd):$(pwd) -w $(pwd) \ ghcr.io/srl-labs/clab bashRun the above command to start Containerlab.
wget https://raw.githubusercontent.com/sflow-rt/containerlab/master/clos3.clab.gotmpl wget https://raw.githubusercontent.com/sflow-rt/containerlab/master/clos3.clab_vars.ymlDownload the template and settings files.
containerlab deploy -t clos3.clab.gotmplCreate the emulated network.
docker exec -it clab-clos3-leaf1 vtysh -c "show running-config"See configuration of leaf1 router. Connect to the web interface, http://localhost:8008. The sFlow-RT dashboard verifies that telemetry is being received from the four (two leaf and two spine) switches in the topology. See the sFlow-RT Quickstart guide for more information. The screen capture shows a real-time view of traffic flowing across the network during an iperf3 tests. Click on the sFlow-RT Apps menu and select the browse-flows application, or click here for a direct link to a chart with the settings shown above.
docker exec -it clab-clos3-h1 iperf3 -c 172.16.2.2Each of the hosts in the network has an iperf3 server, so running the above command will test bandwidth between h1 and h2.
containerlab destroy -t clos3.clab.gotmpl
When you are finished, run the above command to stop the containers and free the resources associated with the emulation.
Finally, try editing the clos3.clab_vars.yml file and increase the number of leaf switches to 12 and the number of spine switches to 5 and repeat the tests with a more realistic topology. A big advantage of using containers to emulate network devices is that they are extremely lightweight, allowing realistic production networks to be emulated on a laptop. Try the other sflow-rt/containerlab examples to experiment with DDoS mitigation, EVPN monitoring, and flow tracing.


