Skip to content

Network

One of the most important tasks in the process of building container based labs is to create a virtual wiring between the containers and the host. That is one of the problems that containerlab was designed to solve.

In this document we will discuss the networking concepts that containerlab employs to provide the following connectivity scenarios:

  1. Make containers available from the lab host
  2. Interconnect containers to create network topologies of users choice

Management network#

As governed by the well-established container networking principles containers are able to get network connectivity using various drivers/methods. The most common networking driver that is enabled by default for docker-managed containers is the bridge driver.

The bridge driver connects containers to a linux bridge interface named docker0 on most linux operating systems. The containers are then able to communicate with each other and the host via this virtual switch (bridge interface).

In containerlab we follow a similar approach: containers launched by containerlab will be attached with their interface to a containerlab-managed docker network. It's best to be explained by an example which we will base on a two nodes lab from our catalog:

name: srl02

topology:
  kinds:
    nokia_srlinux:
      type: ixrd3
      image: ghcr.io/nokia/srlinux
  nodes:
    srl1:
      kind: nokia_srlinux
    srl2:
      kind: nokia_srlinux

  links:
    - endpoints: ["srl1:e1-1", "srl2:e1-1"]

As seen from the topology definition file, the lab consists of the two SR Linux nodes which are interconnected via a single point-to-point link.

The diagram above shows that these two nodes are not only interconnected between themselves, but also connected to a bridge interface on the lab host. This is driven by the containerlab default management network settings.

Default settings#

When no information about the management network is provided within the topo definition file, containerlab will do the following

  1. create, if not already created, a docker network named clab
  2. configure the IPv4/6 addressing pertaining to this docker network

Info

We often refer to clab docker network simply as management network since it's the network to which management interfaces of the containerized NOS'es are connected.

The addressing information that containerlab will use on this network:

  • IPv4: subnet 172.20.20.0/24, gateway 172.20.20.1
  • IPv6: subnet 3fff:172:20:20::/64, gateway 3fff:172:20:20::1

This management network will be configured with MTU value matching the value of a docker0 host interface to match docker configuration on the system. This option is configurable.

With these defaults in place, the two containers from this lab will get connected to that management network and will be able to communicate using the IP addresses allocated by docker daemon. The addresses that docker carves out for each container are presented to a user once the lab deployment finishes or can be queried any time after:

# addressing information is available once the lab deployment completes
❯ containerlab deploy -t srl02.clab.yml
# deployment log omitted for brevity
╭─────────────────┬───────────────────────┬─────────┬───────────────────╮
│       Name      │       Kind/Image      │  State  │   IPv4/6 Address  │
├─────────────────┼───────────────────────┼─────────┼───────────────────┤
│ clab-srl02-srl1 │ nokia_srlinux         │ running │ 172.20.20.3       │
│                 │ ghcr.io/nokia/srlinux │         │ 3fff:172:20:20::3 │
├─────────────────┼───────────────────────┼─────────┼───────────────────┤
│ clab-srl02-srl2 │ nokia_srlinux         │ running │ 172.20.20.2       │
│                 │ ghcr.io/nokia/srlinux │         │ 3fff:172:20:20::2 │
╰─────────────────┴───────────────────────┴─────────┴───────────────────╯

# addresses can also be fetched afterwards with `inspect` command
❯ containerlab inspect -a
╭────────────────┬──────────┬─────────────────┬───────────────────────┬─────────┬───────────────────╮
│    Topology    │ Lab Name │       Name      │       Kind/Image      │  State  │   IPv4/6 Address  │
├────────────────┼──────────┼─────────────────┼───────────────────────┼─────────┼───────────────────┤
│ srl02.clab.yml │ srl02    │ clab-srl02-srl1 │ nokia_srlinux         │ running │ 172.20.20.3       │
│                │          │                 │ ghcr.io/nokia/srlinux │         │ 3fff:172:20:20::3 │
│                │          ├─────────────────┼───────────────────────┼─────────┼───────────────────┤
│                │          │ clab-srl02-srl2 │ nokia_srlinux         │ running │ 172.20.20.2       │
│                │          │                 │ ghcr.io/nokia/srlinux │         │ 3fff:172:20:20::2 │
╰────────────────┴──────────┴─────────────────┴───────────────────────┴─────────┴───────────────────╯

