Adding New Virtualization Provider for an Existing Device

If you want to run a network device on a virtualization provider that is not yet supported by netlab (example: Cisco IOS packaged as a vrnetlab container), you came to the right place.

Here’s what you have to do:

Adding a Box Name to Topology Defaults

  • Find your device settings within netsim/devices directory

  • Add a new key provider key for the target device (valid keys are libvirt, virtualbox or clab). Add image parameter under the provider key. Its value is the expected Vagrant box name or Docker container.

Example (routeros.yml):

interface_name: ether%d
virtualbox:
  image: mikrotik/chr

Recommended:

  • Use standard Docker Hub container names (which can include the version number in tag field)

  • If you need a version number for a Vagrant image downloaded from Vagrant Cloud, use user/image:version format (example: CumulusCommunity/cumulus-vx:4.3.0)

Changing Provider-Specific Device Settings

You can change default device settings for a specific virtualization provider within the device parameter file.

There are four types of settings you can change:

Default settings (easy) – provider.something settings are merged with the device settings.

Example: Change management interface name and container image on Arista cEOS:

mgmt_if: Management1
clab:
  mgmt_if: Management0devices:
  image: ceos:4.31.2F

Ansible group variables (easy) – values specified in group_vars section of device-and-provider-specific settings overwrite the device defaults.

Example: Change Ansible connection for a Cumulus VX container:

interface_name: swp{ifindex}
libvirt:
  image: CumulusCommunity/cumulus-vx:4.4.0
virtualbox:
  image: CumulusCommunity/cumulus-vx:4.3.0
group_vars:
  ansible_user: vagrant
  ansible_ssh_pass: vagrant
  ansible_network_os: cumulus
  ansible_connection: paramiko
clab:
  image: networkop/cx:4.4.0
  group_vars:
    ansible_connection: docker
    ansible_user: root

Node parameters (manageable)– the node dictionary within provider-specific device settings is copied into node data under provider key.

Example: containerlab needs a device kind setting in its configuration file. The configuration file template uses clab.kind value within node data to set that parameter, so we need a mechanism to set clab.kind value for every node.

Solution: use node dictionary within clab device parameters:

interface_name: swp{ifindex}
loopback_interface_name: "lo{ifindex}"
mgmt_if: eth0
libvirt:
  image: CumulusCommunity/cumulus-vx:4.4.0
clab:
  node:
    kind: cvx
    runtime: docker
  image: networkop/cx:4.4.0

Interface names (mind-boggling). Interface names used by the network device might differ from the interface names used by virtualization provider (example: Arista cEOS on containerlab).

Solution: set interface.name in provider-specific device settings. Whenever those settings include interface.name value, the link interface data and node interfaces data includes provider.name value for every interface. That value can then be used in configuration templates.

Example: Arista cEOS containerlab settings

interface_name: Ethernet{ifindex}
description: Arista vEOS
mgmt_if: Management1
loopback_interface_name: Loopback{ifindex}
libvirt:
  image: arista/veos
virtualbox:
  image: arista/veos
clab:
  image: ceos:4.31.2F
  interface:
    name: et{ifindex}

Example: Part of containerlab configuration template

...
  links:
{% for l in links %}
  - endpoints:
{%   for n in nodes.values() %}
{%     for nl in n.interfaces if nl.linkindex == l.linkindex %}
{%       set clab = nl.clab|default({}) %}
    - "{{ n.name }}:{{ clab.name|default(nl.ifname) }}"
{%     endfor %}
{%   endfor %}
{% endfor %}