Skip to content

Release 0.80#

2026-10-09 · Full Changelog

Breaking changes: CLAB_* environment variables replaced by kind-specific config

Kind-specific node settings are now set as plain YAML keys on the node definition. The CLAB_* environment variables that previously provided these settings are removed and are no longer read, see Kind-specific config for the table of removed environment variables and their replacements.

C9s runtime#

Containerlab can run labs on Kubernetes powered by the all-new open-source project called c9s.

Our end game is to ensure that the containerlab binary can be used both to run host-local labs and know how to spin them on Kubernetes via c9s. The first major stab at this lofy goal comes with this release where we add a new runtime option named simply c9s:

containerlab --runtime c9s deploy -t topo.clab.yml

Same deploy, inspect, exec, events, node lifecycle actions, and destroy commands are supported against the c9s runtime. See the Containerlab runtime documentation for more details.

Well, we'd be lying if we said that this is a fully baked runtime. It is not. But it is a good start and we are looking forward to your feedback and contributions.

Thanks @FloSch62 #3217

MACVLAN management networks and Contianerlab IPAM#

The management network can now be created with the macvlan driver, which places node management interfaces directly on the host network. The driver is selected with driver: macvlan and requires a macvlan-parent interface that already exists on the host:

name: macvlan-mgmt
mgmt:
  driver: macvlan
  macvlan-parent: eth1
  ipv4-subnet: 192.168.10.0/24

Containerlab ships its own IPAM provider for macvlan networks: addresses are allocated deterministically, saved in the topology state file, and verified with duplicate address detection. For MACVLAN networks, DAD checks local addresses and the ARP/ND cache, then sends an ARP and/or IPv6 neighbour solicitation out the parent interface.

Containerlab also creates an owned macvlan interface in the host namespace by default, so the host keeps access to the management network. Set macvlan-aux: false to disable it; the auxiliary interface is disabled automatically for private, vepa, and passthru modes.

Existing Docker networks with a non-bridge driver can be reused by name — bridge-specific setup is skipped when no Linux bridge is associated with the network.

Thanks @kaelemc #3399 #3348

Multiple management networks#

If the above was not mindblowing enough, how about we tell you you can create multiple management networks (and yes, some can be macvlan) and attach your nodes to them in the same lab? The mgmt section accepts a list of networks. Nodes select their network with the mgmt-net key, which follows the standard node, group, kind, and defaults inheritance order:

name: multi-mgmt-network
mgmt:
  - network: net1
    ipv4-subnet: 172.31.10.0/24
  - network: net2
    driver: macvlan
    macvlan-parent: eth1
topology:
  nodes:
    r1:
      mgmt-net: net1
    r2:
      mgmt-net: net2

Multiple management networks are currently supported with the Docker runtime only. Every node must have a mgmt-net defined (or inherited), and the first defined network is the default for tools containers. Nodes using network-mode ignore the mgmt-net key. See multiple management networks.

Thanks @kaelemc #3447

Tailscale management network#

The management (again!) network can join a Tailscale tailnet. In sidecar mode every node gets a tailscale sidecar container and appears as a device in your tailnet, authenticated with a reusable auth-key:

name: mylab
mgmt:
  tailscale:
    auth-key: ${TS_AUTHKEY}

In proxy mode the whole lab appears as a single device in the tailnet, authenticated via SSO. Individual nodes are exposed by forwarding ports with the /ts port suffix, e.g. 8022:22/ts maps port 8022 of the lab device to SSH of that node.

Thanks @kaelemc #3423

Kind-specific config#

Kinds that need more than the generic node settings accept their own keys right on the node definition. Kind config keys participate in the regular inheritance model with per-key precedence: node > group > kinds.<kind> > defaults.

topology:
  kinds:
    cisco_iol:
      pid-offset: 64 # previously set with CLAB_IOL_PID_OFFSET env var
  nodes:
    sros1:
      kind: nokia_srsim
      config-mode: classic
    iol1:
      kind: cisco_iol
      mgmt-intf: Ethernet1/0

