Building a Multi-Access Network with a Bridge Node

Testing failure scenarios in virtual networks is a bit harder than in the real world. Shutting down an interface might bring down adjacent interfaces, or trigger an interface-down event on the remote node if you’re connecting devices with vEth pairs. Even worse, some devices might reenable interfaces you try to shut down with ip link set down Linux command instead of the shutdown configuration command.

Inserting a virtual bridge between adjacent virtual machines with the type: lan link attribute solves some of the abovementioned problems. If you shut down the interface connected to the virtual bridge with the ip link set interface down command, you usually experience similar effects to transceiver/switch failure in the real world – the node interface is up, but it cannot receive or send any traffic. Unfortunately, you cannot use the same approach for point-to-point links between containers (netlab never uses a Linux bridge for point-to-point container links); you must attach an extra node to the link to force netlab to use a Linux bridge.

Even though you could use the Linux bridge trick to get host interfaces you can shut down, you must be familiar with Linux networking commands to find the bridge and attached interface names, and to shut down the desired interface.

netlab release 2.0 allows you to replace a Linux bridge in a multi-access network with another lab device (VM or container) with role: bridge attribute. The rules are straightforward:

  • Add another node to the lab topology with the role: bridge attribute. The device you use for the bridge must support the bridge role.

For example, in the following topology, you would get an Arista EOS container acting as a simple bridge inserted between two FRR routers:

provider: clab
defaults.device: frr

nodes:
  a:
  b:
  br:
    role: bridge
    device: eos

links:
- a:
  b:
  bridge: br

After starting the lab, the following configuration is deployed on the Arista EOS br node (only the relevant parts are included in the printout):

vlan 100
   name br_vlan_100
!
interface Ethernet1
   description [Access VLAN br_vlan_100] br -> a
   mac-address 52:dc:ca:fe:03:01
   switchport access vlan 100
!
interface Ethernet2
   description [Access VLAN br_vlan_100] br -> b
   mac-address 52:dc:ca:fe:03:02
   switchport access vlan 100

You can now shut down an interface on the br node using familiar configuration commands (manually, using netlab config, or with a validate config action) to emulate a link loss.

Using a Bridge Node in a Validation Test

Here’s an example (taken from the VRRP integration test) of using a bridge node in a validation test:

  • The lab topology uses a link implemented with a Linux container acting as a bridge device (we have to use a bridge node because the validation tests cannot execute commands on the host):

links:
- bridge: br_a       # Use an explicit Linux bridge on the client network
  h1:
  dut:
    gateway.vrrp.priority: 30
  r2:
    gateway.vrrp.priority: 20
  gateway: True
  prefix: source
  • A custom configuration template finds the Linux interface with the desired neighbor (specified in the Ansible neighbor variable) and shuts it down (it has to match the neighbor value with the node attribute of entries in the intf.neighbors list):

#!/bin/bash
{% for intf in interfaces
     if neighbor in intf.neighbors|map(attribute='node',default='')
       and intf.vlan.access_id is defined %}
ip link set {{ intf.ifname }} {{ ifstate|default('down') }}
{% endfor %}
  • The custom configuration template is used in validation tests to disconnect a node from the LAN segment and reconnect it:

validate:
  r2_disconnect:
    description: Disable R2 link on client LAN
    nodes: [ br_a ]
    config:
      template: linkdown
      variable.neighbor: r2
      variable.ifstate: 'down'
    pass: R2 link has been disabled on client LAN
    stop_on_error: True
...
  r2_reconnect:
    description: Reconnect R2 to the client LAN
    nodes: [ br_a ]
    config:
      template: linkdown
      variable.neighbor: r2
      variable.ifstate: 'up'
    pass: R2 has been reconnected to client LAN
    stop_on_error: True