The output above shows that srl1 container has been assigned 172.20.20.3/24 / 3fff:172:20:20::3/80 IPv4/6 address. We can ensure this by querying the srl1 management interfaces address info:

❯ docker exec clab-srl02-srl1 ip address show dummy-mgmt0
6: dummy-mgmt0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 2a:66:2b:09:2e:4d brd ff:ff:ff:ff:ff:ff
    inet 172.20.20.3/24 brd 172.20.20.255 scope global dummy-mgmt0
       valid_lft forever preferred_lft forever
    inet6 3fff:172:20:20::3/80 scope global
       valid_lft forever preferred_lft forever

Now it's possible to reach the assigned IP address from the lab host as well as from other containers connected to this management network.

# ping srl1 management interface from srl2
❯ docker exec -it clab-srl02-srl2 sr_cli "ping 172.20.20.3 network-instance mgmt"
x -> $176x48
Using network instance mgmt
PING 172.20.20.3 (172.20.20.3) 56(84) bytes of data.
64 bytes from 172.20.20.3: icmp_seq=1 ttl=64 time=2.43 ms

Note

If you run multiple labs without changing the default management settings, the containers of those labs will end up connecting to the same management network with their management interface.

Host mode networking#

In addition to the bridge-based management network containerlab supports launching nodes in host networking mode. In this mode containers are attached to the host network namespace. Host mode is enabled with network-mode node setting.

Configuring management network#

Most of the time there is no need to change the defaults for management network configuration, but sometimes it is needed. For example, it might be that the default network ranges are overlapping with the existing addressing scheme on the lab host, or it might be desirable to have predefined management IP addresses.

For such cases, the users need to add the mgmt container at the top level of their topology definition file:

name: srl02

mgmt:
  network: custom_mgmt                # management network name
  ipv4-subnet: 172.100.100.0/24       # ipv4 range
  ipv6-subnet: 3fff:172:100:100::/80  # ipv6 range (optional)

topology:
# the rest of the file is omitted for brevity

With these settings in place, the container will get their IP addresses from the specified ranges accordingly.

Network name#

The default container network name is clab. To customize this name, users should specify a new value within the network element:

mgmt:
  network: myNetworkName

User-defined addresses#

By default, containerlab will assign the management IP addresses for the nodes. While containerlab assigns these in a deterministic nature, it's sometimes helpful to have user-defined addressing in the management network.

For such cases, users can define the desired IPv4/6 addresses on a per-node basis:

mgmt:
  network: fixedips
  ipv4-subnet: 172.100.100.0/24
  ipv6-subnet: 3fff:172:100:100::/80

topology:
  nodes:
    n1:
      kind: nokia_srlinux
      mgmt-ipv4: 172.100.100.11       # set ipv4 address on management network
      mgmt-ipv6: 3fff:172:100:100::11 # set ipv6 address on management network

Users can specify either IPv4 or IPv6 or both addresses. If one of the addresses is omitted, it will be assigned by container runtime in an arbitrary fashion.

Note

  1. If user-defined IP addresses are needed, they must be provided for all containers attached to a given network to avoid address collision.
  2. IPv4/6 addresses set on a node level must be from the management network range.
  3. IPv6 addresses are truncated by Docker1, therefore do not use bytes 5 through 8 of the IPv6 network range.

IP range#

By specifying ipv4-range/ipv6-range under the management network the range from which IP addresses are allocated for a management subnet can be limited.

mgmt:
  network: custom-net
  ipv4-subnet: 10.20.30.0/24 #(1)!
  ipv4-range: 10.20.30.128/25 #(2)!
  1. The subnet must be specified for IP ranges to work. For an existing bridge network, a different IP range setting has no effect. An incompatible range on an existing macvlan network is rejected.
  2. The IPAM provider allocates addresses from 10.20.30.128/25, excluding 10.20.30.0/25.

IPAM#

In the management network, the IPAM provider is what allocates IP addresses to the nodes in the topology. There are two providers:

  • Containerlab (default).
  • Runtime. Delegates to Docker/Podman IPAM.

The below example sets the IPAM provider to the container runtime.

mgmt:
  ipam:
    provider: runtime
Address allocation#

When allocating addresses to nodes, the containerlab provider attempts to do so in a determinsitc manner so that subsequent redeployments of the topology shall result in the same IP addressing for all nodes in the topology.

