├── .deepsource.toml ├── .devcontainer ├── Dockerfile ├── dclab ├── docker-in-docker │ └── devcontainer.json ├── docker-in-docker_slim │ └── devcontainer.json ├── docker-outside-of-docker │ └── devcontainer.json ├── docker-outside-of-docker_slim │ └── devcontainer.json ├── slim.Dockerfile └── zsh │ ├── .p10k.zsh │ ├── .zshrc │ ├── .zshrc-slim │ ├── install-tools-completions.sh │ └── install-zsh-plugins.sh ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── build-containerlab.yml │ ├── build-devcontainer.yml │ ├── cicd.yml │ ├── cisco_iol-tests.yml │ ├── codeql-analysis.yml │ ├── fdio_vpp-tests.yml │ ├── force-build.yml │ ├── fortigate-tests.yml │ ├── golangci-lint.yml │ ├── install-podman.sh │ ├── kind-tests.yml │ ├── smoke-tests.yml │ ├── srlinux-tests.yml │ ├── sros-tests.yml │ └── vxlan-tests.yml ├── .gitignore ├── .gitlab-ci.yml ├── .golangci.yml ├── .goreleaser.yml ├── .markdownlint.yml ├── .mk └── lint.mk ├── .pre-commit-config.yaml ├── LICENSE ├── Makefile ├── README.md ├── cert ├── ca.go ├── cert.go ├── certificate.go ├── csr_input.go └── local_dir_cert_storage.go ├── clab ├── authz_keys.go ├── cert.go ├── clab.go ├── clab_test.go ├── config.go ├── config │ ├── send.go │ ├── template.go │ ├── templates │ │ ├── base__srl.tmpl │ │ ├── base__vr-sros.tmpl │ │ └── srl-ifaces__srl.tmpl │ ├── transport │ │ ├── ssh.go │ │ ├── sshkind.go │ │ └── transport.go │ ├── utils.go │ └── utils_test.go ├── config_test.go ├── dependency_manager │ ├── dependency_manager.go │ ├── dependency_manager_test.go │ ├── dependency_node.go │ └── depender_node_stage.go ├── deploy_options.go ├── exec │ ├── exec.go │ └── exec_test.go ├── exec_options.go ├── export.go ├── export_templates │ ├── auto.tmpl │ └── full.tmpl ├── file.go ├── graph.go ├── graph_templates │ └── nextui │ │ ├── LICENSE.txt │ │ ├── nextui.html │ │ └── static │ │ ├── css │ │ ├── next.css │ │ └── tailwind.css │ │ ├── fonts │ │ ├── CiscoSansExtraLight.otf │ │ ├── CiscoSansRegular.otf │ │ ├── ciscosansextralight-webfont.eot │ │ ├── ciscosansextralight-webfont.svg │ │ ├── ciscosansextralight-webfont.ttf │ │ ├── ciscosansextralight-webfont.woff │ │ ├── ciscosansregular-webfont.eot │ │ ├── ciscosansregular-webfont.svg │ │ ├── ciscosansregular-webfont.ttf │ │ ├── ciscosansregular-webfont.woff │ │ ├── next-font.eot │ │ ├── next-font.svg │ │ ├── next-font.ttf │ │ └── next-font.woff │ │ └── js │ │ ├── next.js │ │ └── script.js ├── hostsfile.go ├── inventory.go ├── inventory_ansible.go.tpl ├── inventory_nornir_simple.go.tpl ├── inventory_test.go ├── network.go ├── register.go ├── ssh_config.go.tpl ├── sshconfig.go └── test_data │ ├── clab-topo2 │ └── node1 │ │ └── node1 │ ├── default.lic │ ├── envfile1 │ ├── envfile2 │ ├── kind.lic │ ├── node1.lic │ ├── topo1.yml │ ├── topo10.yml │ ├── topo11-ext-cont.yaml │ ├── topo12.yml │ ├── topo13.yml │ ├── topo14.yml │ ├── topo15.yml │ ├── topo2.yml │ ├── topo3.yml │ ├── topo4.yml │ ├── topo5.yml │ ├── topo6.yml │ ├── topo7-dup-rootnetns.yml │ ├── topo8_ansible_groups.yml │ ├── topo8_nornir_groups.yml │ └── topo9.yml ├── cmd ├── common │ ├── common.go │ └── sudo.go ├── completion.go ├── config.go ├── config_template.go ├── deploy.go ├── destroy.go ├── disableTxOffload.go ├── exec.go ├── generate.go ├── generate_test.go ├── graph.go ├── inspect │ ├── inspect.go │ └── inspect_interfaces.go ├── redeploy.go ├── root.go ├── save.go ├── tool_sshx.go ├── tools.go ├── tools_api.go ├── tools_api_start.go ├── tools_api_status.go ├── tools_api_stop.go ├── tools_cert.go ├── tools_netem.go ├── tools_veth.go ├── version │ ├── check.go │ ├── logo.txt │ ├── upgrade.go │ ├── version.go │ └── version_test.go └── vxlan.go ├── codecov.yml ├── docs ├── CNAME ├── cmd │ ├── completion.md │ ├── deploy.md │ ├── destroy.md │ ├── exec.md │ ├── generate.md │ ├── graph.md │ ├── inspect │ │ ├── index.md │ │ └── interfaces.md │ ├── redeploy.md │ ├── save.md │ ├── tools │ │ ├── api-server │ │ │ ├── start.md │ │ │ ├── status.md │ │ │ └── stop.md │ │ ├── cert │ │ │ ├── ca │ │ │ │ └── create.md │ │ │ └── sign.md │ │ ├── disable-tx-offload.md │ │ ├── netem │ │ │ ├── reset.md │ │ │ ├── set.md │ │ │ └── show.md │ │ ├── sshx │ │ │ ├── attach.md │ │ │ ├── detach.md │ │ │ ├── list.md │ │ │ └── reattach.md │ │ ├── veth │ │ │ └── create.md │ │ └── vxlan │ │ │ ├── create.md │ │ │ └── delete.md │ └── version │ │ ├── check.md │ │ └── index.md ├── community.md ├── htmltest-w-github.yml ├── htmltest.yml ├── images │ ├── containerlab-og.png │ ├── containerlab_black.png │ ├── containerlab_dark_no_text.svg │ ├── containerlab_export.svg │ ├── containerlab_export_white_ink.svg │ ├── containerlab_export_white_ink_js.svg │ ├── containerlab_full_white_no_text.svg │ ├── containerlab_grey.pdf │ ├── containerlab_grey.png │ ├── containerlab_white_no_text.svg │ ├── favicon.svg │ ├── flask.svg │ └── topoviewer-icons │ │ ├── client.svg │ │ ├── controller.svg │ │ ├── dcgw.svg │ │ ├── pon.svg │ │ ├── rgw.svg │ │ ├── router.svg │ │ ├── server.svg │ │ ├── spine.svg │ │ └── switch.svg ├── index.md ├── install.md ├── lab-examples │ ├── bgp-vpls-nok-jun.md │ ├── cvx01.md │ ├── cvx02.md │ ├── ext-bridge.md │ ├── freebsd01.md │ ├── frr01.md │ ├── ftdv01.md │ ├── generic_vm01.md │ ├── ixiacone-srl.md │ ├── lab-examples.md │ ├── min-5clos.md │ ├── min-clos.md │ ├── multinode.md │ ├── openbsd01.md │ ├── ost-srl.md │ ├── peering-lab.md │ ├── rare-freertr.md │ ├── single-srl.md │ ├── srl-ceos.md │ ├── srl-crpd.md │ ├── srl-frr.md │ ├── srl-sonic.md │ ├── srl-vjunos-switch.md │ ├── srl-vjunosevolved.md │ ├── srl-xrd.md │ ├── templated01.md │ ├── templated02.md │ ├── two-srls.md │ ├── vr-sros.md │ ├── vr-vmx.md │ ├── vr-xrv.md │ ├── vr-xrv9k.md │ ├── vsrx01.md │ └── wan.md ├── macos.md ├── manual │ ├── cert.md │ ├── clabernetes │ │ ├── index.md │ │ ├── install.md │ │ ├── pcap.md │ │ └── quickstart.md │ ├── codespaces.md │ ├── conf-artifacts.md │ ├── config-mgmt.md │ ├── dev │ │ ├── debug.md │ │ ├── doc.md │ │ ├── index.md │ │ └── test.md │ ├── images.md │ ├── impairments.md │ ├── inventory.md │ ├── kinds │ │ ├── 6wind_vsr.md │ │ ├── bridge.md │ │ ├── c8000.md │ │ ├── ceos.md │ │ ├── checkpoint_cloudguard.md │ │ ├── cisco_iol.md │ │ ├── crpd.md │ │ ├── cvx.md │ │ ├── dell_sonic.md │ │ ├── ext-container.md │ │ ├── fdio_vpp.md │ │ ├── fortinet_fortigate.md │ │ ├── freebsd.md │ │ ├── generic_vm.md │ │ ├── host.md │ │ ├── huawei_vrp.md │ │ ├── index.md │ │ ├── ipinfusion-ocnos.md │ │ ├── k8s-kind.md │ │ ├── keysight_ixia-c-one.md │ │ ├── linux.md │ │ ├── openbsd.md │ │ ├── openwrt.md │ │ ├── ostinato.md │ │ ├── ovs-bridge.md │ │ ├── rare-freertr.md │ │ ├── sonic-vm.md │ │ ├── sonic-vs.md │ │ ├── srl.md │ │ ├── vr-aoscx.md │ │ ├── vr-c8000v.md │ │ ├── vr-cat9kv.md │ │ ├── vr-csr.md │ │ ├── vr-ftdv.md │ │ ├── vr-ftosv.md │ │ ├── vr-n9kv.md │ │ ├── vr-pan.md │ │ ├── vr-ros.md │ │ ├── vr-sros.md │ │ ├── vr-veos.md │ │ ├── vr-vjunosevolved.md │ │ ├── vr-vjunosrouter.md │ │ ├── vr-vjunosswitch.md │ │ ├── vr-vmx.md │ │ ├── vr-vqfx.md │ │ ├── vr-vsrx.md │ │ ├── vr-xrv.md │ │ ├── vr-xrv9k.md │ │ └── xrd.md │ ├── multi-node.md │ ├── network.md │ ├── node-filtering.md │ ├── nodes.md │ ├── share-access.md │ ├── topo-def-file.md │ ├── vrnetlab.md │ ├── vsc-extension.md │ └── wireshark.md ├── overrides │ ├── .icons │ │ └── clab │ │ │ └── icon.svg │ ├── main.html │ └── partials │ │ ├── comments.html │ │ └── copyright.html ├── quickstart.md ├── rn │ ├── 0.11.0.md │ ├── 0.12.0.md │ ├── 0.13.0.md │ ├── 0.14.0.md │ ├── 0.14.1.md │ ├── 0.14.2.md │ ├── 0.14.3.md │ ├── 0.14.4.md │ ├── 0.15.md │ ├── 0.16.md │ ├── 0.17.md │ ├── 0.18.md │ ├── 0.19.md │ ├── 0.20.md │ ├── 0.21.md │ ├── 0.22.md │ ├── 0.23.md │ ├── 0.24.md │ ├── 0.25.md │ ├── 0.26.md │ ├── 0.27.md │ ├── 0.28.md │ ├── 0.29.md │ ├── 0.30.md │ ├── 0.31.md │ ├── 0.32.md │ ├── 0.33.md │ ├── 0.34.md │ ├── 0.35.md │ ├── 0.36.md │ ├── 0.37.md │ ├── 0.38.md │ ├── 0.39.md │ ├── 0.40.md │ ├── 0.41.md │ ├── 0.42.md │ ├── 0.43.md │ ├── 0.44.md │ ├── 0.45.md │ ├── 0.46.md │ ├── 0.47.md │ ├── 0.48.md │ ├── 0.49.md │ ├── 0.50.md │ ├── 0.51.md │ ├── 0.52.md │ ├── 0.53.md │ ├── 0.54.md │ ├── 0.55.md │ ├── 0.56.md │ ├── 0.57.md │ ├── 0.58.md │ ├── 0.59.md │ ├── 0.60.md │ ├── 0.61.md │ ├── 0.62.md │ ├── 0.63.md │ ├── 0.64.md │ ├── 0.65.md │ ├── 0.66.md │ ├── 0.67.md │ └── 0.68.md ├── stylesheets │ └── extra.css └── windows.md ├── errors └── errors.go ├── get.sh ├── git ├── __repo_parser_test.go ├── git.go ├── github.go ├── github_test.go ├── gitlab.go ├── gitlab_test.go └── repo.go ├── go.mod ├── go.sum ├── goreleaser.dockerfile ├── internal ├── mermaid │ └── graph.go ├── slices │ └── slices.go └── tc │ └── tc.go ├── lab-examples ├── .gitignore ├── br01 │ └── br01.clab.yml ├── cert01 │ └── cert01.clab.yml ├── clos01 │ └── clos01.clab.yml ├── clos02 │ ├── README.md │ ├── clos02.clab.yml │ ├── configs │ │ ├── client1.sh │ │ ├── client2.sh │ │ ├── client3.sh │ │ ├── client4.sh │ │ ├── leaf1.yaml │ │ ├── leaf2.yaml │ │ ├── leaf3.yaml │ │ ├── leaf4.yaml │ │ ├── spine1.yaml │ │ ├── spine2.yaml │ │ ├── spine3.yaml │ │ ├── spine4.yaml │ │ ├── superspine1.yaml │ │ └── superspine2.yaml │ ├── setup.clos02.clab.yml │ └── setup.sh ├── cvx01 │ ├── README.md │ ├── sw1 │ │ └── interfaces │ ├── sw2 │ │ └── frr.conf │ └── topo.clab.yml ├── cvx02 │ ├── README.md │ ├── h1 │ │ └── interfaces │ ├── sw1 │ │ └── interfaces │ └── topo.clab.yml ├── fortigate │ └── fortigate.clab.yml ├── freebsd01 │ └── freebsd01.clab.yml ├── frr01 │ ├── PC-interfaces.sh │ ├── README.md │ ├── frr01.clab.yml │ ├── router1 │ │ ├── daemons │ │ └── frr.conf │ ├── router2 │ │ ├── daemons │ │ └── frr.conf │ ├── router3 │ │ ├── daemons │ │ └── frr.conf │ └── run.sh ├── ftdv01 │ └── ftdv01.yml ├── generic_vm01 │ └── generic_vm.clab.yml ├── ixiac01 │ ├── go.mod │ ├── go.sum │ ├── ipv4_forwarding.go │ ├── ixiac01.clab.yml │ └── srl.cfg ├── k8s_kind01 │ ├── k01-config.yaml │ └── k8s_kind01.clab.yml ├── openbsd01 │ └── openbsd01.yml ├── ost-srl │ ├── ost-srl.clab.yml │ ├── ost-srl.ossn │ └── srl.cfg ├── sonic01 │ └── sonic01.clab.yml ├── srl-quickstart │ ├── srl01.clab.yml │ └── srl02.clab.yml ├── srl01 │ └── srl01.clab.yml ├── srl02 │ ├── srl02.clab.yml │ ├── srl1.cfg │ └── srl2.cfg ├── srl03 │ └── srl03.clab.yml ├── srlceos01 │ └── srlceos01.clab.yml ├── srlcrpd01 │ └── srlcrpd01.clab.yml ├── srlfrr01 │ ├── daemons │ ├── frr.cfg │ ├── srl.cfg │ └── srlfrr01.clab.yml ├── srlvjunos01 │ ├── srl.cli │ ├── srlvjunos01.clab.yml │ └── vjunos.cfg ├── srlvjunos02 │ ├── srl.cli │ ├── srlvjunos02.clab.yml │ └── vjunos.cfg ├── srlxrd01 │ ├── srl.cfg │ ├── srlxrd01.clab.yml │ └── xrd.cfg ├── templated01 │ ├── configure.sh │ ├── templated01.clab.gotmpl │ ├── templated01.clab_vars.yaml │ └── topology_config.gotmpl ├── templated02 │ ├── configure.sh │ ├── templated02.clab.gotmpl │ ├── templated02.clab_vars.yaml │ └── topology_config.gotmpl ├── vr01 │ ├── srl.cfg │ ├── sros.cfg │ └── vr01.clab.yml ├── vr02 │ ├── srl.cfg │ ├── vmx.cfg │ └── vr02.clab.yml ├── vr03 │ ├── srl.cfg │ ├── vr03.clab.yml │ └── xrv.cfg ├── vr04 │ ├── srl.cfg │ ├── vr04.clab.yml │ └── xrv9k.cfg ├── vr05 │ ├── sros4.clab.yml │ └── vr01.clab.yml ├── vsrx01 │ ├── srx1.cfg │ └── vsrx01.yml └── vxlan01 │ ├── vxlan-sros.clab.yml │ └── vxlan-vmx.clab.yml ├── labels └── labels.go ├── links ├── endpoint.go ├── endpoint_bridge.go ├── endpoint_dummy.go ├── endpoint_host.go ├── endpoint_macvlan.go ├── endpoint_raw.go ├── endpoint_veth.go ├── endpoint_vxlan.go ├── generic_link_node.go ├── link.go ├── link_brief.go ├── link_dummy.go ├── link_host.go ├── link_macvlan.go ├── link_mgmt-net.go ├── link_test.go ├── link_veth.go ├── link_veth_test.go ├── link_vxlan.go └── link_vxlan_stitched.go ├── macros └── main.py ├── main.go ├── mkdocs.yml ├── mocks ├── dependency_manager.go ├── exec.go ├── mocknodes │ ├── default_node.go │ └── node.go └── mockruntime │ └── runtime.go ├── netconf └── netconf.go ├── nodes ├── 6wind_vsr │ ├── 6wind_vsr.go │ └── 6wind_vsr_default_config.go.tpl ├── bridge │ └── bridge.go ├── c8000 │ ├── c8000.cfg │ └── c8000.go ├── ceos │ ├── ceos.cfg │ └── ceos.go ├── checkpoint_cloudguard │ └── checkpoint_cloudguard.go ├── crpd │ ├── crpd.cfg │ ├── crpd.go │ └── sshd_config ├── cvx │ └── cvx.go ├── default_node.go ├── default_node_test.go ├── dell_sonic │ └── dell_sonic.go ├── ext_container │ └── ext_container.go ├── fdio_vpp │ ├── fdio_vpp.go │ └── vpp_startup_config.go.tpl ├── fortinet_fortigate │ ├── fortigate.go │ └── fortigate_test.go ├── generic_vm │ └── generic_vm.go ├── host │ └── host.go ├── huawei_vrp │ └── huawei_vrp.go ├── iol │ ├── iol.cfg.tmpl │ └── iol.go ├── ipinfusion_ocnos │ └── ipinfusion_ocnos.go ├── k8s_kind │ ├── k8s_kind.go │ └── logger.go ├── keysight_ixiacone │ └── ixiac-one.go ├── linux │ └── linux.go ├── node.go ├── node_registry.go ├── ovs │ └── ovs.go ├── rare │ └── rare.go ├── sonic │ └── sonic.go ├── sonic_vm │ └── sonic_vm.go ├── srl │ ├── banner.go │ ├── eda.go │ ├── macaddr.go │ ├── prompt.go │ ├── prompt_test.go │ ├── srl.go │ ├── srl_default_config.go.tpl │ ├── srl_test.go │ ├── test_data │ │ └── rsa_key │ ├── topology │ │ ├── 7215IXSA1.yml │ │ ├── 7220IXRD1.yml │ │ ├── 7220IXRD2.yml │ │ ├── 7220IXRD2L.yml │ │ ├── 7220IXRD3.yml │ │ ├── 7220IXRD3L.yml │ │ ├── 7220IXRD4.yml │ │ ├── 7220IXRD5.yml │ │ ├── 7220IXRH2.yml │ │ ├── 7220IXRH3.yml │ │ ├── 7220IXRH4-32D.yml │ │ ├── 7220IXRH4.yml │ │ ├── 7220IXRH5-32D.yml │ │ ├── 7220IXRH5-64D.yml │ │ ├── 7220IXRH5-64O.yml │ │ ├── 7250IXR10.yml │ │ ├── 7250IXR10e.yml │ │ ├── 7250IXR18e.yml │ │ ├── 7250IXR6.yml │ │ ├── 7250IXR6e.yml │ │ ├── 7250IXRX1b.yml │ │ ├── 7250IXRX3b.yml │ │ ├── 7730SXR-1d-32d.yml │ │ └── 7730SXR-1x-44s.yml │ ├── version.go │ └── version_test.go ├── state │ └── state.go ├── vr_aoscx │ ├── vr-aoscx.go │ └── vr-aoscx_test.go ├── vr_c8000v │ ├── vr-c8000v.go │ └── vr-c8000v_test.go ├── vr_cat9kv │ └── vr-cat9kv.go ├── vr_csr │ ├── vr-csr.go │ └── vr-csr_test.go ├── vr_freebsd │ ├── vr-freebsd.go │ └── vr-freebsd_test.go ├── vr_ftdv │ ├── vr-ftdv.go │ └── vr-ftdv_test.go ├── vr_ftosv │ └── vr-ftosv.go ├── vr_n9kv │ ├── vr-n9kv.go │ └── vr-n9kv_test.go ├── vr_node.go ├── vr_node_test.go ├── vr_openbsd │ ├── vr-openbsd.go │ └── vr-openbsd_test.go ├── vr_openwrt │ └── vr_openwrt.go ├── vr_pan │ ├── vr-pan.go │ └── vr-pan_test.go ├── vr_ros │ ├── vr-ros.go │ └── vr-ros_test.go ├── vr_sros │ ├── sshKey.go │ ├── sshKey_test.go │ ├── ssh_keys.go.tpl │ ├── vr-sros.go │ └── vr-sros_test.go ├── vr_veos │ ├── vr-veos.go │ └── vr-veos_test.go ├── vr_vjunosevolved │ ├── vr-vjunosevolved.go │ └── vr-vjunosevolved_test.go ├── vr_vjunosswitch │ ├── vr-vjunosswitch.go │ └── vr-vjunosswitch_test.go ├── vr_vmx │ ├── vr-vmx.go │ └── vr-vmx_test.go ├── vr_vqfx │ ├── vr-vqfx.go │ └── vr-vqfx_test.go ├── vr_vsrx │ ├── vr-vsrx.go │ └── vr-vsrx_test.go ├── vr_xrv │ ├── vr-vrx_test.go │ └── vr-xrv.go ├── vr_xrv9k │ ├── vr-xrv9k.go │ └── vr-xrv9k_test.go └── xrd │ ├── mgmt_intf_v6_addr.sh.tmpl │ ├── xrd.cfg │ └── xrd.go ├── pyproject.toml ├── runtime ├── all │ ├── all.go │ └── all_with_podman.go ├── docker │ ├── auth.go │ ├── auth_test.go │ ├── docker.go │ ├── firewall.go │ ├── firewall │ │ ├── definitions │ │ │ └── definitions.go │ │ ├── firewall.go │ │ ├── iptables │ │ │ └── client.go │ │ └── nftables │ │ │ ├── client.go │ │ │ └── rule.go │ └── test_data │ │ ├── docker.config │ │ └── invalid_docker.config ├── generic_container.go ├── ignite │ └── ignite.go ├── podman │ ├── podman.go │ ├── portmaps.go │ └── util.go └── runtime.go ├── schemas └── clab.schema.json ├── tests ├── 01-smoke │ ├── 01-basic-flow.robot │ ├── 01-linux-nodes.clab.yml │ ├── 01-linux-single-node.clab.yml │ ├── 01-test.json │ ├── 01-test.txt │ ├── 02-destroy-all.robot │ ├── 03-bridges-and-host.robot │ ├── 03-linux-nodes-to-bridge-and-host.clab.yml │ ├── 04-generate.robot │ ├── 05-docker-bridge.clab.yml │ ├── 05-docker-bridge.robot │ ├── 06-tools-certs.robot │ ├── 07-keep-mgmt-net.robot │ ├── 07-linux-single-node.clab.yml │ ├── 08-tools-cmds.robot │ ├── 09-external-ca.clab.yml │ ├── 09-external-ca.robot │ ├── 10-ca-parameter.robot │ ├── 10-internal-ca.clab.yml │ ├── 11-node-filter.robot │ ├── 12-tools-veth.clab.yaml │ ├── 12-tools-veth.robot │ ├── 13-stdin-lab.robot │ ├── 14-macvlan.robot │ ├── 15-netw-modes.robot │ ├── 16-mgmtnet.robot │ ├── 16-mgmtnetinterface.clab.yml │ ├── 17-cloned-lab.robot │ ├── 18-stages.robot │ ├── 19-stages-race.robot │ ├── 20-graph-generation.robot │ ├── 21-tools-sshx.robot │ ├── 22-tools-api-server.robot │ ├── macvlan.clab.yml │ ├── netmodes.clab.yml │ ├── node-filter.clab.yml │ ├── single-topo-folder │ │ └── lab1.clab.yml │ ├── stages-race.clab.yml │ └── stages.clab.yml ├── 02-basic-srl │ ├── 01-two-srls.robot │ ├── 02-srl02.clab.yml │ ├── 03-srl-bgp.clab.yml │ ├── 03-srl-bgp.robot │ ├── 03-srl1-bgp.config │ ├── 03-srl2-bgp.config │ ├── srl1-startup.cli │ └── srl2-startup.cli ├── 03-basic-ceos │ ├── 01-two-ceos.robot │ └── 03-ceos01-clab.yml ├── 04-basic-ixiacone │ ├── 01-ixiacone.robot │ └── 04-ixiacone01-clab.yml ├── 05-k8s-kind │ ├── 01-basic-k8s-kind.clab.yml │ ├── 01-basic-k8s-kind.robot │ └── k01-config.yaml ├── 06-ext-container │ ├── 01-ext-container.clab.yml │ ├── 01-ext-container.robot │ ├── 02-shared-namespace-ext.clab.yaml │ ├── 02-shared-namespace.clab.yaml │ └── 02-shared-namespace.robot ├── 07-sros │ ├── 01-single-sros.robot │ └── 1-sros.clab.yml ├── 08-vxlan │ ├── 01-vxlan-s1.config │ ├── 01-vxlan.clab.yml │ ├── 01-vxlan.robot │ ├── 02-vxlan-stitch.clab.yml │ ├── 02-vxlan-stitch.robot │ ├── 03-tools-veth-vxlan.robot │ └── 03-vxlan-tools.clab.yml ├── 09-fortigate │ ├── 01-two-fortigates.robot │ └── fortigates.clab.yml ├── 10-basic-cisco_iol │ ├── 01-iol.robot │ ├── iol.clab.yml │ ├── loopback_config.partial │ └── router3-full.cfg ├── 11-fdio-vpp │ ├── 01-e2e-lab.robot │ └── e2e-lab │ │ ├── config │ │ ├── vpp1 │ │ │ ├── bird-local.conf │ │ │ └── vppcfg.yaml │ │ └── vpp2 │ │ │ ├── bird-local.conf │ │ │ └── vppcfg.yaml │ │ └── vpp.clab.yml ├── common.robot ├── rf-run.sh └── ssh.robot ├── types ├── bind.go ├── constants.go ├── host_requirements.go ├── license_policy_value.go ├── node_definition.go ├── settings.go ├── ssh_config.go ├── stages.go ├── stages_test.go ├── test_data │ ├── config.cfg │ └── lic1.key ├── topo_paths.go ├── topology.go ├── topology_test.go └── types.go ├── utils ├── containers.go ├── containers_test.go ├── env.go ├── env_test.go ├── ethtool.go ├── file.go ├── file_test.go ├── firacode-download.ps1 ├── if-wait.go ├── ip.go ├── kernel_module.go ├── kernel_module_test.go ├── keys.go ├── netlink.go ├── networkcli.go ├── password.go ├── pointer.go ├── postinstall.sh ├── process.go ├── quick-setup.sh ├── regexp.go ├── resolve.go ├── resolve_test.go ├── ssh.go ├── ssh_test.go ├── template.go ├── template_test.go ├── test_data │ ├── keys │ └── keys1.txt └── userauth.go ├── uv.lock └── virt ├── memory.go └── virt.go /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | test_patterns = ["*/*_test.go"] 4 | 5 | [[analyzers]] 6 | name = "go" 7 | enabled = true 8 | 9 | [analyzers.meta] 10 | import_root = "github.com/srl-labs/containerlab" 11 | -------------------------------------------------------------------------------- /.devcontainer/dclab: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /clab/bin/containerlab "$@" 3 | -------------------------------------------------------------------------------- /.devcontainer/zsh/install-tools-completions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | gnmic completion zsh > "/home/vscode/.oh-my-zsh/custom/plugins/zsh-autocomplete/Completions/_gnmic" 3 | # generate gnoic completions 4 | gnoic completion zsh > "/home/vscode/.oh-my-zsh/custom/plugins/zsh-autocomplete/Completions/_gnoic" 5 | # generate gh 6 | gh completion -s zsh > "/home/vscode/.oh-my-zsh/custom/plugins/zsh-autocomplete/Completions/_gh" 7 | -------------------------------------------------------------------------------- /.devcontainer/zsh/install-zsh-plugins.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # atuin 3 | # bash <(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh) 4 | curl -LsSf https://github.com/atuinsh/atuin/releases/download/v18.3.0/atuin-installer.sh | sh 5 | 6 | # theme 7 | git clone --depth 1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k 8 | 9 | # zsh-autosuggestions and autocompletions 10 | git clone --depth 1 https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 11 | git clone --depth 1 https://github.com/marlonrichert/zsh-autocomplete.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autocomplete 12 | 13 | # syntax highlighting 14 | git clone --depth 1 https://github.com/z-shell/F-Sy-H.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/F-Sy-H 15 | 16 | ### 17 | ### Shell completions 18 | ### 19 | # generate containerlab completions 20 | /usr/bin/containerlab completion zsh > "/home/vscode/.oh-my-zsh/custom/plugins/zsh-autocomplete/Completions/_containerlab" 21 | # add clab alias to the completions 22 | sed -i 's/compdef _containerlab containerlab/compdef _containerlab containerlab clab/g' /home/vscode/.oh-my-zsh/custom/plugins/zsh-autocomplete/Completions/_containerlab 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Do not detect languages in the following folders 2 | templates/** -linguist-detectable 3 | docs/** -linguist-detectable 4 | lab-examples/** -linguist-detectable 5 | # nextui is vendored 6 | clab/graph_templates/nextui/** linguist-vendored -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | - package-ecosystem: "gomod" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | -------------------------------------------------------------------------------- /.github/workflows/build-containerlab.yml: -------------------------------------------------------------------------------- 1 | name: build-clab 2 | 3 | "on": 4 | workflow_call: 5 | inputs: 6 | go_ver: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | build-clab: 12 | runs-on: ubuntu-22.04 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: WillAbides/setup-go-faster@v1.14.0 16 | with: 17 | go-version: ${{ inputs.go_ver }} 18 | 19 | - name: Cache go modules 20 | uses: actions/cache@v4 21 | with: 22 | # In order: 23 | # * Module download cache 24 | # * Build cache (Linux) 25 | path: | 26 | ~/go/pkg/mod 27 | ~/.cache/go-build 28 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 29 | restore-keys: | 30 | ${{ runner.os }}-go- 31 | 32 | - name: Build containerlab 33 | run: make build-with-podman-debug BINARY=containerlab 34 | # store clab binary as artifact 35 | - name: Upload containerlab binary 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: containerlab 39 | path: containerlab 40 | compression-level: 0 41 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | workflow_dispatch: 4 | jobs: 5 | golangci: 6 | name: lint 7 | runs-on: ubuntu-20.04 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: golangci-lint 11 | uses: golangci/golangci-lint-action@v8 12 | with: 13 | version: v1.38 14 | -------------------------------------------------------------------------------- /.github/workflows/install-podman.sh: -------------------------------------------------------------------------------- 1 | sudo apt purge -y podman 2 | sudo mkdir -p /etc/apt/keyrings 3 | curl -fsSL "https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key" \ 4 | | gpg --dearmor \ 5 | | sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null 6 | 7 | echo \ 8 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ 9 | https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \ 10 | | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null 11 | 12 | sudo apt-get update -qq 13 | sudo apt-get -qq -y install podman 14 | sudo systemctl start podman 15 | sudo mkdir -p /var/run/netns -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | bin 8 | bin/* 9 | rpm 10 | rpm/* 11 | dist 12 | private 13 | clab-* 14 | .envrc 15 | 16 | tmp/ 17 | # Test binary, built with `go test -c` 18 | *.test 19 | 20 | # Output of the go coverage tool, specifically when used with LiteIDE 21 | *.out 22 | tests/coverage 23 | 24 | # clab directories 25 | lab-examples/**/clab-* 26 | 27 | # ignore the following files/directories 28 | graph/* 29 | 30 | license.key 31 | container-lab 32 | containerlab 33 | site/ 34 | .vscode/ 35 | .idea/ 36 | .DS_Store 37 | __rd* 38 | tests/out 39 | # ignore backup clab topo files 40 | **/.*clab.y*ml.bak 41 | **/*.y*ml.bak 42 | 43 | .python-version 44 | 45 | .devcontainer/private-* 46 | 47 | 48 | # readd test labDir files 49 | !clab/test_data/clab-* 50 | __pycache__ -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | "MD007": false # allow 4 spaced indentation for ul as this is used by mkdocs for nested lists 2 | "MD026": false # allow trailing punctuation to support icons shortcodes at the end of a sentence 3 | "MD038": false 4 | "MD033": false # inline html 5 | "MD013": false # line-length 6 | "MD040": false # fenced code blocks should have language selected 7 | "MD053": false # do not remove mkdocs materials footnotes 8 | "MD071": false # do not remove unordered list indentation 9 | "MD034": false # do not add angle brackets around bare links 10 | -------------------------------------------------------------------------------- /.mk/lint.mk: -------------------------------------------------------------------------------- 1 | GOFUMPT_CMD := docker run --rm -it -e GOFUMPT_SPLIT_LONG_LINES=on -v $(CURDIR):/work ghcr.io/hellt/gofumpt:v0.7.0 2 | GOFUMPT_FLAGS := -l -w . 3 | 4 | GODOT_CMD := docker run --rm -it -v $(CURDIR):/work ghcr.io/hellt/godot:1.4.11 5 | GODOT_FLAGS := -w . 6 | 7 | GOLANGCI_CMD := docker run -it --rm -v $(CURDIR):/app -w /app golangci/golangci-lint:v1.47.2 golangci-lint 8 | GOLANGCI_FLAGS := --config ./.github/workflows/linters/.golangci.yml run -v --fix 9 | 10 | 11 | # when running in a CI env we use locally installed bind 12 | ifdef CI 13 | GOFUMPT_CMD := GOFUMPT_SPLIT_LONG_LINES=on gofumpt 14 | GODOT_CMD := godot 15 | GOLANGCI_CMD := golangci-lint 16 | endif 17 | 18 | 19 | format: gofumpt godot # apply Go formatters 20 | 21 | gofumpt: 22 | ${GOFUMPT_CMD} ${GOFUMPT_FLAGS} 23 | 24 | godot: 25 | ${GODOT_CMD} ${GODOT_FLAGS} 26 | 27 | golangci: # linting with golang-ci lint container 28 | ${GOLANGCI_CMD} ${GOLANGCI_FLAGS} -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/codespell-project/codespell 3 | rev: v2.1.0 4 | hooks: 5 | - id: codespell 6 | - repo: https://github.com/syntaqx/git-hooks 7 | rev: v0.0.17 8 | hooks: 9 | - id: forbid-binary 10 | - id: go-fmt 11 | - id: go-test 12 | - id: go-mod-tidy 13 | - id: shfmt 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Nokia. All rights reserved. 2 | 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /cert/cert.go: -------------------------------------------------------------------------------- 1 | package cert 2 | 3 | // Cert is a wrapper struct for the Certificate Authority and the Certificate Storage. 4 | type Cert struct { 5 | *CA 6 | CertStorage 7 | } 8 | 9 | // CertStorage is an interface that wraps methods to load and store certificates. 10 | type CertStorage interface { 11 | LoadCaCert() (*Certificate, error) 12 | LoadNodeCert(nodeName string) (*Certificate, error) 13 | StoreCaCert(cert *Certificate) error 14 | StoreNodeCert(nodeName string, cert *Certificate) error 15 | } 16 | -------------------------------------------------------------------------------- /cert/csr_input.go: -------------------------------------------------------------------------------- 1 | package cert 2 | 3 | import "time" 4 | 5 | // CACSRInput struct. 6 | type CACSRInput struct { 7 | CommonName string 8 | Country string 9 | Locality string 10 | Organization string 11 | OrganizationUnit string 12 | Expiry time.Duration 13 | KeySize int 14 | } 15 | 16 | // NodeCSRInput struct. 17 | type NodeCSRInput struct { 18 | Hosts []string 19 | CommonName string 20 | Country string 21 | Locality string 22 | Organization string 23 | OrganizationUnit string 24 | Expiry time.Duration 25 | KeySize int 26 | } 27 | -------------------------------------------------------------------------------- /clab/cert.go: -------------------------------------------------------------------------------- 1 | package clab 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/srl-labs/containerlab/cert" 7 | ) 8 | 9 | // LoadOrGenerateCA loads the CA certificate from the storage, or generates a new one if it does not exist. 10 | func (c *CLab) LoadOrGenerateCA(caCertInput *cert.CACSRInput) error { 11 | // try loading the CA cert, and if it fails, generate a new one 12 | caCertificate, err := c.Cert.LoadCaCert() 13 | if err != nil { 14 | // if loading certs failed, try to generate new RootCA 15 | caCertificate, err = c.Cert.GenerateCACert(caCertInput) 16 | if err != nil { 17 | return fmt.Errorf("failed generating new Root CA %v", err) 18 | } 19 | // store the root CA 20 | err = c.Cert.StoreCaCert(caCertificate) 21 | if err != nil { 22 | return nil 23 | } 24 | } 25 | 26 | // set CA cert that was either loaded or generated 27 | err = c.Cert.SetCACert(caCertificate) 28 | if err != nil { 29 | return nil 30 | } 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /clab/config/send.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/srl-labs/containerlab/clab/config/transport" 7 | ) 8 | 9 | func Send(cs *NodeConfig, _ string) error { 10 | var tx transport.Transport 11 | var err error 12 | 13 | ct, ok := cs.TargetNode.Labels["config.transport"] 14 | if !ok { 15 | ct = "ssh" 16 | } 17 | 18 | if ct == "ssh" { 19 | ssh_cred := cs.Credentials 20 | if err != nil { 21 | return err 22 | } 23 | 24 | if len(ssh_cred) < 2 { 25 | return fmt.Errorf("SSH credentials for node %s of type %s not found, cannot configure", 26 | cs.TargetNode.ShortName, cs.TargetNode.Kind) 27 | } 28 | tx, err = transport.NewSSHTransport( 29 | cs.TargetNode, 30 | transport.WithUserNamePassword( 31 | ssh_cred[0], 32 | ssh_cred[1]), 33 | transport.HostKeyCallback(), 34 | ) 35 | if err != nil { 36 | return err 37 | } 38 | } else if ct == "grpc" { 39 | // NewGRPCTransport 40 | } else { 41 | return fmt.Errorf("unknown transport: %s", ct) 42 | } 43 | 44 | err = transport.Write(tx, cs.TargetNode.LongName, cs.Data, cs.Info) 45 | if err != nil { 46 | return err 47 | } 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /clab/config/templates/srl-ifaces__srl.tmpl: -------------------------------------------------------------------------------- 1 | {{ expect .clab_system_ip "ip" }} 2 | {{ range .clab_links }} 3 | {{ expect .port "^(ethernet-\\d+/|e\\d+-)\\d+$" }} 4 | {{ end }} 5 | /interface lo0 { 6 | admin-state enable 7 | subinterface 0 { 8 | ipv4 { 9 | address {{ .clab_system_ip }} { 10 | } 11 | } 12 | ipv6 { 13 | address ::c1ab:{{ ip .clab_system_ip }}/128 { 14 | } 15 | } 16 | } 17 | } 18 | /network-instance default { 19 | router-id {{ ip .clab_system_ip }} 20 | interface lo0.0 { 21 | } 22 | } 23 | /system lldp admin-state enable 24 | / network-instance mgmt { 25 | description "set from clab" 26 | } 27 | {{ range .clab_links }} 28 | /interface {{ .port }} { 29 | admin-state enable 30 | } 31 | {{ end }} -------------------------------------------------------------------------------- /clab/config/transport/transport.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // DebugCount is a debug verbosity counter. 8 | var DebugCount int 9 | 10 | type TransportOption func(*Transport) 11 | 12 | type Transport interface { 13 | // Connect to the target host 14 | Connect(host string, options ...TransportOption) error 15 | // Execute some config 16 | Write(data *string, info *string) error 17 | Close() 18 | } 19 | 20 | // Write config to a node. 21 | func Write(tx Transport, host string, data, info []string, options ...TransportOption) error { 22 | // the Kind should configure the transport parameters before 23 | 24 | err := tx.Connect(host, options...) 25 | if err != nil { 26 | return fmt.Errorf("%s: %s", host, err) 27 | } 28 | 29 | defer tx.Close() 30 | 31 | for i1, d1 := range data { 32 | err := tx.Write(&d1, &info[i1]) 33 | if err != nil { 34 | return fmt.Errorf("could not write config %s: %s", d1, err) 35 | } 36 | } 37 | 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /clab/dependency_manager/depender_node_stage.go: -------------------------------------------------------------------------------- 1 | package dependency_manager 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/srl-labs/containerlab/types" 7 | ) 8 | 9 | // dependerNodeStage is used to keep track of waitgroups that should be decreased (unblocked) 10 | // as soon as a certain delpoy stage is reached. 11 | type dependerNodeStage struct { 12 | depender *DependencyNode // reference to the node 13 | stage types.WaitForStage // reference to the nodes wg that is to be decremented 14 | } 15 | 16 | func newDependerNodeStage(node *DependencyNode, stage types.WaitForStage) *dependerNodeStage { 17 | return &dependerNodeStage{ 18 | depender: node, 19 | stage: stage, 20 | } 21 | } 22 | 23 | func (d *dependerNodeStage) SignalDone() { 24 | d.depender.getStageWG(d.stage).Done() 25 | } 26 | 27 | func (d *dependerNodeStage) IncreaseDependencyWG() { 28 | d.depender.stageWG[d.stage].Add(1) 29 | } 30 | 31 | func (d *dependerNodeStage) String() string { 32 | return fmt.Sprintf("Node %s, State %s", d.depender.GetShortName(), d.stage) 33 | } 34 | -------------------------------------------------------------------------------- /clab/exec/exec_test.go: -------------------------------------------------------------------------------- 1 | package exec 2 | 3 | import "testing" 4 | 5 | func TestParseExecOutputFormat(t *testing.T) { 6 | type args struct { 7 | s string 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want string 13 | wantErr bool 14 | }{ 15 | { 16 | name: "Valid value: plain", 17 | want: ExecFormatPlain, 18 | wantErr: false, 19 | args: args{ 20 | s: "plain", 21 | }, 22 | }, 23 | { 24 | name: "Valid value: pLAiN", 25 | want: ExecFormatPlain, 26 | wantErr: false, 27 | args: args{ 28 | s: "plain", 29 | }, 30 | }, 31 | { 32 | name: "Valid value: json", 33 | want: ExecFormatJSON, 34 | wantErr: false, 35 | args: args{ 36 | s: "json", 37 | }, 38 | }, 39 | { 40 | name: "Valid value: table (mapped to plain)", 41 | want: ExecFormatPlain, 42 | wantErr: false, 43 | args: args{ 44 | s: "table", 45 | }, 46 | }, 47 | { 48 | name: "Invalid value: foobar", 49 | want: "", 50 | wantErr: true, 51 | args: args{ 52 | s: "foobar", 53 | }, 54 | }, 55 | } 56 | for _, tt := range tests { 57 | t.Run(tt.name, func(t *testing.T) { 58 | got, err := ParseExecOutputFormat(tt.args.s) 59 | if (err != nil) != tt.wantErr { 60 | t.Errorf("ParseExecOutputFormat() error = %v, wantErr %v", err, tt.wantErr) 61 | return 62 | } 63 | if got != tt.want { 64 | t.Errorf("ParseExecOutputFormat() = %v, want %v", got, tt.want) 65 | } 66 | }) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /clab/exec_options.go: -------------------------------------------------------------------------------- 1 | package clab 2 | 3 | import "github.com/srl-labs/containerlab/types" 4 | 5 | type ExecOptions struct { 6 | filters []*types.GenericFilter 7 | } 8 | 9 | func NewExecOptions(filters []*types.GenericFilter) *ExecOptions { 10 | return &ExecOptions{ 11 | filters: filters, 12 | } 13 | } 14 | 15 | func (e *ExecOptions) AddFilters(f ...*types.GenericFilter) { 16 | e.filters = append(e.filters, f...) 17 | } 18 | -------------------------------------------------------------------------------- /clab/export_templates/full.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ .Name }}", 3 | "type": "{{ .Type }}", 4 | "clab": {{ ToJSONPretty .Clab " " " "}}, 5 | "ssh-pub-keys": {{ ToJSON .SSHPubKeys }}, 6 | "nodes": { {{- $i:=0 }}{{range $n, $c := .NodeConfigs}}{{if $i}},{{end}}{{ $k := dict "tls-key" $c.TLSKey }} 7 | "{{$n}}":{{ $cj := $c | data.ToJSON | data.JSON }} {{ $dst := coll.Merge $cj $k }}{{ ToJSONPretty $dst " " " " }}{{$i = add $i 1}}{{end}} 8 | }, 9 | "links": [{{range $i, $l := .Clab.Links}}{{if $i}},{{end}} 10 | {{- $eps := $l.GetEndpoints }} 11 | {{- $ep := index $eps 0 }} 12 | { 13 | "a": { 14 | "node": "{{ $ep.GetNode.GetShortName }}", 15 | "interface": "{{ $ep.GetIfaceName }}", 16 | "mac": "{{ $ep.GetMac }}", 17 | "peer": "{{if eq (len $eps) 2}}z{{else}}dummy{{end}}" 18 | } 19 | {{- if eq (len $eps) 2 }} 20 | {{- $ep := index $eps 1 }}, 21 | "z": { 22 | "node": "{{ $ep.GetNode.GetShortName }}", 23 | "interface": "{{ $ep.GetIfaceName }}", 24 | "mac": "{{ $ep.GetMac }}", 25 | "peer": "a" 26 | } 27 | {{- end }} 28 | }{{end}} 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/CiscoSansExtraLight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/CiscoSansExtraLight.otf -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/CiscoSansRegular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/CiscoSansRegular.otf -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.eot -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.ttf -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansextralight-webfont.woff -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.eot -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.ttf -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/ciscosansregular-webfont.woff -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/next-font.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/next-font.eot -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/next-font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/next-font.ttf -------------------------------------------------------------------------------- /clab/graph_templates/nextui/static/fonts/next-font.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/graph_templates/nextui/static/fonts/next-font.woff -------------------------------------------------------------------------------- /clab/inventory_nornir_simple.go.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | {{- range $kind, $nodes := .Nodes -}} 3 | {{- $kindProps := index $.Kinds $kind -}} 4 | {{- range $node := $nodes }} 5 | {{ $node.ShortName }}: 6 | username: {{ $kindProps.Username }} 7 | password: {{ $kindProps.Password }} 8 | platform: {{ $kindProps.Platform }} 9 | hostname: {{ $node.MgmtIPv4Address }} 10 | {{- if $node.NornirGroups }} 11 | groups: 12 | {{- range $group := $node.NornirGroups }} 13 | - {{ $group }} 14 | {{- end }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} -------------------------------------------------------------------------------- /clab/network.go: -------------------------------------------------------------------------------- 1 | package clab 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/srl-labs/containerlab/labels" 7 | ) 8 | 9 | func (c *CLab) CreateNetwork(ctx context.Context) error { 10 | // create docker network or use existing one 11 | if err := c.globalRuntime().CreateNet(ctx); err != nil { 12 | return err 13 | } 14 | 15 | // save mgmt bridge name as a label 16 | for _, n := range c.Nodes { 17 | n.Config().Labels[labels.NodeMgmtNetBr] = c.globalRuntime().Mgmt().Bridge 18 | } 19 | 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /clab/ssh_config.go.tpl: -------------------------------------------------------------------------------- 1 | # Containerlab SSH Config for the {{ .TopologyName }} lab 2 | 3 | {{- range .Nodes }} 4 | Host {{ .Name }} 5 | {{- if ne .Username ""}} 6 | User {{ .Username }} 7 | {{- end }} 8 | StrictHostKeyChecking=no 9 | UserKnownHostsFile=/dev/null 10 | {{- if ne .SSHConfig.PubkeyAuthentication "" }} 11 | PubkeyAuthentication={{ .SSHConfig.PubkeyAuthentication.String }} 12 | {{- end }} 13 | {{ end }} -------------------------------------------------------------------------------- /clab/test_data/clab-topo2/node1/node1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/test_data/clab-topo2/node1/node1 -------------------------------------------------------------------------------- /clab/test_data/default.lic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/test_data/default.lic -------------------------------------------------------------------------------- /clab/test_data/envfile1: -------------------------------------------------------------------------------- 1 | ENVFILE1=SOMEENVVARDATA -------------------------------------------------------------------------------- /clab/test_data/envfile2: -------------------------------------------------------------------------------- 1 | ENVFILE1=SOMEOTHERDATA 2 | ENVFILE2=THISANDTHAT -------------------------------------------------------------------------------- /clab/test_data/kind.lic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/test_data/kind.lic -------------------------------------------------------------------------------- /clab/test_data/node1.lic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/clab/test_data/node1.lic -------------------------------------------------------------------------------- /clab/test_data/topo1.yml: -------------------------------------------------------------------------------- 1 | name: topo1 2 | topology: 3 | nodes: 4 | node1: 5 | kind: nokia_srlinux 6 | license: node1.lic 7 | binds: 8 | - node1.lic:/dst 9 | env: 10 | env1: val1 11 | env2: val2 12 | mgmt-ipv4: 172.100.100.11 13 | node2: 14 | kind: nokia_srlinux 15 | license: node1.lic 16 | user: custom 17 | mgmt-ipv4: 172.100.100.12 18 | labels: 19 | node-label: value 20 | # tests that unset $value is not substituted 21 | with-dollar-sign: some$value 22 | -------------------------------------------------------------------------------- /clab/test_data/topo10.yml: -------------------------------------------------------------------------------- 1 | name: topo10 2 | topology: 3 | defaults: 4 | env-files: 5 | - envfile2 6 | nodes: 7 | node1: 8 | kind: linux 9 | env: 10 | env1: val1 11 | env2: val2 12 | mgmt-ipv4: 172.100.100.11 13 | node2: 14 | kind: linux 15 | mgmt-ipv4: 172.100.100.12 16 | labels: 17 | node-label: value 18 | env-files: 19 | - envfile1 20 | 21 | -------------------------------------------------------------------------------- /clab/test_data/topo11-ext-cont.yaml: -------------------------------------------------------------------------------- 1 | name: topo11 2 | topology: 3 | nodes: 4 | node1: 5 | kind: ext-container 6 | exec: 7 | - ip l 8 | node2: 9 | kind: linux 10 | image: alpine:latest 11 | 12 | 13 | -------------------------------------------------------------------------------- /clab/test_data/topo12.yml: -------------------------------------------------------------------------------- 1 | name: topo12 2 | 3 | topology: 4 | defaults: 5 | suppress-startup-config: true 6 | kinds: 7 | ceos: 8 | suppress-startup-config: false 9 | nodes: 10 | node1: 11 | kind: ceos 12 | suppress-startup-config: true 13 | node2: 14 | kind: ceos 15 | suppress-startup-config: false 16 | node3: 17 | kind: ceos 18 | node4: 19 | kind: linux 20 | 21 | links: 22 | - endpoints: ["node1:eth1", "node2:eth1"] 23 | - endpoints: ["node2:eth2", "node3:eth1"] 24 | -------------------------------------------------------------------------------- /clab/test_data/topo13.yml: -------------------------------------------------------------------------------- 1 | name: topo13 2 | topology: 3 | kinds: 4 | nokia_srlinux: 5 | startup-config: ./configs/fabric/__clabNodeName__.cfg 6 | nodes: 7 | node1: 8 | kind: nokia_srlinux 9 | -------------------------------------------------------------------------------- /clab/test_data/topo14.yml: -------------------------------------------------------------------------------- 1 | name: topo14 2 | topology: 3 | nodes: 4 | node1: 5 | kind: nokia_srlinux 6 | startup-config: ./configs/fabric/__clabNodeName__.cfg 7 | exec: 8 | - echo "Hello world" 9 | - echo "Hello node __clabNodeName__" 10 | -------------------------------------------------------------------------------- /clab/test_data/topo15.yml: -------------------------------------------------------------------------------- 1 | name: topo15 2 | topology: 3 | defaults: 4 | startup-config: ./configs/fabric/__clabNodeName__.cfg 5 | nodes: 6 | node1: 7 | kind: nokia_srlinux 8 | -------------------------------------------------------------------------------- /clab/test_data/topo2.yml: -------------------------------------------------------------------------------- 1 | name: topo2 2 | topology: 3 | kinds: 4 | nokia_srlinux: 5 | license: kind.lic 6 | type: ixrd2l 7 | env: 8 | env1: val1 9 | user: customkind 10 | labels: 11 | kind-label: value 12 | nodes: 13 | node1: 14 | kind: nokia_srlinux 15 | binds: 16 | - node1.lic:/dst1 17 | - kind.lic:/dst2 18 | - __clabNodeDir__/__clabNodeName__:/somefile 19 | node2: 20 | kind: nokia_srlinux 21 | type: ixr10 22 | -------------------------------------------------------------------------------- /clab/test_data/topo3.yml: -------------------------------------------------------------------------------- 1 | name: topo3 2 | topology: 3 | defaults: 4 | license: default.lic 5 | binds: 6 | - default.lic:/dst 7 | type: ixrd2l 8 | env: 9 | env1: val1 10 | user: customglobal 11 | labels: 12 | default-label: value 13 | nodes: 14 | node1: 15 | kind: nokia_srlinux 16 | type: ixrd3l 17 | node2: 18 | kind: nokia_srlinux 19 | -------------------------------------------------------------------------------- /clab/test_data/topo4.yml: -------------------------------------------------------------------------------- 1 | name: topo4 2 | topology: 3 | defaults: 4 | license: default.lic 5 | binds: 6 | - default.lic:/dst3 7 | env: 8 | env1: global 9 | env2: global 10 | env3: global 11 | user: customglobal 12 | kinds: 13 | nokia_srlinux: 14 | license: kind.lic 15 | binds: 16 | - kind.lic:/dst2 17 | env: 18 | env2: kind 19 | env4: kind 20 | user: customkind 21 | nodes: 22 | node1: 23 | kind: nokia_srlinux 24 | type: ixrd3 25 | license: node1.lic 26 | binds: 27 | - node1.lic:/dst1 28 | env: 29 | env1: node 30 | env5: node 31 | user: customnode 32 | -------------------------------------------------------------------------------- /clab/test_data/topo5.yml: -------------------------------------------------------------------------------- 1 | name: topo5 2 | topology: 3 | kinds: 4 | nokia_srlinux: 5 | binds: 6 | - kind.lic:/dst 7 | nodes: 8 | node1: 9 | kind: nokia_srlinux 10 | type: ixrd3 11 | license: node1.lic 12 | binds: 13 | - node1.lic:/dst2 14 | -------------------------------------------------------------------------------- /clab/test_data/topo6.yml: -------------------------------------------------------------------------------- 1 | name: topo6 2 | 3 | topology: 4 | nodes: 5 | lin1: 6 | kind: linux 7 | image: alpine:3 8 | lin2: 9 | kind: linux 10 | image: alpine:3 11 | 12 | links: 13 | - endpoints: ["lin1:eth1", lin2:eth1] 14 | - endpoints: ["lin1:eth1", lin2:eth2] 15 | - endpoints: ["lin1:eth3", lin2:eth2] 16 | - endpoints: ["lin1:eth4", lin1:eth4] 17 | -------------------------------------------------------------------------------- /clab/test_data/topo7-dup-rootnetns.yml: -------------------------------------------------------------------------------- 1 | name: topo7 2 | 3 | topology: 4 | nodes: 5 | br1: 6 | kind: bridge 7 | l1: 8 | kind: linux 9 | image: alpine:latest 10 | cmd: sleep infinity 11 | 12 | links: 13 | - endpoints: ["l1:eth1", "br1:eth76"] 14 | - endpoints: ["l1:eth2", "host:eth76"] 15 | -------------------------------------------------------------------------------- /clab/test_data/topo8_ansible_groups.yml: -------------------------------------------------------------------------------- 1 | name: topo8_ansible_groups 2 | topology: 3 | nodes: 4 | node1: 5 | kind: nokia_srlinux 6 | type: ixrd3 7 | license: node1.lic 8 | binds: 9 | - node1.lic:/dst 10 | env: 11 | env1: val1 12 | env2: val2 13 | mgmt-ipv4: 172.100.100.11 14 | labels: 15 | ansible-group: spine 16 | nornir-group: spine 17 | node2: 18 | kind: nokia_srlinux 19 | license: node1.lic 20 | user: custom 21 | mgmt-ipv4: 172.100.100.12 22 | labels: 23 | node-label: value 24 | ansible-group: extra_group 25 | nornir-group: extra_group 26 | 27 | node3: 28 | kind: nokia_srlinux 29 | license: node1.lic 30 | user: custom 31 | mgmt-ipv4: 172.100.100.13 32 | labels: 33 | node-label: value 34 | ansible-group: extra_group 35 | nornir-group: extra_group 36 | 37 | node4: 38 | kind: linux 39 | image: alpine:3 40 | mgmt-ipv4: 172.100.100.14 41 | labels: 42 | ansible-no-host-var: true 43 | -------------------------------------------------------------------------------- /clab/test_data/topo8_nornir_groups.yml: -------------------------------------------------------------------------------- 1 | name: topo8_ansible_groups 2 | topology: 3 | nodes: 4 | node1: 5 | kind: nokia_srlinux 6 | type: ixrd3 7 | license: node1.lic 8 | binds: 9 | - node1.lic:/dst 10 | env: 11 | env1: val1 12 | env2: val2 13 | mgmt-ipv4: 172.100.100.11 14 | labels: 15 | nornir-group: spine 16 | node2: 17 | kind: nokia_srlinux 18 | license: node1.lic 19 | user: custom 20 | mgmt-ipv4: 172.100.100.12 21 | labels: 22 | node-label: value 23 | nornir-group: extra_group 24 | nornir-group-2: second_extra_group 25 | 26 | node3: 27 | kind: nokia_srlinux 28 | license: node1.lic 29 | user: custom 30 | mgmt-ipv4: 172.100.100.13 31 | labels: 32 | node-label: value 33 | nornir-group: extra_group 34 | 35 | node4: 36 | kind: linux 37 | image: alpine:3 38 | mgmt-ipv4: 172.100.100.14 39 | labels: 40 | ansible-no-host-var: true 41 | -------------------------------------------------------------------------------- /clab/test_data/topo9.yml: -------------------------------------------------------------------------------- 1 | name: topo4 2 | topology: 3 | defaults: 4 | license: default.lic 5 | binds: 6 | - default.lic:/dst 7 | env: 8 | env1: global 9 | env2: global 10 | env3: global 11 | user: customglobal 12 | kinds: 13 | nokia_srlinux: 14 | license: kind.lic 15 | binds: 16 | - kind.lic:/dst 17 | env: 18 | env2: kind 19 | env4: kind 20 | user: customkind 21 | nodes: 22 | node1: 23 | kind: nokia_srlinux 24 | type: ixrd3 25 | license: node1.lic 26 | binds: 27 | - node1.lic:/dst 28 | env: 29 | env1: node 30 | env5: ${CONTAINERLAB_TEST_ENV5} 31 | user: customnode 32 | -------------------------------------------------------------------------------- /cmd/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var ( 8 | Debug bool 9 | Timeout time.Duration 10 | ) 11 | 12 | // path to the topology file. 13 | var Topo string 14 | 15 | var ( 16 | VarsFile string 17 | Graph bool 18 | Runtime string 19 | ) 20 | 21 | // subset of nodes to work with. 22 | var NodeFilter []string 23 | 24 | // lab Name. 25 | var Name string 26 | 27 | // Use graceful shutdown. 28 | var Graceful bool 29 | -------------------------------------------------------------------------------- /cmd/tools.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Nokia 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package cmd 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | // toolsCmd represents the tools command. 12 | var toolsCmd = &cobra.Command{ 13 | Use: "tools", 14 | Short: "various tools your lab might need", 15 | Long: "tools command groups various tools you might need for your lab\nreference: https://containerlab.dev/cmd/tools/", 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(toolsCmd) 20 | } 21 | -------------------------------------------------------------------------------- /cmd/tools_api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2025 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package cmd 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func init() { 12 | toolsCmd.AddCommand(apiServerCmd) 13 | } 14 | 15 | // apiServerCmd represents the api-server command container 16 | var apiServerCmd = &cobra.Command{ 17 | Use: "api-server", 18 | Short: "Containerlab API server operations", 19 | Long: "Start, stop, and manage Containerlab API server containers", 20 | } 21 | -------------------------------------------------------------------------------- /cmd/version/logo.txt: -------------------------------------------------------------------------------- 1 | ____ ___ _ _ _____ _ ___ _ _ _____ ____ _ _  2 | / ___/ _ \| \ | |_ _|/ \ |_ _| \ | | ____| _ \| | __ _| |__  3 | | | | | | | \| | | | / _ \ | || \| | _| | |_) | |/ _` | '_ \  4 | | |__| |_| | |\ | | |/ ___ \ | || |\ | |___| _ <| | (_| | |_) | 5 | \____\___/|_| \_| |_/_/ \_\___|_| \_|_____|_| \_\_|\__,_|_.__/  6 | -------------------------------------------------------------------------------- /cmd/version/version_test.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | ) 8 | 9 | func TestDocsLinkFromVer(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | version string 13 | expected string 14 | }{ 15 | { 16 | name: "major and minor only", 17 | version: "0.47.0", 18 | expected: "0.47/", 19 | }, 20 | { 21 | name: "major, minor, and patch version", 22 | version: "0.47.2", 23 | expected: "0.47/#0472", 24 | }, 25 | } 26 | 27 | for _, tt := range tests { 28 | t.Run(tt.name, func(t *testing.T) { 29 | got := docsLinkFromVer(tt.version) 30 | if diff := cmp.Diff(got, tt.expected); diff != "" { 31 | t.Fatalf("docsLinkFromVer() mismatch (-want +got):\n%s", diff) 32 | } 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | patch: 4 | default: 5 | informational: true # don't fail the build if PR coverage is missing 6 | comment: 7 | layout: "diff, files" 8 | behavior: new 9 | github_checks: 10 | annotations: false 11 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | containerlab.dev -------------------------------------------------------------------------------- /docs/cmd/tools/disable-tx-offload.md: -------------------------------------------------------------------------------- 1 | # disable-tx-offload command 2 | 3 | ### Description 4 | 5 | The `disable-tx-offload` command under the `tools` command disables tx checksum offload for `eth0` interface of a container referenced by its name. 6 | 7 | The need for `disable-tx-offload` might arise when you launch a container outside of containerlab or restart a container. Some nodes, like SR Linux, will require correct checksums in TCP packets; thus, it is needed to disable checksum offload on those containers to do checksum calculations instead of offloading it. 8 | 9 | ### Usage 10 | 11 | `containerlab tools disable-tx-offload [local-flags]` 12 | 13 | ### Flags 14 | 15 | #### container 16 | With the local mandatory `--container | -c` flag, a user specifies which container to remove tx offload. 17 | 18 | ### Examples 19 | 20 | ```bash 21 | # disable tx checksum offload on gnmic container 22 | ❯ clab tools disable-tx-offload -c clab-st-gnmic 23 | INFO[0000] getting container 'clab-st-gnmic' information 24 | INFO[0000] Tx checksum offload disabled for eth0 interface of clab-st-gnmic container 25 | ``` -------------------------------------------------------------------------------- /docs/cmd/tools/netem/reset.md: -------------------------------------------------------------------------------- 1 | # Resetting Link Impairments 2 | 3 | With the `containerlab tools netem reset` command users can remove (reset) all network impairments on a specified interface of a containerlab node. This command deletes the netem qdisc associated with the interface, restoring it to its default state. If no impairments are present, the command will complete successfully without error. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | containerlab tools netem reset [local-flags] 9 | ``` 10 | 11 | ## Flags 12 | 13 | ### node 14 | 15 | The mandatory `--node | -n` flag specifies the name of the containerlab node on which to reset link impairments. 16 | 17 | ### interface 18 | 19 | The mandatory `--interface | -i` flag specifies the interface on which the netem impairments should be reset. 20 | 21 | ## Examples 22 | 23 | ### Resetting impairments on an interface 24 | 25 | This example resets the impairments on the interface `eth1` of node `clab-netem-r1`: 26 | 27 | ```bash 28 | containerlab tools netem reset -n clab-netem-r1 -i eth1 29 | ``` 30 | 31 | Output: 32 | 33 | ```bash 34 | Reset impairments on node "clab-netem-r1", interface "eth1" 35 | ``` 36 | 37 | ### Resetting impairments when none are set 38 | 39 | If no impairments are configured on the specified interface, the command will complete without error: 40 | 41 | ```bash 42 | containerlab tools netem reset -n clab-netem-r1 -i eth0 43 | ``` 44 | 45 | Output: 46 | 47 | ```bash 48 | Reset impairments on node "clab-netem-r1", interface "eth0" 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/cmd/tools/vxlan/delete.md: -------------------------------------------------------------------------------- 1 | # vxlan delete 2 | 3 | ### Description 4 | 5 | The `delete` sub-command under the `tools vxlan` command deletes VxLAN interfaces which name matches a user specified prefix. The `delete` command is typically used to remove VxLAN interfaces created with [`create`](create.md) command. 6 | 7 | ### Usage 8 | 9 | `containerlab tools vxlan delete [local-flags]` 10 | 11 | ### Flags 12 | 13 | #### prefix 14 | Set a prefix with `--prefix | -p` flag. The VxLAN interfaces which name is matched by the prefix will be deleted. Default prefix is `vx-` which is matched the default prefix used by [`create`](create.md) command. 15 | 16 | ### Examples 17 | 18 | ```bash 19 | # delete all VxLAN interfaces created by containerlab 20 | ❯ clab tools vxlan create delete 21 | INFO[0000] Deleting VxLAN link vx-srl_e1-1 22 | ``` -------------------------------------------------------------------------------- /docs/cmd/version/check.md: -------------------------------------------------------------------------------- 1 | # check 2 | 3 | ## Description 4 | 5 | The `version check` command checks if a newer version of containerlab is available. 6 | 7 | ## Usage 8 | 9 | ``` 10 | containerlab version check 11 | ``` 12 | 13 | When executed, the containerlab binary will reach out to the github API and check if a newer version is available and display the result. 14 | 15 | Example result output: 16 | 17 | ``` 18 | 🎉 A newer containerlab version (0.62.2) is available! 19 | Release notes: https://containerlab.dev/rn/0.62/#0622 20 | Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for installation options. 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/cmd/version/index.md: -------------------------------------------------------------------------------- 1 | # version 2 | 3 | ## Description 4 | 5 | The `version` command displays the version of containerlab installed. 6 | 7 | ## Usage 8 | 9 | ``` 10 | containerlab version 11 | ``` 12 | 13 | The version command contains: 14 | 15 | * version in the semantic versioning format 16 | * commit hash of the project repository 17 | * build date 18 | * a link to the github repo 19 | * a link to the release notes of the current version 20 | -------------------------------------------------------------------------------- /docs/images/containerlab-og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/docs/images/containerlab-og.png -------------------------------------------------------------------------------- /docs/images/containerlab_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/docs/images/containerlab_black.png -------------------------------------------------------------------------------- /docs/images/containerlab_grey.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/docs/images/containerlab_grey.pdf -------------------------------------------------------------------------------- /docs/images/containerlab_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/docs/images/containerlab_grey.png -------------------------------------------------------------------------------- /docs/images/flask.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/client.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/controller.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/dcgw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/pon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/rgw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/router.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/spine.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/topoviewer-icons/switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/manual/dev/index.md: -------------------------------------------------------------------------------- 1 | # Developers Guide 2 | 3 | Containerlab relies on contributions from the community to improve existing functionality and add new features. The developers guide provides information on how to contribute to various bits of the project. 4 | 5 | Remember, that all contributions are welcome and important, no matter how big or small they are. Spot a typo in the documentation? Found a bug? Have an idea for a new feature? Want to improve the performance of the code? All of these are valuable contributions to the project. 6 | 7 | Thank you for considering contributing to containerlab! 8 | -------------------------------------------------------------------------------- /docs/manual/impairments.md: -------------------------------------------------------------------------------- 1 | --- 2 | comments: true 3 | --- 4 | 5 | # Link Impairments 6 | 7 | Labs are meant to be a reflection of real-world scenarios. To make simulated networks exhibit real-life behavior you can set link impairments (delay, jitter, packet loss) on any link that belongs to a container node. Link impairment feature is powered by the `tools netem` command collection: 8 | 9 | * [`tools netem set`](../cmd/tools/netem/set.md) 10 | * [`tools netem show`](../cmd/tools/netem/show.md) 11 | * [`tools netem reset`](../cmd/tools/netem/reset.md) 12 | 13 | These commands allow users to set, show and reset link impairments (delay, jitter, packet loss) on any link that belongs to a container node and create labs simulating real-world network conditions. 14 | 15 | ```bash title="setting packet loss at 10% rate on eth1 interface of clab-netem-r1 node" 16 | containerlab tools netem set -n clab-netem-r1 -i eth1 --loss 10 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/manual/kinds/host.md: -------------------------------------------------------------------------------- 1 | --- 2 | search: 3 | boost: 4 4 | --- 5 | 6 | # Host 7 | 8 | A node of kind `host` represents the containerlab host the labs are running on. It is a special node that is implicitly used when nodes have links connected to the host - see [host links](../network.md#host-links). 9 | 10 | But there is a use case when users might want to define the node of kind `host` explicitly in the topology. For example, when some commands need to be executed on the host for the lab to function. 11 | 12 | In such case, the following topology definition can be used: 13 | 14 | ```yaml 15 | h1: 16 | kind: host 17 | exec: 18 | - ip link set dev enp0s3 up 19 | ``` 20 | 21 | In the above example, the node `h1` is defined as a node of kind `host` and the `exec` option is used to run the command `ip link set dev enp0s3 up` in the containerlab host. Of course, the command can be any other command that is required for the lab to function. 22 | -------------------------------------------------------------------------------- /docs/rn/0.14.1.md: -------------------------------------------------------------------------------- 1 | # Release 0.14.1 2 | :material-calendar: 2021-05-20 3 | 4 | ## fix lab deletion data race 5 | This patch release fixes data race which could occur during the deletion of a lab with many nodes. -------------------------------------------------------------------------------- /docs/rn/0.14.2.md: -------------------------------------------------------------------------------- 1 | # Release 0.14.2 2 | :material-calendar: 2021-05-27 3 | 4 | ## fix additional interfaces to management network 5 | This patch release fixes issues with containerlab failing to add additional data interfaces to management network as described [here](../manual/network.md#additional-connections-to-management-network). -------------------------------------------------------------------------------- /docs/rn/0.14.3.md: -------------------------------------------------------------------------------- 1 | # Release 0.14.3 2 | :material-calendar: 2021-05-28 3 | 4 | 5 | ## Fixes and improvements 6 | - fixed missing IPv4/6 information in `containerlab inspect --all` output 7 | - prevented deployment of the lab if the same-named lab has already been deployed 8 | - install script now checks if the released version set by the user actually exists 9 | 10 | -------------------------------------------------------------------------------- /docs/rn/0.14.4.md: -------------------------------------------------------------------------------- 1 | # Release 0.14.4 2 | :material-calendar: 2021-06-06 3 | 4 | 5 | ## Fixes and improvements 6 | - [fixed](https://github.com/srl-labs/containerlab/pull/440) generate command 7 | - added "Y/n" prompt when doing `containerlab version upgrade`. 8 | - version command will return a link to the relevant release notes 9 | 10 | -------------------------------------------------------------------------------- /docs/rn/0.27.md: -------------------------------------------------------------------------------- 1 | # Release 0.27 2 | :material-calendar: 2022-07-06 3 | 4 | ## Multiple kind names 5 | When we started containerlab, using short kind names was easy. Everybody knew that `srl` is SR Linux, and, say, `ceos` is cEOS. As we grew, more people started to use containerlab and not everyone knew the short names of NOSes. 6 | 7 | Therefore we added an ability to use long names for kinds, for example, `nokia_srlinux` or `arista_ceos`. These new "long" names have been added to kind docs. 8 | 9 | ## Juniper vQFX and Juniper vMX startup config 10 | We finally added support to provision vMX and vQFX with startup configuration. The same [`startup-config`](../manual/nodes.md#startup-config) node property allows users to point to a file that contains configuration lines that will get applied to a network element when it starts. 11 | 12 | 13 | ## Misc 14 | 15 | * SR Linux nodes will be able to use the names of the other nodes of the same #891 16 | 17 | ## Patches 18 | 19 | ### 0.27.1 20 | 21 | * adding missing config dir mount for vMX -------------------------------------------------------------------------------- /docs/rn/0.28.md: -------------------------------------------------------------------------------- 1 | # Release 0.28 2 | :material-calendar: 2022-06-27 3 | 4 | ## Topology file auto-detect 5 | With embedded shorthands `containerlab`->`clab`, `deploy`->`dep` and so on, we made using containerlab over the CLI a fast and pleasant experience. But even then, typing `clab dep -t mytopo.clab.yml` is one argument too long. 6 | 7 | Please welcome the topology file auto-detect feature which turns `clab dep -t mytopo.clab.yml` to just `clab dep` :partying_face: 8 | 9 | !!!note 10 | A single file matching `*.clab.y*ml` pattern must be present in the current working directory for auto-detect feature to work. 11 | 12 | Should you have multiple topology files, use the `--topo` flag as before. 13 | 14 | ## Ignite-based linux containers 15 | Weaveworks/ignite runtime integration that was added by @networkop for [Cumulus VX](../manual/kinds/cvx.md) nodes got a new application. With #910 merged, users now can run Linux VMs in a container packaging and leverage VM-like experience while running lightweight and fast. 16 | 17 | ## Miscellaneous 18 | 19 | * added `-c` shorthand for `--reconfigure` as it is very handy to use `clab dep -c` to cleanly redeploy the lab during the iterations of lab build-out. 20 | 21 | ## Patches 22 | 23 | ### 0.28.1 24 | 25 | * fixed crpd kind name #922 26 | * added missing kinds to clab.schema.json 27 | * ceos nodes now have default route pointing to management gw address #920 28 | * iptables has been added to clab container #921 29 | * diagrams rendering engine update to latest version 30 | -------------------------------------------------------------------------------- /docs/rn/0.29.md: -------------------------------------------------------------------------------- 1 | # Release 0.29 2 | 3 | :material-calendar: 2022-07-11 4 | 5 | ## Checkpoint Cloudguard 6 | 7 | Our firewall-focused camp got a new member - [Checkpoint Cloudguard](../manual/kinds/checkpoint_cloudguard.md) platform. This platform is built with [boxen](https://github.com/carlmontanari/boxen) project instead of vrnetlab. We are slowly building confidence in boxen and new platforms will likely be solely powered by boxen. PR #934 8 | 9 | ## Miscellaneous 10 | 11 | * added `-c` shorthand for `--cleanup` flag of the `destroy` command. Now to remove a lab and get rid of the lab directory simply call `clab des -c`. 12 | * [`inspect`](../cmd/inspect/index.md) command has been fixed to display IP information even for nodes connected to external networks. 13 | * added srlinux 6e and 10e platforms 14 | -------------------------------------------------------------------------------- /docs/rn/0.30.md: -------------------------------------------------------------------------------- 1 | # Release 0.30 2 | 3 | :material-calendar: 2022-07-28 4 | 5 | ## Podman v4 6 | 7 | Podman v4 delivers a new API to schedule containers within the Podman runtime. Version 4 allows us to deliver better support for this runtime in the context of containerlab #919. 8 | 9 | ## Miscellaneous 10 | 11 | * ipv6 gateway support in arista ceos startup-config #940. 12 | * management vrf support in ceos with the use of a [`CLAB_MGMT_VRF` env var](../manual/kinds/ceos.md#mgmt-vrf) #941 13 | * SR Linux mac address generation function allows for multi-node setups with random seed #942 14 | * fixed Netconf save operations #953 15 | -------------------------------------------------------------------------------- /docs/rn/0.33.md: -------------------------------------------------------------------------------- 1 | # Release 0.33 2 | 3 | :material-calendar: 2022-11-28 4 | 5 | ## External container kind 6 | 7 | With a new [`ext-container`](../manual/kinds/ext-container.md) kind it is possible to enrich clab topology with nodes scheduled by other tools (e.g. `k8s-kind`). Thanks @steiler. 8 | 9 | ## Graph enhancements 10 | 11 | Thanks to @gamerslouis our [graph](../cmd/graph.md) feature got some important fixes like properly displaying bridge properties in #1097 and renders bridges in offline mode in #1098. 12 | 13 | ## SR OS and BOF persistency 14 | 15 | Making SR OS BOF persistent was not a trivial task, but @mabra94 added a nice doc section explaining how bind mounts and boot-good-exec SR OS option combined can achieve that. #1107 16 | 17 | ## Miscellaneous 18 | 19 | * fixed ssse3 check #1092 20 | * housekeeping item by @steiler - default node embedding #1099 21 | * startup-config support for PAN OS nodes #1109 22 | * save CPU from spinning when waiting for nodes to boot #1108 23 | -------------------------------------------------------------------------------- /docs/rn/0.34.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: fontawesome/solid/tree 3 | --- 4 | 5 | # Release 0.34 :christmas_tree: 6 | 7 | :material-calendar: 2022-12-23 8 | 9 | ## Cisco XRd support 10 | 11 | Thanks to @trustywolf we finally landed support for [Cisco XRd](../manual/kinds/xrd.md)! No more dealing with a 16GB mem-hungry VM monster when all you need is a control plane. #1144 12 | 13 | ## Major codebase refactoring 14 | 15 | @steiler went into the berzerk mode and refactored half of the containerlab's internal code base to have a cleaner separation of packages, internal APIs and increased extensibility. 16 | 17 | This change was carried over in multiple PRs and touched a lot of files; while we did quite some testing and maintained the same user experience, there might be things that work differently, do let us know if there is something out of order. 18 | 19 | ## Miscellaneous 20 | 21 | * Containerlab can now be installed on Core OS #1115 22 | * Fixed pull image function to support pulling images without explicit tags #1123 23 | * Memory calculation function has been fixed to report on available memory, not just free one #1133 24 | -------------------------------------------------------------------------------- /docs/rn/0.35.md: -------------------------------------------------------------------------------- 1 | # Release 0.35 2 | 3 | :material-calendar: 2023-01-17 4 | 5 | ## DNS options 6 | 7 | A new node property - [DNS](../manual/nodes.md#dns) - allows users to provide DNS options to the nodes. 8 | 9 | ## `containerlab exec` fixes and improvements 10 | 11 | Thanks to efforts by @steiler we have refactored [`exec`](../cmd/exec.md) command and fixed a few bugs along the way. The command now supports multiple `--cmd` arguments. #1161 12 | 13 | ## Miscellaneous 14 | 15 | * Internal refactoring of the node registry #1156 16 | * fixed ovs-bridge init #1172 17 | * interface name checks enabled for all VM-based nodes #1191 18 | 19 | ## Patches 20 | 21 | ### 0.35.1 22 | 23 | * fixed the regexp used in the interface name check function #1201 24 | 25 | ### 0.35.2 26 | 27 | * removed interface name checks for linux kinds. 28 | * added a note on [`et_X_Y`](../manual/kinds/ceos.md#additional-interface-naming-considerations) nameing of ceos. 29 | * fixed `containerlab config` command for SR OS nodes. 30 | -------------------------------------------------------------------------------- /docs/rn/0.36.md: -------------------------------------------------------------------------------- 1 | # Release 0.36 2 | 3 | :material-calendar: 2023-01-27 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Image Pull Policy 6 | 7 | Now we give you control over the image pulling behavior by introducing [`image-pull-policy`](../manual/nodes.md#image-pull-policy) node property. You want your image to be always fetched from the remote registry? Now it is possible. #1223 8 | 9 | ## Cisco c8000 10 | 11 | A new kind - [`cisco_8000`](../manual/kinds/c8000.md) - has been added to the list of supported platforms thanks to an awesome contribution from @rskorka in #1216. 12 | 13 | ## Miscellaneous 14 | 15 | * Fixed Cumulus interface name checks #1224 16 | * Housekeeping items in #1208 #1209 and #1225 by @steiler 17 | * Fixed credentials extraction for DockerHub images 18 | 19 | ## Patches 20 | 21 | ### 0.36.1 22 | 23 | * fixed certificate creation for SR Linux nodes identified with `nokia_srlinux` kind. 24 | -------------------------------------------------------------------------------- /docs/rn/0.38.md: -------------------------------------------------------------------------------- 1 | # Release 0.38 2 | 3 | :material-calendar: 2023-03-13 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Remote startup-configs 6 | 7 | Node's [`startup-config`](../manual/nodes.md#startup-config) can now point to a remote http/https location. Containerlab will download the remote file and use it as a startup-config. #1283 8 | 9 | ## Link MTU 10 | 11 | Now users can set the MTU of the link between two nodes. This is done by [setting the `mtu`](../manual/network.md#link-mtu) field in the link definition. Prior to that change, MTU was always 9500B. #1285 12 | 13 | ## Miscellaneous 14 | 15 | * Network mode `none` has been added to allow running nodes without docker networking #1284 16 | * Fix extra newline chars added to files that already had one #1286 17 | * Default interface name checks are no longer enforced, with only specific kinds using them #1276 18 | * Updated Go to v1.20 #1287 19 | -------------------------------------------------------------------------------- /docs/rn/0.40.md: -------------------------------------------------------------------------------- 1 | # Release 0.40 2 | 3 | :material-calendar: 2023-04-28 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## IPv4/6 SANs for SR Linux 6 | 7 | In #1345 we added support for IPv4/6 SANs for SR Linux nodes. With this addition, the certificate will contain IPv4/6 addresses assigned by the container runtime as SANs, so TLS connections can be established using these addresses. 8 | 9 | ## Miscellaneous 10 | 11 | * SR Linux variants D4 and H4 have been added #1339 12 | * Deploy command honors Ctrl-C and cleans up interrupted deployment #1340 13 | * SR Linux agent path can now be a remote HTTP(S) URL #1336 14 | * Improvements to the license handling process #1330 15 | * Doc examples updated to comply with changes in SR Linux 23.3.1 #1341 16 | -------------------------------------------------------------------------------- /docs/rn/0.42.md: -------------------------------------------------------------------------------- 1 | # Release 0.42 2 | 3 | :material-calendar: 2023-06-17 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Home dir for `sudo` user 6 | 7 | Now when you run `sudo containerlab deploy`, the topology files will be searched in the home directory of the user that runs the command and not the root user. Before that change users had to use `sudo -E` to preserve the environment variables and run the command as the current user. Now we made it simpler, just in the spirit of containerlab. #1412 8 | 9 | ## Miscellaneous 10 | 11 | * Optimized link creation #1395 12 | * Kernel version check is performed for topologies with SR Linux nodes which require kernel v4.10+ #1415 13 | * SNMP has been added to the list of services that are enabled by default in SR Linux #1416 14 | * Checkpoint named `clab-initial` is automatically generated on SR Linux nodes when the node is booted #1431 15 | * Partial startup configs with no commands do not cause panic anymore #1423 16 | -------------------------------------------------------------------------------- /docs/rn/0.49.md: -------------------------------------------------------------------------------- 1 | --- 2 | icon: fontawesome/solid/tree 3 | --- 4 | # Release 0.49 :christmas_tree: 5 | 6 | :material-calendar: 2023-12-21 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 7 | 8 | ## Healthchecks 9 | 10 | @steiler added support for container [healthchecks](../manual/nodes.md#healthcheck) in #1426. Now you can specify healthcheck parameters for your containers in the lab topology file and Containerlab will configure the healthcheck for you. 11 | 12 | This allows you to monitor health of your containerlab nodes as well as serves as a prerequisite for the upcoming [dependency manager improvements](https://github.com/srl-labs/containerlab/pull/1759) to create dependencies on healthiness of the lab nodes. 13 | 14 | ## OpenBSD support 15 | 16 | Fearless @dteslya added support for the mighty [OpenBSD](../manual/kinds/openbsd.md) in #1762. Not only you can deploy labs with OpenBSD, but also startup config support were baked in. 17 | 18 | ## Juniper Evolved (EVO) support 19 | 20 | Thanks to @akielaries Containerlab got another platform under its belt! Welcome [Juniper vJunos-Evolved](../manual/kinds/vr-vjunosevolved.md) #1775. 21 | 22 | ## Cisco FTDv support 23 | 24 | Again thanks to @dteslya we now have support for [Cisco FTDv](../manual/kinds/vr-ftdv.md) platform #1783. 25 | 26 | ## Miscellaneous 27 | 28 | * Ctrl+C now does not remove the lab files #1769 29 | * When using filters to execute commands with [`exec`](../cmd/exec.md), the error is now returned if no nodes match the filter #1786 30 | * ixia-c example lab has been updated by @bortok to feature latest developments done for the ixia-c kind #1795 31 | -------------------------------------------------------------------------------- /docs/rn/0.53.md: -------------------------------------------------------------------------------- 1 | # Release 0.53 2 | 3 | :material-calendar: 2024-03-25 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Fortinet Fortigate 6 | 7 | @robotwalk added support for the Fortinet Fortigate firewall image. Refer to the [`fortinet_fortigate`](../manual/kinds/fortinet_fortigate.md) kind documentation to learn more about the supported options. 8 | 9 | ## FreeBSD 10 | 11 | After clearing the OpenBSD, @dteslya added support for the [FreeBSD](../manual/kinds/freebsd.md) kind as well! 12 | 13 | ## Containerlab to Drawio 14 | 15 | @FloSch62 created a new tool - [clab-io-draw](https://github.com/srl-labs/clab-io-draw/) - that allows containerlab users to generate drawio (aka diagrams.net) diagrams from their containerlab topologies. The tool is available as a standalone container image, and we packaged it under the [`containerlab graph --drawio`](../cmd/graph.md) command to make it easier to use. 16 | 17 | ![clab-io-draw](https://gitlab.com/rdodin/pics/-/wikis/uploads/9d1bfa7c03fd1b8096d210f6c460604b/image.png) 18 | 19 | /// note 20 | This feature is in the "preview" status, we will likely change the command structure in the next release. 21 | /// 22 | 23 | ## Miscellaneous 24 | 25 | * Support for SR Linux release 24.3+ 26 | * fixed container network mode #1940 27 | * first steps in making containerlab consumable as a package #1906 28 | -------------------------------------------------------------------------------- /docs/rn/0.54.md: -------------------------------------------------------------------------------- 1 | # Release 0.54 2 | 3 | :material-calendar: 2024-04-04 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Cisco c8000v 6 | 7 | @mzagozen added support for the long-awaited Cisco c8000v router image. Cisco c8000v is a successor of [Cisco CSR1000v](../manual/kinds/vr-csr.md) and is a **different** product from [Cisco 8000](../manual/kinds/c8000.md) platform emulator. 8 | 9 | Refer to the [`cisco_c8000v`](../manual/kinds/vr-c8000v.md) kind documentation to learn more about the supported options. 10 | 11 | ## Miscellaneous 12 | 13 | * root login allowed for crpd #1967 14 | * support for podman local images #1969 15 | * fixes to SR Linux v24.3+ startup config #1968 #1971 16 | 17 | ## Patches 18 | 19 | ### 0.54.1 20 | 21 | * add `insecure-mgmt` gRPC server to the [default SR Linux config](../manual/kinds/srl.md#grpc-server) #1979 22 | * use Docker v25 API and Podman v5 #1980 23 | 24 | ### 0.54.2 25 | 26 | * fix inspect command behavior with respect to the named-based lab fetching #1984 27 | -------------------------------------------------------------------------------- /docs/rn/0.59.md: -------------------------------------------------------------------------------- 1 | # Release 0.59 2 | 3 | :material-calendar: 2024-10-23 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Per-stage exec hooks 6 | 7 | Back in 0.51 when we introduced the stages support every stage had a single exec hook that allowed you to execute a command in a container when it enters/exits a stage. It was a good start, but it had one hole in it - it was not possible to execute a command on a host machine when a container enters/exits a particular stage. 8 | 9 | Thanks to @steiler the stages support for execs became much more powerful in this release with allowing you to flexibly define where command is executed (host or container) and when (what stage and what event). Here is an example of a refactored exec hooks: 10 | 11 | ```yaml 12 | nodes: 13 | node1: 14 | stages: 15 | create-links: 16 | exec: 17 | - command: ls /sys/class/net/ 18 | target: container #(1)! 19 | phase: on-enter #(2)! 20 | ``` 21 | 22 | 1. `target` defaults to "container" and can be omitted. Possible values `container` or `host` 23 | 2. `phase` defaults to "on-enter" and can be omitted. Possible values `on-enter` or `on-exit` 24 | 25 | 26 | Note, this is a breaking change if you used execs in the stages before. 27 | 28 | ## Miscellaneous 29 | 30 | - fixed loading custom export templates #2240 31 | - iptables kernel load to support compressed modules #2251 32 | - fixed the release retrieval routine #2250 33 | - Cisco IOL to support custom PIDs and randomized MACs #2239 34 | - SR Linux kind drops support for mounted authz_keys file #2254 35 | -------------------------------------------------------------------------------- /docs/rn/0.66.md: -------------------------------------------------------------------------------- 1 | # Release 0.66 2 | 3 | :material-calendar: 2025-03-07 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Netem Reset Command 6 | 7 | The [`reset` command](../cmd/tools/netem/reset.md) has been added to the `netem` tools command to reset the network emulation settings. #2488 8 | 9 | ## WSL-Containerlab goes GA 10 | 11 | The [Containerlab on Windows](../windows.md) documentation has been updated with recommendations to use WSL-Containerlab distribution as the default choice. #2498 12 | 13 | If you haven't yet tried out WSL-Containerlab, now is the time to do it! 14 | 15 | ## Miscellaneous 16 | 17 | * fixed sudo-less operation when AD groups are used #2496 18 | * added missing `seq` template function #2497 19 | * updated VS Code extension documentation #2499 20 | * support for detecting proxy settings when performing `containerlab version upgrade` command #2507 21 | * support for custom SR Linux topology files #2509 22 | -------------------------------------------------------------------------------- /docs/rn/0.67.md: -------------------------------------------------------------------------------- 1 | # Release 0.67 2 | 3 | :material-calendar: 2025-04-01 · :material-list-status: [Full Changelog](https://github.com/srl-labs/containerlab/releases) 4 | 5 | ## Share access to lab nodes 6 | 7 | Lightweight, fast to deploy, and reproducible containerlabs are meant to be shared via Git. But sometimes, you can't quite share the entire lab... Maybe the recipient doesn't have access to the container images or has other limitations that prevent them from running a copy of you lab. 8 | 9 | Yet, you might find yourself in need to share access of your lab with one or many users. Quite often you want someone else to have a look at your lab when you found something or got stuck. Or maybe you are a lecturer and want to broadcast your lab interaction to your students. 10 | 11 | Checkout the web-based on-demand lab access sharing [using sshx](../manual/share-access.md). 12 | 13 | ## Nornir inventory support 14 | 15 | Thanks to @danlindow, Containerlab will now [generate Nornir' Simple Inventory](../manual/inventory.md#nornir) right next to the Ansible inventory. This opens up a door to your reusing your existing automation stacks built with Nornir. 16 | 17 | ## Miscellaneous 18 | 19 | * docker version you get installed when using the quick-setup script has been bumped to 27.5.1 20 | * added openwrt kind support (no docs yet) 21 | * new SR Linux types - `ixr18e` and `ixrh432d` 22 | * delete process won't require lab dir presence anymore 23 | * bumped required Go version to 1.23 24 | -------------------------------------------------------------------------------- /errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import "errors" 4 | 5 | // ErrFileNotFound is returned when a file is not found. 6 | var ErrFileNotFound = errors.New("file not found") 7 | 8 | // ErrIncorrectInput is returned when the user input is incorrect. 9 | var ErrIncorrectInput = errors.New("incorrect input") 10 | -------------------------------------------------------------------------------- /goreleaser.dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3 2 | 3 | LABEL maintainer="Roman Dodin " 4 | LABEL documentation="https://containerlab.dev" 5 | LABEL repo="https://github.com/srl-labs/containerlab" 6 | 7 | RUN apk add --no-cache bash \ 8 | curl \ 9 | docker-cli \ 10 | git \ 11 | openssh \ 12 | make \ 13 | iptables \ 14 | device-mapper \ 15 | e2fsprogs-extra 16 | 17 | COPY containerlab_*.apk /tmp/ 18 | RUN apk add --allow-untrusted /tmp/containerlab_*.apk && rm -f /tmp/containerlab_*.apk 19 | 20 | CMD ["/usr/bin/containerlab", "help"] 21 | -------------------------------------------------------------------------------- /internal/mermaid/graph.go: -------------------------------------------------------------------------------- 1 | package mermaid 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "golang.org/x/exp/slices" 8 | ) 9 | 10 | // A very minimalistic Mermaid flowchart generator 11 | // that covers the usecase of `containerlab graph` 12 | // command. 13 | 14 | type FlowChart struct { 15 | title string 16 | direction string 17 | edges []Edge 18 | } 19 | 20 | type Edge struct { 21 | nodeA string 22 | nodeB string 23 | } 24 | 25 | func NewFlowChart() *FlowChart { 26 | return &FlowChart{ 27 | edges: []Edge{}, 28 | } 29 | } 30 | 31 | func (fc *FlowChart) SetTitle(title string) { 32 | fc.title = title 33 | } 34 | 35 | func (fc *FlowChart) SetDirection(direction string) error { 36 | validDirections := []string{"TB", "TD", "BT", "RL", "LR"} 37 | if !slices.Contains(validDirections, direction) { 38 | return fmt.Errorf("invalid direction %s (should be one of %v)", direction, validDirections) 39 | } 40 | fc.direction = direction 41 | return nil 42 | } 43 | 44 | func (fc *FlowChart) AddEdge(nodeA string, nodeB string) { 45 | fc.edges = append(fc.edges, Edge{nodeA: nodeA, nodeB: nodeB}) 46 | } 47 | 48 | func (fc *FlowChart) Generate(w io.Writer) { 49 | fmt.Fprintf(w, "---\n") 50 | fmt.Fprintf(w, "title: %s\n", fc.title) 51 | fmt.Fprintf(w, "---\n") 52 | fmt.Fprintf(w, "graph %s\n", fc.direction) 53 | for _, edge := range fc.edges { 54 | fmt.Fprintf(w, " %s---%s\n", edge.nodeA, edge.nodeB) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /internal/slices/slices.go: -------------------------------------------------------------------------------- 1 | package slices 2 | 3 | // Index returns the index of the first occurrence of v in s, 4 | // or -1 if not present. 5 | func Index[E comparable](s []E, v E) int { 6 | for i, vs := range s { 7 | if v == vs { 8 | return i 9 | } 10 | } 11 | return -1 12 | } 13 | 14 | // Contains reports whether v is present in s. 15 | func Contains[E comparable](s []E, v E) bool { 16 | return Index(s, v) >= 0 17 | } 18 | -------------------------------------------------------------------------------- /lab-examples/.gitignore: -------------------------------------------------------------------------------- 1 | clab-* -------------------------------------------------------------------------------- /lab-examples/br01/br01.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/ext-bridge/ 2 | name: br01 3 | 4 | topology: 5 | kinds: 6 | nokia_srlinux: 7 | type: ixrd2l 8 | image: ghcr.io/nokia/srlinux 9 | nodes: 10 | srl1: 11 | kind: nokia_srlinux 12 | srl2: 13 | kind: nokia_srlinux 14 | srl3: 15 | kind: nokia_srlinux 16 | # note, that the bridge br-clab must be created manually 17 | br-clab: 18 | kind: bridge 19 | 20 | links: 21 | - endpoints: ["srl1:e1-1", "br-clab:eth1"] 22 | - endpoints: ["srl2:e1-1", "br-clab:eth2"] 23 | - endpoints: ["srl3:e1-1", "br-clab:eth3"] 24 | -------------------------------------------------------------------------------- /lab-examples/cert01/cert01.clab.yml: -------------------------------------------------------------------------------- 1 | name: cert01 2 | topology: 3 | nodes: 4 | sr: 5 | kind: nokia_sros 6 | image: vrnetlab/vr-sros:21.2.R1 7 | license: license-sros21.txt 8 | -------------------------------------------------------------------------------- /lab-examples/clos01/clos01.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/min-clos/ 2 | name: clos01 3 | 4 | topology: 5 | kinds: 6 | nokia_srlinux: 7 | image: ghcr.io/nokia/srlinux 8 | linux: 9 | image: ghcr.io/hellt/network-multitool 10 | nodes: 11 | leaf1: 12 | kind: nokia_srlinux 13 | type: ixrd2l 14 | leaf2: 15 | kind: nokia_srlinux 16 | type: ixrd2l 17 | spine: 18 | kind: nokia_srlinux 19 | type: ixrd3l 20 | client1: 21 | kind: linux 22 | client2: 23 | kind: linux 24 | 25 | links: 26 | - endpoints: ["leaf1:e1-1", "spine:e1-1"] 27 | - endpoints: ["leaf2:e1-1", "spine:e1-2"] 28 | - endpoints: ["client1:eth1", "leaf1:e1-2"] 29 | - endpoints: ["client2:eth1", "leaf2:e1-2"] 30 | -------------------------------------------------------------------------------- /lab-examples/clos02/configs/client1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > /etc/network/interfaces << EOF 4 | auto eth1 5 | 6 | iface eth1 inet static 7 | address 10.0.0.25 8 | netmask 255.255.255.254 9 | 10 | iface eth1 inet6 static 11 | address 1000:10:0:0::25 12 | netmask 127 13 | pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra 14 | EOF 15 | 16 | ifup eth1 17 | -------------------------------------------------------------------------------- /lab-examples/clos02/configs/client2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > /etc/network/interfaces << EOF 4 | auto eth1 5 | 6 | iface eth1 inet static 7 | address 10.0.0.27 8 | netmask 255.255.255.254 9 | 10 | iface eth1 inet6 static 11 | address 1000:10:0:0::27 12 | netmask 127 13 | pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra 14 | EOF 15 | 16 | ifup eth1 17 | -------------------------------------------------------------------------------- /lab-examples/clos02/configs/client3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > /etc/network/interfaces << EOF 4 | auto eth1 5 | 6 | iface eth1 inet static 7 | address 10.0.0.29 8 | netmask 255.255.255.254 9 | 10 | iface eth1 inet6 static 11 | address 1000:10:0:0::29 12 | netmask 127 13 | pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra 14 | EOF 15 | 16 | ifup eth1 17 | -------------------------------------------------------------------------------- /lab-examples/clos02/configs/client4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > /etc/network/interfaces << EOF 4 | auto eth1 5 | 6 | iface eth1 inet static 7 | address 10.0.0.31 8 | netmask 255.255.255.254 9 | 10 | iface eth1 inet6 static 11 | address 1000:10:0:0::31 12 | netmask 127 13 | pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra 14 | EOF 15 | 16 | ifup eth1 17 | -------------------------------------------------------------------------------- /lab-examples/clos02/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CFG_DIR=./configs 4 | SRL_PASSWORD=NokiaSrl1! 5 | 6 | configure_SRL() { 7 | OUT=$(gnmic -a clab-clos02-$1 --timeout 30s -u admin -p $SRL_PASSWORD -e json_ietf --skip-verify set --update-path / --update-file $CFG_DIR/$1.yaml 2>&1) 8 | echo $OUT | grep -q -e '\"operation\": \"UPDATE\"' 9 | if [ $? -eq 0 ]; then 10 | docker exec clab-clos02-$1 sr_cli "save startup" > /dev/null 11 | else 12 | echo "Error: Unable to push config into clab-clos02-$1." 13 | fi 14 | echo $OUT > /dev/null 15 | } 16 | 17 | configure_CLIENT() { 18 | docker cp $CFG_DIR/$1.sh clab-clos02-$1:/tmp/ 19 | docker exec clab-clos02-$1 bash /tmp/$1.sh 2>/dev/null 20 | } 21 | 22 | echo 23 | PIDS="" 24 | NE=("leaf1" "leaf2" "leaf3" "leaf4" "spine1" "spine2" "spine3" "spine4" "superspine1" "superspine2") 25 | CLIENT=("client1" "client2" "client3" "client4") 26 | 27 | for VARIANT in ${NE[@]}; do 28 | ( configure_SRL $VARIANT ) & 29 | REF=$! 30 | echo "[$REF] Configuring $VARIANT..." 31 | PIDS+=" $REF" 32 | done 33 | 34 | for VARIANT in ${CLIENT[@]}; do 35 | ( configure_CLIENT $VARIANT ) & 36 | REF=$! 37 | echo "[$REF] Configuring $VARIANT..." 38 | PIDS+=" $REF" 39 | done 40 | 41 | echo 42 | for p in $PIDS; do 43 | if wait $p; then 44 | echo "Process $p success" 45 | else 46 | echo "Process $p fail" 47 | fi 48 | done 49 | echo -------------------------------------------------------------------------------- /lab-examples/cvx01/README.md: -------------------------------------------------------------------------------- 1 | Example of how to run `cvx` inside `ignite` runtime together with nodes running in `docker` runtime. -------------------------------------------------------------------------------- /lab-examples/cvx01/sw1/interfaces: -------------------------------------------------------------------------------- 1 | auto swp12 2 | iface swp12 3 | address 12.12.12.1/24 -------------------------------------------------------------------------------- /lab-examples/cvx01/sw2/frr.conf: -------------------------------------------------------------------------------- 1 | interface eth21 2 | ip address 12.12.12.2/24 3 | ! 4 | 5 | -------------------------------------------------------------------------------- /lab-examples/cvx01/topo.clab.yml: -------------------------------------------------------------------------------- 1 | name: cvx01 2 | 3 | topology: 4 | nodes: 5 | sw1: 6 | kind: cumulus_cvx 7 | image: networkop/cx:4.3.0 8 | binds: 9 | - sw1/interfaces:/etc/network/interfaces.d/host-mounts 10 | sw2: 11 | kind: linux 12 | image: frrouting/frr:v7.5.1 13 | binds: 14 | - sw2/frr.conf:/etc/frr/frr.conf 15 | 16 | links: 17 | - endpoints: ["sw1:swp12", "sw2:eth21"] 18 | -------------------------------------------------------------------------------- /lab-examples/cvx02/README.md: -------------------------------------------------------------------------------- 1 | Example of how to run `cvx` nodes inside docker runtime. 2 | 3 | -------------------------------------------------------------------------------- /lab-examples/cvx02/h1/interfaces: -------------------------------------------------------------------------------- 1 | auto lo 2 | iface lo inet loopback 3 | 4 | auto eth1 5 | iface eth1 6 | address 12.12.12.2/24 -------------------------------------------------------------------------------- /lab-examples/cvx02/sw1/interfaces: -------------------------------------------------------------------------------- 1 | auto lo 2 | iface lo inet loopback 3 | 4 | auto mgmt 5 | iface mgmt 6 | vrf-table auto 7 | 8 | auto eth0 9 | iface eth0 10 | vrf mgmt 11 | 12 | auto swp12 13 | iface swp12 14 | address 12.12.12.1/24 -------------------------------------------------------------------------------- /lab-examples/cvx02/topo.clab.yml: -------------------------------------------------------------------------------- 1 | name: cvx02 2 | 3 | topology: 4 | nodes: 5 | sw1: 6 | kind: cumulus_cvx 7 | image: networkop/cx:4.3.0 8 | runtime: docker 9 | binds: 10 | - /lib/modules:/lib/modules:ro # for kernel modules like ebtables 11 | - sw1/interfaces:/etc/network/interfaces 12 | h1: 13 | kind: linux 14 | image: networkop/host:ifreload 15 | binds: 16 | - h1/interfaces:/etc/network/interfaces 17 | cmd: "2" # wait for 2 interfaces to be connected: eth0 + eth1 18 | 19 | links: 20 | - endpoints: ["sw1:swp12", "h1:eth1"] 21 | -------------------------------------------------------------------------------- /lab-examples/fortigate/fortigate.clab.yml: -------------------------------------------------------------------------------- 1 | name: fortigate 2 | topology: 3 | nodes: 4 | forti1: 5 | kind: fortinet_fortigate 6 | image: vrnetlab/vr-fortigate:7.0.14 7 | forti2: 8 | kind: fortinet_fortigate 9 | image: vrnetlab/vr-fortigate:7.0.14 10 | links: 11 | - endpoints: ["forti1:eth1", "forti2:eth1"] 12 | -------------------------------------------------------------------------------- /lab-examples/freebsd01/freebsd01.clab.yml: -------------------------------------------------------------------------------- 1 | name: freebsd01 2 | topology: 3 | nodes: 4 | fbsd1: 5 | kind: freebsd 6 | image: vrnetlab/vr-freebsd:13.2 7 | client1: 8 | kind: "linux" 9 | image: wbitt/network-multitool:alpine-extra 10 | exec: 11 | - ip addr add 192.168.1.2/30 dev eth1 12 | - ip route add 192.168.2.0/30 via 192.168.1.1 13 | client2: 14 | kind: "linux" 15 | image: wbitt/network-multitool:alpine-extra 16 | exec: 17 | - ip addr add 192.168.2.2/30 dev eth1 18 | - ip route add 192.168.1.0/30 via 192.168.2.1 19 | links: 20 | - endpoints: ["fbsd1:eth1", "client1:eth1"] 21 | - endpoints: ["fbsd1:eth2", "client2:eth1"] -------------------------------------------------------------------------------- /lab-examples/frr01/PC-interfaces.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sudo docker exec -d clab-frr01-PC1 ip link set eth1 up 3 | sudo docker exec -d clab-frr01-PC1 ip addr add 192.168.11.2/24 dev eth1 4 | sudo docker exec -d clab-frr01-PC1 ip route add 192.168.0.0/16 via 192.168.11.1 dev eth1 5 | sudo docker exec -d clab-frr01-PC1 ip route add 10.10.10.0/24 via 192.168.11.1 dev eth1 6 | 7 | sudo docker exec -d clab-frr01-PC2 ip link set eth1 up 8 | sudo docker exec -d clab-frr01-PC2 ip addr add 192.168.12.2/24 dev eth1 9 | sudo docker exec -d clab-frr01-PC2 ip route add 192.168.0.0/16 via 192.168.12.1 dev eth1 10 | sudo docker exec -d clab-frr01-PC2 ip route add 10.10.10.0/24 via 192.168.12.1 dev eth1 11 | 12 | sudo docker exec -d clab-frr01-PC3 ip link set eth1 up 13 | sudo docker exec -d clab-frr01-PC3 ip addr add 192.168.13.2/24 dev eth1 14 | sudo docker exec -d clab-frr01-PC3 ip route add 192.168.0.0/16 via 192.168.13.1 dev eth1 15 | sudo docker exec -d clab-frr01-PC3 ip route add 10.10.10.0/24 via 192.168.13.1 dev eth1 16 | -------------------------------------------------------------------------------- /lab-examples/frr01/README.md: -------------------------------------------------------------------------------- 1 | # Simple OSPF lab using FRR 2 | 3 | This lab example consists of three FRR routers connected in a ring topology. Each router has one PC connected to it. 4 | 5 | This is also an example of how to pre-configure lab nodes on "linux" node types in Containerlab. 6 | 7 | To start this lab, run the *run.sh* script, which will run the containerlab deploy commands, and then configure the PC interfaces. 8 | 9 | The lab configuration is documented in detail at: https://www.brianlinkletter.com/2021/05/use-containerlab-to-emulate-open-source-routers/ 10 | -------------------------------------------------------------------------------- /lab-examples/frr01/frr01.clab.yml: -------------------------------------------------------------------------------- 1 | name: frr01 2 | 3 | topology: 4 | nodes: 5 | router1: 6 | kind: linux 7 | image: frrouting/frr:v7.5.1 8 | binds: 9 | - router1/daemons:/etc/frr/daemons 10 | - router1/frr.conf:/etc/frr/frr.conf 11 | router2: 12 | kind: linux 13 | image: frrouting/frr:v7.5.1 14 | binds: 15 | - router2/daemons:/etc/frr/daemons 16 | - router2/frr.conf:/etc/frr/frr.conf 17 | router3: 18 | kind: linux 19 | image: frrouting/frr:v7.5.1 20 | binds: 21 | - router3/daemons:/etc/frr/daemons 22 | - router3/frr.conf:/etc/frr/frr.conf 23 | PC1: 24 | kind: linux 25 | image: praqma/network-multitool:latest 26 | PC2: 27 | kind: linux 28 | image: praqma/network-multitool:latest 29 | PC3: 30 | kind: linux 31 | image: praqma/network-multitool:latest 32 | 33 | links: 34 | - endpoints: ["router1:eth1", "router2:eth1"] 35 | - endpoints: ["router1:eth2", "router3:eth1"] 36 | - endpoints: ["router2:eth2", "router3:eth2"] 37 | - endpoints: ["PC1:eth1", "router1:eth3"] 38 | - endpoints: ["PC2:eth1", "router2:eth3"] 39 | - endpoints: ["PC3:eth1", "router3:eth3"] 40 | -------------------------------------------------------------------------------- /lab-examples/frr01/router1/daemons: -------------------------------------------------------------------------------- 1 | zebra=yes 2 | bgpd=no 3 | ospfd=yes 4 | ospf6d=no 5 | ripd=no 6 | ripngd=no 7 | isisd=no 8 | pimd=no 9 | ldpd=yes 10 | nhrpd=no 11 | eigrpd=no 12 | babeld=no 13 | sharpd=no 14 | staticd=no 15 | pbrd=no 16 | bfdd=no 17 | fabricd=no 18 | 19 | vtysh_enable=yes 20 | zebra_options=" -s 90000000 --daemon -A 127.0.0.1" 21 | bgpd_options=" --daemon -A 127.0.0.1" 22 | ospfd_options=" --daemon -A 127.0.0.1" 23 | ospf6d_options=" --daemon -A ::1" 24 | ripd_options=" --daemon -A 127.0.0.1" 25 | ripngd_options=" --daemon -A ::1" 26 | isisd_options=" --daemon -A 127.0.0.1" 27 | pimd_options=" --daemon -A 127.0.0.1" 28 | ldpd_options=" --daemon -A 127.0.0.1" 29 | nhrpd_options=" --daemon -A 127.0.0.1" 30 | eigrpd_options=" --daemon -A 127.0.0.1" 31 | babeld_options=" --daemon -A 127.0.0.1" 32 | sharpd_options=" --daemon -A 127.0.0.1" 33 | staticd_options=" --daemon -A 127.0.0.1" 34 | pbrd_options=" --daemon -A 127.0.0.1" 35 | bfdd_options=" --daemon -A 127.0.0.1" 36 | fabricd_options=" --daemon -A 127.0.0.1" 37 | -------------------------------------------------------------------------------- /lab-examples/frr01/router1/frr.conf: -------------------------------------------------------------------------------- 1 | frr version 7.5.1_git 2 | frr defaults traditional 3 | hostname router1 4 | no ipv6 forwarding 5 | ! 6 | interface eth1 7 | ip address 192.168.1.1/24 8 | ! 9 | interface eth2 10 | ip address 192.168.2.1/24 11 | ! 12 | interface eth3 13 | ip address 192.168.11.1/24 14 | ! 15 | interface lo 16 | ip address 10.10.10.1/32 17 | ! 18 | router ospf 19 | passive-interface eth3 20 | network 192.168.1.0/24 area 0.0.0.0 21 | network 192.168.2.0/24 area 0.0.0.0 22 | network 192.168.11.0/24 area 0.0.0.0 23 | ! 24 | line vty 25 | ! 26 | -------------------------------------------------------------------------------- /lab-examples/frr01/router2/daemons: -------------------------------------------------------------------------------- 1 | zebra=yes 2 | bgpd=no 3 | ospfd=yes 4 | ospf6d=no 5 | ripd=no 6 | ripngd=no 7 | isisd=no 8 | pimd=no 9 | ldpd=yes 10 | nhrpd=no 11 | eigrpd=no 12 | babeld=no 13 | sharpd=no 14 | staticd=no 15 | pbrd=no 16 | bfdd=no 17 | fabricd=no 18 | 19 | vtysh_enable=yes 20 | zebra_options=" -s 90000000 --daemon -A 127.0.0.1" 21 | bgpd_options=" --daemon -A 127.0.0.1" 22 | ospfd_options=" --daemon -A 127.0.0.1" 23 | ospf6d_options=" --daemon -A ::1" 24 | ripd_options=" --daemon -A 127.0.0.1" 25 | ripngd_options=" --daemon -A ::1" 26 | isisd_options=" --daemon -A 127.0.0.1" 27 | pimd_options=" --daemon -A 127.0.0.1" 28 | ldpd_options=" --daemon -A 127.0.0.1" 29 | nhrpd_options=" --daemon -A 127.0.0.1" 30 | eigrpd_options=" --daemon -A 127.0.0.1" 31 | babeld_options=" --daemon -A 127.0.0.1" 32 | sharpd_options=" --daemon -A 127.0.0.1" 33 | staticd_options=" --daemon -A 127.0.0.1" 34 | pbrd_options=" --daemon -A 127.0.0.1" 35 | bfdd_options=" --daemon -A 127.0.0.1" 36 | fabricd_options=" --daemon -A 127.0.0.1" 37 | -------------------------------------------------------------------------------- /lab-examples/frr01/router2/frr.conf: -------------------------------------------------------------------------------- 1 | frr version 7.5.1_git 2 | frr defaults traditional 3 | hostname router2 4 | no ipv6 forwarding 5 | ! 6 | interface eth1 7 | ip address 192.168.1.2/24 8 | ! 9 | interface eth2 10 | ip address 192.168.3.1/24 11 | ! 12 | interface eth3 13 | ip address 192.168.12.1/24 14 | ! 15 | interface lo 16 | ip address 10.10.10.2/32 17 | ! 18 | router ospf 19 | passive-interface eth3 20 | network 192.168.1.0/24 area 0.0.0.0 21 | 22 | network 192.168.3.0/24 area 0.0.0.0 23 | network 192.168.12.0/24 area 0.0.0.0 24 | ! 25 | line vty 26 | ! 27 | -------------------------------------------------------------------------------- /lab-examples/frr01/router3/daemons: -------------------------------------------------------------------------------- 1 | zebra=yes 2 | bgpd=no 3 | ospfd=yes 4 | ospf6d=no 5 | ripd=no 6 | ripngd=no 7 | isisd=no 8 | pimd=no 9 | ldpd=yes 10 | nhrpd=no 11 | eigrpd=no 12 | babeld=no 13 | sharpd=no 14 | staticd=no 15 | pbrd=no 16 | bfdd=no 17 | fabricd=no 18 | 19 | vtysh_enable=yes 20 | zebra_options=" -s 90000000 --daemon -A 127.0.0.1" 21 | bgpd_options=" --daemon -A 127.0.0.1" 22 | ospfd_options=" --daemon -A 127.0.0.1" 23 | ospf6d_options=" --daemon -A ::1" 24 | ripd_options=" --daemon -A 127.0.0.1" 25 | ripngd_options=" --daemon -A ::1" 26 | isisd_options=" --daemon -A 127.0.0.1" 27 | pimd_options=" --daemon -A 127.0.0.1" 28 | ldpd_options=" --daemon -A 127.0.0.1" 29 | nhrpd_options=" --daemon -A 127.0.0.1" 30 | eigrpd_options=" --daemon -A 127.0.0.1" 31 | babeld_options=" --daemon -A 127.0.0.1" 32 | sharpd_options=" --daemon -A 127.0.0.1" 33 | staticd_options=" --daemon -A 127.0.0.1" 34 | pbrd_options=" --daemon -A 127.0.0.1" 35 | bfdd_options=" --daemon -A 127.0.0.1" 36 | fabricd_options=" --daemon -A 127.0.0.1" 37 | -------------------------------------------------------------------------------- /lab-examples/frr01/router3/frr.conf: -------------------------------------------------------------------------------- 1 | frr version 7.5.1_git 2 | frr defaults traditional 3 | hostname router3 4 | no ipv6 forwarding 5 | ! 6 | interface eth1 7 | ip address 192.168.2.2/24 8 | ! 9 | interface eth2 10 | ip address 192.168.3.2/24 11 | ! 12 | interface eth3 13 | ip address 192.168.13.1/24 14 | ! 15 | interface lo 16 | ip address 10.10.10.3/32 17 | ! 18 | router ospf 19 | passive-interface eth3 20 | network 192.168.2.0/24 area 0.0.0.0 21 | network 192.168.3.0/24 area 0.0.0.0 22 | network 192.168.13.0/24 area 0.0.0.0 23 | ! 24 | line vty 25 | ! 26 | -------------------------------------------------------------------------------- /lab-examples/frr01/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | clab deploy --topo frr01.clab.yml 3 | ./PC-interfaces.sh 4 | -------------------------------------------------------------------------------- /lab-examples/ftdv01/ftdv01.yml: -------------------------------------------------------------------------------- 1 | name: ftdv01 2 | topology: 3 | nodes: 4 | ftdv1: 5 | kind: cisco_ftdv 6 | image: vrnetlab/vr-ftdv:7.2.5 7 | client1: 8 | kind: "linux" 9 | image: wbitt/network-multitool:alpine-extra 10 | exec: 11 | - ip addr add 192.168.1.2/30 dev eth1 12 | - ip route add 192.168.2.0/30 via 192.168.1.1 13 | client2: 14 | kind: "linux" 15 | image: wbitt/network-multitool:alpine-extra 16 | exec: 17 | - ip addr add 192.168.2.2/30 dev eth1 18 | - ip route add 192.168.1.0/30 via 192.168.2.1 19 | links: 20 | - endpoints: ["ftdv1:eth1", "client1:eth1"] 21 | - endpoints: ["ftdv1:eth2", "client2:eth1"] 22 | -------------------------------------------------------------------------------- /lab-examples/generic_vm01/generic_vm.clab.yml: -------------------------------------------------------------------------------- 1 | name: generic_vm 2 | 3 | topology: 4 | nodes: 5 | ubuntu: 6 | kind: generic_vm 7 | image: vrnetlab/vr-ubuntu:jammy 8 | srl: 9 | kind: nokia_srlinux 10 | image: ghcr.io/nokia/srlinux:24.3.2 11 | startup-config: | 12 | set / interface ethernet-1/1 admin-state enable 13 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 14 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.2/24 15 | set / network-instance default interface ethernet-1/1.0 16 | links: 17 | - endpoints: ["srl:e1-1", "ubuntu:eth1"] 18 | -------------------------------------------------------------------------------- /lab-examples/ixiac01/go.mod: -------------------------------------------------------------------------------- 1 | module ixiac01 2 | 3 | go 1.23 4 | 5 | toolchain go1.23.0 6 | 7 | require github.com/open-traffic-generator/snappi/gosnappi v1.31.0 8 | 9 | require ( 10 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 11 | github.com/ghodss/yaml v1.0.0 // indirect 12 | github.com/kr/text v0.2.0 // indirect 13 | golang.org/x/net v0.35.0 // indirect 14 | golang.org/x/sys v0.30.0 // indirect 15 | golang.org/x/text v0.22.0 // indirect 16 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 17 | google.golang.org/grpc v1.72.2 // indirect 18 | google.golang.org/protobuf v1.36.6 // indirect 19 | gopkg.in/yaml.v2 v2.4.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /lab-examples/ixiac01/ixiac01.clab.yml: -------------------------------------------------------------------------------- 1 | name: ixiac01 2 | topology: 3 | nodes: 4 | ixia-c: 5 | kind: keysight_ixia-c-one 6 | image: ghcr.io/open-traffic-generator/ixia-c-one:1.31.0-3 7 | srl: 8 | kind: nokia_srlinux 9 | image: ghcr.io/nokia/srlinux:23.10.1 10 | startup-config: srl.cfg 11 | links: 12 | - endpoints: ["ixia-c:eth1", "srl:e1-1"] 13 | - endpoints: ["ixia-c:eth2", "srl:e1-2"] 14 | -------------------------------------------------------------------------------- /lab-examples/ixiac01/srl.cfg: -------------------------------------------------------------------------------- 1 | set /interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 2 | set /interface ethernet-1/1 subinterface 0 ipv4 address 1.1.1.2/24 3 | set /interface ethernet-1/2 subinterface 0 ipv4 admin-state enable 4 | set /interface ethernet-1/2 subinterface 0 ipv4 address 2.2.2.2/24 5 | set /network-instance default interface ethernet-1/1.0 6 | set /network-instance default interface ethernet-1/2.0 7 | 8 | set /network-instance default next-hop-groups group group1 nexthop 1 ip-address 2.2.2.1 admin-state enable 9 | set /network-instance default static-routes route 20.20.20.0/24 next-hop-group group1 admin-state enable 10 | -------------------------------------------------------------------------------- /lab-examples/k8s_kind01/k01-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | nodes: 4 | - role: control-plane 5 | - role: worker 6 | -------------------------------------------------------------------------------- /lab-examples/k8s_kind01/k8s_kind01.clab.yml: -------------------------------------------------------------------------------- 1 | name: kind01 2 | 3 | topology: 4 | kinds: 5 | nokia_srlinux: 6 | image: ghcr.io/nokia/srlinux:23.10.1 7 | nodes: 8 | srl01: 9 | kind: nokia_srlinux 10 | k01: 11 | kind: k8s-kind 12 | startup-config: k01-config.yaml 13 | k02: 14 | kind: k8s-kind 15 | 16 | # k01 cluster contains 2 nodes: a control-plane and a worker 17 | # the cluster config is defined in k01-config.yaml 18 | k01-control-plane: 19 | kind: ext-container 20 | exec: 21 | - "ip addr add dev eth1 192.168.10.1/24" 22 | k01-worker: 23 | kind: ext-container 24 | exec: 25 | - "ip addr add dev eth1 192.168.11.1/24" 26 | 27 | # k02 cluster has an all-in-one node 28 | k02-control-plane: 29 | kind: ext-container 30 | exec: 31 | - "ip addr add dev eth1 192.168.20.1/24" 32 | 33 | links: 34 | - endpoints: ["srl01:e1-1", "k01-control-plane:eth1"] 35 | - endpoints: ["srl01:e1-2", "k01-worker:eth1"] 36 | 37 | - endpoints: ["srl01:e1-4", "k02-control-plane:eth1"] 38 | -------------------------------------------------------------------------------- /lab-examples/openbsd01/openbsd01.yml: -------------------------------------------------------------------------------- 1 | name: openbsd01 2 | topology: 3 | nodes: 4 | obsd1: 5 | kind: openbsd 6 | image: vrnetlab/vr-openbsd:7.3 7 | client1: 8 | kind: "linux" 9 | image: wbitt/network-multitool:alpine-extra 10 | exec: 11 | - ip addr add 192.168.1.2/30 dev eth1 12 | - ip route add 192.168.2.0/30 via 192.168.1.1 13 | client2: 14 | kind: "linux" 15 | image: wbitt/network-multitool:alpine-extra 16 | exec: 17 | - ip addr add 192.168.2.2/30 dev eth1 18 | - ip route add 192.168.1.0/30 via 192.168.2.1 19 | links: 20 | - endpoints: ["obsd1:eth1", "client1:eth1"] 21 | - endpoints: ["obsd1:eth2", "client2:eth1"] -------------------------------------------------------------------------------- /lab-examples/ost-srl/ost-srl.clab.yml: -------------------------------------------------------------------------------- 1 | name: ost-srl 2 | 3 | topology: 4 | nodes: 5 | ost: 6 | kind: linux 7 | image: ostinato/ostinato:v1.3.0-1 8 | ports: 9 | - 5900:5900/tcp 10 | - 7878:7878/tcp 11 | binds: 12 | - .:/root/shared 13 | srl: 14 | kind: nokia_srlinux 15 | image: ghcr.io/nokia/srlinux:24.3.2 16 | startup-config: srl.cfg 17 | links: 18 | - endpoints: ["ost:eth1", "srl:e1-1"] 19 | - endpoints: ["ost:eth2", "srl:e1-2"] 20 | -------------------------------------------------------------------------------- /lab-examples/ost-srl/ost-srl.ossn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/lab-examples/ost-srl/ost-srl.ossn -------------------------------------------------------------------------------- /lab-examples/ost-srl/srl.cfg: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 subinterface 0 ipv4 address 10.0.0.1/24 2 | set / interface ethernet-1/2 subinterface 0 ipv4 address 20.0.0.1/24 3 | set / network-instance default interface ethernet-1/1.0 4 | set / network-instance default interface ethernet-1/2.0 5 | -------------------------------------------------------------------------------- /lab-examples/sonic01/sonic01.clab.yml: -------------------------------------------------------------------------------- 1 | name: sonic01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | sonic: 9 | kind: sonic-vs 10 | image: docker-sonic-vs:2020-11-12 11 | 12 | links: 13 | - endpoints: ["srl:e1-1", "sonic:eth1"] 14 | -------------------------------------------------------------------------------- /lab-examples/srl-quickstart/srl01.clab.yml: -------------------------------------------------------------------------------- 1 | name: srl 2 | # node name will be srl unless overridden by CLAB_PREFIX 3 | prefix: ${CLAB_PREFIX:=""} 4 | 5 | topology: 6 | nodes: 7 | srl: 8 | kind: nokia_srlinux 9 | image: ${SRL_IMAGE:=ghcr.io/nokia/srlinux}:${SRL_VERSION:=latest} 10 | type: ${SRL_TYPE:=ixrd3l} 11 | -------------------------------------------------------------------------------- /lab-examples/srl-quickstart/srl02.clab.yml: -------------------------------------------------------------------------------- 1 | name: srl2 2 | # node names will be srl1 and srl2 unless overridden by CLAB_PREFIX 3 | prefix: ${CLAB_PREFIX:=""} 4 | 5 | topology: 6 | nodes: 7 | srl1: 8 | kind: nokia_srlinux 9 | image: ghcr.io/nokia/srlinux:${SRL_VERSION:=latest} 10 | type: ${SRL_TYPE:=ixrd3l} 11 | 12 | srl2: 13 | kind: nokia_srlinux 14 | image: ghcr.io/nokia/srlinux:${SRL_VERSION:=latest} 15 | type: ${SRL_TYPE:=ixrd3l} 16 | 17 | links: 18 | - endpoints: [srl1:e1-1, srl2:e1-1] 19 | - endpoints: [srl1:e1-2, srl2:e1-2] 20 | -------------------------------------------------------------------------------- /lab-examples/srl01/srl01.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/single-srl/ 2 | name: srl01 3 | 4 | topology: 5 | kinds: 6 | nokia_srlinux: 7 | type: ixrd3 8 | image: ghcr.io/nokia/srlinux 9 | nodes: 10 | srl: 11 | kind: nokia_srlinux 12 | -------------------------------------------------------------------------------- /lab-examples/srl02/srl02.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/two-srls/ 2 | name: srl02 3 | 4 | topology: 5 | nodes: 6 | srl1: 7 | kind: nokia_srlinux 8 | image: ghcr.io/nokia/srlinux 9 | startup-config: srl1.cfg 10 | srl2: 11 | kind: nokia_srlinux 12 | image: ghcr.io/nokia/srlinux 13 | startup-config: srl2.cfg 14 | 15 | links: 16 | - endpoints: ["srl1:e1-1", "srl2:e1-1"] 17 | -------------------------------------------------------------------------------- /lab-examples/srl02/srl1.cfg: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 0 3 | set / interface ethernet-1/1 subinterface 0 ipv4 4 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 5 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.0/31 6 | set / interface ethernet-1/1 subinterface 0 ipv6 7 | set / interface ethernet-1/1 subinterface 0 ipv6 admin-state enable 8 | set / interface ethernet-1/1 subinterface 0 ipv6 address 2002::192.168.0.0/127 9 | 10 | set / network-instance default 11 | set / network-instance default interface ethernet-1/1.0 12 | -------------------------------------------------------------------------------- /lab-examples/srl02/srl2.cfg: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 0 3 | set / interface ethernet-1/1 subinterface 0 ipv4 4 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 5 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.1/31 6 | set / interface ethernet-1/1 subinterface 0 ipv6 7 | set / interface ethernet-1/1 subinterface 0 ipv6 admin-state enable 8 | set / interface ethernet-1/1 subinterface 0 ipv6 address 2002::192.168.0.1/127 9 | 10 | set / network-instance default 11 | set / network-instance default interface ethernet-1/1.0 -------------------------------------------------------------------------------- /lab-examples/srlceos01/srlceos01.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/srl-ceos/ 2 | name: srlceos01 3 | 4 | topology: 5 | nodes: 6 | srl: 7 | kind: nokia_srlinux 8 | image: ghcr.io/nokia/srlinux:24.10 9 | ceos: 10 | kind: arista_ceos 11 | image: ceos:4.32.0F 12 | 13 | links: 14 | - endpoints: ["srl:ethernet-1/1", "ceos:eth1"] 15 | -------------------------------------------------------------------------------- /lab-examples/srlcrpd01/srlcrpd01.clab.yml: -------------------------------------------------------------------------------- 1 | # topology documentation: http://containerlab.dev/lab-examples/srl-crpd/ 2 | name: srlcrpd01 3 | topology: 4 | nodes: 5 | crpd: 6 | kind: juniper_crpd 7 | image: crpd:20.2R1.10 8 | srl: 9 | kind: nokia_srlinux 10 | image: ghcr.io/nokia/srlinux 11 | 12 | links: 13 | - endpoints: ["srl:e1-1", "crpd:eth1"] 14 | -------------------------------------------------------------------------------- /lab-examples/srlfrr01/frr.cfg: -------------------------------------------------------------------------------- 1 | interface eth1 2 | ip address 192.168.1.2/24 3 | ! 4 | interface lo 5 | ip address 10.10.10.2/32 6 | ! 7 | router bgp 65001 8 | bgp router-id 10.10.10.2 9 | neighbor 192.168.1.1 remote-as 65001 10 | ! 11 | address-family ipv4 unicast 12 | network 10.10.10.2/32 13 | exit-address-family -------------------------------------------------------------------------------- /lab-examples/srlfrr01/srl.cfg: -------------------------------------------------------------------------------- 1 | # enter candidate datastore 2 | enter candidate 3 | 4 | # configure loopback and data interfaces 5 | set / interface ethernet-1/1 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 admin-state enable 7 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.1.1/24 8 | 9 | set / interface lo0 subinterface 0 admin-state enable 10 | set / interface lo0 subinterface 0 ipv4 address 10.10.10.1/32 11 | set / network-instance default interface ethernet-1/1.0 12 | set / network-instance default interface lo0.0 13 | 14 | # configure BGP 15 | set / network-instance default protocols bgp admin-state enable 16 | set / network-instance default protocols bgp router-id 10.10.10.1 17 | set / network-instance default protocols bgp autonomous-system 65001 18 | set / network-instance default protocols bgp group ibgp ipv4-unicast admin-state enable 19 | set / network-instance default protocols bgp group ibgp export-policy export-lo 20 | set / network-instance default protocols bgp neighbor 192.168.1.2 admin-state enable 21 | set / network-instance default protocols bgp neighbor 192.168.1.2 peer-group ibgp 22 | set / network-instance default protocols bgp neighbor 192.168.1.2 peer-as 65001 23 | 24 | # create export policy 25 | set / routing-policy policy export-lo statement 10 match protocol local 26 | set / routing-policy policy export-lo statement 10 action accept 27 | 28 | # commit config 29 | commit now -------------------------------------------------------------------------------- /lab-examples/srlfrr01/srlfrr01.clab.yml: -------------------------------------------------------------------------------- 1 | name: srlfrr01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | frr: 9 | kind: linux 10 | image: frrouting/frr:v7.5.0 11 | binds: 12 | - daemons:/etc/frr/daemons 13 | 14 | links: 15 | - endpoints: ["srl:e1-1", "frr:eth1"] 16 | -------------------------------------------------------------------------------- /lab-examples/srlvjunos01/srl.cli: -------------------------------------------------------------------------------- 1 | interface ethernet-1/1 { 2 | admin-state enable 3 | subinterface 0 { 4 | ipv4 { 5 | admin-state enable 6 | address 192.168.0.2/24 { 7 | } 8 | } 9 | } 10 | } 11 | interface ethernet-1/2 { 12 | admin-state enable 13 | subinterface 0 { 14 | ipv4 { 15 | admin-state enable 16 | address 192.168.1.2/24 { 17 | } 18 | } 19 | } 20 | } 21 | interface ethernet-1/3 { 22 | admin-state enable 23 | subinterface 0 { 24 | ipv4 { 25 | admin-state enable 26 | address 192.168.2.2/24 { 27 | } 28 | } 29 | } 30 | } 31 | 32 | network-instance default { 33 | interface ethernet-1/1.0 { 34 | } 35 | interface ethernet-1/2.0 { 36 | } 37 | interface ethernet-1/3.0 { 38 | } 39 | } -------------------------------------------------------------------------------- /lab-examples/srlvjunos01/srlvjunos01.clab.yml: -------------------------------------------------------------------------------- 1 | name: srlvjunos01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux:23.7.1 8 | startup-config: srl.cli 9 | 10 | vswitch: 11 | kind: juniper_vjunosswitch 12 | image: vrnetlab/vr-vjunosswitch:23.2R1.14 13 | startup-config: vjunos.cfg 14 | 15 | links: 16 | - endpoints: ["srl:e1-1", "vswitch:eth1"] 17 | - endpoints: ["srl:e1-2", "vswitch:eth2"] 18 | - endpoints: ["srl:e1-3", "vswitch:eth3"] 19 | -------------------------------------------------------------------------------- /lab-examples/srlvjunos01/vjunos.cfg: -------------------------------------------------------------------------------- 1 | interfaces { 2 | ge-0/0/0 { 3 | unit 0 { 4 | family inet { 5 | address 192.168.0.1/24; 6 | } 7 | } 8 | } 9 | ge-0/0/1 { 10 | unit 0 { 11 | family inet { 12 | address 192.168.1.1/24; 13 | } 14 | } 15 | } 16 | ge-0/0/2 { 17 | unit 0 { 18 | family inet { 19 | address 192.168.2.1/24; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lab-examples/srlvjunos02/srl.cli: -------------------------------------------------------------------------------- 1 | interface ethernet-1/1 { 2 | admin-state enable 3 | subinterface 0 { 4 | ipv4 { 5 | admin-state enable 6 | address 192.168.0.2/24 { 7 | } 8 | } 9 | } 10 | } 11 | interface ethernet-1/2 { 12 | admin-state enable 13 | subinterface 0 { 14 | ipv4 { 15 | admin-state enable 16 | address 192.168.1.2/24 { 17 | } 18 | } 19 | } 20 | } 21 | interface ethernet-1/3 { 22 | admin-state enable 23 | subinterface 0 { 24 | ipv4 { 25 | admin-state enable 26 | address 192.168.2.2/24 { 27 | } 28 | } 29 | } 30 | } 31 | 32 | network-instance default { 33 | interface ethernet-1/1.0 { 34 | } 35 | interface ethernet-1/2.0 { 36 | } 37 | interface ethernet-1/3.0 { 38 | } 39 | } -------------------------------------------------------------------------------- /lab-examples/srlvjunos02/srlvjunos02.clab.yml: -------------------------------------------------------------------------------- 1 | name: srlvjunos02 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux:23.7.1 8 | startup-config: srl.cli 9 | 10 | vevo: 11 | kind: juniper_vjunosevolved 12 | image: vrnetlab/vr-vjunosevolved:23.2R1-S1.8-EVO 13 | startup-config: vjunos.cfg 14 | 15 | links: 16 | - endpoints: ["srl:e1-1", "vevo:eth1"] 17 | - endpoints: ["srl:e1-2", "vevo:eth2"] 18 | - endpoints: ["srl:e1-3", "vevo:eth3"] 19 | -------------------------------------------------------------------------------- /lab-examples/srlvjunos02/vjunos.cfg: -------------------------------------------------------------------------------- 1 | interfaces { 2 | et-0/0/0 { 3 | unit 0 { 4 | family inet { 5 | address 192.168.0.1/24; 6 | } 7 | } 8 | } 9 | et-0/0/1 { 10 | unit 0 { 11 | family inet { 12 | address 192.168.1.1/24; 13 | } 14 | } 15 | } 16 | et-0/0/2 { 17 | unit 0 { 18 | family inet { 19 | address 192.168.2.1/24; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lab-examples/srlxrd01/srl.cfg: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 0 3 | set / interface ethernet-1/1 subinterface 0 ipv4 4 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 5 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.0/31 6 | set / interface ethernet-1/1 subinterface 0 ipv6 7 | set / interface ethernet-1/1 subinterface 0 ipv6 admin-state enable 8 | set / interface ethernet-1/1 subinterface 0 ipv6 address 2002::192.168.0.0/127 9 | 10 | set / network-instance default 11 | set / network-instance default interface ethernet-1/1.0 -------------------------------------------------------------------------------- /lab-examples/srlxrd01/srlxrd01.clab.yml: -------------------------------------------------------------------------------- 1 | name: srlxrd01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | startup-config: srl.cfg 9 | 10 | xrd: 11 | kind: cisco_xrd 12 | image: xrd-control-plane 13 | startup-config: xrd.cfg 14 | 15 | links: 16 | - endpoints: ["srl:e1-1", "xrd:Gi0-0-0-0"] 17 | -------------------------------------------------------------------------------- /lab-examples/srlxrd01/xrd.cfg: -------------------------------------------------------------------------------- 1 | ! 2 | hostname {{ .ShortName }} 3 | ! 4 | username clab 5 | group root-lr 6 | group cisco-support 7 | secret clab@123 8 | ! 9 | grpc 10 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 11 | port 9339 12 | no-tls 13 | address-family dual 14 | ! 15 | {{- if .Env.CLAB_MGMT_VRF }} 16 | vrf {{ .Env.CLAB_MGMT_VRF }} 17 | address-family ipv4 unicast 18 | ! 19 | address-family ipv6 unicast 20 | ! 21 | {{- end}} 22 | ! 23 | line default 24 | transport input ssh 25 | ! 26 | netconf-yang agent 27 | ssh 28 | ! 29 | interface MgmtEth0/RP0/CPU0/0 30 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 31 | ! 32 | interface GigabitEthernet0/0/0/0 33 | ipv4 address 192.168.0.1 255.255.255.254 34 | ! 35 | router static 36 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 37 | {{- if .MgmtIPv4Gateway }} 38 | address-family ipv4 unicast 39 | 0.0.0.0/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv4Gateway }} 40 | ! 41 | {{- end}} 42 | {{- if .MgmtIPv6Gateway }} 43 | address-family ipv6 unicast 44 | ::/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv6Gateway }} 45 | ! 46 | {{- end}} 47 | ! 48 | ssh server v2 49 | {{- if .Env.CLAB_MGMT_VRF }} 50 | ssh server vrf {{ .Env.CLAB_MGMT_VRF }} 51 | {{- end}} 52 | ssh server netconf {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 53 | end 54 | -------------------------------------------------------------------------------- /lab-examples/templated01/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # make sure gnmic is installed 6 | gnmic --help >/dev/null 7 | # make sure gomplate is installed 8 | gomplate --help >/dev/null 9 | # make sure curl is installed 10 | curl --help >/dev/null 11 | 12 | # generate the variables file based on the number of spines and leaves in the topology 13 | gomplate -f topology_config.gotmpl -d templated01.clab_vars.yaml >vars.yaml 14 | 15 | # build targets string 16 | targets=$(docker ps -f label=clab-node-kind=nokia_srlinux -f label=containerlab=templated01 --format {{.Names}} | paste -s -d, -) 17 | # base gnmic command 18 | gnmic_cmd="gnmic --log -a ${targets} --skip-verify -u admin -p NokiaSrl1!" 19 | 20 | curl -sLO https://raw.githubusercontent.com/karimra/gnmic/main/examples/set-request-templates/Nokia/SRL/1.interfaces/interfaces_template.gotmpl 21 | curl -sLO https://raw.githubusercontent.com/karimra/gnmic/main/examples/set-request-templates/Nokia/SRL/1.interfaces/subinterfaces_template.gotmpl 22 | 23 | # run gNMI interfaces config 24 | $gnmic_cmd \ 25 | set \ 26 | --request-file interfaces_template.gotmpl \ 27 | --request-vars vars.yaml 28 | 29 | # run gNMI subinterfaces config 30 | $gnmic_cmd \ 31 | set \ 32 | --request-file subinterfaces_template.gotmpl \ 33 | --request-vars vars.yaml 34 | 35 | # delete generated variables file 36 | rm vars.yaml 37 | 38 | # delete downloaded templates 39 | rm interfaces_template.gotmpl 40 | rm subinterfaces_template.gotmpl 41 | -------------------------------------------------------------------------------- /lab-examples/templated01/templated01.clab.gotmpl: -------------------------------------------------------------------------------- 1 | name: templated01 2 | 3 | topology: 4 | defaults: 5 | kind: nokia_srlinux 6 | kinds: 7 | nokia_srlinux: 8 | image: ghcr.io/nokia/srlinux 9 | 10 | nodes: 11 | # spines 12 | {{- range $spineIndex := seq 1 $.spines.num }} 13 | {{ $.spines.prefix }}{{ $spineIndex }}: 14 | type: {{ $.spines.type }} 15 | {{- end }} 16 | # leaves 17 | {{- range $leafIndex := seq 1 $.leaves.num }} 18 | {{ $.leaves.prefix }}{{ $leafIndex }}: 19 | type: {{ $.leaves.type }} 20 | {{- end }} 21 | 22 | links: 23 | {{- range $spineIndex := seq 1 $.spines.num }} 24 | # {{ $.spines.prefix }}{{ $spineIndex }} 25 | {{- range $leafIndex := seq 1 $.leaves.num }} 26 | - endpoints: ["{{ $.spines.prefix }}{{ $spineIndex }}:e1-{{ $leafIndex }}", "{{ $.leaves.prefix }}{{ $leafIndex }}:e1-{{ $spineIndex }}"] 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /lab-examples/templated01/templated01.clab_vars.yaml: -------------------------------------------------------------------------------- 1 | spines: 2 | # SRL spine type 3 | type: ixrd3 4 | # number of spines 5 | num: 2 6 | # prefix of spines name: ${prefix}${index} 7 | prefix: spine 8 | leaves: 9 | # SRL leaf type 10 | type: ixrd3 11 | # number of leaves 12 | num: 4 13 | # prefix of leaf name: ${prefix}${index} 14 | prefix: leaf 15 | -------------------------------------------------------------------------------- /lab-examples/templated02/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # make sure gnmic is installed 6 | gnmic --help >/dev/null 7 | # make sure gomplate is installed 8 | gomplate --help >/dev/null 9 | # make sure curl is installed 10 | curl --help >/dev/null 11 | 12 | # generate the variables file based on the number of spines and leaves in the topology 13 | gomplate -f topology_config.gotmpl -d templated02.clab_vars.yaml >vars.yaml 14 | 15 | # build targets string 16 | targets=$(docker ps -f label=clab-node-kind=nokia_srlinux -f label=containerlab=templated02 --format {{.Names}} | paste -s -d, -) 17 | # base gnmic command 18 | gnmic_cmd="gnmic --log -a ${targets} --skip-verify -u admin -p NokiaSrl1!" 19 | 20 | curl -sLO https://raw.githubusercontent.com/karimra/gnmic/main/examples/set-request-templates/Nokia/SRL/1.interfaces/interfaces_template.gotmpl 21 | curl -sLO https://raw.githubusercontent.com/karimra/gnmic/main/examples/set-request-templates/Nokia/SRL/1.interfaces/subinterfaces_template.gotmpl 22 | 23 | # run gNMI interfaces config 24 | $gnmic_cmd \ 25 | set \ 26 | --request-file interfaces_template.gotmpl \ 27 | --request-vars vars.yaml 28 | 29 | # run gNMI subinterfaces config 30 | $gnmic_cmd \ 31 | set \ 32 | --request-file subinterfaces_template.gotmpl \ 33 | --request-vars vars.yaml 34 | 35 | # delete generated variables file 36 | rm vars.yaml 37 | 38 | # delete downloaded templates 39 | rm interfaces_template.gotmpl 40 | rm subinterfaces_template.gotmpl 41 | -------------------------------------------------------------------------------- /lab-examples/templated02/templated02.clab_vars.yaml: -------------------------------------------------------------------------------- 1 | super_spines: 2 | # SRL super spine type 3 | type: ixrd3l 4 | # number of super spines 5 | num: 2 6 | # prefix of super spines name: ${prefix}${index} 7 | prefix: super-spine 8 | 9 | pods: 10 | # number of pods 11 | num: 4 12 | spines: 13 | # SRL spine type 14 | type: ixrd3l 15 | # number of spines per pod 16 | num: 2 17 | # prefix of spines name: ${prefix}${pod_index}-${index} 18 | prefix: spine 19 | leaves: 20 | # SRL leaf type 21 | type: ixrd2l 22 | # number of leaves per pod 23 | num: 4 24 | # prefix of leaf name: ${prefix}${pod_index}-${index} 25 | prefix: leaf 26 | -------------------------------------------------------------------------------- /lab-examples/vr01/srl.cfg: -------------------------------------------------------------------------------- 1 | enter candidate 2 | set / interface ethernet-1/1 admin-state enable 3 | set / interface ethernet-1/1 subinterface 0 4 | set / interface ethernet-1/1 subinterface 0 ipv4 5 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.1.1/24 7 | set / network-instance default 8 | set / network-instance default interface ethernet-1/1.0 9 | commit now -------------------------------------------------------------------------------- /lab-examples/vr01/vr01.clab.yml: -------------------------------------------------------------------------------- 1 | name: vr01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | sros: 9 | kind: nokia_sros 10 | image: nokia_sros:20.10.R1 11 | type: sr-1 12 | license: /opt/nokia/sros/license-sros20.txt # Not included in the lab, ask your Nokia representative 13 | 14 | links: 15 | - endpoints: ["srl:e1-1", "sros:eth1"] 16 | -------------------------------------------------------------------------------- /lab-examples/vr02/srl.cfg: -------------------------------------------------------------------------------- 1 | enter candidate 2 | set / interface ethernet-1/1 admin-state enable 3 | set / interface ethernet-1/1 subinterface 0 4 | set / interface ethernet-1/1 subinterface 0 ipv4 5 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.1.1/24 7 | set / network-instance default 8 | set / network-instance default interface ethernet-1/1.0 9 | commit now -------------------------------------------------------------------------------- /lab-examples/vr02/vmx.cfg: -------------------------------------------------------------------------------- 1 | configure 2 | set interfaces ge-0/0/0 unit 0 family inet address 192.168.1.2/24 3 | commit 4 | -------------------------------------------------------------------------------- /lab-examples/vr02/vr02.clab.yml: -------------------------------------------------------------------------------- 1 | name: vr02 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | vmx: 9 | kind: juniper_vmx 10 | image: vrnetlab/vr-vmx:20.2R1.10 11 | 12 | links: 13 | - endpoints: ["srl:e1-1", "vmx:eth1"] 14 | -------------------------------------------------------------------------------- /lab-examples/vr03/srl.cfg: -------------------------------------------------------------------------------- 1 | enter candidate 2 | set / interface ethernet-1/1 admin-state enable 3 | set / interface ethernet-1/1 subinterface 0 4 | set / interface ethernet-1/1 subinterface 0 ipv4 5 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.1.1/24 7 | set / network-instance default 8 | set / network-instance default interface ethernet-1/1.0 9 | commit now -------------------------------------------------------------------------------- /lab-examples/vr03/vr03.clab.yml: -------------------------------------------------------------------------------- 1 | name: vr03 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | xrv: 9 | kind: cisco_xrv 10 | image: vrnetlab/vr-xrv:6.1.2 11 | 12 | links: 13 | - endpoints: ["srl:e1-1", "xrv:eth1"] 14 | -------------------------------------------------------------------------------- /lab-examples/vr03/xrv.cfg: -------------------------------------------------------------------------------- 1 | configure 2 | interface Gi0/0/0/0 ipv4 address 192.168.1.2 255.255.255.0 3 | commit -------------------------------------------------------------------------------- /lab-examples/vr04/srl.cfg: -------------------------------------------------------------------------------- 1 | enter candidate 2 | set / interface ethernet-1/1 admin-state enable 3 | set / interface ethernet-1/1 subinterface 0 4 | set / interface ethernet-1/1 subinterface 0 ipv4 5 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.1.1/24 7 | set / network-instance default 8 | set / network-instance default interface ethernet-1/1.0 9 | commit now -------------------------------------------------------------------------------- /lab-examples/vr04/vr04.clab.yml: -------------------------------------------------------------------------------- 1 | name: vr04 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | xrv9k: 9 | kind: cisco_xrv9k 10 | image: vr-xrv9k:7.2.1 # do not forget to re-tag the image if needed 11 | 12 | links: 13 | - endpoints: ["srl:e1-1", "xrv9k:eth1"] 14 | -------------------------------------------------------------------------------- /lab-examples/vr04/xrv9k.cfg: -------------------------------------------------------------------------------- 1 | configure 2 | interface GigabitEthernet 0/0/0/0 3 | ipv4 address 192.168.1.2/24 4 | no shutdown 5 | commit -------------------------------------------------------------------------------- /lab-examples/vr05/sros4.clab.yml: -------------------------------------------------------------------------------- 1 | name: conf1 2 | 3 | topology: 4 | defaults: 5 | kind: nokia_sros 6 | image: vrnetlab/vr-sros:21.2.R1 7 | license: ~/license/sros.txt 8 | config: 9 | vars: 10 | isis_iid: 1 11 | nodes: 12 | sr1: 13 | config: 14 | vars: 15 | clab_system_ip: 10.0.50.31/32 16 | sid_idx: 1 17 | sr2: 18 | config: 19 | vars: 20 | clab_system_ip: 10.0.50.32/32 21 | sid_idx: 2 22 | sr3: 23 | config: 24 | vars: 25 | clab_system_ip: 10.0.50.33/32 26 | sid_idx: 3 27 | sr4: 28 | config: 29 | vars: 30 | clab_system_ip: 10.0.50.34/32 31 | sid_idx: 4 32 | links: 33 | - endpoints: [sr1:eth1, sr2:eth2] 34 | vars: 35 | port: [1/1/c1/1, 1/1/c2/1] 36 | clab_link_ip: 1.1.1.2/30 37 | vlan: [99, 99] 38 | isis_iid: 1 39 | - endpoints: [sr2:eth1, sr3:eth2] 40 | vars: 41 | port: [1/1/c1/1, 1/1/c2/1] 42 | vlan: 98 43 | isis_iid: 1 44 | - endpoints: [sr3:eth1, sr4:eth2] 45 | vars: 46 | port: [1/1/c1/1, 1/1/c2/1] 47 | isis_iid: 1 48 | - endpoints: [sr4:eth1, sr1:eth2] 49 | vars: 50 | port: [1/1/c1/1, 1/1/c2/1] 51 | isis_iid: 1 52 | -------------------------------------------------------------------------------- /lab-examples/vr05/vr01.clab.yml: -------------------------------------------------------------------------------- 1 | name: vr01 2 | 3 | topology: 4 | nodes: 5 | srl: 6 | kind: nokia_srlinux 7 | image: ghcr.io/nokia/srlinux 8 | config: 9 | vars: 10 | clab_system_ip: 10.0.50.50/32 11 | isis_iid: 1 12 | sid_idx: 11 13 | sros: 14 | kind: nokia_sros 15 | image: vrnetlab/vr-sros:21.2.R1 16 | type: sr-1 17 | license: ~/license/sros.txt 18 | config: 19 | vars: 20 | clab_system_ip: 10.0.50.51/32 21 | sid_idx: 10 22 | isis_iid: 1 23 | 24 | links: 25 | - endpoints: ["srl:e1-1", "sros:eth1"] 26 | vars: 27 | port: [ethernet-1/1, 1/1/c1/1] 28 | vlan: 10 29 | isis_iid: 1 30 | -------------------------------------------------------------------------------- /lab-examples/vsrx01/srx1.cfg: -------------------------------------------------------------------------------- 1 | interfaces ge-0/0/0 { 2 | unit 0 { 3 | family { 4 | inet { 5 | address 192.168.1.1/30; 6 | } 7 | } 8 | } 9 | } 10 | interfaces ge-0/0/1 { 11 | unit 0 { 12 | family { 13 | inet { 14 | address 192.168.2.1/30; 15 | } 16 | } 17 | } 18 | } 19 | security { 20 | zones { 21 | security-zone trust { 22 | interfaces ge-0/0/0 { 23 | host-inbound-traffic { 24 | system-services all; 25 | } 26 | } 27 | interfaces ge-0/0/1 { 28 | host-inbound-traffic { 29 | system-services all; 30 | } 31 | } 32 | } 33 | } 34 | forwarding-options { 35 | family { 36 | mpls { 37 | mode { 38 | packet-based; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | system { 45 | services { 46 | web-management { 47 | https { 48 | system-generated-certificate; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lab-examples/vsrx01/vsrx01.yml: -------------------------------------------------------------------------------- 1 | name: vsrx1 2 | topology: 3 | nodes: 4 | srx1: 5 | kind: juniper_vsrx 6 | image: vrnetlab/vr-vsrx:23.2R1.13 7 | startup-config: srx1.cfg 8 | client1: 9 | kind: "linux" 10 | image: wbitt/network-multitool:alpine-extra 11 | exec: 12 | - ip addr add 192.168.1.2/30 dev eth1 13 | - ip route add 192.168.2.0/30 via 192.168.1.1 14 | client2: 15 | kind: "linux" 16 | image: wbitt/network-multitool:alpine-extra 17 | exec: 18 | - ip addr add 192.168.2.2/30 dev eth1 19 | - ip route add 192.168.1.0/30 via 192.168.2.1 20 | links: 21 | - endpoints: ["srx1:eth1", "client1:eth1"] 22 | - endpoints: ["srx1:eth2", "client2:eth1"] 23 | -------------------------------------------------------------------------------- /lab-examples/vxlan01/vxlan-sros.clab.yml: -------------------------------------------------------------------------------- 1 | name: vxlan 2 | 3 | topology: 4 | nodes: 5 | sros: 6 | kind: nokia_sros 7 | image: vr-sros:21.2.R1 8 | license: license-sros20.txt 9 | # vmx node is defined in a `vxlan-vmx.clab.yml` topo file 10 | # that is launched on another VM 11 | 12 | links: 13 | # we expose two sros container interfaces 14 | # to host namespace by using host interfaces style 15 | # docs: https://containerlab.dev/manual/network/#host-links 16 | - endpoints: ["sros:eth1", "host:sr-eth1"] 17 | - endpoints: ["sros:eth2", "host:sr-eth2"] 18 | -------------------------------------------------------------------------------- /lab-examples/vxlan01/vxlan-vmx.clab.yml: -------------------------------------------------------------------------------- 1 | name: vxlan 2 | 3 | topology: 4 | nodes: 5 | vmx: 6 | kind: juniper_vmx 7 | image: vrnetlab/vr-vmx:20.4R1.12 8 | # sros node is defined in a `vxlan-sros.clab.yml` topo file 9 | # that is launched on another VM 10 | 11 | links: 12 | # we expose two sros container interfaces 13 | # to host namespace by using host interfaces style 14 | # docs: https://containerlab.dev/manual/network/#host-links 15 | - endpoints: ["vmx:eth1", "host:vmx-eth1"] 16 | - endpoints: ["vmx:eth2", "host:vmx-eth2"] 17 | -------------------------------------------------------------------------------- /labels/labels.go: -------------------------------------------------------------------------------- 1 | package labels 2 | 3 | const ( 4 | // label names constants. 5 | Containerlab = "containerlab" 6 | NodeName = "clab-node-name" 7 | LongName = "clab-node-longname" 8 | NodeKind = "clab-node-kind" 9 | NodeType = "clab-node-type" 10 | NodeGroup = "clab-node-group" 11 | NodeLabDir = "clab-node-lab-dir" 12 | TopoFile = "clab-topo-file" 13 | NodeMgmtNetBr = "clab-mgmt-net-bridge" 14 | Owner = "clab-owner" 15 | ) 16 | -------------------------------------------------------------------------------- /links/endpoint_dummy.go: -------------------------------------------------------------------------------- 1 | package links 2 | 3 | import "context" 4 | 5 | type EndpointDummy struct { 6 | EndpointGeneric 7 | } 8 | 9 | func NewEndpointDummy(eg *EndpointGeneric) *EndpointDummy { 10 | return &EndpointDummy{ 11 | EndpointGeneric: *eg, 12 | } 13 | } 14 | 15 | // Verify verifies the veth based deployment pre-conditions. 16 | func (e *EndpointDummy) Verify(_ context.Context, _ *VerifyLinkParams) error { 17 | return CheckEndpointUniqueness(e) 18 | } 19 | 20 | func (e *EndpointDummy) Deploy(ctx context.Context) error { 21 | return e.GetLink().Deploy(ctx, e) 22 | } 23 | 24 | func (*EndpointDummy) IsNodeless() bool { 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /links/endpoint_host.go: -------------------------------------------------------------------------------- 1 | package links 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | ) 7 | 8 | type EndpointHost struct { 9 | EndpointGeneric 10 | } 11 | 12 | func NewEndpointHost(eg *EndpointGeneric) *EndpointHost { 13 | return &EndpointHost{ 14 | EndpointGeneric: *eg, 15 | } 16 | } 17 | 18 | func (e *EndpointHost) Deploy(ctx context.Context) error { 19 | return e.GetLink().Deploy(ctx, e) 20 | } 21 | 22 | func (e *EndpointHost) Verify(ctx context.Context, _ *VerifyLinkParams) error { 23 | var errs []error 24 | err := CheckEndpointUniqueness(e) 25 | if err != nil { 26 | errs = append(errs, err) 27 | } 28 | err = CheckEndpointDoesNotExistYet(ctx, e) 29 | if err != nil { 30 | errs = append(errs, err) 31 | } 32 | if len(errs) > 0 { 33 | return errors.Join(errs...) 34 | } 35 | return nil 36 | } 37 | 38 | func (e *EndpointHost) IsNodeless() bool { 39 | return true 40 | } 41 | -------------------------------------------------------------------------------- /links/endpoint_macvlan.go: -------------------------------------------------------------------------------- 1 | package links 2 | 3 | import "context" 4 | 5 | type EndpointMacVlan struct { 6 | EndpointGeneric 7 | } 8 | 9 | func NewEndpointMacVlan(eg *EndpointGeneric) *EndpointMacVlan { 10 | return &EndpointMacVlan{ 11 | EndpointGeneric: *eg, 12 | } 13 | } 14 | 15 | func (e *EndpointMacVlan) Deploy(ctx context.Context) error { 16 | return e.GetLink().Deploy(ctx, e) 17 | } 18 | 19 | // Verify runs verification to check if the endpoint can be deployed. 20 | func (e *EndpointMacVlan) Verify(ctx context.Context, _ *VerifyLinkParams) error { 21 | return CheckEndpointExists(ctx, e) 22 | } 23 | 24 | func (e *EndpointMacVlan) IsNodeless() bool { 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /links/endpoint_veth.go: -------------------------------------------------------------------------------- 1 | package links 2 | 3 | import "context" 4 | 5 | type EndpointVeth struct { 6 | EndpointGeneric 7 | } 8 | 9 | func NewEndpointVeth(eg *EndpointGeneric) *EndpointVeth { 10 | return &EndpointVeth{ 11 | EndpointGeneric: *eg, 12 | } 13 | } 14 | 15 | // Verify verifies the veth based deployment pre-conditions. 16 | func (e *EndpointVeth) Verify(_ context.Context, _ *VerifyLinkParams) error { 17 | return CheckEndpointUniqueness(e) 18 | } 19 | 20 | func (e *EndpointVeth) Deploy(ctx context.Context) error { 21 | return e.GetLink().Deploy(ctx, e) 22 | } 23 | 24 | func (e *EndpointVeth) IsNodeless() bool { 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /links/endpoint_vxlan.go: -------------------------------------------------------------------------------- 1 | package links 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | ) 8 | 9 | type EndpointVxlan struct { 10 | EndpointGeneric 11 | udpPort int 12 | remote net.IP 13 | parentIface string 14 | vni int 15 | randName string 16 | } 17 | 18 | func NewEndpointVxlan(node Node, link Link) *EndpointVxlan { 19 | return &EndpointVxlan{ 20 | randName: genRandomIfName(), 21 | EndpointGeneric: EndpointGeneric{ 22 | Link: link, 23 | Node: node, 24 | }, 25 | } 26 | } 27 | 28 | func (e *EndpointVxlan) String() string { 29 | return fmt.Sprintf("vxlan remote: %q, udp-port: %d, vni: %d", e.remote, e.udpPort, e.vni) 30 | } 31 | 32 | // Verify verifies that the endpoint is valid and can be deployed. 33 | func (e *EndpointVxlan) Verify(_ context.Context, _ *VerifyLinkParams) error { 34 | return CheckEndpointUniqueness(e) 35 | } 36 | 37 | func (e *EndpointVxlan) Deploy(ctx context.Context) error { 38 | return e.GetLink().Deploy(ctx, e) 39 | } 40 | 41 | func (e *EndpointVxlan) IsNodeless() bool { 42 | return false 43 | } 44 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Nokia 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import "github.com/srl-labs/containerlab/cmd" 8 | 9 | func main() { 10 | cmd.Execute() 11 | } 12 | -------------------------------------------------------------------------------- /mocks/exec.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: clab/exec/exec.go 3 | // 4 | // Generated by this command: 5 | // 6 | // mockgen -package=mocks -source=clab/exec/exec.go -destination=./mocks/exec.go 7 | // 8 | 9 | // Package mocks is a generated GoMock package. 10 | package mocks 11 | -------------------------------------------------------------------------------- /netconf/netconf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Nokia 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | // Package netconf contains netconf-based functions used in containerlab. 6 | package netconf 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/scrapli/scrapligo/driver/netconf" 12 | "github.com/scrapli/scrapligo/driver/options" 13 | "github.com/scrapli/scrapligo/transport" 14 | "github.com/scrapli/scrapligo/util" 15 | ) 16 | 17 | // SaveConfig saves the running config to the startup by means 18 | // of invoking a netconf rpc from running to startup datastore 19 | // this method is used on the network elements that can't perform configuration save via other means. 20 | func SaveConfig(addr, username, password, _ string) error { 21 | opts := []util.Option{ 22 | options.WithAuthNoStrictKey(), 23 | options.WithAuthUsername(username), 24 | options.WithAuthPassword(password), 25 | options.WithTransportType(transport.StandardTransport), 26 | options.WithPort(830), 27 | } 28 | 29 | d, err := netconf.NewDriver( 30 | addr, 31 | opts..., 32 | ) 33 | if err != nil { 34 | return fmt.Errorf("could not create netconf driver for %s: %+v", addr, err) 35 | } 36 | 37 | err = d.Open() 38 | if err != nil { 39 | return fmt.Errorf("failed to open netconf driver for %s: %+v", addr, err) 40 | } 41 | defer d.Close() 42 | 43 | _, err = d.CopyConfig("running", "startup") 44 | if err != nil { 45 | return fmt.Errorf("%s: Could not send save config via Netconf: %+v", addr, err) 46 | } 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /nodes/6wind_vsr/6wind_vsr_default_config.go.tpl: -------------------------------------------------------------------------------- 1 | / vrf main ssh-server 2 | {{- if .SSHPubKeys }} 3 | / system auth 4 | / system auth user admin 5 | / system auth user admin role admin 6 | {{- range $idx, $key := .SSHPubKeys }} 7 | / system auth user admin authorized-key "{{ $key }}" 8 | {{- end }} 9 | {{- end }} 10 | {{- if .License }} 11 | / system license online serial "{{ .License }}" 12 | {{- end }} 13 | {{- if .Banner }} 14 | cmd banner post-login message "{{ .Banner }}" 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /nodes/c8000/c8000.cfg: -------------------------------------------------------------------------------- 1 | ! 2 | hostname {{ .ShortName }} 3 | ! 4 | username cisco123 5 | group root-lr 6 | group cisco-support 7 | secret cisco123 8 | 9 | grpc 10 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 11 | port 9339 12 | no-tls 13 | address-family dual 14 | ! 15 | {{- if .Env.CLAB_MGMT_VRF }} 16 | vrf {{ .Env.CLAB_MGMT_VRF }} 17 | address-family ipv4 unicast 18 | ! 19 | address-family ipv6 unicast 20 | ! 21 | {{- end}} 22 | ! 23 | line default 24 | transport input ssh 25 | ! 26 | netconf-yang agent 27 | ssh 28 | ! 29 | interface MgmtEth0/RP0/CPU0/0 30 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 31 | ! 32 | router static 33 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 34 | {{- if .MgmtIPv4Gateway }} 35 | address-family ipv4 unicast 36 | 0.0.0.0/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv4Gateway }} 37 | ! 38 | {{- end}} 39 | {{- if .MgmtIPv6Gateway }} 40 | address-family ipv6 unicast 41 | ::/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv6Gateway }} 42 | ! 43 | {{- end}} 44 | ! 45 | ssh server v2 46 | {{- if .Env.CLAB_MGMT_VRF }} 47 | ssh server vrf {{ .Env.CLAB_MGMT_VRF }} 48 | {{- end}} 49 | ssh server netconf {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 50 | end 51 | -------------------------------------------------------------------------------- /nodes/ceos/ceos.cfg: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Nokia 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | hostname {{ .ShortName }} 6 | username admin privilege 15 secret admin 7 | ! 8 | service routing protocols model multi-agent 9 | ! 10 | {{- if .Env.CLAB_MGMT_VRF }} 11 | vrf instance {{ .Env.CLAB_MGMT_VRF }} 12 | ! 13 | {{end}} 14 | {{ if .MgmtIPv4Gateway }}ip route {{ if .Env.CLAB_MGMT_VRF }}vrf {{ .Env.CLAB_MGMT_VRF }} {{end}}0.0.0.0/0 {{ .MgmtIPv4Gateway }}{{end}} 15 | {{ if .MgmtIPv6Gateway }}ipv6 route {{ if .Env.CLAB_MGMT_VRF }}vrf {{ .Env.CLAB_MGMT_VRF }} {{end}}::0/0 {{ .MgmtIPv6Gateway }}{{end}} 16 | ! 17 | interface {{ .MgmtIntf }} 18 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 19 | {{ if .MgmtIPv4Address }}ip address {{ .MgmtIPv4Address }}/{{.MgmtIPv4PrefixLength}}{{end}} 20 | {{ if .MgmtIPv6Address }}ipv6 address {{ .MgmtIPv6Address }}/{{.MgmtIPv6PrefixLength}}{{end}} 21 | ! 22 | management api gnmi 23 | transport grpc default 24 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 25 | ! 26 | management api netconf 27 | transport ssh default 28 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 29 | ! 30 | management api http-commands 31 | no shutdown 32 | {{- if .Env.CLAB_MGMT_VRF }} 33 | ! 34 | vrf {{ .Env.CLAB_MGMT_VRF }} 35 | no shutdown 36 | {{end}} 37 | ! 38 | end 39 | -------------------------------------------------------------------------------- /nodes/crpd/crpd.cfg: -------------------------------------------------------------------------------- 1 | system { 2 | root-authentication { 3 | encrypted-password "$6$lB5c6$Zeud8c6IhCTE6hnZxXBl3ZMZTC2hOx9pxxYUWTHKW1oC32SATWLMH2EXarxWS5k685qMggUfFur1lq.o4p4cg1"; ## SECRET-DATA 4 | } 5 | services { 6 | ssh { 7 | root-login allow; 8 | } 9 | netconf { 10 | ssh; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /nodes/fdio_vpp/vpp_startup_config.go.tpl: -------------------------------------------------------------------------------- 1 | ## VPP Startup configuration 2 | ## Generated by clab 3 | 4 | unix { 5 | interactive 6 | log /var/log/vpp/vpp.log 7 | full-coredump 8 | cli-listen /run/vpp/cli.sock 9 | cli-prompt {{ .ShortName }}# 10 | cli-no-pager 11 | poll-sleep-usec 100 12 | exec /etc/vpp/bootstrap.vpp 13 | } 14 | 15 | api-trace { 16 | on 17 | } 18 | 19 | memory { 20 | main-heap-size 512M 21 | main-heap-page-size 4k 22 | } 23 | 24 | buffers { 25 | buffers-per-numa 16000 26 | default data-size 2048 27 | page-size 4k 28 | } 29 | 30 | statseg { 31 | size 64M 32 | page-size 4k 33 | per-node-counters on 34 | } 35 | 36 | plugins { 37 | plugin default { enable } 38 | plugin dpdk_plugin.so { disable } 39 | plugin linux_cp_plugin.so { enable } 40 | plugin linux_nl_plugin.so { enable } 41 | plugin sflow_plugin.so { enable } 42 | } 43 | 44 | linux-cp { 45 | default netns dataplane 46 | lcp-sync 47 | lcp-auto-subint 48 | del-static-on-link-down 49 | del-dynamic-on-link-down 50 | } 51 | -------------------------------------------------------------------------------- /nodes/iol/iol.cfg.tmpl: -------------------------------------------------------------------------------- 1 | hostname {{ .Hostname }} 2 | ! 3 | no aaa new-model 4 | ! 5 | ip domain name lab 6 | ! 7 | ip cef 8 | ! 9 | ipv6 unicast-routing 10 | ! 11 | no ip domain lookup 12 | ! 13 | username admin privilege 15 secret admin 14 | ! 15 | vrf definition clab-mgmt 16 | description clab-mgmt 17 | address-family ipv4 18 | ! 19 | address-family ipv6 20 | ! 21 | ! 22 | interface Ethernet0/0 23 | {{ if .IsL2Node }} 24 | no switchport 25 | {{ end }} 26 | vrf forwarding clab-mgmt 27 | description clab-mgmt 28 | ip address {{ .MgmtIPv4Addr }} {{ .MgmtIPv4SubnetMask }} 29 | ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }} 30 | no shutdown 31 | !{{ range $index, $item := .DataIFaces }} 32 | interface Ethernet{{ .Slot }}/{{ .Port }} 33 | no shutdown 34 | !{{ end }} 35 | ip forward-protocol nd 36 | ! 37 | ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 Ethernet0/0 {{ .MgmtIPv4GW }} 38 | ipv6 route vrf clab-mgmt ::/0 Ethernet0/0 {{ .MgmtIPv6GW }} 39 | ! 40 | ip ssh version 2 41 | crypto key generate rsa modulus 2048 42 | ! 43 | line vty 0 4 44 | login local 45 | transport input ssh 46 | ! 47 | {{ .PartialCfg }} 48 | end 49 | -------------------------------------------------------------------------------- /nodes/srl/macaddr.go: -------------------------------------------------------------------------------- 1 | package srl 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | "math/big" 7 | 8 | "github.com/srl-labs/containerlab/types" 9 | ) 10 | 11 | type mac struct { 12 | MAC string 13 | } 14 | 15 | // genMac returns a struct with a generated MAC address string to use in SR Linux 16 | // topology file. 17 | func genMac(cfg *types.NodeConfig) mac { 18 | // Generated MAC address conforms to the following addressing scheme 19 | // first byte - `1a` - fixed for easy identification of SRL Mac addresses 20 | // second byte - random, to distinguish projects 21 | // third byte - index of the topology node 22 | 23 | projID, _ := rand.Int(rand.Reader, big.NewInt(256)) 24 | macPrefix := fmt.Sprintf("1a:%02x", projID) 25 | 26 | // labs up to 256 nodes are supported, behaviour is undefined when more nodes are defined 27 | m := fmt.Sprintf("%s:%02x:00:00:00", macPrefix, cfg.Index%256) 28 | 29 | // set system Mac in NodeConfig 30 | cfg.MacAddress = m 31 | 32 | return mac{ 33 | MAC: m, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nodes/srl/prompt_test.go: -------------------------------------------------------------------------------- 1 | package srl 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_getPrompt(t *testing.T) { 8 | tests := []struct { 9 | name string 10 | s string 11 | want string 12 | wantErr bool 13 | }{ 14 | { 15 | name: "Test with valid input", 16 | s: `value = "test-prompt"`, 17 | want: "test-prompt", 18 | wantErr: false, 19 | }, 20 | { 21 | name: "Test with invalid input", 22 | s: `invalid input`, 23 | want: "", 24 | wantErr: true, 25 | }, 26 | } 27 | for _, tt := range tests { 28 | t.Run(tt.name, func(t *testing.T) { 29 | got, err := getPrompt(tt.s) 30 | if (err != nil) != tt.wantErr { 31 | t.Errorf("getPrompt() error = %v, wantErr %v", err, tt.wantErr) 32 | return 33 | } 34 | if got != tt.want { 35 | t.Errorf("getPrompt() = %v, want %v", got, tt.want) 36 | } 37 | }) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nodes/srl/test_data/rsa_key: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs4Qv1yrBk6ygt+o7J4sUcYv+WfDjdAyABDoinOt3PgSmCcVqqAP2qS8UtTnMNuy93Orp6+/R/7/R3O5xdY6I4YViK3WVlKTAUVm7vdeTKp9uq1tNeWgo7+J3baSbQ3INp85ScTfFvRzRCFkr/W97Wh6pTa7ysgkcPvc2/tXG2z36Mx7/TFBk3Q1LY3ByKLtGrC5JnVpMTrqrsCwcLEVHHEZ4z5R4FZED/lpz+wTNFnR/l9HA6yDkKYensHynx+guqYpYD6y4yEGY/LcUnwBg0zIlUhmOsvdmxWBz12Lp7EBiNjSwhnPfe+o3efLGGnjWUAa4TgO8Sa8PQP0pK/ZNd -------------------------------------------------------------------------------- /nodes/srl/topology/7215IXSA1.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 80 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 196 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 196 13 | "mda_type": 8 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD1.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 64 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 175 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 175 13 | "mda_type": 196 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD2.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 65 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 176 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 176 13 | "mda_type": 195 # imm48-25g-sfp28+8-100g-qsfp28 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD2L.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 72 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 187 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 187 13 | "mda_type": 208 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD3.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 66 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 177 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 177 13 | "mda_type": 194 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD3L.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 73 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 188 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 188 13 | "mda_type": 202 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD4.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 78 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 189 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 189 13 | "mda_type": 210 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRD5.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 71 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 190 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 190 13 | "mda_type": 201 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH2.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 61 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 179 # imm128-100g-qsfp28 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 179 13 | "mda_type": 197 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH3.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 62 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 178 #IMM2_10g_sfpp_32_400g_qsfpdd 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 178 13 | "mda_type": 198 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH4-32D.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 84 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 18 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 18 13 | "mda_type": 25 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH4.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 79 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 191 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 191 13 | "mda_type": 211 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH5-32D.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 47 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 180 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 180 13 | "mda_type": 106 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH5-64D.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 85 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 171 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 171 13 | "mda_type": 18 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7220IXRH5-64O.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 98 7 | "base_mac": "{{.MAC}}" 8 | "cpm_card_type": 157 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 157 13 | "mda_type": 154 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXR10.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 43 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 69 # cpm2-ixr 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 127 13 | "mda_type": 36 # 32xQSFP28+4xQSFP-DD (imm32-100g-qsfp28+4-400g-qsfpdd) 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXR10e.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 69 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 184 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 182 13 | "mda_type": 199 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXR18e.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 70 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 184 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 33 13 | "mda_type": 13 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXR6.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 42 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 69 # cpm2-ixr 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 127 13 | "mda_type": 36 # 32xQSFP28+4xQSFP-DD (imm32-100g-qsfp28+4-400g-qsfpdd) 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXR6e.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 68 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 184 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 182 13 | "mda_type": 199 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXRX1b.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 82 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 32 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 32 13 | "mda_type": 19 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7250IXRX3b.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 81 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 27 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 27 13 | "mda_type": 12 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7730SXR-1d-32d.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 54 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 11 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 11 13 | "mda_type": 201 14 | -------------------------------------------------------------------------------- /nodes/srl/topology/7730SXR-1x-44s.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | chassis_configuration: 6 | "chassis_type": 51 7 | "base_mac": "{{ .MAC }}" 8 | "cpm_card_type": 177 9 | 10 | slot_configuration: 11 | 1: 12 | "card_type": 2 13 | "mda_type": 40 14 | -------------------------------------------------------------------------------- /nodes/state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | type NodeState uint 4 | 5 | const ( 6 | Unknown NodeState = iota 7 | // Deployed means the underlying container has been started and deploy function succeeded. 8 | Deployed 9 | ) 10 | -------------------------------------------------------------------------------- /nodes/vr_openwrt/vr_openwrt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Nokia 2 | // Licensed under the BSD 3-Clause License. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | package vr_openwrt 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "path/filepath" 10 | 11 | "github.com/srl-labs/containerlab/nodes" 12 | "github.com/srl-labs/containerlab/types" 13 | "github.com/srl-labs/containerlab/utils" 14 | ) 15 | 16 | var kindNames = []string{"openwrt"} 17 | 18 | const ( 19 | generateable = true 20 | generateIfFormat = "eth%d" 21 | ) 22 | 23 | // Register registers the node in the NodeRegistry. 24 | func Register(r *nodes.NodeRegistry) { 25 | generateNodeAttributes := nodes.NewGenerateNodeAttributes(generateable, generateIfFormat) 26 | nrea := nodes.NewNodeRegistryEntryAttributes(nil, generateNodeAttributes, nil) 27 | 28 | r.Register(kindNames, func() nodes.Node { 29 | return new(vrOpenWrt) 30 | }, nrea) 31 | } 32 | 33 | type vrOpenWrt struct { 34 | nodes.DefaultNode 35 | } 36 | 37 | func (n *vrOpenWrt) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error { 38 | // Init DefaultNode 39 | n.DefaultNode = *nodes.NewDefaultNode(n) 40 | 41 | n.Cfg = cfg 42 | for _, o := range opts { 43 | o(n) 44 | } 45 | 46 | // Add a simple bind-mount for the 'overlay' directory 47 | n.Cfg.Binds = append(n.Cfg.Binds, 48 | fmt.Sprint(filepath.Join(n.Cfg.LabDir, "overlay"), ":/overlay"), 49 | ) 50 | 51 | return nil 52 | } 53 | 54 | func (n *vrOpenWrt) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error { 55 | // Ensure the overlay directory exists 56 | utils.CreateDirectory(filepath.Join(n.Cfg.LabDir, "overlay"), 0777) 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /nodes/vr_sros/ssh_keys.go.tpl: -------------------------------------------------------------------------------- 1 | {{/* this is a template for sros public key config for ssh admin user access */}} 2 | 3 | {{/* to enable long list of keys from agent where the configured key may not be in the default first three keys */}} 4 | /configure system security user-params attempts count 64 5 | 6 | {{ range $index, $key := .SSHPubKeysRSA }} 7 | /configure system security user-params local-user user "admin" public-keys rsa rsa-key {{ subtract 32 $index }} key-value {{ $key }} 8 | {{ end }} 9 | 10 | {{ range $index, $key := .SSHPubKeysECDSA }} 11 | /configure system security user-params local-user user "admin" public-keys ecdsa ecdsa-key {{ subtract 32 $index }} key-value {{ $key }} 12 | {{ end }} -------------------------------------------------------------------------------- /nodes/xrd/mgmt_intf_v6_addr.sh.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /pkg/bin/ztp_helper.sh 4 | 5 | xrapply_string "interface MgmtEth0/RP0/CPU0/0\n no ipv6 address\n{{- if .MgmtIPv6Addr }}ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }}\n{{- end}}" -------------------------------------------------------------------------------- /nodes/xrd/xrd.cfg: -------------------------------------------------------------------------------- 1 | ! 2 | hostname {{ .ShortName }} 3 | ! 4 | username clab 5 | group root-lr 6 | group cisco-support 7 | secret clab@123 8 | ! 9 | grpc 10 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 11 | port 9339 12 | no-tls 13 | address-family dual 14 | ! 15 | {{- if .Env.CLAB_MGMT_VRF }} 16 | vrf {{ .Env.CLAB_MGMT_VRF }} 17 | address-family ipv4 unicast 18 | ! 19 | address-family ipv6 unicast 20 | ! 21 | {{- end}} 22 | ! 23 | line default 24 | transport input ssh 25 | ! 26 | netconf-yang agent 27 | ssh 28 | ! 29 | interface MgmtEth0/RP0/CPU0/0 30 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 31 | ! 32 | router static 33 | {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 34 | {{- if .MgmtIPv4Gateway }} 35 | address-family ipv4 unicast 36 | 0.0.0.0/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv4Gateway }} 37 | ! 38 | {{- end}} 39 | {{- if .MgmtIPv6Gateway }} 40 | address-family ipv6 unicast 41 | ::/0 MgmtEth0/RP0/CPU0/0 {{ .MgmtIPv6Gateway }} 42 | ! 43 | {{- end}} 44 | ! 45 | ssh server v2 46 | {{- if .Env.CLAB_MGMT_VRF }} 47 | ssh server vrf {{ .Env.CLAB_MGMT_VRF }} 48 | {{- end}} 49 | ssh server netconf {{ if .Env.CLAB_MGMT_VRF }} vrf {{ .Env.CLAB_MGMT_VRF }}{{end}} 50 | end 51 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "containerlab" 3 | version = "0.1.0" 4 | description = "Containerlab testing framework" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "robotframework==6.1.1", 9 | "robotframework-sshlibrary==3.8.0", 10 | ] 11 | -------------------------------------------------------------------------------- /runtime/all/all.go: -------------------------------------------------------------------------------- 1 | //go:build !podman 2 | // +build !podman 3 | 4 | package all 5 | 6 | import ( 7 | _ "github.com/srl-labs/containerlab/runtime/docker" 8 | _ "github.com/srl-labs/containerlab/runtime/ignite" 9 | ) 10 | -------------------------------------------------------------------------------- /runtime/all/all_with_podman.go: -------------------------------------------------------------------------------- 1 | //go:build linux && podman 2 | // +build linux,podman 3 | 4 | package all 5 | 6 | import ( 7 | _ "github.com/srl-labs/containerlab/runtime/docker" 8 | _ "github.com/srl-labs/containerlab/runtime/ignite" 9 | _ "github.com/srl-labs/containerlab/runtime/podman" 10 | ) 11 | -------------------------------------------------------------------------------- /runtime/docker/firewall/definitions/definitions.go: -------------------------------------------------------------------------------- 1 | package definitions 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ErrNotAvailable = errors.New("not available") 8 | 9 | const ( 10 | DockerUserChain = "DOCKER-USER" 11 | ForwardChain = "FORWARD" 12 | FilterTable = "filter" 13 | AcceptAction = "ACCEPT" 14 | InDirection = "in" 15 | OutDirection = "out" 16 | 17 | ContainerlabComment = "set by containerlab" 18 | 19 | IPTablesCommentMaxSize = 256 20 | ) 21 | 22 | // ClabFirewall is the interface that all firewall clients must implement. 23 | type ClabFirewall interface { 24 | DeleteForwardingRules(rule FirewallRule) error 25 | InstallForwardingRules(rule FirewallRule) error 26 | Name() string 27 | } 28 | 29 | type FirewallRule struct { 30 | Chain string 31 | Table string 32 | Interface string 33 | Direction string 34 | Action string 35 | Comment string 36 | } 37 | -------------------------------------------------------------------------------- /runtime/docker/firewall/firewall.go: -------------------------------------------------------------------------------- 1 | package firewall 2 | 3 | import ( 4 | "github.com/srl-labs/containerlab/runtime/docker/firewall/definitions" 5 | "github.com/srl-labs/containerlab/runtime/docker/firewall/iptables" 6 | "github.com/srl-labs/containerlab/runtime/docker/firewall/nftables" 7 | ) 8 | 9 | // NewFirewallClient returns a firewall client based on the availability of nftables or iptables. 10 | func NewFirewallClient() (definitions.ClabFirewall, error) { 11 | var clf definitions.ClabFirewall 12 | 13 | clf, err := nftables.NewNftablesClient() 14 | if err == nil { 15 | return clf, nil 16 | } 17 | 18 | clf, err = iptables.NewIpTablesClient() 19 | if err == nil { 20 | return clf, nil 21 | } 22 | 23 | return nil, err 24 | } 25 | -------------------------------------------------------------------------------- /runtime/docker/test_data/docker.config: -------------------------------------------------------------------------------- 1 | { 2 | "auths": { 3 | "test.example.com": { 4 | "auth": "dGVzdHVzZXIxOnRlc3RwYXNzMQo=" 5 | }, 6 | "other.example.com": { 7 | "auth": "dGVzdHVzZXI6dGVzdHBhc3MK" 8 | }, 9 | "bad.example.com": { 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /runtime/docker/test_data/invalid_docker.config: -------------------------------------------------------------------------------- 1 | { 2 | "auths": { 3 | "test.example.com": { 4 | "auth": "dGVzdHVzZXIxOnRlc3RwYXNzMQo=" 5 | } 6 | "other.example.com": { 7 | "auth": "dGVzdHVzZXI6dGVzdHBhc3MK" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /tests/01-smoke/01-linux-single-node.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: single-node 6 | 7 | mgmt: 8 | network: test 9 | ipv4-subnet: 172.20.30.0/24 10 | ipv4-range: 172.20.30.8/30 11 | 12 | topology: 13 | nodes: 14 | l1: 15 | kind: linux 16 | image: alpine:3 17 | cmd: ash -c "sleep 9999" 18 | -------------------------------------------------------------------------------- /tests/01-smoke/01-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "containerlab": "is cool" 3 | } -------------------------------------------------------------------------------- /tests/01-smoke/01-test.txt: -------------------------------------------------------------------------------- 1 | Hello, containerlab -------------------------------------------------------------------------------- /tests/01-smoke/03-linux-nodes-to-bridge-and-host.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 03-bridge-and-host 6 | mgmt: 7 | bridge: 01-03-mgmt 8 | 9 | topology: 10 | nodes: 11 | l1: 12 | kind: linux 13 | image: alpine:3 14 | cmd: ash -c "sleep 9999" 15 | br-01-03-clab: 16 | kind: bridge 17 | hostnode: # is not used, it is here for coverage 18 | kind: host 19 | 20 | links: 21 | - endpoints: ["l1:eth1", "br-01-03-clab:l1-eth1"] 22 | - endpoints: ["br-01-03-clab:l1-eth2", "l1:eth2"] 23 | # l1:eth3 is connected to host via host link 24 | # https://containerlab.dev/manual/network/#host-links 25 | - endpoints: ["l1:eth3", "host:l1-01-03-eth3"] 26 | -------------------------------------------------------------------------------- /tests/01-smoke/05-docker-bridge.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 05-docker-bridge 6 | # use the default docker network named "bridge" 7 | mgmt: 8 | network: bridge 9 | 10 | topology: 11 | nodes: 12 | l1: 13 | kind: linux 14 | image: alpine:3 15 | cmd: ash -c "sleep 9999" 16 | -------------------------------------------------------------------------------- /tests/01-smoke/07-linux-single-node.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: single-node 6 | mgmt: 7 | bridge: 01-07-net 8 | 9 | topology: 10 | nodes: 11 | l1: 12 | kind: linux 13 | image: alpine:3 14 | cmd: ash -c "sleep 9999" 15 | -------------------------------------------------------------------------------- /tests/01-smoke/09-external-ca.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: external-ca 6 | 7 | settings: 8 | certificate-authority: 9 | cert: rootCACert.pem 10 | key: rootCAKey.pem 11 | 12 | topology: 13 | nodes: 14 | l1: 15 | kind: linux 16 | image: alpine:3 17 | certificate: 18 | issue: true 19 | -------------------------------------------------------------------------------- /tests/01-smoke/10-internal-ca.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: internal-ca 6 | 7 | settings: 8 | certificate-authority: 9 | key-size: 512 10 | validity-duration: 5h 11 | 12 | topology: 13 | defaults: 14 | certificate: 15 | issue: true 16 | key-size: 512 17 | nodes: 18 | l1: 19 | kind: linux 20 | image: alpine:3 21 | certificate: 22 | issue: true 23 | validity-duration: 25h 24 | l2: 25 | kind: linux 26 | image: alpine:3 27 | certificate: 28 | issue: true 29 | key-size: 1024 30 | sans: 31 | - 192.168.33.44 32 | - my.text.fqdn 33 | l3: 34 | kind: linux 35 | image: alpine:3 36 | certificate: 37 | issue: false 38 | -------------------------------------------------------------------------------- /tests/01-smoke/12-tools-veth.clab.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: dual-node 6 | 7 | topology: 8 | nodes: 9 | n1: 10 | kind: linux 11 | image: alpine:latest 12 | 13 | n2: 14 | kind: linux 15 | image: alpine:latest 16 | -------------------------------------------------------------------------------- /tests/01-smoke/13-stdin-lab.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library OperatingSystem 3 | Library String 4 | Library Process 5 | Resource ../common.robot 6 | 7 | Suite Teardown Run Keyword Teardown 8 | 9 | 10 | *** Variables *** 11 | ${lab-url} https://gist.githubusercontent.com/hellt/9baa28d7e3cb8290ade1e1be38a8d12b/raw/03067e242d44c9bbe38afa81131e46bab1fa0c42/test.clab.yml 12 | 13 | 14 | *** Test Cases *** 15 | Deploy remote lab 16 | ${rc} ${output} = Run And Return Rc And Output 17 | ... sudo curl -s ${lab-url} | ${CLAB_BIN} --runtime ${runtime} deploy -c -t - 18 | Log ${output} 19 | Should Be Equal As Integers ${rc} 0 20 | 21 | Ensure inspect works 22 | ${rc} ${output} = Run And Return Rc And Output 23 | ... ${CLAB_BIN} --runtime ${runtime} inspect --all 24 | Log ${output} 25 | Should Be Equal As Integers ${rc} 0 26 | 27 | 28 | *** Keywords *** 29 | Teardown 30 | # destroy all labs 31 | Run ${CLAB_BIN} --runtime ${runtime} destroy -c -a 32 | -------------------------------------------------------------------------------- /tests/01-smoke/15-netw-modes.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library OperatingSystem 3 | Library String 4 | Library Process 5 | Resource ../common.robot 6 | 7 | Suite Setup Run Keyword Teardown 8 | Suite Teardown Run Keyword Teardown 9 | 10 | 11 | *** Variables *** 12 | ${lab} ${CURDIR}/netmodes.clab.yml 13 | 14 | 15 | *** Test Cases *** 16 | Deploy lab 17 | ${output} = Process.Run Process 18 | ... ${CLAB_BIN} --runtime ${runtime} deploy -t ${lab} 19 | ... shell=True 20 | Log ${output.stdout} 21 | Log ${output.stderr} 22 | Should Be Equal As Integers ${output.rc} 0 23 | 24 | 25 | *** Keywords *** 26 | Teardown 27 | # destroy all labs 28 | Run ${CLAB_BIN} --runtime ${runtime} destroy -c -a 29 | -------------------------------------------------------------------------------- /tests/01-smoke/16-mgmtnet.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library OperatingSystem 3 | Library String 4 | Library Process 5 | Resource ../common.robot 6 | 7 | Suite Setup Setup 8 | Suite Teardown Run Keyword Teardown 9 | 10 | 11 | *** Variables *** 12 | ${lab-name} mgmtnetif 13 | ${topo} ${CURDIR}/16-mgmtnetinterface.clab.yml 14 | ${runtime} docker 15 | 16 | 17 | *** Test Cases *** 18 | Deploy ${lab-name} lab 19 | ${result} = Run Process 20 | ... ${CLAB_BIN} --runtime ${runtime} deploy -t ${topo} 21 | ... shell=True 22 | Log ${result.stdout} 23 | Should Be Equal As Integers ${result.rc} 0 24 | 25 | Check host side interface is attached to mgmt bridge and up 26 | ${params} = Set Variable docker network inspect clab --format '{{ $opt := index .Options "com.docker.network.bridge.name"}}{{ $opt }}' 27 | ${mgmtbrname} = Run Process ${params} 28 | ... shell=True 29 | Log ${mgmtbrname.stdout} 30 | ${result} = Run Process 31 | ... sudo -E ip link show dev l1eth1 32 | ... shell=True 33 | Log ${result.stdout} 34 | Should Be Equal As Integers ${result.rc} 0 35 | Should Contain ${result.stdout} state UP 36 | Should Contain ${result.stdout} master ${mgmtbrname.stdout} 37 | 38 | *** Keywords *** 39 | Teardown 40 | # destroy all labs 41 | Run ${CLAB_BIN} --runtime ${runtime} destroy -c -a 42 | 43 | Setup 44 | # skipping this test suite for podman for now 45 | Skip If '${runtime}' == 'podman' 46 | -------------------------------------------------------------------------------- /tests/01-smoke/16-mgmtnetinterface.clab.yml: -------------------------------------------------------------------------------- 1 | name: mgmtnetif 2 | 3 | topology: 4 | nodes: 5 | l1: 6 | kind: linux 7 | image: alpine:latest 8 | cmd: sleep infinity 9 | links: 10 | - endpoints: [l1:eth1, mgmt-net:l1eth1] -------------------------------------------------------------------------------- /tests/01-smoke/macvlan.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: macvlan 6 | 7 | topology: 8 | nodes: 9 | l1: 10 | kind: linux 11 | image: alpine:3 12 | exec: 13 | - apk add iproute2 14 | 15 | links: 16 | - endpoints: ["l1:eth1", "macvlan:${host_link:=ens3}"] 17 | -------------------------------------------------------------------------------- /tests/01-smoke/netmodes.clab.yml: -------------------------------------------------------------------------------- 1 | name: container-mode 2 | topology: 3 | nodes: 4 | node1: 5 | kind: linux 6 | image: alpine:3 7 | node2: 8 | kind: linux 9 | image: alpine:3 10 | network-mode: container:node1 11 | -------------------------------------------------------------------------------- /tests/01-smoke/node-filter.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: node-filter 6 | # based on https://containerlab.dev/manual/node-filtering/ 7 | topology: 8 | defaults: 9 | kind: linux 10 | image: alpine:3 11 | nodes: 12 | node1: 13 | node2: 14 | node3: 15 | node4: 16 | 17 | links: 18 | - endpoints: ["node1:eth1", "node2:eth1"] 19 | - endpoints: ["node1:eth2", "node3:eth2"] 20 | - endpoints: ["node1:eth3", "node4:eth3"] 21 | - endpoints: ["node2:eth2", "node4:eth2"] 22 | - endpoints: ["node3:eth1", "node4:eth1"] 23 | -------------------------------------------------------------------------------- /tests/01-smoke/single-topo-folder/lab1.clab.yml: -------------------------------------------------------------------------------- 1 | name: lab1 2 | 3 | topology: 4 | nodes: 5 | node1: 6 | kind: linux 7 | image: alpine:3 -------------------------------------------------------------------------------- /tests/01-smoke/stages-race.clab.yml: -------------------------------------------------------------------------------- 1 | name: stages-race 2 | 3 | topology: 4 | kinds: 5 | linux: 6 | image: alpine 7 | nodes: 8 | l1: 9 | kind: linux 10 | exec: 11 | - ip l show dev eth1 12 | l2: 13 | kind: linux 14 | startup-delay: 3 15 | links: 16 | - endpoints: ["l1:eth1", "l2:eth1"] 17 | -------------------------------------------------------------------------------- /tests/02-basic-srl/02-srl02.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 02-01-two-srls 6 | 7 | topology: 8 | kinds: 9 | nokia_srlinux: 10 | image: ghcr.io/nokia/srlinux 11 | nodes: 12 | srl1: 13 | kind: nokia_srlinux 14 | startup-config: srl1-startup.cli 15 | mgmt-ipv4: 172.20.20.200 16 | srl2: 17 | kind: nokia_srlinux 18 | image: ghcr.io/nokia/srlinux 19 | env: 20 | SRL_LOCATION: test123 21 | startup-config: https://raw.githubusercontent.com/srl-labs/containerlab/main/tests/02-basic-srl/srl2-startup.cli 22 | mgmt-ipv4: 172.20.20.201 23 | 24 | links: 25 | - endpoints: ["srl1:ethernet-1/1", "srl2:e1-1"] 26 | -------------------------------------------------------------------------------- /tests/02-basic-srl/03-srl-bgp.clab.yml: -------------------------------------------------------------------------------- 1 | name: srl-bgp 2 | 3 | topology: 4 | kinds: 5 | nokia_srlinux: 6 | image: ghcr.io/nokia/srlinux 7 | nodes: 8 | srl1: 9 | kind: nokia_srlinux 10 | startup-config: 03-srl1-bgp.config 11 | srl2: 12 | kind: nokia_srlinux 13 | startup-config: 03-srl2-bgp.config 14 | 15 | links: 16 | - endpoints: ["srl1:e1-1", "srl2:e1-1"] 17 | -------------------------------------------------------------------------------- /tests/02-basic-srl/srl1-startup.cli: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 0 3 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 4 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.0/31 5 | set / interface ethernet-1/1 subinterface 0 ipv6 admin-state enable 6 | set / interface ethernet-1/1 subinterface 0 ipv6 address 2002::192.168.0.0/127 7 | 8 | set / network-instance default 9 | set / network-instance default interface ethernet-1/1.0 -------------------------------------------------------------------------------- /tests/02-basic-srl/srl2-startup.cli: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 0 3 | set / interface ethernet-1/1 subinterface 0 admin-state enable 4 | set / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable 5 | set / interface ethernet-1/1 subinterface 0 ipv4 address 192.168.0.1/31 6 | set / interface ethernet-1/1 subinterface 0 ipv6 admin-state enable 7 | set / interface ethernet-1/1 subinterface 0 ipv6 address 2002::192.168.0.1/127 8 | 9 | set / network-instance default 10 | set / network-instance default interface ethernet-1/1.0 11 | 12 | set / system information location {{.Env.SRL_LOCATION}} -------------------------------------------------------------------------------- /tests/03-basic-ceos/03-ceos01-clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 03-01-two-ceos 6 | 7 | topology: 8 | kinds: 9 | ceos: 10 | image: ceos:4.32.0F 11 | env: 12 | CLAB_MGMT_VRF: MGMT 13 | nodes: 14 | n1: 15 | kind: ceos 16 | n2: 17 | kind: ceos 18 | mgmt-ipv4: 172.20.20.22 19 | 20 | links: 21 | - endpoints: ["n1:eth1", "n2:eth1"] 22 | -------------------------------------------------------------------------------- /tests/04-basic-ixiacone/04-ixiacone01-clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 04-01-ixiacone 6 | prefix: "" 7 | topology: 8 | nodes: 9 | ixia: 10 | kind: keysight_ixia-c-one 11 | image: ghcr.io/open-traffic-generator/ixia-c-one:1.31.0-3 12 | linux: 13 | kind: linux 14 | image: alpine:3 15 | links: 16 | - endpoints: ["ixia:eth1", "linux:eth1"] 17 | - endpoints: ["ixia:eth2", "linux:eth2"] 18 | -------------------------------------------------------------------------------- /tests/05-k8s-kind/01-basic-k8s-kind.clab.yml: -------------------------------------------------------------------------------- 1 | name: 01-basic-k8s-kind 2 | 3 | topology: 4 | kinds: 5 | nokia_srlinux: 6 | type: ixrd3 7 | image: ghcr.io/nokia/srlinux 8 | nodes: 9 | br01: 10 | kind: bridge 11 | alpine: 12 | kind: linux 13 | image: alpine 14 | cmd: ash -c "sleep 9999" 15 | exec: 16 | - "ip a add dev eth1 192.168.237.20/24" 17 | k01: 18 | kind: k8s-kind 19 | startup-config: k01-config.yaml 20 | k02: 21 | kind: k8s-kind 22 | 23 | # k01 -> resulting nodes due to startup-config assigned config `k01-config.yaml` 24 | k01-control-plane: 25 | kind: ext-container 26 | exec: 27 | - "ip a del dev eth1" 28 | - "ip a add dev eth1 192.168.237.1/24" 29 | 30 | k01-worker: 31 | kind: ext-container 32 | exec: 33 | - "ip a del dev eth1" 34 | - "ip a add dev eth1 192.168.237.2/24" 35 | 36 | k02-control-plane: 37 | kind: ext-container 38 | exec: 39 | - "ip a del dev eth1" 40 | - "ip a add dev eth1 192.168.237.3/24" 41 | 42 | links: 43 | - endpoints: ["br01:e1", "k01-control-plane:eth1"] 44 | - endpoints: ["br01:e2", "k01-worker:eth1"] 45 | - endpoints: ["br01:e3", "k02-control-plane:eth1"] 46 | - endpoints: ["br01:e4", "alpine:eth1"] 47 | 48 | - endpoints: ["br01:e5", "k01-control-plane:eth2"] 49 | - endpoints: ["br01:e6", "k02-control-plane:eth2"] 50 | -------------------------------------------------------------------------------- /tests/05-k8s-kind/k01-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | nodes: 4 | - role: control-plane 5 | - role: worker -------------------------------------------------------------------------------- /tests/06-ext-container/01-ext-container.clab.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Nokia 2 | # Licensed under the BSD 3-Clause License. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | name: 06-ext-container 6 | 7 | topology: 8 | nodes: 9 | ext1: 10 | kind: ext-container 11 | exec: 12 | - "ip address add dev eth1 192.168.0.1/24" 13 | ext2: 14 | kind: ext-container 15 | exec: 16 | - "ip address add dev eth1 192.168.0.2/24" 17 | 18 | links: 19 | - endpoints: ["ext1:eth1", "ext2:eth1"] 20 | -------------------------------------------------------------------------------- /tests/06-ext-container/02-shared-namespace-ext.clab.yaml: -------------------------------------------------------------------------------- 1 | name: shared-namespace-ext 2 | prefix: "" 3 | 4 | topology: 5 | kinds: 6 | linux: 7 | cmd: sh 8 | nodes: 9 | ext-node: 10 | kind: linux 11 | image: alpine 12 | exec: 13 | - ip l add dev d1 type dummy 14 | - ip a add dev d1 128.66.0.1/32 -------------------------------------------------------------------------------- /tests/06-ext-container/02-shared-namespace.clab.yaml: -------------------------------------------------------------------------------- 1 | name: shared-namespace 2 | 3 | topology: 4 | kinds: 5 | linux: 6 | cmd: sh 7 | nodes: 8 | node0: 9 | kind: linux 10 | image: alpine 11 | exec: 12 | - ip a 13 | node1: 14 | kind: linux 15 | image: alpine 16 | network-mode: container:ext-node 17 | exec: 18 | - ip a 19 | links: 20 | - endpoints: ["node0:net0", "node1:net0"] -------------------------------------------------------------------------------- /tests/07-sros/1-sros.clab.yml: -------------------------------------------------------------------------------- 1 | name: 1-sros 2 | 3 | topology: 4 | nodes: 5 | sros1: 6 | kind: nokia_sros 7 | image: registry.srlinux.dev/pub/vr-sros:23.10.R2 8 | license: sros23.key 9 | -------------------------------------------------------------------------------- /tests/08-vxlan/01-vxlan-s1.config: -------------------------------------------------------------------------------- 1 | set / interface ethernet-1/1 admin-state enable 2 | set / interface ethernet-1/1 subinterface 1 admin-state enable 3 | set / interface ethernet-1/1 subinterface 1 ipv4 4 | set / interface ethernet-1/1 subinterface 1 ipv4 admin-state enable 5 | set / interface ethernet-1/1 subinterface 1 ipv4 address 192.168.67.1/30 6 | set / network-instance default interface ethernet-1/1.1 -------------------------------------------------------------------------------- /tests/08-vxlan/01-vxlan.clab.yml: -------------------------------------------------------------------------------- 1 | name: vxlan 2 | 3 | mgmt: 4 | network: clab-vxlan 5 | bridge: clab-vxlan-br 6 | ipv4-subnet: 172.20.25.0/24 7 | 8 | topology: 9 | nodes: 10 | srl1: 11 | kind: nokia_srlinux 12 | image: ghcr.io/nokia/srlinux 13 | startup-config: 01-vxlan-s1.config 14 | mgmt-ipv4: 172.20.25.21 15 | l2: 16 | kind: linux 17 | image: alpine:3 18 | exec: 19 | - > 20 | ash -c ' 21 | apk add iproute2 && 22 | ip link add name vxlan0 type vxlan id 100 remote 172.20.25.21 dstport 14788 && 23 | ip l set dev vxlan0 up && 24 | ip addr add dev vxlan0 192.168.67.2/30' 25 | mgmt-ipv4: 172.20.25.22 26 | 27 | links: 28 | - type: vxlan 29 | endpoint: 30 | node: srl1 31 | interface: e1-1 32 | mac: 02:00:00:00:00:04 33 | remote: 172.20.25.22 34 | vni: 100 35 | udp-port: 14788 36 | -------------------------------------------------------------------------------- /tests/08-vxlan/02-vxlan-stitch.clab.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../schemas/clab.schema.json 2 | name: vxlan-stitch 3 | 4 | mgmt: 5 | network: clab-vxlan 6 | bridge: clab-vxlan-br 7 | mtu: 9100 8 | ipv4-subnet: 172.20.25.0/24 9 | 10 | topology: 11 | nodes: 12 | srl1: 13 | kind: nokia_srlinux 14 | image: ghcr.io/nokia/srlinux 15 | startup-config: 01-vxlan-s1.config 16 | mgmt-ipv4: 172.20.25.21 17 | 18 | # this node doesn't participate in the vxlan datapath 19 | # we just put it here to test that long named nodes 20 | # are treated correctly with ip aliases added to link name. 21 | some_very_long_node_name_l1: 22 | kind: linux 23 | image: alpine:3 24 | exec: 25 | - apk add iproute2 26 | 27 | l2: 28 | kind: linux 29 | image: alpine:3 30 | exec: 31 | - > 32 | ash -c ' 33 | apk add iproute2 && 34 | ip link add name vxlan0 type vxlan id 100 remote 172.20.25.21 dstport 14788 && 35 | ip l set dev vxlan0 up && 36 | ip addr add dev vxlan0 192.168.67.2/30' 37 | mgmt-ipv4: 172.20.25.22 38 | 39 | links: 40 | - type: vxlan-stitch 41 | endpoint: 42 | node: srl1 43 | interface: e1-1 44 | mac: 02:00:00:00:00:04 45 | remote: 172.20.25.22 46 | vni: 100 47 | udp-port: 14788 48 | 49 | - type: vxlan-stitch 50 | endpoint: 51 | node: some_very_long_node_name_l1 52 | interface: e1-1 53 | remote: 172.20.25.23 54 | vni: 101 55 | udp-port: 14789 56 | -------------------------------------------------------------------------------- /tests/09-fortigate/fortigates.clab.yml: -------------------------------------------------------------------------------- 1 | name: forti 2 | topology: 3 | nodes: 4 | forti1: 5 | kind: fortinet_fortigate 6 | image: ghcr.io/srl-labs/fortigate:7.0.14 7 | # image: registry.srlinux.dev/pub/fortinet_fortigate:7.0.14 8 | forti2: 9 | kind: fortinet_fortigate 10 | image: ghcr.io/srl-labs/fortigate:7.0.14 11 | # image: registry.srlinux.dev/pub/fortinet_fortigate:7.0.14 12 | links: 13 | - endpoints: ["forti1:eth1", "forti2:eth1"] 14 | -------------------------------------------------------------------------------- /tests/10-basic-cisco_iol/iol.clab.yml: -------------------------------------------------------------------------------- 1 | name: iol 2 | topology: 3 | nodes: 4 | router1: 5 | kind: cisco_iol 6 | image: ghcr.io/srl-labs/containerlab/cisco_iol:17.12.01 7 | router2: 8 | kind: cisco_iol 9 | image: ghcr.io/srl-labs/containerlab/cisco_iol:17.12.01 10 | startup-config: ./loopback_config.partial 11 | router3: 12 | kind: cisco_iol 13 | image: ghcr.io/srl-labs/containerlab/cisco_iol:17.12.01 14 | startup-config: ./router3-full.cfg 15 | switch: 16 | kind: cisco_iol 17 | image: ghcr.io/srl-labs/containerlab/cisco_iol:L2-17.12.01 18 | type: l2 19 | links: 20 | - endpoints: ["router1:Ethernet0/1", "switch:Ethernet0/1"] 21 | - endpoints: ["router2:Ethernet0/1", "switch:e0/2"] 22 | -------------------------------------------------------------------------------- /tests/10-basic-cisco_iol/loopback_config.partial: -------------------------------------------------------------------------------- 1 | interface Loopback0 2 | description PARTIAL_CFG 3 | ! -------------------------------------------------------------------------------- /tests/10-basic-cisco_iol/router3-full.cfg: -------------------------------------------------------------------------------- 1 | hostname FULL_STARTUP_CFG-{{ .Hostname }} 2 | ! 3 | no aaa new-model 4 | ! 5 | ip domain name lab 6 | ! 7 | ip cef 8 | ! 9 | ipv6 unicast-routing 10 | ! 11 | no ip domain lookup 12 | ! 13 | username admin privilege 15 secret admin 14 | ! 15 | vrf definition clab-mgmt 16 | description clab-mgmt 17 | address-family ipv4 18 | ! 19 | address-family ipv6 20 | ! 21 | ! 22 | interface Ethernet0/0 23 | {{ if .IsL2Node }} 24 | no switchport 25 | {{ end }} 26 | vrf forwarding clab-mgmt 27 | description clab-mgmt 28 | ip address {{ .MgmtIPv4Addr }} {{ .MgmtIPv4SubnetMask }} 29 | ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }} 30 | no shutdown 31 | !{{ range $index, $item := .DataIFaces }} 32 | interface Ethernet{{ .Slot }}/{{ .Port }} 33 | no shutdown 34 | !{{ end }} 35 | ip forward-protocol nd 36 | ! 37 | ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 Ethernet0/0 {{ .MgmtIPv4GW }} 38 | ipv6 route vrf clab-mgmt ::/0 Ethernet0/0 {{ .MgmtIPv6GW }} 39 | ! 40 | ip ssh version 2 41 | crypto key generate rsa modulus 2048 42 | ! 43 | line vty 0 4 44 | login local 45 | transport input ssh 46 | ! 47 | end 48 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/01-e2e-lab.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library OperatingSystem 3 | Resource ../ssh.robot 4 | Resource ../common.robot 5 | 6 | Suite Teardown Run Keyword Cleanup 7 | 8 | 9 | *** Variables *** 10 | ${lab-name} e2e-vpp 11 | ${lab-file-name} e2e-lab/vpp.clab.yml 12 | ${runtime} docker 13 | 14 | 15 | *** Test Cases *** 16 | Deploy ${lab-name} lab 17 | Log ${CURDIR} 18 | ${rc} ${output} = Run And Return Rc And Output 19 | ... ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/${lab-file-name} 20 | Log ${output} 21 | Should Be Equal As Integers ${rc} 0 22 | 23 | Pause to let OSPF converge 24 | Sleep 40s 25 | 26 | Ensure client1 can ping client2 27 | ${rc} ${output} = Run And Return Rc And Output 28 | ... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=client1 --cmd "ping -c 5 10.82.98.82" 29 | Log ${output} console=True 30 | Should Be Equal As Integers ${rc} 0 31 | Should Contain ${output} 5 packets transmitted, 4 packets received, 20% packet loss 32 | 33 | 34 | *** Keywords *** 35 | Cleanup 36 | Run ${CLAB_BIN} --runtime ${runtime} destroy -t ${CURDIR}/${lab-file-name} --cleanup 37 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/e2e-lab/config/vpp1/bird-local.conf: -------------------------------------------------------------------------------- 1 | protocol bfd bfd1 { 2 | interface "eth2" { interval 100 ms; multiplier 30; }; 3 | } 4 | 5 | protocol ospf v2 ospf4 { 6 | ipv4 { import all; export all; }; 7 | area 0 { 8 | interface "loop0" { stub yes; }; 9 | interface "eth2" { type pointopoint; cost 10; bfd on; }; 10 | }; 11 | } 12 | 13 | protocol ospf v3 ospf6 { 14 | ipv6 { import all; export all; }; 15 | area 0 { 16 | interface "loop0" { stub yes; }; 17 | interface "eth2" { type pointopoint; cost 10; bfd on; }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/e2e-lab/config/vpp1/vppcfg.yaml: -------------------------------------------------------------------------------- 1 | interfaces: 2 | eth1: 3 | description: "To client1" 4 | mtu: 1500 5 | lcp: eth1 6 | addresses: [10.82.98.65/28, 2001:db8:8298:101::1/64] 7 | eth2: 8 | description: "To vpp2" 9 | mtu: 9216 10 | lcp: eth2 11 | addresses: [10.82.98.16/31, 2001:db8:8298:1::1/64] 12 | loopbacks: 13 | loop0: 14 | description: "vpp1" 15 | lcp: loop0 16 | addresses: [10.82.98.0/32, 2001:db8:8298::/128] 17 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/e2e-lab/config/vpp2/bird-local.conf: -------------------------------------------------------------------------------- 1 | protocol bfd bfd1 { 2 | interface "eth2" { interval 100 ms; multiplier 30; }; 3 | } 4 | 5 | protocol ospf v2 ospf4 { 6 | ipv4 { import all; export all; }; 7 | area 0 { 8 | interface "loop0" { stub yes; }; 9 | interface "eth2" { type pointopoint; cost 10; bfd on; }; 10 | }; 11 | } 12 | 13 | protocol ospf v3 ospf6 { 14 | ipv6 { import all; export all; }; 15 | area 0 { 16 | interface "loop0" { stub yes; }; 17 | interface "eth2" { type pointopoint; cost 10; bfd on; }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/e2e-lab/config/vpp2/vppcfg.yaml: -------------------------------------------------------------------------------- 1 | interfaces: 2 | eth1: 3 | description: "To client2" 4 | mtu: 1500 5 | lcp: eth1 6 | addresses: [10.82.98.81/28, 2001:db8:8298:102::1/64] 7 | eth2: 8 | description: "To vpp1" 9 | mtu: 9216 10 | lcp: eth2 11 | addresses: [10.82.98.17/31, 2001:db8:8298:1::2/64] 12 | loopbacks: 13 | loop0: 14 | description: "vpp2" 15 | lcp: loop0 16 | addresses: [10.82.98.1/32, 2001:db8:8298::1/128] 17 | -------------------------------------------------------------------------------- /tests/11-fdio-vpp/e2e-lab/vpp.clab.yml: -------------------------------------------------------------------------------- 1 | name: e2e-vpp 2 | 3 | topology: 4 | kinds: 5 | fdio_vpp: 6 | image: git.ipng.ch/ipng/vpp-containerlab:latest 7 | startup-config: config/__clabNodeName__/vppcfg.yaml 8 | binds: 9 | - config/__clabNodeName__/bird-local.conf:/etc/bird/bird-local.conf:ro 10 | linux: 11 | image: alpine:latest 12 | 13 | nodes: 14 | vpp1: 15 | kind: fdio_vpp 16 | vpp2: 17 | kind: fdio_vpp 18 | client1: 19 | kind: linux 20 | exec: 21 | - ip link set address 00:c1:ab:00:00:01 dev eth1 22 | - ip addr add 10.82.98.66/28 dev eth1 23 | - ip route add 10.82.98.0/24 via 10.82.98.65 24 | - ip addr add 2001:db8:8298:101::2/64 dev eth1 25 | - ip route add 2001:db8:8298::/48 via 2001:db8:8298:101::1 26 | client2: 27 | kind: linux 28 | exec: 29 | - ip link set address 00:c1:ab:00:00:02 dev eth1 30 | - ip addr add 10.82.98.82/28 dev eth1 31 | - ip route add 10.82.98.0/24 via 10.82.98.81 32 | - ip addr add 2001:db8:8298:102::2/64 dev eth1 33 | - ip route add 2001:db8:8298::/48 via 2001:db8:8298:102::1 34 | 35 | links: 36 | - endpoints: ["vpp1:eth2", "vpp2:eth2"] 37 | - endpoints: ["client1:eth1", "vpp1:eth1"] 38 | - endpoints: ["client2:eth1", "vpp2:eth1"] 39 | -------------------------------------------------------------------------------- /tests/common.robot: -------------------------------------------------------------------------------- 1 | *** Variables *** 2 | ${CLAB_BIN} containerlab 3 | -------------------------------------------------------------------------------- /tests/rf-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Nokia 3 | # Licensed under the BSD 3-Clause License. 4 | # SPDX-License-Identifier: BSD-3-Clause 5 | 6 | # arguments 7 | # $1 - container runtime: [docker, podman] 8 | # $2 - test suite to execute 9 | 10 | # set containerlab binary path to a value of CLAB_BIN env variable 11 | # unless it is not set, then use 'containerlab' as a default value 12 | if [ -z "${CLAB_BIN}" ]; then 13 | CLAB_BIN=containerlab 14 | fi 15 | 16 | echo "Running tests with containerlab binary at $(which ${CLAB_BIN}) path and selected runtime: $1" 17 | 18 | COV_DIR=/tmp/clab-tests/coverage 19 | 20 | # coverage output directory 21 | mkdir -p ${COV_DIR} 22 | 23 | # parses the dir or file name passed to the rf-run.sh script 24 | # and in case of a directory, it returns the name of the directory 25 | # in case of a file it returns the name of the file's dir catenated with file name without extension 26 | function get_logname() { 27 | path=$1 28 | filename=$(basename "$path") 29 | if [[ "$filename" == *.* ]]; then 30 | dirname=$(dirname "$path") 31 | basename=$(basename "$path" | cut -d. -f1) 32 | echo "${dirname##*/}-${basename}" 33 | else 34 | echo "${filename}" 35 | fi 36 | } 37 | 38 | # activate venv 39 | source .venv/bin/activate 40 | 41 | GOCOVERDIR=${COV_DIR} robot --consolecolors on -r none --variable CLAB_BIN:${CLAB_BIN} --variable runtime:$1 -l ./tests/out/$(get_logname $2)-$1-log --output ./tests/out/$(basename $2)-$1-out.xml $2 42 | -------------------------------------------------------------------------------- /tests/ssh.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SSHLibrary 3 | 4 | 5 | *** Keywords *** 6 | Login via SSH with username and password 7 | [Arguments] 8 | ... ${address}=${None} 9 | ... ${port}=22 10 | ... ${username}=${None} 11 | ... ${password}=${None} 12 | # seconds to try and succesfully login 13 | ... ${try_for}=4 14 | ... ${conn_timeout}=3 15 | FOR ${i} IN RANGE ${try_for} 16 | SSHLibrary.Open Connection ${address} timeout=${conn_timeout} 17 | ${status}= Run Keyword And Return Status SSHLibrary.Login ${username} ${password} 18 | IF ${status} BREAK 19 | Sleep 1s 20 | END 21 | IF $status!=True 22 | Fail Unable to connect to ${address} via SSH in ${try_for} attempts 23 | END 24 | Log Exited the loop. 25 | 26 | Login via SSH with public key 27 | [Arguments] 28 | ... ${address}=${None} 29 | ... ${port}=22 30 | ... ${username}=${None} 31 | ... ${keyfile}=~/.ssh/id_rsa 32 | # seconds to try and succesfully login 33 | ... ${try_for}=4 34 | ... ${conn_timeout}=3 35 | Log ${keyfile} 36 | FOR ${i} IN RANGE ${try_for} 37 | SSHLibrary.Open Connection ${address} timeout=${conn_timeout} 38 | ${status}= Run Keyword And Return Status SSHLibrary.Login With Public Key ${username} ${keyfile} 39 | IF ${status} BREAK 40 | Sleep 1s 41 | END 42 | IF $status!=True 43 | Fail Unable to connect to ${address} via SSH in ${try_for} attempts 44 | END 45 | Log Exited the loop. 46 | -------------------------------------------------------------------------------- /types/constants.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | // env var containing the expected number of interfaces injected into every container. 5 | CLAB_ENV_INTFS = "CLAB_INTFS" 6 | ) 7 | -------------------------------------------------------------------------------- /types/license_policy_value.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // LicensePolicy is a value of LicensePolicy. 4 | type LicensePolicy string 5 | 6 | const ( 7 | // LicensePolicyRequired means a node should exit if no license provided. 8 | LicensePolicyRequired = "required" 9 | // LicensePolicyWarn means a node should warn (but not exit) if no license provided. 10 | LicensePolicyWarn = "warn" 11 | // LicensePolicyNone means a node doesn't care about a license. 12 | LicensePolicyNone = "none" 13 | ) 14 | -------------------------------------------------------------------------------- /types/settings.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "time" 4 | 5 | // Settings is the structure for global containerlab settings. 6 | type Settings struct { 7 | CertificateAuthority *CertificateAuthority `yaml:"certificate-authority"` 8 | } 9 | 10 | // CertificateAuthority is the structure for global containerlab certificate authority settings. 11 | type CertificateAuthority struct { 12 | // Cert is the path to the CA certificate file in the External CA mode of operation. 13 | Cert string `yaml:"cert"` 14 | // Key is the path to the CA private key file in the External CA mode of operation. 15 | Key string `yaml:"key"` 16 | // KeySize is the size of the CA private key in bits 17 | // when containerlab is in charge of the CA generation. 18 | KeySize int `yaml:"key-size"` 19 | // ValidityDuration is the duration of the CA certificate validity 20 | // when containerlab is in charge of the CA generation. 21 | ValidityDuration time.Duration `yaml:"validity-duration"` 22 | } 23 | -------------------------------------------------------------------------------- /types/ssh_config.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type PubkeyAuthValue string 4 | 5 | const ( 6 | PubkeyAuthValueYes PubkeyAuthValue = "yes" 7 | PubkeyAuthValueNo PubkeyAuthValue = "no" 8 | PubkeyAuthValueHostBound PubkeyAuthValue = "host-bound" 9 | PubkeyAuthValueUnbound PubkeyAuthValue = "unbound" 10 | ) 11 | 12 | func (p PubkeyAuthValue) String() string { 13 | return string(p) 14 | } 15 | 16 | // SSHConfig is the SSH client configuration that a clab node requires. 17 | type SSHConfig struct { 18 | PubkeyAuthentication PubkeyAuthValue 19 | } 20 | 21 | func NewSSHConfig() *SSHConfig { 22 | return &SSHConfig{} 23 | } 24 | -------------------------------------------------------------------------------- /types/test_data/config.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/types/test_data/config.cfg -------------------------------------------------------------------------------- /types/test_data/lic1.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srl-labs/containerlab/0c0f592795be47424fe0470bd5ce182ebf078102/types/test_data/lic1.key -------------------------------------------------------------------------------- /utils/if-wait.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // IfWaitScript is used in ENTRYPOINT/CMD of the nodes that need to ensure that all 4 | // of the clab links/interfaces are available in the container before calling the main process. 5 | var IfWaitScript string = `#!/bin/sh 6 | 7 | INTFS=$(echo $CLAB_INTFS) 8 | SLEEP=0 9 | 10 | int_calc () 11 | { 12 | index=0 13 | for i in $(ls -1v /sys/class/net/ | grep -E '^et|^ens|^eno|^e[0-9]'); do 14 | index=$((index+1)) 15 | done 16 | MYINT=$index 17 | } 18 | 19 | int_calc 20 | 21 | echo "Waiting for all $INTFS interfaces to be connected" 22 | while [ "$MYINT" -lt "$INTFS" ]; do 23 | echo "Connected $MYINT interfaces out of $INTFS" 24 | sleep 1 25 | int_calc 26 | done 27 | 28 | echo "Sleeping $SLEEP seconds before boot" 29 | sleep $SLEEP 30 | ` 31 | -------------------------------------------------------------------------------- /utils/ip.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "fmt" 7 | "net" 8 | "strings" 9 | 10 | "github.com/charmbracelet/log" 11 | ) 12 | 13 | // GenerateIPv6ULASubnet creates a random /64 ULA (Unique Local Address) IPv6 subnet in the fd00::/8 range. 14 | func GenerateIPv6ULASubnet() (string, error) { 15 | var ula strings.Builder 16 | 17 | ula.WriteString("fd00:") 18 | 19 | bytes := make([]byte, 2) 20 | for i := 0; i < 3; i++ { 21 | // Generate a random 16-bit hex field 22 | if _, err := rand.Read(bytes); err != nil { 23 | return "", err 24 | } 25 | 26 | ula.WriteString(hex.EncodeToString(bytes)) 27 | ula.WriteString(":") 28 | } 29 | 30 | ula.WriteString(":/64") 31 | 32 | return ula.String(), nil 33 | } 34 | 35 | // CIDRToDDN converts CIDR mask to a Dotted Decimal Notation 36 | // ie CIDR: 24 -> DDN: 255.255.255.0 37 | // The result is a string. 38 | func CIDRToDDN(length int) string { 39 | // check mask length is valid 40 | if length < 0 || length > 32 { 41 | log.Errorf("Invalid prefix length: %d", length) 42 | return "" 43 | } 44 | 45 | mask := net.CIDRMask(length, 32) 46 | return fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) 47 | } 48 | -------------------------------------------------------------------------------- /utils/keys.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/charmbracelet/log" 5 | "golang.org/x/crypto/ssh" 6 | ) 7 | 8 | // LoadSSHPubKeysFromFiles parses openssh keys from the files referenced by the paths 9 | // and returns a slice of ssh.PublicKey pointers. 10 | // The files may contain multiple keys each on a separate line. 11 | func LoadSSHPubKeysFromFiles(paths []string) ([]ssh.PublicKey, error) { 12 | var keys []ssh.PublicKey 13 | 14 | for _, p := range paths { 15 | lines, err := FileLines(p, "#") 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | for _, l := range lines { 21 | pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(l)) 22 | 23 | log.Debugf("Loaded public key %s", l) 24 | 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | keys = append(keys, pubKey) 30 | } 31 | 32 | } 33 | 34 | return keys, nil 35 | } 36 | -------------------------------------------------------------------------------- /utils/password.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "golang.org/x/term" 8 | ) 9 | 10 | func ReadPasswordFromTerminal() (string, error) { 11 | fmt.Print("password: ") 12 | pass, err := term.ReadPassword(int(os.Stdin.Fd())) 13 | if err != nil { 14 | return "", err 15 | } 16 | fmt.Println() 17 | return string(pass), nil 18 | } 19 | -------------------------------------------------------------------------------- /utils/pointer.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // Pointer returns a pointer to a value of any type. 4 | func Pointer[T any](v T) *T { 5 | return &v 6 | } 7 | -------------------------------------------------------------------------------- /utils/process.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "syscall" 4 | 5 | // PauseProcessGroup sends the SIGSTOP signal to a process group, causing all 6 | // the processes within the group to be Paused e.g. SRL runs multilpe processes, if the 7 | // container is meant to be stopped, all the related processes must be paused. 8 | // To me it seams like the ProcessGroupID is set correctly so we can count on that field. 9 | // The syscall.Kill interpretes negative ints as a PGID and not as a common PID. 10 | func PauseProcessGroup(pgid int) error { 11 | return syscall.Kill(-pgid, syscall.SIGSTOP) 12 | } 13 | 14 | // UnpauseProcessGroup send the SIGCONT to the given ProcessGroup identified by its ID. 15 | func UnpauseProcessGroup(pgid int) error { 16 | return syscall.Kill(-pgid, syscall.SIGCONT) 17 | } 18 | -------------------------------------------------------------------------------- /utils/regexp.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | func GetRegexpCaptureGroups(r *regexp.Regexp, search string) (map[string]string, error) { 9 | matches := r.FindStringSubmatch(search) 10 | if len(matches) == 0 { 11 | return nil, fmt.Errorf("%q does not match regexp %q, no match", search, r) 12 | } 13 | 14 | captureGroups := make(map[string]string) 15 | for i, name := range r.SubexpNames() { 16 | if i != 0 && name != "" { 17 | captureGroups[name] = matches[i] 18 | } 19 | } 20 | 21 | return captureGroups, nil 22 | } 23 | -------------------------------------------------------------------------------- /utils/test_data/keys: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs4Qv1yrBk6ygt+o7J4sUcYv+WfDjdAyABDoinOt3PgSmCcVqqAP2qS8UtTnMNuy93Orp6+/R/7/R3O5xdY6I4YViK3WVlKTAUVm7vdeTKp9uq1tNeWgo7+J3baSbQ3INp85ScTfFvRzRCFkr/W97Wh6pTa7ysgkcPvc2/tXG2z36Mx7/TFBk3Q1LY3ByKLtGrC5JnVpMTrqrsCwcLEVHHEZ4z5R4FZED/lpz+wTNFnR/l9HA6yDkKYensHynx+guqYpYD6y4yEGY/LcUnwBg0zIlUhmOsvdmxWBz12Lp7EBiNjSwhnPfe+o3efLGGnjWUAa4TgO8Sa8PQP0pK/ZNd 2 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILKdXYzPIq8kHRJtDrh21wMVI76AnuPk7HDLeDteKN74 -------------------------------------------------------------------------------- /utils/test_data/keys1.txt: -------------------------------------------------------------------------------- 1 | valid line 2 | # comment 3 | another valid line -------------------------------------------------------------------------------- /virt/memory.go: -------------------------------------------------------------------------------- 1 | package virt 2 | 3 | import ( 4 | "github.com/charmbracelet/log" 5 | "github.com/mackerelio/go-osstat/memory" 6 | ) 7 | 8 | type MemoryType int 9 | 10 | const ( 11 | MemoryTypeTotal MemoryType = iota 12 | MemoryTypeAvailable 13 | ) 14 | 15 | // GetSysMemory reports on total installed or available memory (in bytes). 16 | func GetSysMemory(mt MemoryType) uint64 { 17 | memoryResult, err := memory.Get() 18 | if err != nil { 19 | log.Errorf("unable to determine available memory: %v", err) 20 | return 0 21 | } 22 | switch mt { 23 | case MemoryTypeAvailable: 24 | return memoryResult.Available 25 | case MemoryTypeTotal: 26 | return memoryResult.Total 27 | } 28 | return 0 29 | } 30 | --------------------------------------------------------------------------------