Every key is validated: unknown keys are rejected with an error naming the topology block they were set in, and values are strictly type-checked. The JSON schema models the kind config keys of each kind, so editor autocompletion and validation cover them too. Kind names in the kinds: block are matched case-insensitively.

Breaking changes: CLAB_* environment variables replaced by kind-specific config

Kind-specific node settings are now set as plain YAML keys on the node definition with the new kind-specific config mechanism. The CLAB_* environment variables that previously provided these settings are removed and are no longer read.

Unknown or mistyped keys are rejected at deploy time with an error naming the topology block they were set in, so audit your defaults and groups blocks when they apply to multiple kinds.

cisco_iol

Removed environment variable Kind config key
CLAB_IOL_PID_OFFSET pid-offset
CLAB_IOL_MGMT_INTF mgmt-intf
CLAB_IOL_BOOTSTRAP_CONFIG bootstrap-config

nokia_srsim

Removed environment variable Kind config key
CLAB_SROS_CONFIG_MODE config-mode
CLAB_SROS_DISABLE_COMPONENT_CONFIG gen-component-config

nokia_sros

Removed environment variable Kind config key
CLAB_SROS_CONFIG_MODE config-mode
CLAB_SKIP_SROS_SSH_KEY_CONFIG inject-ssh-keys
NOKIA_SROS_SFM sfm

nokia_srlinux

Removed environment variable Kind config key
CLAB_CUSTOM_PROMPT custom-prompt
CLAB_EDA_USE_DEFAULT_GRPC_SERVER eda-default-grpc-server

The components key keeps working for the Nokia kinds and SR Linux, but is now a validated kind-specific config key instead of a generic node field. Per-component VM resources for nokia_sros are set with the typed cpu, ram, and max-nics component keys instead of env entries.

With clab apply, a node whose stored kind config no longer decodes — for example, when a key changed between releases — counts as changed and gets reconciled.

Thanks @kaelemc #3432

FRRouting kind#

The new frr kind makes FRRouting a first-class citizen in containerlab. Configuration files — frr.conf, daemons, and vtysh.conf — are generated into the node's lab directory and bind-mounted over the container's /etc/frr, so startup-config, enforce-startup-config, and suppress-startup-config behave as they do for other kinds. Which daemons run is selected with extras.frr.daemons; when omitted, every daemon is started.

topology:
  nodes:
    r1:
      kind: frr
      image: quay.io/frrouting/frr:containerlab-10.7.1
      startup-config: r1.frr.conf

FRR publishes a containerlab image alongside its plain release image, tagged containerlab-<version>. It adds an SSH server with an admin user whose login shell is vtysh, and removes the management network's default routes so they stay out of the lab's routing protocols. clab save writes the running configuration back to the lab directory.

Thanks @mwinter-osr #3382 #3429

SR Linux line card selection#

Modular SR Linux chassis — 7250 IXR-6e, IXR-10e, and IXR-18e — accept several line card flavours, which are now selected with a components block instead of bind-mounting a hand-written topology file:

name: srl_modular
topology:
  nodes:
    srl1:
      kind: nokia_srlinux
      type: ixr-10e
      components:
        - slot: 1
          type: imm3-36-800g-osfp

Each of the 13 chassis and line card combinations is validated and also registered as its own type — such as ixr-10e-gen3-osfp — so labs can pin a flavour without a components block. See modular chassis.

Thanks @sacckth #3387

Cisco c8000v ZTP mode#

The cisco_c8000v kind supports a third type: ztp. The node boots with no startup configuration and provisions itself over DHCP, which makes it a good fit for zero-touch provisioning labs behind a DHCP/ZTP server. It requires an image tagged ztp-$VERSION, where the install phase is skipped.

topology:
  nodes:
    dut:
      kind: cisco_c8000v
      image: vrnetlab/vr-c8000v:ztp-17.18.02
      type: ztp

A startup-config is rejected on ztp nodes, since IOS XE starts ZTP provisioning only on an empty startup configuration.

Thanks @mzagozen #3427