Upon deployment, allocations are saved in the topology state file and reused when still available. Without that state file it is possible for allocations to shift on topology reconciliations.

Duplicate address detection#

Duplicate address detection is enabled by default and ensures allocations by the containerlab IPAM provider are not duplicate on the network. This has no effect on the runtime provider.

The default bridge management network relies on runtime address exclusions collected before allocation.

For the MACVLAN driver on mode: bridge, DAD checks local addresses and the ARP/ND cache, then sends an ARP and/or IPv6 neighbour solicitation out the parent interface.

Given the below example, the ARP/ND packets will be sent out the enp2s0 interface.

mgmt:
  driver: macvlan
  macvlan-parent: enp2s0

Scalability of DAD with MACVLAN driver

Containerlab sends packets out the parent interface and waits for a response. If no reply is received, the address can be used.

While this process does happen concurrently as the topology scales to 1000+ nodes the checks could add extra time to the lab deployment, and it may be worth disabling the DAD checks.

See below to disable DAD:

mgmt:
  ipam:
    dad: false

Multiple management networks#

The mgmt section also accepts a list of networks. Nodes join a particular network by using the mgmt-net key under the node definition. The management network is identified by the network name provided in the network key.

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

Note

Multiple management networks are currently supported with the Docker runtime only.

When multiple management networks are defined, every node must have a mgmt-net defined (or inherited from groups/kinds/defaults).

The first defined management network becomes the default network for things like tools containers.

The following also should be taken into consideration:

  • Nodes using network-mode ignore the mgmt-net key.
  • The --network, --ipv4/6-subnet flag is not supported.
  • skip-when-unused is evaluated per network: a network with the flag set is not created when every node attached to it runs with network-mode: none.
  • When a management network is dropped from the mgmt list, the next destroy removes it together with the networks the topology still defines.

Drivers#

The driver specifies the type of network that is created. Either bridge or macvlan.

The default is bridge when the driver is not explicitly specified.

Bridge#

The bridge driver connects management interfaces through a Linux bridge on the host, as described in Management network. It is the default for new management networks.

Auto-assigned addresses#

The default network addresses chosen by containerlab - 172.20.20.0/24 and 3fff:172:20:20::/64 - may clash with the existing addressing scheme on the lab host. With the user-defined addresses discussed above, users can avoid such conflicts, but this requires manual changes to the lab topology file and may not be convenient.

To address this issue, containerlab provides a way to automatically assign the management network v4/v6 addresses. This is achieved by setting the ipv4-subnet and/or ipv6-subnet to auto:

mgmt:
  ipv4-subnet: auto
  ipv6-subnet: auto

With this setting in place, the container runtime selects management subnets that do not conflict with the existing addressing scheme on the lab host. The configured IPAM provider then assigns node addresses from the resolved subnets.

Both the default containerlab provider and the runtime provider are supported.

Docker rejects static endpoint addresses on subnets selected from its default address pools, including when reusing an existing network. If Docker rejects an address allocated by containerlab, containerlab retries with Docker assigning the address. Explicit mgmt-ipv4 and mgmt-ipv6 settings are preserved; they require a user-configured subnet in the Docker network.

MTU#

The MTU of the management network defaults to an MTU value of docker0 interface, but it can be set to a user defined value:

mgmt:
  network: clab_mgmt
  mtu: 2100 # set mtu of the management network to 2100

This will result in every interface connected to that network to inherit this MTU value.

Default Docker network#

To make clab nodes start in the default docker network bridge, which uses the docker0 bridge interface, users need to mention this explicitly in the configuration:

mgmt:
  network: bridge

Since bridge network is created by default by docker, using its name in the configuration will make nodes to connect to this network.

IPAM

Docker's built-in bridge network will always uses runtime IPAM since Docker rejects user-specified IP addresses on that network.

Explicitly setting the provider to be containerlab has no effect, hence DAD is also not handled by Containerlab in this case.

Bridge name#

By default, containerlab will create a linux bridge backing the management docker network with the following name br-<network-id>. The network-id part is coming from the docker network ID that docker manages.

We allow our users to change the bridge name that the management network will use. This can be used to connect containers to an already existing bridge with other workloads connected:

mgmt:
  # a bridge with a name mybridge will be created or reused
  # as a backing bridge for the management network
  bridge: mybridge

If the existing bridge has already been addressed with IPv4/6 address, containerlab will respect this address and use it in the IPAM configuration blob of the docker network.

If there is no existing IPv4/6 address defined for the custom bridge, docker will assign the first interface from the subnet associated with the bridge.

It is possible to set the desired gateway IP (that is the IP assigned to the bridge) with the ipv4-gw/ipv6-gw setting under mgmt container:

mgmt:
  network: custom-net
  bridge: mybridge
  ipv4-subnet: 10.20.30.0/24 # ip range for the docker network
  ipv4-gw: 10.20.30.100 # set custom gateway ip
Access from external hosts#

Containerlab will attempt to enable external management access to the nodes by default. This means that external systems/hosts will be able to communicate with the nodes of your topology without requiring any manual iptables/nftables rules to be installed.

To allow external communications containerlab installs a rule in the DOCKER-USER chain for v4 and v6, allowing all packets targeting containerlab's management network. The rule looks like follows:

sudo iptables -vnL DOCKER-USER
Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     0    --  br-1351328e1855 *       0.0.0.0/0            0.0.0.0/0            /* set by containerlab */
    0     0 ACCEPT     0    --  *      br-1351328e1855  0.0.0.0/0            0.0.0.0/0            /* set by containerlab */
    0     0 RETURN     0    --  *      *       0.0.0.0/0            0.0.0.0/0
  1. The br-1351328e1855 bridge interface is the interface that backs up the containerlab's management network (clab docker network).

The rule will be removed together with the management network.

RHEL 9 users