Cisco IOL improvements#

IOL nodes with L2 images now receive management IP addressing and SSH bootstrap. Console readiness is detected with stream-based prompt detection instead of a fixed 25-second wait, which cuts the deployment wait down to a few seconds, and the SSH host keys generated in the bootstrap template persist across lab restarts.

Thanks @naoya-oyama #3416

Cumulus VX breakout ports#

cumulus_vx nodes can generate a breakout port layout with the port-count and breakouts kind config keys, producing a ports.conf that renames selected ports to the Cumulus breakout form swpNsM — e.g. port 10 split into four lanes becomes swp10s0 through swp10s3:

topology:
  nodes:
    leaf:
      kind: nvidia_cumulusvx
      image: vrnetlab/nvidia_cumulus-vx:5.16.1
      port-count: 64
      breakouts:
        - port: 1..20
          channels: 4
        - port: 64
          channels: 2

This requires an image built with vrnetlab's Cumulus VX breakout support. See breakout ports.

Thanks @nemith #3417

Topology-aware netem#

The tools netem set, show, and reset commands accept --topo/-t or --name, so impairments can be set, inspected, and cleared with topology node names instead of container names. Interface aliases are resolved too, and netem show lists the impairments of all nodes in the topology when --node is omitted.

containerlab tools netem set -n r1 -t netem.clab.yml -i eth1 --delay 5ms
containerlab tools netem show -t netem.clab.yml

Thanks @kaelemc #3409

SR-SIM netns ownership#

SR-SIM distributed chassis components are attached to an internal namespace pause container — the same way Kubernetes holds pod namespaces — so any component container can be killed and brought back without losing the network namespace. The internal container is hidden from inspect output unless --all is set.

Thanks @kaelemc #3397

Fortinet FortiProxy#

The new fortinet_fortiproxy kind aliases the fortinet_fortigate kind. For both kinds, the node's license file is now mounted into the vrnetlab container, where a TFTP server serves it to the VM for license activation.

Thanks @KarelChanivecky #3228

network-mode: container: with apply#

apply no longer rejects nodes with network-mode: container:<target>, so sidecars sharing another node's netns can be added or changed on a running lab. When the target node is recreated, dependent nodes are recreated as well, and they wait for their target independently of the --max-workers pool.

Thanks @steiler #3383

Miscellaneous#

  • SR Linux interface names are validated when a lab is deployed: only the ethernet-L/P, ethernet-L/P/C, or short eL-P, eL-P-C forms are accepted. A post-deploy panic for restored, runtime-discovered endpoints without topology links is fixed too. #3395
  • Bridges added to a running lab are now treated as new nodes on apply. #3438
  • Interface names passed to vxlan-stitch links are sanitized, which fixes SR-SIM deployments with long node or interface names. #3437
  • inspect --all merges repeated cells again when --wide/-w is set. #3378
  • Canonical image names are resolved correctly for registries addressed as host:port, fixing image pulls and auth lookups for such registries. #3391
  • External management access works again for setuid-root installs on iptables-legacy backends, where iptables refused to run with differing real and effective UIDs. #3353
  • Fixed a missing client context in the Podman runtime when copying configuration to containers. #3364
  • Bind mounts in the Podman runtime carry the :z option so files are accessible across security contexts. #3347
  • sonic-vs marks its wire interfaces (ethN) ARP-off and IPv6-off so only the port interface answers, preventing stale ARP entries with the wrong MAC. #3390
  • vr-ftosv link endpoints accept the ethernet1/1/X, ethernet 1/1/X, and 1/1/X names in addition to ethX. #3354
  • The quick setup script installs Docker 29.8.1 on Ubuntu 26.04, uses the official Docker repository for CentOS, checks for an SSH daemon, and relies on the RPM repo config file instead of dnf/yum commands. #3424 #3400 #3431
  • Fixed a flaky management interface update when Cisco IOL nodes are redeployed. #3392
  • The vrnetlab kinds documentation now mentions the 10.0.0.15 management address that transparent management assigns. #3420