By default RHEL 9 (and it's derivatives) will use firewalld as the default firewall, containerlab's iptables and nftables rules will not work in this case and you will not have external access to your labs.

To fix this you must disable firewalld and enable the nftables service.

Take caution when disabling firewalls, you may be exposing things you shouldn't

systemctl disable firewalld
systemctl stop firewalld
systemctl mask firewalld

systemctl enable --now nftables

Should you not want to enable external access to your nodes you can set external-access property to false under the management section of a topology:

name: no-ext-access
mgmt:
  external-access: false #(1)!
topology:
# your regular topology definition
  1. When set to false, containerlab will not touch iptables rules. On most docker installations this will result in restricted external access.
Errors and warnings

External access feature requires nftables kernel API to be present. Kernels newer than v4 typically have this API enabled by default. To understand which API is in use one can issue the following command:

iptables -V
iptables v1.8.5 (nf_tables)

If the outputs contains nf_tables you are all set. If it contains legacy or doesn't say anything about nf_tables then nf_tables API is not available and containerlab will not be able to setup external access. You will have to enable it manually (or better yet - upgrade the kernel).
Older distros, like Centos 7, are known to use the legacy iptables backend and therefore will emit a warning when containerlab will attempt to launch a lab. The warning will not prevent the lab from starting and running, but you will need to setup iptables rules manually if you want your nodes to be accessible from the outside of your containerlab host.

Containerlab will throw an error "missing DOCKER-USER iptables chain" when this chain is not found. This error is typically caused by two factors

  1. Old docker version installed. Typically seen on Centos systems. Minimum required docker version is 17.06.
  2. Docker is installed incorrectly. It is recommended to follow the official installation procedures by selecting "Installation per distro" menu option.

When docker is correctly installed, additional iptables chains will become available and the error will not appear.

Bridge network driver options#

By default, containerlab will create the management bridge with default driver options2, however, for special networking setups required in some cases, this can be overridden in the driver-opts section of the mgmt block.

This section is a key-value pair for each overridden driver option:

mgmt:
  network: custom-net
  bridge: mybridge
  driver-opts:
    com.docker.network.bridge.gateway_mode_ipv4: routed
    com.docker.network.bridge.gateway_mode_ipv6: routed

All driver options can be overridden, even those set by containerlab.

Local-only networking#

The default management bridge driver options are configured to allow external network access from the containers through the management interface, including internet. In order to prevent unintentional internet or external network access, ip masquerading needs to be disabled on the management interface bridge:

mgmt:
  network: custom-net
  driver-opts:
    com.docker.network.bridge.enable_ip_masquerade: false

This allows for bidirectional communication between the host and containers, as well as between containers, while preventing access to the host's external network.

Connection details#

When containerlab needs to create the management network, it asks the docker daemon to do this. Docker will fulfill the request and will create a network with the underlying linux bridge interface backing it. The bridge interface name is generated by the docker daemon, but it is easy to find it:

# list existing docker networks
# notice the presence of the `clab` network with a `bridge` driver
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5d60b6ec8420        bridge              bridge              local
d2169a14e334        clab                bridge              local
58ec5037122a        host                host                local
4c1491a09a1a        none                null                local

# the underlying linux bridge interface name follows the `br-<first_12_chars_of_docker_network_id> pattern
# to find the network ID use:
❯ docker network inspect clab -f {{.ID}} | head -c 12
d2169a14e334

# now the name is known and it's easy to show bridge state
❯ brctl show br-d2169a14e334
bridge name         bridge id      STP enabled   interfaces
br-d2169a14e334  8000.0242fe382b74 no        vetha57b950
                                 vethe9da10a

As explained in the beginning of this article, containers will connect to this docker network. This connection is carried out by the veth devices created and attached with one end to bridge interface in the lab host and the other end in the container namespace. This is illustrated by the bridge output above and the diagram at the beginning the of the article.

Macvlan#

The Macvlan driver connects management interfaces directly to a host interface's Layer 2 network.

Each container is effectively directly on the same layer 2 network as the host is, and thus has its own MAC address on that network.

The minimum definition to use the Macvlan management network specifies:

  • The driver
  • An existing parent interface
  • An IPv4 or IPv6 subnet
name: macvlan-mgmt

mgmt:
  driver: macvlan
  macvlan-parent: eth1
  ipv4-subnet: 192.0.2.0/24
Parent interface#

macvlan-parent is required and must name an interface that already exists on the host.

For VLANs, create the logical VLAN interface before deploying the lab, then use its name as the parent.

The MTU for the management network is inherited from the parent interface and cannot be changed via mgmt.mtu as with the bridge driver.

Mode#

macvlan-mode accepts bridge, private, vepa, or passthru. The default mode is bridge. This is not the same as the bridge management network driver.

Bridge mode allows communication between macvlan interfaces on the same parent. Auxiliary host connectivity is available only in bridge mode and is disabled automatically for private, vepa, and passthru.

IP Addressing#

By default the IPv4/v6 addressing is gleaned from the defined parent interface if the subnet is valid for addressing nodes in the topology (ie. not a /31).

You can also optionally define the subnet. The allocation range and subnet should be defined appropriately to match the physical network.

mgmt:
  driver: macvlan
  macvlan-parent: eth1
  ipv4-subnet: 192.0.2.0/24
  ipv4-gw: 192.0.2.1
  ipv4-range: 192.0.2.128/26

Tip

Reserve the container address range in any external DHCP/IPAM system as the container runtimes' IPAM only prevents address collisions within its own network.

Auxiliary host connectivity#

Linux does not allow a macvlan parent interface to communicate directly with its macvlan children. Resulting in a case whereby the host has no access to the management network of the containers it is running.

To solve this containerlab creates an owned macvlan interface in the host namespace by default.

Set macvlan-aux: false to disable it:

mgmt:
  driver: macvlan
  macvlan-parent: eth1
  macvlan-aux: false
  ipv4-subnet: 192.0.2.0/24

When enabled, containerlab selects an unused /32 or /128 auxiliary address checks it on the parent Layer 2 segment.

After nodes attach to the network, containerlab adds exact /32 or /128 host routes via the auxiliary interface, and a postrouting TCP checksum rule which allows connectivity for NOSes verifying TCP checksums.

Skipping the management network#

When every node in a topology runs with network-mode: none the default clab docker network is created but never used, and an empty CLAB-<lab> marker block is appended to /etc/hosts. Set skip-when-unused: true under mgmt to suppress both:

name: all-none
mgmt:
  skip-when-unused: true
topology:
  defaults:
    network-mode: none
  nodes:
    n1:
    n2:

Inheritance from defaults, kinds, and groups is honored - the network is only skipped when every node resolves to network-mode: none. If any node still attaches to the mgmt network (the default), the flag has no effect.

With multiple management networks the flag is evaluated per network: a network with skip-when-unused: true is not created when every node attached to it resolves to network-mode: none, or when no node selects it with mgmt-net at all. The /etc/hosts marker block is only omitted when every management network is skipped.

Tailscale#

The management network can optionally be joined to a Tailscale tailnet. There are two modes:

  • Sidecar mode: Requires a tailscale auth-key. Each node will appear as a device in your tailnet.

  • Proxy mode: Uses SSO authentication, the lab appears as a single device in your tailnet, and exposed ports are user defined.

Sidecar mode#

In the sidecar mode each node in your topology will get a tailscale sidecar container spun up which represents the node as a device in the tailnet. It will forward all traffic destined to itself to the nodes management IP.

In sidecar mode you must authenticate using the auth-key.

The auth key is generated from the Tailscale admin panel, and should be reusable and ideally ephemeral.

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

topology:
  nodes:
    srl1:
      kind: nokia_srlinux
    srl2:
      kind: nokia_srlinux

In the above topology, in our tailnet we will see devices clab-mylab-srl1 and clab-mylab-srl2. In the background two tailscale containers are spun up on the host and they forward all traffic to the respectie nodes.

Proxy mode#

In the proxy mode, the entire lab is represented by a single device in the tailnet. To access nodes/services in the lab, you must forward ports on a per-node basis.

The proxy mode only supports SSO authentication.

The proxy mode is recommended for users who don't have access to the tailscale admin panel to generate an authnetication key, or users who want to tightly control what services in their lab are exposed to the tailnet.

name: mylab
mgmt:
  tailscale:
    auth-mode: sso

topology:
  nodes:
    srl1:
      kind: nokia_srlinux
      ports:
        - 8022:22/ts
    srl2:
      kind: nokia_srlinux
      ports:
        - 9022:22/ts

In the above topology we will see a single device in our tailnet as clab-mylab. We can connect to port 8022 of this device to SSH to srl1, or 9022 to SSH to srl2.

/// info Currently only TCP ports are forwarded using the /ts port nomenclature. If you require other protocol support, please raise a GitHub issue. ///

Management network is used to provide management access to the NOS containers, it does not carry control or dataplane traffic. In containerlab we create additional point-to-point links between the containers to provide the datapath between the lab nodes.

The above diagram shows how links are created in the topology definition file. In this example, the datapath consists of the two virtual point-to-point wires between SR Linux and cEOS containers. These links are created on-demand by containerlab itself.

The p2p links are typically provided by the veth device pairs where each end of the veth pair is attached to a respective container.

The MTU on the veth links is set by default to 9500B, so a regular jumbo frame shouldn't traverse the links without problems. If you need to change the MTU, you can do so by setting the mtu property in the link definition:

topology:
  links:
    - endpoints: ["router2:eth2", "router3:eth1"]
      mtu: 1500

It is also possible to interconnect container' data interface not with other container or add it to a bridge, but to attach it to a host's root namespace. This is, for example, needed to create a L2 connectivity between containerlab nodes running on different VMs (aka multi-node labs).

This "host-connectivity" is achieved by using a reserved node name - host - referenced in the endpoints section. Consider the following example where an SR Linux container has its only data interface connected to a hosts root namespace via veth interface:

name: host

topology:
  nodes:
    srl:
      kind: nokia_srlinux
      image: ghcr.io/nokia/srlinux
      startup-config: test-srl-config.json
  links:
    - endpoints: ["srl:e1-1", "host:srl_e1-1"]

With this topology definition, we will have a veth interface with its one end in the container' namespace and its other end in the host namespace. The host will have the interface named srl_e1-1 once the lab deployed:

ip link
# SNIP
433: srl_e1-1@if434: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether b2:80:e9:60:c7:9d brd ff:ff:ff:ff:ff:ff link-netns clab-srl01-srl

Additional connections to management network#

By default every lab node will be connected to the docker network named clab which acts as a management network for the nodes.

In addition to that mandatory connection, users can attach additional interfaces to this management network. This might be needed, for example, when data interface of a node needs to talk to the nodes on the management network.

For such connections a special form of endpoint definition was created - mgmt-net:$iface-name.

name: mgmt
topology:
  nodes:
    n1:
      kind: nokia_srlinux
      image: ghcr.io/nokia/srlinux
  links:
    - endpoints:
        - "n1:e1-1"
        - "mgmt-net:n1-e1-1"

In the above example the node n1 connects with its e1-1 interface to the management network. This is done by specifying the endpoint with a reserved name mgmt-net and defining the name of the interface that should be used in that bridge (n1-e1-1).

By specifying mgmt-net name of the node in the endpoint definition we tell containerlab to find out which bridge is used by the management network of our lab and use this bridge as the attachment point for our veth pair.

This is best illustrated with the following diagram:

In addition to the veth links, containerlab supports macvlan links. This type of links is useful when users want to connect containers to the host interface/network directly. This is achieved by defining a link endpoints which has one end defined with a special macvlan:<host-iface-name> signature.

Consider the following example where we connect a Linux container l1 to the hosts enp0s3 interface:

name: macvlan

topology:
  nodes:
    l1:
      kind: linux
      image: alpine:3

  links:
    - endpoints: ["l1:eth1", "macvlan:enp0s3"]

This topology will result in l1 node having its eth1 interface connected to the enp0s3 interface of the host as per the diagram below:

Containerlab will create a macvlan interface in the bridge mode, attach it to the parent enp0s3 interface and then move it to the container's net namespace and name it eth1, as instructed by the endpoint definition in the topology.

Users then can configure the eth1 interface inside the container as they would do with any other interface. As per the diagram above, we configure eth1 interface with ipv4 address from the host's enp0s3 interface subnet:

entering the container's shell
docker exec -it clab-macvlan-l1 ash
# adding v4 address to the eth1 interface
ip address add 10.0.0.111/24 dev eth1

Once v4 address is assigned to the macvlan interface, we can test the connectivity by pinging default gateway of the host:

❯ ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=0.545 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=0.243 ms

When capturing packets from the hosts's enp0s3 interface we can see that the ping packets are coming through it using the mac address assigned to the macvlan interface:

❯ tcpdump -nnei enp0s3 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:35:02.430901 aa:c1:ab:72:b3:fe > fa:16:3e:af:03:05, ethertype IPv4 (0x0800), length 98: 10.0.0.111 > 10.0.0.1: ICMP echo request, id 24, seq 4, length 64
22:35:02.431017 fa:16:3e:af:03:05 > aa:c1:ab:72:b3:fe, ethertype IPv4 (0x0800), length 98: 10.0.0.1 > 10.0.0.111: ICMP echo reply, id 24, seq 4, length 64

Manual control over the management network#

By default containerlab creates a docker network named clab and attaches all the nodes to this network. This network is used as a management network for the nodes and is managed by the container runtime such as docker or podman.

Container runtime is responsible for creating the eth0 interface inside the container and attaching it to the clab network. This interface is used by the container to communicate with the management network. For that reason the links users create in the topology's links section typically do not include the eth0 interface.

However, there might be cases when users want to take control over eth0 interface management. For example, they might want to connect eth0 to a different network or even another container's interface. To achieve that, users can instruct container runtime to not manage the eth0 interface and leave it to the user, using network-mode: none setting.

Consider the following example, where node1's management interface eth0 is provided in the links section and connects to node2's eth1 interface:

name: e0

topology:
  nodes:
    node1:
      kind: linux
      image: alpine:3
      network-mode: none
    node2:
      kind: linux
      image: alpine:3
  links:
    - endpoints: ["node1:eth0", "node2:eth1"]

DNS#

When containerlab finishes the nodes deployment, it also creates static DNS entries inside the /etc/hosts file so that users can access the nodes using their DNS names.

The DNS entries are created for each node's IPv4/6 address, and follow the pattern - clab-$labName-$nodeName.

For a lab named demo with two nodes named l1 and l2 containerlab will create the following section inside the /etc/hosts file.

###### CLAB-demo-START ######
172.20.20.2     clab-demo-l1
172.20.20.3     clab-demo-l2
3fff:172:20:20::2       clab-demo-l1
3fff:172:20:20::3       clab-demo-l2
###### CLAB-demo-END ######

  1. See https://github.com/srl-labs/containerlab/issues/1302#issuecomment-1533796941 for details and links to the original discussion. ↩

  2. The only exception to this is setting the gateway mode to nat-unprotected for Docker version 28 and above, see https://github.com/srl-labs/containerlab/issues/2638 for the original discussion. ↩