diff --git a/docs/module/lag.md b/docs/module/lag.md index ddb24e8b55..3bd679ac89 100644 --- a/docs/module/lag.md +++ b/docs/module/lag.md @@ -34,7 +34,7 @@ The following parameters can be set on individual links: * **lag.ifindex**: Optional parameter that controls the naming of the LAG (bonding, port-channel) interface. * **lag.mlag**: Optional dictionary with peer link parameters; see [below](lag-mlag) -This configuration module creates a virtual link with the link type set to **lag** between the **lag.members** and appends the links described in the **lag.members** list to the topology **links** list. +This configuration module creates virtual **lag** type interfaces on nodes that are listed in **lag.members** and appends the links described in the **lag.members** list to the topology **links** list. ## Example @@ -113,6 +113,38 @@ links: mlag.peergroup: True # (also) used to derive a unique MAC address for this group of MLAG peers ``` +### Peerlink configuration + +The **peerlink** between mlag peers is modeled as a one-to-one lag link, and hence all the various *Netlab* features - such as IP addressing, OSPF and BGP - can be configured on it. Different platforms use different approaches and defaults for implementing the peerlink - e.g. different vlan numbers, irb versus routed mode, etc.; some of these defaults can be changed through _device features_. + +By default, *Netlab* will configure the peerlink as a trunk that allows all VLANs. To restrict this, include a VLAN trunk definition on the peerlink: +``` +links: +- lag: + mlag.peergroup: True + vlan.trunk: [ vlan1000 ] # This will allow only vlan1000 plus the device-specific peerlink vlan and the default vlan +``` + +By default, on most platforms the global `lan` pool will be used to allocate IP addresses similar to regular IRB VLANs. If different addressing is desired, set a custom 'pool' or 'prefix' attribute on the peerlink: +``` +addressing: + custom_peerlink: + ipv4: 169.254.0.0/16 + prefix: 31 + allocation: p2p + +links: +- lag: + mlag.peergroup: True + pool: custom_peerlink + +- lag: + mlag.peergroup: True + prefix: + ipv4: 169.254.127.0/31 + allocation: p2p +``` + ### Advanced MLAG Parameters The **lag.mlag.peer.backup_ip** _device feature_ specifies a property from the node data model that should be used to determine the MLAG peer's backup IP address (the IP address an MLAG node tries to reach when resolving a split-brain scenario). This parameter is part of the device features and can be changed only for a device type, not individual nodes. diff --git a/netsim/ansible/templates/initial/cumulus_nvue.j2 b/netsim/ansible/templates/initial/cumulus_nvue.j2 index 090a4a9973..9f561dd23a 100644 --- a/netsim/ansible/templates/initial/cumulus_nvue.j2 +++ b/netsim/ansible/templates/initial/cumulus_nvue.j2 @@ -1,6 +1,7 @@ {% macro decl_interface(i) %} {{ i.ifname }}: - type: {{ 'svi' if i.type=='svi' else 'sub' if i.type=='vlan_member' else 'bond' if i.type=='lag' else 'swp' }} + type: {{ 'svi' if i.type=='svi' else 'sub' if i.type=='vlan_member' else 'bond' if i.type=='lag' + else 'peerlink' if i.ifname=='peerlink' else 'swp' }} link: {% if i.mtu is defined %} mtu: {{ i.mtu }} @@ -12,28 +13,30 @@ {% elif i.type|default("") == "stub" %} description: Stub interface {% endif %} +{% if 'peerlink' not in i.ifname or i.ipv4 is defined %} ip: -{% if i.ipv4 is defined or (i.ipv6 is string and i.ipv6|ipv6) %} +{% if i.ipv4 is defined or (i.ipv6 is string and i.ipv6|ipv6) %} address: -{% if i.ipv4 is defined %} +{% if i.ipv4 is defined %} {{ (loopback if i.ipv4 == True else i).ipv4 }}: {} -{% endif %} -{% if i.ipv6 is string and i.ipv6|ipv6 %} +{% endif %} +{% if i.ipv6 is string and i.ipv6|ipv6 %} {{ i.ipv6 }}: {} +{% endif %} {% endif %} -{% endif %} ipv6: -{% if i.ipv6 is defined %} +{% if i.ipv6 is defined %} forward: on -{% if 'ipv6' not in i.dhcp.client|default({}) %} +{% if 'ipv6' not in i.dhcp.client|default({}) %} neighbor-discovery: enable: on router-advertisement: enable: on interval: 5000 -{% endif %} -{% else %} +{% endif %} +{% else %} enable: off +{% endif %} {% endif %} {% endmacro %} @@ -57,6 +60,7 @@ address: dhcp: {} type: eth + {# Avoid creating L2-only sub interfaces #} {% for l in interfaces|default([]) if l.type not in ['loopback','vlan_member'] or (l.type=='vlan_member' and ('ipv4' in l or 'ipv6' in l)) %} diff --git a/netsim/ansible/templates/initial/dellos10.j2 b/netsim/ansible/templates/initial/dellos10.j2 index 231bc9748b..de9c4b7c58 100644 --- a/netsim/ansible/templates/initial/dellos10.j2 +++ b/netsim/ansible/templates/initial/dellos10.j2 @@ -30,7 +30,7 @@ interface {{ mgmt.ifname|default('mgmt1/1/1') }} no lldp transmit no lldp receive ! -{% for l in interfaces|default([]) %} +{% for l in interfaces|default([]) if l.ifname!='peerlink' %} interface {{ l.ifname }} no shutdown {% if l.virtual_interface is not defined or (l.type=='lag' and ('ipv4' in l or 'ipv6' in l)) %} diff --git a/netsim/ansible/templates/lag/arubacx.j2 b/netsim/ansible/templates/lag/arubacx.j2 index 442b8e4dce..ecc55bedaa 100644 --- a/netsim/ansible/templates/lag/arubacx.j2 +++ b/netsim/ansible/templates/lag/arubacx.j2 @@ -1,23 +1,3 @@ -{# Provision VSX peerlink #} -{% for intf in interfaces if intf.lag.mlag.peergroup is defined %} - -interface lag {{ intf.lag.mlag.ifindex }} - no shutdown - no routing - vlan trunk native 1 - vlan trunk allowed all - lacp mode active - description VSX ISL - -! -{% for ch in ([intf]+interfaces) if ch==intf or ch.lag._peerlink|default(0) == intf.linkindex %} -interface {{ ch.ifname }} - no shutdown - description {{ ch.name }} (ISL in lag {{intf.lag.mlag.ifindex }}) - lag {{ intf.lag.mlag.ifindex }} -! -{% endfor %} - ! ! VSX Config ! @@ -36,6 +16,11 @@ vsx interface {{ intf.ifname }}{{ mclag_intf }}{{ mclag_intf_static }} {% if '_mlag' in intf.lag %} description {{ intf.name }} (VSX LAG {{ intf.lag.ifindex }}) +{% elif intf.lag.mlag.peergroup is defined %} + no routing + vlan trunk native 1 + vlan trunk allowed all + description VSX ISL {% else %} description {{ intf.name }} {% endif %} @@ -57,6 +42,7 @@ interface {{ intf.ifname }}{{ mclag_intf }}{{ mclag_intf_static }} {% for ch in interfaces if ch.lag._parentindex|default(None) == intf.lag.ifindex %} ! interface {{ ch.ifname }} + no shutdown description {{ ch.name }} in lag {{ intf.lag.ifindex }} lag {{ intf.lag.ifindex }} ! diff --git a/netsim/ansible/templates/lag/cumulus_nvue.j2 b/netsim/ansible/templates/lag/cumulus_nvue.j2 index e9785a6946..bc0408f4f6 100644 --- a/netsim/ansible/templates/lag/cumulus_nvue.j2 +++ b/netsim/ansible/templates/lag/cumulus_nvue.j2 @@ -1,24 +1,5 @@ {% if lag.mlag is defined %} - set: - interface: - peerlink: - bridge: - domain: - br_default: - learning: off # As recommended by NVidia - bond: - member: -{% for intf in interfaces if intf.lag.mlag.peergroup is defined %} - {{ intf.ifname }}: {} -{% for ch in interfaces if ch.lag._peerlink|default(0) == intf.linkindex %} - {{ ch.ifname }}: {} -{% endfor %} -{% endfor %} - type: peerlink - peerlink.{{ lag.mlag.vlan }}: - base-interface: peerlink - type: sub - vlan: {{ lag.mlag.vlan }} mlag: init-delay: 10 backup: @@ -54,6 +35,11 @@ bridge: domain: br_default: {} +{% elif i.ifname=='peerlink' %} + bridge: + domain: + br_default: + learning: off # As recommended by NVidia {% endif %} bond: {% if '_mlag' in i.lag %} diff --git a/netsim/ansible/templates/lag/dellos10.j2 b/netsim/ansible/templates/lag/dellos10.j2 index 11e89dfdb4..5a6e8b89c2 100644 --- a/netsim/ansible/templates/lag/dellos10.j2 +++ b/netsim/ansible/templates/lag/dellos10.j2 @@ -2,17 +2,16 @@ ! OS10 internally uses port-channel 1000 and VLAN 4094 for VLT {% for intf in interfaces if intf.lag.mlag.peergroup is defined %} vlt-domain {{ intf.lag.mlag.peergroup }} - backup destination {{ intf.lag.mlag.peer }} + backup destination {{ intf.lag.mlag.peer_backup_ip }} vlt-mac {{ intf.lag.mlag.mac | hwaddr('linux') }} {# Reduce default 90-second delay timer to avoid wasting time waiting #} delay-restore 30 - discovery-interface {{ intf.ifname }} -{% for ch in interfaces if ch.lag._peerlink|default(0) == intf.linkindex %} +{% for ch in interfaces if ch.lag._parentindex|default(None) == intf.lag.ifindex %} discovery-interface {{ ch.ifname }} {% endfor %} {% endfor %} -{% for intf in interfaces if intf.type == 'lag' %} +{% for intf in interfaces if intf.type == 'lag' and intf.ifname != 'peerlink' %} interface {{ intf.ifname }} {% if '_mlag' in intf.lag %} {% set desc = intf.name.replace(",", "\\\\,") + " in vlt-port-channel " + intf.lag.ifindex|string %} diff --git a/netsim/ansible/templates/lag/eos.j2 b/netsim/ansible/templates/lag/eos.j2 index 26bb4765a0..6084c3e498 100644 --- a/netsim/ansible/templates/lag/eos.j2 +++ b/netsim/ansible/templates/lag/eos.j2 @@ -1,42 +1,34 @@ +{% if lag.mlag is defined %} {# Provision mlag peerlink, EOS supports at most 1 peerlink #} -{% for intf in interfaces if intf.lag.mlag.peergroup is defined %} - -vlan {{ intf.lag.mlag.vlan }} +vlan {{ lag.mlag.vlan }} name "MLAG-peerlink" trunk group m1peer ! -no spanning-tree vlan-id {{ intf.lag.mlag.vlan }} +no spanning-tree vlan-id {{ lag.mlag.vlan }} -interface port-channel {{ intf.lag.mlag.ifindex }} - description MLAG peerlink(s) {{ intf.name }} +interface port-channel {{ lag.mlag.ifindex }} + description MLAG peerlink(s) switchport mode trunk switchport trunk group m1peer ! -interface vlan {{ intf.lag.mlag.vlan }} +interface vlan {{ lag.mlag.vlan }} description MLAG peerlink local-interface - ip address {{ intf.lag.mlag.self }} no autostate ! mlag - domain-id mlag{{ intf.lag.mlag.peergroup }} - local-interface vlan {{ intf.lag.mlag.vlan }} - peer-address {{ intf.lag.mlag.peer }} - peer-link port-channel {{ intf.lag.mlag.ifindex }} + domain-id mlagDomain + local-interface vlan {{ lag.mlag.vlan }} + peer-address {{ lag.mlag.peer }} + peer-link port-channel {{ lag.mlag.ifindex }} no shutdown ! -{% for ch in ([intf]+interfaces) if ch==intf or ch.lag._peerlink|default(0) == intf.linkindex %} -interface {{ ch.ifname }} - description {{ ch.name }} (peerlink in channel-group {{intf.lag.mlag.ifindex }}) - channel-group {{ intf.lag.mlag.ifindex }} mode active -! -{% endfor %} -{% if 'gateway' in module %} +{% if 'gateway' in module %} ip virtual-router mac-address mlag-peer +{% endif %} {% endif %} -{% endfor %} {% for intf in interfaces if intf.type == 'lag' %} interface {{ intf.ifname }} diff --git a/netsim/ansible/templates/vlan/arubacx.j2 b/netsim/ansible/templates/vlan/arubacx.j2 index 9f41a19dc6..4cb2179112 100644 --- a/netsim/ansible/templates/vlan/arubacx.j2 +++ b/netsim/ansible/templates/vlan/arubacx.j2 @@ -4,8 +4,8 @@ interface {{ ifdata.ifname }} {% if ifdata.vlan.trunk_id is defined %} no routing - vlan trunk allow {{ ifdata.vlan.trunk_id|sort|join(",") }} -{% if ifdata.vlan.native is defined %} + vlan trunk allow {{ 'all' if '_allow_all' in ifdata.vlan else ifdata.vlan.trunk_id|sort|join(",") }} +{% if ifdata.vlan.native is defined or '_allow_all' in ifdata.vlan %} vlan trunk native {{ ifdata.vlan.access_id }} {% elif 1 in ifdata.vlan.trunk_id %} vlan trunk native 1 tag diff --git a/netsim/ansible/templates/vlan/cumulus_nvue.j2 b/netsim/ansible/templates/vlan/cumulus_nvue.j2 index 86a25d5011..7c56853e1c 100644 --- a/netsim/ansible/templates/vlan/cumulus_nvue.j2 +++ b/netsim/ansible/templates/vlan/cumulus_nvue.j2 @@ -17,6 +17,7 @@ {% for i in interfaces if (i.vlan.access_id is defined or i.subif_index is defined) and i.vlan.mode|default(None) != 'route' and (i.virtual_interface is not defined or i.type in ["vlan_member","lag"]) %} +{% set _allow_all_vlans = '_allow_all' in i.vlan|default({}) %} - set: interface: {{ i.parent_ifname if i.type=='vlan_member' else i.ifname }}: @@ -27,11 +28,11 @@ vlan: '{{ i.vlan.access_id }}': {} {% elif i.subif_index is defined %} -{% if i.vlan.access_id is defined %} +{% if i.vlan.access_id is defined and not _allow_all_vlans %} vlan: '{{ i.vlan.access_id }}': {} {% endif %} - untagged: {{ i.vlan.access_id if i.vlan.native is defined else 'none' }} + untagged: {{ i.vlan.access_id|default(1) if i.vlan.native is defined or _allow_all_vlans else 'none' }} {% else %} access: {{ i.vlan.access_id }} {% endif %} diff --git a/netsim/ansible/templates/vlan/dellos10.j2 b/netsim/ansible/templates/vlan/dellos10.j2 index eb98477b6f..78f59938cc 100644 --- a/netsim/ansible/templates/vlan/dellos10.j2 +++ b/netsim/ansible/templates/vlan/dellos10.j2 @@ -12,17 +12,19 @@ interface vlan {{ vlan.id }} {% endfor %} {% endif %} ! -{% for ifdata in interfaces if ifdata.vlan is defined %} +{% for ifdata in interfaces if ifdata.vlan is defined and ifdata.ifname != 'peerlink' %} ! interface {{ ifdata.ifname }} {% if ifdata.vlan.trunk_id is defined %} switchport mode trunk -{% if ifdata.vlan.native is defined or 1 in ifdata.vlan.trunk_id %} +{% if ifdata.vlan.native is defined or 1 in ifdata.vlan.trunk_id or '_allow_all' in ifdata.vlan %} switchport access vlan {{ ifdata.vlan.access_id|default(1) }} {% else %} no switchport access vlan {% endif %} +{% if '_allow_all' not in ifdata.vlan %} switchport trunk allowed vlan {{ ifdata.vlan.trunk_id|difference([ifdata.vlan.access_id|default(1)])|join(",") }} +{% endif %} {% elif ifdata.vlan.access_id is defined %} switchport mode access switchport access vlan {{ ifdata.vlan.access_id }} diff --git a/netsim/ansible/templates/vlan/eos.j2 b/netsim/ansible/templates/vlan/eos.j2 index 78c8153715..421b24094c 100644 --- a/netsim/ansible/templates/vlan/eos.j2 +++ b/netsim/ansible/templates/vlan/eos.j2 @@ -11,9 +11,9 @@ interface {{ ifdata.ifname }} {% if ifdata.vlan.trunk_id is defined %} switchport switchport mode trunk - switchport trunk allowed vlan {{ ifdata.vlan.trunk_id|sort|join(",") }} -{% if ifdata.vlan.native is defined %} - switchport trunk native vlan {{ ifdata.vlan.access_id }} + switchport trunk allowed vlan {{ 'all' if '_allow_all' in ifdata.vlan else ifdata.vlan.trunk_id|sort|join(",") }} +{% if ifdata.vlan.native is defined or '_allow_all' in ifdata.vlan %} + switchport trunk native vlan {{ ifdata.vlan.access_id|default(1) }} {% else %} switchport trunk native vlan tag {% endif %} diff --git a/netsim/devices/arubacx.yml b/netsim/devices/arubacx.yml index 64ef19adfc..c08407b6b7 100644 --- a/netsim/devices/arubacx.yml +++ b/netsim/devices/arubacx.yml @@ -52,8 +52,9 @@ features: lag: mlag: peer: - ifindex: 255 # Use this port-channel - mac: 0600.0000.0000 # Base to generate a virtual MAC + ifindex: 255 # Use this port-channel + ifname: "lag{ifindex}" + mac: 0600.0000.0000 # Base to generate a virtual MAC passive: True mpls: ldp: true diff --git a/netsim/devices/cumulus_nvue.yml b/netsim/devices/cumulus_nvue.yml index f9ff343d3f..8af4a83c9b 100644 --- a/netsim/devices/cumulus_nvue.yml +++ b/netsim/devices/cumulus_nvue.yml @@ -20,6 +20,7 @@ group_vars: ansible_network_os: cumulus_nvue ansible_connection: paramiko ansible_python_interpreter: auto_silent + netlab_show_command: [ sudo, vtysh, -c, 'show $@' ] features: initial: system_mtu: True @@ -47,7 +48,10 @@ features: global: True # Use global node level settings for peerlink mac: 44:38:39:ff:00:00 # Base to generate a virtual MAC. NVidia reserved range vlan: 4094 # Use this vlan - ip: linklocal # Use this IP subnet + vlan_mode: route + ifindex: 4094 # Use this (dummy) ifindex + ifname: peerlink + pool: mlag_linklocal # Use this pool by default, unless overridden backup_ip: loopback.ipv4 # Use loopback.ipv4 as a backup IP address for peerlink ospf: import: [ bgp, connected, vrf ] diff --git a/netsim/devices/dellos10.yml b/netsim/devices/dellos10.yml index 1d18e04aee..3d0e3446c8 100644 --- a/netsim/devices/dellos10.yml +++ b/netsim/devices/dellos10.yml @@ -25,11 +25,13 @@ features: gateway: protocol: [ anycast, vrrp ] lag: - reserved_ifindex_range: [ 1000 ] mlag: peer: - mac: 0200.01a9.0000 # Base to generate a virtual MAC - ip: loopback.ipv4 # Use loopback.ipv4 for peer IP address + mac: 0200.01a9.0000 # Base to generate a virtual MAC + backup_ip: loopback.ipv4 # Use loopback.ipv4 for peer IP address + ifindex: 1000 # OS10 uses port-channel 1000 for mlag peering + vlan: 1002 # VLAN 4094 is used for VLT peering, but not configurable. 1002 is reserved on IOS + vlan_mode: irb # Routed subintf not supported passive: True ospf: default: True diff --git a/netsim/devices/eos.yml b/netsim/devices/eos.yml index 4d07688c83..8bd73158a4 100644 --- a/netsim/devices/eos.yml +++ b/netsim/devices/eos.yml @@ -59,9 +59,11 @@ features: lag: mlag: peer: + global: True # EOS only supports a single peerlink vlan: 4094 # Use this vlan + vlan_mode: irb ifindex: 4094 # Use this port-channel - ip: 169.254.127.0/31 # Use this subnet + ifname: "port-channel{ifindex}" passive: True mpls: 6pe: true diff --git a/netsim/devices/none.yml b/netsim/devices/none.yml index 2492c8dfef..e40014c51b 100644 --- a/netsim/devices/none.yml +++ b/netsim/devices/none.yml @@ -74,7 +74,9 @@ features: ipv6: True network: True lag: - mlag: True + mlag: + peer: + vlan: 1234 passive: True mpls: ldp: True diff --git a/netsim/modules/lag.py b/netsim/modules/lag.py index c4655f93ff..f4024ef944 100644 --- a/netsim/modules/lag.py +++ b/netsim/modules/lag.py @@ -5,7 +5,7 @@ from . import _Module, _dataplane from .. import data from ..data import types as _types -from ..utils import log +from ..utils import log, strings from ..augment import devices, links ID_SET = 'lag_id' @@ -63,17 +63,24 @@ def check_lag_config(node: str, linkname: str, topology: Box) -> bool: return True """ -check_mlag_support - check if the given node supports mlag +check_mlag_support - check if the given node supports mlag, returns mlag feature flags if supported """ -def check_mlag_support(node: str, linkname: str, topology: Box) -> bool: +def check_mlag_support(node: str, linkname: str, topology: Box) -> typing.Optional[Box]: _n = topology.nodes[node] features = devices.get_device_features(_n,topology.defaults) if not features.lag.get('mlag',False): log.error(f'Node {_n.name} ({_n.device}) does not support MLAG, cannot be part of peerlink or M-side of LAG {linkname}', category=log.IncorrectValue, module='lag') - return False - return True + return None + + # Check that the VLAN module is enabled for MLAG nodes that use a VLAN on their peerlink + if 'vlan' in features.lag.mlag.peer and not 'vlan' in _n.module: + log.error(f'Node {_n.name} ({_n.device}) does not have the VLAN module enabled, required for MLAG peerlink', + category=log.MissingDependency, + module='lag') + return None + return features.lag.mlag.peer """ normalized_members - builds a normalized list of lag member links. It also checks that: @@ -108,7 +115,7 @@ def normalized_members(l: Box, topology: Box, peerlink: bool = False) -> list: return members """ -set_lag_ifindex - Assign lag.ifindex, check for overlap with any reserved values +set_lag_ifindex - Assign lag.ifindex, check for overlap with mlag port-channel if any """ def set_lag_ifindex(bond: Box, intf: Box, topology: Box) -> bool: intf_lag_ifindex = intf.get('lag.ifindex',None) # Use user provided lag.ifindex, if any @@ -123,7 +130,7 @@ def set_lag_ifindex(bond: Box, intf: Box, topology: Box) -> bool: if is_mside: # For M: side we need matching lag.ifindex if next_ifindex is None: # Do we have a local preference? next_ifindex = _dataplane.get_next_id(ID_SET) # No -> allocate globally - bond.lag.ifindex = link_lag_ifindex = next_ifindex # Put on the link for the other M side to match + bond.lag.ifindex = link_lag_ifindex = next_ifindex # Put on the link for the other M side to match else: if next_ifindex is None: next_ifindex = topology.defaults.lag.start_lag_id # Start at start_lag_id (default 1) @@ -139,20 +146,19 @@ def set_lag_ifindex(bond: Box, intf: Box, topology: Box) -> bool: bond.lag.ifindex = link_lag_ifindex = intf_lag_ifindex features = devices.get_device_features(_n,topology.defaults) - if 'reserved_ifindex_range' in features.lag: # Exclude any reserved port channel IDs - if intf_lag_ifindex in features.lag.reserved_ifindex_range: - log.error(f'Selected lag.ifindex({intf_lag_ifindex}) conflicts with device specific reserved range ' + - f'{features.lag.reserved_ifindex_range} for node {_n.name} ({_n.device})', - category=log.IncorrectValue, - module='lag') - return False + if features.get('lag.mlag.peer.ifindex',None)==intf_lag_ifindex: + log.error(f'Selected lag.ifindex({intf_lag_ifindex}) conflicts with device specific reserved MLAG ' + + f'port-channel for node {_n.name} ({_n.device})', + category=log.IncorrectValue, + module='lag') + return False return True """ create_lag_member_links -- expand lag.members for link l and create physical p2p links """ -def create_lag_member_links(l: Box, topology: Box) -> bool: - members = normalized_members(l,topology) # Build list of normalized member links +def create_lag_member_links(l: Box, topology: Box, peerlink: bool = False) -> bool: + members = normalized_members(l,topology,peerlink) # Build list of normalized member links if not members: return False l.lag.members = members # Update for create_lag_interfaces @@ -234,54 +240,84 @@ def create_lag_interfaces(link: Box, mlag_pairs: dict, topology: Box) -> None: link.interfaces.append( ifatts ) """ -create_peer_links: creates and configures physical link(s) for given peer link from peer link's lag.members +create_peer_vlan - create a global VLAN for the peerlink (if supported), to enable features like OSPF """ -def create_peer_links(l: Box, mlag_pairs: dict, topology: Box) -> bool: +def create_peer_vlan(peerlink: Box, mlag_peer_features: Box, topology: Box) -> None: + if peerlink.get('prefix',None) is False: # Skip VLAN creation if prefix is set to False + return + + if 'vlan' in mlag_peer_features and mlag_peer_features.vlan: # Check if device supports an explicit peering VLAN + vlan_name = f"peervlan_{ peerlink[PEERLINK_ID_ATT] }" + vlan = data.get_box({ 'id': mlag_peer_features.vlan, 'mode': 'irb', '_mlag_peer': True }) + if 'stp' in topology.module: + vlan.stp.enable = False + lag_peervlan_attr = list(topology.defaults.lag.attributes.lag_peervlan_attr) + for a in list(peerlink.keys()): + if a in lag_peervlan_attr: # Move all l3 attributes to the vlan interface + vlan[a] = peerlink.pop(a,None) + + if 'pool' not in vlan: # Configure a default pool if device needs it + vlan_pool = mlag_peer_features.get('pool',None) + if vlan_pool: + vlan.pool = vlan_pool + + vlan_trunk = peerlink.get('vlan.trunk',[]) + if not vlan_trunk: + peerlink.vlan._allow_all = True # Unless the user configured a trunk, allow all vlans + # including native VLAN + peerlink.vlan.trunk = vlan_trunk + [ vlan_name ] + topology.vlans[ vlan_name ] = vlan + node_mode = mlag_peer_features.get('vlan_mode','route') + if node_mode=='route': # Override 'irb' mode at each mlag peer node + for intf in peerlink.interfaces: + intf.vlan.trunk[vlan_name].vlan.mode = 'route' - """ - check_same_pair - Verifies that the given member connects the same pair of nodes as the first - """ - first_pair : typing.List[str] = [] - def check_same_pair(member: Box) -> bool: - others = { n.node for n in member.interfaces if n.node not in first_pair } - if others: - log.error(f'All member links must connect the same pair of nodes({first_pair}), found {others}', - category=log.IncorrectValue, - module='lag') - return False - return True + if log.debug_active('lag'): + print(f'create_peer_vlan: {vlan_name} = {vlan}') - members = normalized_members(l,topology,peerlink=True) - l2_linkdata = create_l2_link_base(l,topology) + if log.debug_active('lag'): + print(f'create_peer_vlan: peerlink = {peerlink}') + +""" +create_peer_links: creates and configures physical link(s) for given peer link from peer link's lag.members +""" +def create_peer_links(peerlink: Box, mlag_pairs: dict, topology: Box) -> bool: - for idx,member in enumerate(members): - member = l2_linkdata + member # Copy L2 data into member link - if idx==0: # For the first member, use the existing link - topology.links[l.linkindex-1] = l + member # Update topology (l is a copy) + # Create the peerlink as a regular virtual lag link, add physical links for the members + if not create_lag_member_links(peerlink,topology,peerlink=True): + return False + first_pair : typing.List[str] = [] + for idx,member in enumerate(peerlink.lag.members): + if idx==0: first_pair = [ i.node for i in member.interfaces ] - _devs = { topology.nodes[n].device for n in first_pair } - if len(_devs)!=1: # Check that both are the same device type - log.error(f'Nodes {first_pair} on MLAG peerlink {member._linkname} have different device types ({_devs})', + node = topology.nodes[ first_pair[0] ] + if node.device != topology.nodes[ first_pair[1] ].device: # Check that both are the same device type + log.error(f'Nodes {first_pair} on MLAG peerlink {member._linkname} have different device types', category=log.IncorrectValue, module='lag') return False - for node in first_pair: - if not check_mlag_support(node,l._linkname,topology): - return False - mlag_pairs[ first_pair[0] ] = first_pair[1] # Keep track of mlag peers + mlag_features = check_mlag_support(node.name,peerlink._linkname,topology) + if not mlag_features: + return False + ifname = strings.eval_format(mlag_features.get('ifname','peerlink'),mlag_features) + peerlink.interfaces = [ { 'node': i.node, 'ifname': ifname, '_type': 'lag' } for i in member.interfaces ] + peerlink.lag.ifindex = mlag_features.get('ifindex',0) # Set lag.ifindex, default to 0 if not provided + create_peer_vlan(peerlink, mlag_features, topology) + if 'prefix' not in peerlink: + peerlink.prefix = False + + topology.links[peerlink.linkindex-1] = peerlink # Update topology + mlag_pairs[ first_pair[0] ] = first_pair[1] # Keep track of mlag peers mlag_pairs[ first_pair[1] ] = first_pair[0] - if log.debug_active('lag'): - print(f'LAG create_peer_links -> updated first link {l} from {member} -> {topology.links[l.linkindex-1]}') else: - if not check_same_pair(member): # Check that any additional links connect the same nodes + others = { n.node for n in member.interfaces if n.node not in first_pair } + if others: + log.error(f'All peerlinks must connect the same pair of nodes({first_pair}), found {others}', + category=log.IncorrectValue, + module='lag') return False - member.linkindex = len(topology.links)+1 - member.lag._peerlink = l.linkindex # Keep track of parent - if log.debug_active('lag'): - print(f'LAG create_peer_links -> adding link {member}') - topology.links.append(member) - topology.links[l.linkindex-1].pop("lag.members",None) # Cleanup + topology.links[peerlink.linkindex-1].pop("lag.members",None) # Cleanup return True """ @@ -303,8 +339,7 @@ def process_lag_link(link: Box, mlag_pairs: dict, topology: Box) -> bool: if peerlink_id: if peerlink_id is True: # Auto-assign peerlink ID if requested link[PEERLINK_ID_ATT] = _dataplane.get_next_id(PEERLINK_ID_SET) - link.type = 'p2p' - link.prefix = False # L2-only + link._peerlink = True # Mark it as a virtual peerlink, to be removed return create_peer_links(link,mlag_pairs,topology) else: link._virtual_lag = True # Temporary virtual link, removed in module_post_link_transform @@ -314,26 +349,26 @@ def process_lag_link(link: Box, mlag_pairs: dict, topology: Box) -> bool: # populate_mlag_peer - Lookup the IPv4 loopback address for the mlag peer, and derive a virtual MAC to use # def populate_mlag_peer(node: Box, intf: Box, topology: Box) -> None: - peer = topology.nodes[intf.neighbors[0].node] + nbs = intf.get('_vlan_saved_neighbors', intf.get('neighbors',[])) + if not nbs: + log.error("Internal error: Unable to determine neighbors",module='lag') + return + peer = topology.nodes[nbs[0].node] features = devices.get_device_features(node,topology.defaults) mlag_peer = features.get('lag.mlag.peer',{}) - _target = node.lag if mlag_peer.get('global',False) else intf.lag # Set at node or intf level? - if 'ip' in mlag_peer: - if mlag_peer.ip == 'linklocal': - _target.mlag.peer = 'linklocal' - elif 'loopback' in mlag_peer.ip: # Could check if an IGP is configured - ip = peer.get(mlag_peer.ip,None) - if ip: - _target.mlag.peer = str(netaddr.IPNetwork(ip).ip) - else: - log.error(f'Node {peer.name} must have {mlag_peer.ip} defined to support MLAG', - category=log.IncorrectValue, - module='lag') + _target = node.lag if mlag_peer.get('global',False) else intf.lag # Set at node or intf level? + + for i in node.interfaces: # Figure out which IP Netlab assigned to the peer + if not i.pop('_mlag_peer',None): + continue + if i.neighbors and 'ipv4' in i.neighbors[0] and i.neighbors[0].get('ipv6',None) is not True: + _ip = i.neighbors[0].ipv4 + if isinstance(_ip,bool): + _ip = peer.loopback.ipv4 + _target.mlag.peer = str(netaddr.IPNetwork(_ip).ip) else: - net = netaddr.IPNetwork(mlag_peer.ip) - id = 0 if node.id < peer.id else 1 - _target.mlag.peer = str(net[1-id]) # Higher node ID gets .1 - _target.mlag.self = f"{net[id]}/{net.prefixlen}" # including /prefix + _target.mlag.peer = 'linklocal' + break if 'backup_ip' in mlag_peer: bk_ip = peer.get(mlag_peer.backup_ip,None) @@ -345,15 +380,13 @@ def populate_mlag_peer(node: Box, intf: Box, topology: Box) -> None: module='lag') if 'mac' in mlag_peer and not isinstance(_target.get('mlag.mac',None),str): - mac = netaddr.EUI(mlag_peer.mac) # Generate unique virtual MAC per MLAG group - mac._set_value(mac.value + intf.get(PEERLINK_ID_ATT,0) % 65536 ) # ...based on lag.mlag.peergroup + mac = netaddr.EUI(mlag_peer.mac) # Generate unique virtual MAC per MLAG group + mac._set_value(mac.value + intf.get(PEERLINK_ID_ATT,0) % 65536 ) # ...based on lag.mlag.peergroup _target.mlag.mac = str(mac) for v in ['vlan','ifindex']: if v in mlag_peer: _target.mlag[v] = mlag_peer[v] - - intf.pop('vlan',None) # Remove any VLANs provisioned on peerlinks """ Sanity check: LAG links that are configured to use a Linux bridge do not support LACP @@ -422,13 +455,12 @@ def link_pre_link_transform(self, link: Box, topology: Box) -> None: intf.type = intf.pop('_type') """ - module_post_transform - remove temporary 'virtual_lag' links, and check for links with Linux bridges - - e.g. mixed provider links - that would block LACP + module_post_transform - remove temporary 'virtual_lag' links and check for Linux bridges blocking LACP """ def module_post_transform(self, topology: Box) -> None: if log.debug_active('lag'): - print(f'LAG module_post_transform: Cleanup "virtual_lag" links') - topology.links = [ link for link in topology.links if '_virtual_lag' not in link ] + print(f'LAG module_post_transform: Cleanup "virtual_lag" and "_peerlink" links') + topology.links = [ link for link in topology.links if '_virtual_lag' not in link and '_peerlink' not in link ] check_bridge_links(topology) """ @@ -442,36 +474,35 @@ def node_post_transform(self, node: Box, topology: Box) -> None: has_peerlink = False uses_mlag = False for i in node.interfaces: + if i.type!='lag': + continue + if i.get(PEERLINK_ID_ATT,None): # Fill in peer loopback IP and vMAC for MLAG peer links populate_mlag_peer(node,i,topology) has_peerlink = True - elif i.type=='lag': - node_atts = { k:v for k,v in node.get('lag',{}).items() if k!='mlag'} - i.lag = node_atts + i.lag # Merge node level settings with interface overrides - - if 'mode' in i.lag: - log.warning( - text=f'lag.mode {i.lag.mode} used by node {node.name} is deprecated, use only 802.3ad', - module='lag') - if i.lag.mode != '802.3ad': - i.lag.lacp = 'off' # Disable LACP for other modes - - linkindex = i.pop('linkindex',None) # Remove linkindex (copied from link that no longer exists) - for m in node.interfaces: # Update members to point to lag.ifindex, replacing linkindex - if m.get('lag._parentindex',None)==linkindex: + node_atts = { k:v for k,v in node.get('lag',{}).items() if k!='mlag'} + i.lag = node_atts + i.lag # Merge node level settings with interface overrides + if 'mode' in i.lag: + log.warning( + text=f'lag.mode {i.lag.mode} used by node {node.name} is deprecated, use only 802.3ad', + module='lag') + if i.lag.mode != '802.3ad': + i.lag.lacp = 'off' # Disable LACP for other modes + linkindex = i.pop('linkindex',None) # Remove linkindex (copied from link that no longer exists) + for m in node.interfaces: # Update members to point to lag.ifindex, replacing linkindex + if m.get('lag._parentindex',None)==linkindex: m.lag._parentindex = i.lag.ifindex # Make _parentindex point to lag.ifindex instead - - lacp_mode = i.get('lag.lacp_mode') - if lacp_mode=='passive' and not features.lag.get('passive',False): - log.error(f'Node {node.name}({node.device}) does not support passive LACP configured on interface {i.ifname}', + lacp_mode = i.get('lag.lacp_mode') + if lacp_mode=='passive' and not features.lag.get('passive',False): + log.error(f'Node {node.name}({node.device}) does not support passive LACP configured on interface {i.ifname}', + category=log.IncorrectAttr, + module='lag') + if i.lag.get('_mlag',False) is True: + uses_mlag = True + if 'ipv4' in i or 'ipv6' in i: + log.error(f'Node {node.name}: IP address directly on MLAG interface {i.ifname} is not supported, use a VLAN instead', category=log.IncorrectAttr, module='lag') - if i.lag.get('_mlag',False) is True: - uses_mlag = True - if 'ipv4' in i or 'ipv6' in i: - log.error(f'Node {node.name}: IP address directly on MLAG interface {i.ifname} is not supported, use a VLAN instead', - category=log.IncorrectAttr, - module='lag') if uses_mlag and not has_peerlink: log.error(f'Node {node.name} uses MLAG but has no peerlink (lag with {PEERLINK_ID_ATT}) configured', diff --git a/netsim/modules/lag.yml b/netsim/modules/lag.yml index 0a92672cd6..b53ddd54a6 100644 --- a/netsim/modules/lag.yml +++ b/netsim/modules/lag.yml @@ -57,3 +57,18 @@ attributes: _linkname: name: ifindex: + + # Copy these link attributes to the peer VLAN + lag_peervlan_attr: + pool: + prefix: + ospf: + isis: + bgp: + gateway: + +_top: # Modification of global defaults to add mlag_linklocal pool + addressing: + mlag_linklocal: + ipv4: False + ipv6: True diff --git a/netsim/modules/vlan.py b/netsim/modules/vlan.py index 3b98318ab3..0636ecb98a 100644 --- a/netsim/modules/vlan.py +++ b/netsim/modules/vlan.py @@ -18,7 +18,8 @@ 'access': { 'type' : str, 'vlan': True, 'single': True }, 'native': { 'type' : str, 'vlan': True, 'single': True }, 'mode': { 'type' : str }, - 'trunk' : { 'type' : dict,'vlan': True } + 'trunk' : { 'type' : dict,'vlan': True }, + '_allow_all' : { 'type': bool }, } def populate_vlan_id_set(topology: Box) -> None: @@ -128,9 +129,9 @@ def validate_vlan_attributes(obj: Box, topology: Box) -> None: vlan_pool = [ vdata.pool ] if isinstance(vdata.get('pool',None),str) else [] vlan_pool.extend(['vlan','lan']) - pfx_list = links.assign_link_prefix(vdata,vlan_pool,topology.pools,topology.nodes,f'{obj_path}.{vname}') - vdata.prefix = addressing.rebuild_prefix(pfx_list) - if not 'allocation' in vdata.prefix: + links.assign_link_prefix(vdata,vlan_pool,topology.pools,topology.nodes,f'{obj_path}.{vname}') + # vdata.prefix = addressing.rebuild_prefix(pfx_list) + if isinstance(vdata.get('prefix',None),Box) and not 'allocation' in vdata.prefix: vdata.prefix.allocation = 'id_based' """ diff --git a/tests/integration/lag/12-mlag-ospf-peerlink.yml b/tests/integration/lag/12-mlag-ospf-peerlink.yml new file mode 100644 index 0000000000..b90ff36106 --- /dev/null +++ b/tests/integration/lag/12-mlag-ospf-peerlink.yml @@ -0,0 +1,32 @@ +message: | + The devices under test are an MLAG pair peering through OSPFv2 using ipv4 unnumbered on the peerlink + +# defaults.devices.cumulus_nvue.warnings.ospfv3: False +ospf.af: + ipv4: True + ipv6: False + +addressing: + ospf_peerlink: + ipv4: True # Use IPv4 unnumbered + ipv6: True # Use IPv6 LLA + +groups: + _auto_create: true + switches: + members: [ s1, s2 ] + module: [ lag, vlan, ospf ] + +links: +- lag: + members: [s1-s2] + mlag.peergroup: true + pool: ospf_peerlink + +validate: + adj: + description: Check OSPF adjacencies + wait_msg: Waiting for OSPF adjacency process to complete + wait: 50 + nodes: [ s2 ] + plugin: ospf_neighbor(nodes.s1.ospf.router_id) diff --git a/tests/topology/expected/lag-mlag-m_to_m.yml b/tests/topology/expected/lag-mlag-m_to_m.yml index bdc2db5a90..06de96c20a 100644 --- a/tests/topology/expected/lag-mlag-m_to_m.yml +++ b/tests/topology/expected/lag-mlag-m_to_m.yml @@ -30,9 +30,8 @@ links: ifname: Ethernet1 node: a2 lag: - mlag: - peergroup: 1 - linkindex: 1 + _parentindex: 1 + linkindex: 4 node_count: 2 prefix: false type: p2p @@ -45,9 +44,8 @@ links: ifname: Ethernet1 node: b2 lag: - mlag: - peergroup: 2 - linkindex: 2 + _parentindex: 2 + linkindex: 5 node_count: 2 prefix: false type: p2p @@ -61,7 +59,7 @@ links: node: b1 lag: _parentindex: 3 - linkindex: 4 + linkindex: 6 node_count: 2 prefix: false type: p2p @@ -75,12 +73,12 @@ links: node: b2 lag: _parentindex: 3 - linkindex: 5 + linkindex: 7 node_count: 2 prefix: false type: p2p - _linkname: vlans.red.links[1] - bridge: input_6 + bridge: input_8 interfaces: - _vlan_mode: irb ifindex: 3 @@ -93,7 +91,7 @@ links: ifname: eth1 ipv4: 172.16.0.5/24 node: h1 - linkindex: 6 + linkindex: 8 node_count: 2 prefix: allocation: id_based @@ -102,7 +100,7 @@ links: vlan: access: red - _linkname: vlans.red.links[2] - bridge: input_7 + bridge: input_9 interfaces: - _vlan_mode: irb ifindex: 3 @@ -115,7 +113,7 @@ links: ifname: eth1 ipv4: 172.16.0.6/24 node: h2 - linkindex: 7 + linkindex: 9 node_count: 2 prefix: allocation: id_based @@ -136,22 +134,27 @@ nodes: device: eos id: 1 interfaces: - - ifindex: 1 - ifname: Ethernet1 + - ifindex: 30000 + ifname: port-channel4094 lag: + ifindex: 4094 + lacp: fast + lacp_mode: active mlag: - ifindex: 4094 - peer: 169.254.127.1 peergroup: 1 - self: 169.254.127.0/31 - vlan: 4094 - linkindex: 1 name: a1 -> a2 neighbors: - - ifname: Ethernet1 + - ifname: port-channel4094 node: a2 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel10 lag: _mlag: true @@ -173,20 +176,30 @@ nodes: red: {} trunk_id: - 1000 + - ifindex: 1 + ifname: Ethernet1 + lag: + _parentindex: 4094 + linkindex: 4 + name: a1 -> a2 + neighbors: + - ifname: Ethernet1 + node: a2 + type: p2p - ifindex: 2 ifname: Ethernet2 lag: _parentindex: 10 - linkindex: 4 + linkindex: 6 name: a1 -> b1 neighbors: - ifname: Ethernet2 node: b1 type: p2p - - bridge: input_6 + - bridge: input_8 ifindex: 3 ifname: Ethernet3 - linkindex: 6 + linkindex: 8 name: '[Access VLAN red] a1 -> h1' neighbors: - ifname: eth1 @@ -222,9 +235,27 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: Vlan4094 + ipv4: 172.16.1.1/24 + name: VLAN peervlan_1 (4094) -> [a2] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.2/24 + node: a2 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.1.2 + vlan: 4094 loopback: ifindex: 0 ifname: Loopback0 @@ -242,8 +273,16 @@ nodes: name: a1 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_1: + _mlag_peer: true + bridge_group: 2 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: bridge_group: 1 id: 1000 @@ -258,22 +297,27 @@ nodes: device: eos id: 2 interfaces: - - ifindex: 1 - ifname: Ethernet1 + - ifindex: 30000 + ifname: port-channel4094 lag: + ifindex: 4094 + lacp: fast + lacp_mode: active mlag: - ifindex: 4094 - peer: 169.254.127.0 peergroup: 1 - self: 169.254.127.1/31 - vlan: 4094 - linkindex: 1 name: a2 -> a1 neighbors: - - ifname: Ethernet1 + - ifname: port-channel4094 node: a1 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel10 lag: _mlag: true @@ -295,11 +339,21 @@ nodes: red: {} trunk_id: - 1000 + - ifindex: 1 + ifname: Ethernet1 + lag: + _parentindex: 4094 + linkindex: 4 + name: a2 -> a1 + neighbors: + - ifname: Ethernet1 + node: a1 + type: p2p - ifindex: 2 ifname: Ethernet2 lag: _parentindex: 10 - linkindex: 5 + linkindex: 7 name: a2 -> b2 neighbors: - ifname: Ethernet2 @@ -307,6 +361,20 @@ nodes: type: p2p - bridge_group: 1 ifindex: 40000 + ifname: Vlan4094 + ipv4: 172.16.1.2/24 + name: VLAN peervlan_1 (4094) -> [a1] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.1/24 + node: a1 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 + - bridge_group: 2 + ifindex: 40001 ifname: Vlan1000 ipv4: 172.16.0.2/24 name: VLAN red (1000) -> [h1,a1,b1,b2,h2] @@ -334,6 +402,10 @@ nodes: lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.1.1 + vlan: 4094 loopback: ifindex: 0 ifname: Loopback0 @@ -351,10 +423,18 @@ nodes: name: a2 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: - red: + peervlan_1: + _mlag_peer: true bridge_group: 1 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 + red: + bridge_group: 2 id: 1000 mode: irb prefix: @@ -367,22 +447,27 @@ nodes: device: eos id: 3 interfaces: - - ifindex: 1 - ifname: Ethernet1 + - ifindex: 30000 + ifname: port-channel4094 lag: + ifindex: 4094 + lacp: fast + lacp_mode: active mlag: - ifindex: 4094 - peer: 169.254.127.1 peergroup: 2 - self: 169.254.127.0/31 - vlan: 4094 - linkindex: 2 name: b1 -> b2 neighbors: - - ifname: Ethernet1 + - ifname: port-channel4094 node: b2 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_2: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel20 lag: _mlag: true @@ -404,11 +489,21 @@ nodes: red: {} trunk_id: - 1000 + - ifindex: 1 + ifname: Ethernet1 + lag: + _parentindex: 4094 + linkindex: 5 + name: b1 -> b2 + neighbors: + - ifname: Ethernet1 + node: b2 + type: p2p - ifindex: 2 ifname: Ethernet2 lag: _parentindex: 20 - linkindex: 4 + linkindex: 6 name: b1 -> a1 neighbors: - ifname: Ethernet2 @@ -416,6 +511,20 @@ nodes: type: p2p - bridge_group: 1 ifindex: 40000 + ifname: Vlan4094 + ipv4: 172.16.2.3/24 + name: VLAN peervlan_2 (4094) -> [b2] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.2.4/24 + node: b2 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_2 + - bridge_group: 2 + ifindex: 40001 ifname: Vlan1000 ipv4: 172.16.0.3/24 name: VLAN red (1000) -> [h1,a1,a2,b2,h2] @@ -443,6 +552,10 @@ nodes: lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.2.4 + vlan: 4094 loopback: ifindex: 0 ifname: Loopback0 @@ -460,10 +573,18 @@ nodes: name: b1 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: - red: + peervlan_2: + _mlag_peer: true bridge_group: 1 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 + red: + bridge_group: 2 id: 1000 mode: irb prefix: @@ -476,22 +597,27 @@ nodes: device: eos id: 4 interfaces: - - ifindex: 1 - ifname: Ethernet1 + - ifindex: 30000 + ifname: port-channel4094 lag: + ifindex: 4094 + lacp: fast + lacp_mode: active mlag: - ifindex: 4094 - peer: 169.254.127.0 peergroup: 2 - self: 169.254.127.1/31 - vlan: 4094 - linkindex: 2 name: b2 -> b1 neighbors: - - ifname: Ethernet1 + - ifname: port-channel4094 node: b1 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_2: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel20 lag: _mlag: true @@ -513,20 +639,30 @@ nodes: red: {} trunk_id: - 1000 + - ifindex: 1 + ifname: Ethernet1 + lag: + _parentindex: 4094 + linkindex: 5 + name: b2 -> b1 + neighbors: + - ifname: Ethernet1 + node: b1 + type: p2p - ifindex: 2 ifname: Ethernet2 lag: _parentindex: 20 - linkindex: 5 + linkindex: 7 name: b2 -> a2 neighbors: - ifname: Ethernet2 node: a2 type: p2p - - bridge: input_7 + - bridge: input_9 ifindex: 3 ifname: Ethernet3 - linkindex: 7 + linkindex: 9 name: '[Access VLAN red] b2 -> h2' neighbors: - ifname: eth1 @@ -562,9 +698,27 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: Vlan4094 + ipv4: 172.16.2.4/24 + name: VLAN peervlan_2 (4094) -> [b1] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.2.3/24 + node: b1 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_2 lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.2.3 + vlan: 4094 loopback: ifindex: 0 ifname: Loopback0 @@ -582,8 +736,16 @@ nodes: name: b2 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_2: + _mlag_peer: true + bridge_group: 2 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 red: bridge_group: 1 id: 1000 @@ -598,13 +760,13 @@ nodes: device: linux id: 5 interfaces: - - bridge: input_6 + - bridge: input_8 gateway: ipv4: 172.16.0.1/24 ifindex: 1 ifname: eth1 ipv4: 172.16.0.5/24 - linkindex: 6 + linkindex: 8 name: h1 -> [a1,a2,b1,b2,h2] neighbors: - ifname: Vlan1000 @@ -660,13 +822,13 @@ nodes: device: linux id: 6 interfaces: - - bridge: input_7 + - bridge: input_9 gateway: ipv4: 172.16.0.1/24 ifindex: 1 ifname: eth1 ipv4: 172.16.0.6/24 - linkindex: 7 + linkindex: 9 name: h2 -> [h1,a1,a2,b1,b2] neighbors: - ifname: eth1 @@ -717,6 +879,36 @@ nodes: ipv4: 172.16.0.1 provider: libvirt vlans: + peervlan_1: + _mlag_peer: true + host_count: 0 + id: 4094 + mode: irb + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.2/24 + node: a2 + - ifname: Vlan4094 + ipv4: 172.16.1.1/24 + node: a1 + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 + peervlan_2: + _mlag_peer: true + host_count: 0 + id: 4094 + mode: irb + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.2.4/24 + node: b2 + - ifname: Vlan4094 + ipv4: 172.16.2.3/24 + node: b1 + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 red: host_count: 2 id: 1000 diff --git a/tests/topology/expected/lag-mlag.yml b/tests/topology/expected/lag-mlag.yml index 8f4dbac5a0..d6fe2ad497 100644 --- a/tests/topology/expected/lag-mlag.yml +++ b/tests/topology/expected/lag-mlag.yml @@ -27,24 +27,8 @@ links: ifname: ethernet1/1/1 node: s2 lag: - mlag: - peergroup: 1 - linkindex: 1 - node_count: 2 - prefix: false - type: p2p -- _linkname: links[6].peerlink[1] - interfaces: - - ifindex: 1 - ifname: ethernet1/1/1 - node: s3 - - ifindex: 1 - ifname: ethernet1/1/1 - node: s4 - lag: - mlag: - peergroup: 2 - linkindex: 6 + _parentindex: 1 + linkindex: 8 node_count: 2 prefix: false type: p2p @@ -57,8 +41,8 @@ links: ifname: ethernet1/1/2 node: s1 lag: - _peerlink: 1 - linkindex: 8 + _parentindex: 1 + linkindex: 9 node_count: 2 prefix: false type: p2p @@ -72,7 +56,7 @@ links: node: s1 lag: _parentindex: 2 - linkindex: 9 + linkindex: 10 node_count: 2 prefix: false type: p2p @@ -86,7 +70,7 @@ links: node: s1 lag: _parentindex: 2 - linkindex: 10 + linkindex: 11 node_count: 2 prefix: false type: p2p @@ -100,7 +84,7 @@ links: node: s2 lag: _parentindex: 2 - linkindex: 11 + linkindex: 12 node_count: 2 prefix: false type: p2p @@ -114,7 +98,7 @@ links: node: s2 lag: _parentindex: 2 - linkindex: 12 + linkindex: 13 node_count: 2 prefix: false type: p2p @@ -128,7 +112,7 @@ links: node: s1 lag: _parentindex: 3 - linkindex: 13 + linkindex: 14 node_count: 2 prefix: false type: p2p @@ -142,7 +126,7 @@ links: node: s1 lag: _parentindex: 3 - linkindex: 14 + linkindex: 15 node_count: 2 prefix: false type: p2p @@ -156,7 +140,7 @@ links: node: s1 lag: _parentindex: 4 - linkindex: 15 + linkindex: 16 node_count: 2 prefix: false type: p2p @@ -170,7 +154,7 @@ links: node: s1 lag: _parentindex: 4 - linkindex: 16 + linkindex: 17 node_count: 2 prefix: false type: p2p @@ -184,7 +168,7 @@ links: node: s2 lag: _parentindex: 4 - linkindex: 17 + linkindex: 18 node_count: 2 prefix: false type: p2p @@ -198,7 +182,7 @@ links: node: s2 lag: _parentindex: 4 - linkindex: 18 + linkindex: 19 node_count: 2 prefix: false type: p2p @@ -212,7 +196,7 @@ links: node: s1 lag: _parentindex: 5 - linkindex: 19 + linkindex: 20 node_count: 2 prefix: false type: p2p @@ -226,7 +210,21 @@ links: node: s2 lag: _parentindex: 5 - linkindex: 20 + linkindex: 21 + node_count: 2 + prefix: false + type: p2p +- _linkname: links[6].peerlink[1] + interfaces: + - ifindex: 1 + ifname: ethernet1/1/1 + node: s3 + - ifindex: 1 + ifname: ethernet1/1/1 + node: s4 + lag: + _parentindex: 6 + linkindex: 22 node_count: 2 prefix: false type: p2p @@ -240,7 +238,7 @@ links: node: s3 lag: _parentindex: 7 - linkindex: 21 + linkindex: 23 node_count: 2 prefix: false type: p2p @@ -254,7 +252,7 @@ links: node: s4 lag: _parentindex: 7 - linkindex: 22 + linkindex: 24 node_count: 2 prefix: false type: p2p @@ -268,7 +266,7 @@ links: node: s3 lag: _parentindex: 7 - linkindex: 23 + linkindex: 25 node_count: 2 prefix: false type: p2p @@ -282,7 +280,7 @@ links: node: s4 lag: _parentindex: 7 - linkindex: 24 + linkindex: 26 node_count: 2 prefix: false type: p2p @@ -296,7 +294,7 @@ links: node: s4 lag: _parentindex: 7 - linkindex: 25 + linkindex: 27 node_count: 2 prefix: false type: p2p @@ -349,7 +347,7 @@ nodes: ifname: eth1 lag: _parentindex: 1 - linkindex: 9 + linkindex: 10 name: h1 -> s1 neighbors: - ifname: ethernet1/1/3 @@ -359,7 +357,7 @@ nodes: ifname: eth2 lag: _parentindex: 1 - linkindex: 10 + linkindex: 11 name: h1 -> s1 neighbors: - ifname: ethernet1/1/4 @@ -369,7 +367,7 @@ nodes: ifname: eth3 lag: _parentindex: 1 - linkindex: 11 + linkindex: 12 name: h1 -> s2 neighbors: - ifname: ethernet1/1/3 @@ -379,7 +377,7 @@ nodes: ifname: eth4 lag: _parentindex: 1 - linkindex: 12 + linkindex: 13 name: h1 -> s2 neighbors: - ifname: ethernet1/1/4 @@ -389,7 +387,7 @@ nodes: ifname: eth5 lag: _parentindex: 2 - linkindex: 13 + linkindex: 14 name: h1 -> s1 neighbors: - ifname: ethernet1/1/5 @@ -399,7 +397,7 @@ nodes: ifname: eth6 lag: _parentindex: 2 - linkindex: 14 + linkindex: 15 name: h1 -> s1 neighbors: - ifname: ethernet1/1/6 @@ -503,7 +501,7 @@ nodes: ifname: eth1 lag: _parentindex: 1 - linkindex: 15 + linkindex: 16 name: h2 -> s1 neighbors: - ifname: ethernet1/1/7 @@ -513,7 +511,7 @@ nodes: ifname: eth2 lag: _parentindex: 1 - linkindex: 16 + linkindex: 17 name: h2 -> s1 neighbors: - ifname: ethernet1/1/8 @@ -523,7 +521,7 @@ nodes: ifname: eth3 lag: _parentindex: 1 - linkindex: 17 + linkindex: 18 name: h2 -> s2 neighbors: - ifname: ethernet1/1/5 @@ -533,7 +531,7 @@ nodes: ifname: eth4 lag: _parentindex: 1 - linkindex: 18 + linkindex: 19 name: h2 -> s2 neighbors: - ifname: ethernet1/1/6 @@ -543,7 +541,7 @@ nodes: ifname: eth5 lag: _parentindex: 2 - linkindex: 19 + linkindex: 20 name: h2 -> s1 neighbors: - ifname: ethernet1/1/9 @@ -553,7 +551,7 @@ nodes: ifname: eth6 lag: _parentindex: 2 - linkindex: 20 + linkindex: 21 name: h2 -> s2 neighbors: - ifname: ethernet1/1/7 @@ -617,22 +615,32 @@ nodes: hostname: clab-input-s1 id: 1 interfaces: - - clab: - name: eth1 - ifindex: 1 - ifname: ethernet1/1/1 + - ifindex: 30000 + ifname: peerlink lag: + ifindex: 1000 + lacp: fast + lacp_mode: active mlag: + ifindex: 1000 mac: 02-00-01-A9-00-01 - peer: 10.0.0.2 + peer: 172.16.1.2 + peer_backup_ip: 10.0.0.2 peergroup: 1 - linkindex: 1 + vlan: 1002 name: s1 -> s2 neighbors: - - ifname: ethernet1/1/1 + - ifname: peerlink node: s2 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 1002 + - ifindex: 30001 ifname: port-channel1 lag: _mlag: true @@ -652,7 +660,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30001 + - ifindex: 30002 ifname: port-channel2 lag: ifindex: 2 @@ -665,7 +673,7 @@ nodes: pool: l2only type: lag virtual_interface: true - - ifindex: 30002 + - ifindex: 30003 ifname: port-channel3 lag: _mlag: true @@ -685,7 +693,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30003 + - ifindex: 30004 ifname: port-channel4 lag: _mlag: true @@ -705,7 +713,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30004 + - ifindex: 30005 ifname: port-channel5 lag: _mlag: true @@ -723,13 +731,25 @@ nodes: pool: l2only type: lag virtual_interface: true + - clab: + name: eth1 + ifindex: 1 + ifname: ethernet1/1/1 + lag: + _parentindex: 1000 + linkindex: 8 + name: s1 -> s2 + neighbors: + - ifname: ethernet1/1/1 + node: s2 + type: p2p - clab: name: eth2 ifindex: 2 ifname: ethernet1/1/2 lag: - _peerlink: 1 - linkindex: 8 + _parentindex: 1000 + linkindex: 9 name: s1 -> s2 neighbors: - ifname: ethernet1/1/2 @@ -741,7 +761,7 @@ nodes: ifname: ethernet1/1/3 lag: _parentindex: 1 - linkindex: 9 + linkindex: 10 name: s1 -> h1 neighbors: - ifname: eth1 @@ -753,7 +773,7 @@ nodes: ifname: ethernet1/1/4 lag: _parentindex: 1 - linkindex: 10 + linkindex: 11 name: s1 -> h1 neighbors: - ifname: eth2 @@ -765,7 +785,7 @@ nodes: ifname: ethernet1/1/5 lag: _parentindex: 2 - linkindex: 13 + linkindex: 14 name: s1 -> h1 neighbors: - ifname: eth5 @@ -777,7 +797,7 @@ nodes: ifname: ethernet1/1/6 lag: _parentindex: 2 - linkindex: 14 + linkindex: 15 name: s1 -> h1 neighbors: - ifname: eth6 @@ -789,7 +809,7 @@ nodes: ifname: ethernet1/1/7 lag: _parentindex: 3 - linkindex: 15 + linkindex: 16 name: s1 -> h2 neighbors: - ifname: eth1 @@ -801,7 +821,7 @@ nodes: ifname: ethernet1/1/8 lag: _parentindex: 3 - linkindex: 16 + linkindex: 17 name: s1 -> h2 neighbors: - ifname: eth2 @@ -813,7 +833,7 @@ nodes: ifname: ethernet1/1/9 lag: _parentindex: 4 - linkindex: 19 + linkindex: 20 name: s1 -> h2 neighbors: - ifname: eth5 @@ -825,7 +845,7 @@ nodes: ifname: ethernet1/1/10 lag: _parentindex: 5 - linkindex: 21 + linkindex: 23 name: s1 -> s3 neighbors: - ifname: ethernet1/1/2 @@ -837,7 +857,7 @@ nodes: ifname: ethernet1/1/11 lag: _parentindex: 5 - linkindex: 22 + linkindex: 24 name: s1 -> s4 neighbors: - ifname: ethernet1/1/2 @@ -863,6 +883,20 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: virtual-network1002 + ipv4: 172.16.1.1/24 + name: VLAN peervlan_1 (1002) -> [s2] + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.1.2/24 + node: s2 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 lag: lacp: fast lacp_mode: active @@ -883,8 +917,16 @@ nodes: mtu: 1500 name: s1 vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_1: + _mlag_peer: true + bridge_group: 2 + id: 1002 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: bridge_group: 1 id: 1000 @@ -902,22 +944,32 @@ nodes: hostname: clab-input-s2 id: 2 interfaces: - - clab: - name: eth1 - ifindex: 1 - ifname: ethernet1/1/1 + - ifindex: 30000 + ifname: peerlink lag: + ifindex: 1000 + lacp: fast + lacp_mode: active mlag: + ifindex: 1000 mac: 02-00-01-A9-00-01 - peer: 10.0.0.1 + peer: 172.16.1.1 + peer_backup_ip: 10.0.0.1 peergroup: 1 - linkindex: 1 + vlan: 1002 name: s2 -> s1 neighbors: - - ifname: ethernet1/1/1 + - ifname: peerlink node: s1 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 1002 + - ifindex: 30001 ifname: port-channel1 lag: _mlag: true @@ -937,7 +989,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30001 + - ifindex: 30002 ifname: port-channel3 lag: _mlag: true @@ -957,7 +1009,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30002 + - ifindex: 30003 ifname: port-channel4 lag: _mlag: true @@ -977,7 +1029,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30003 + - ifindex: 30004 ifname: port-channel5 lag: _mlag: true @@ -995,13 +1047,25 @@ nodes: pool: l2only type: lag virtual_interface: true + - clab: + name: eth1 + ifindex: 1 + ifname: ethernet1/1/1 + lag: + _parentindex: 1000 + linkindex: 8 + name: s2 -> s1 + neighbors: + - ifname: ethernet1/1/1 + node: s1 + type: p2p - clab: name: eth2 ifindex: 2 ifname: ethernet1/1/2 lag: - _peerlink: 1 - linkindex: 8 + _parentindex: 1000 + linkindex: 9 name: s2 -> s1 neighbors: - ifname: ethernet1/1/2 @@ -1013,7 +1077,7 @@ nodes: ifname: ethernet1/1/3 lag: _parentindex: 1 - linkindex: 11 + linkindex: 12 name: s2 -> h1 neighbors: - ifname: eth3 @@ -1025,7 +1089,7 @@ nodes: ifname: ethernet1/1/4 lag: _parentindex: 1 - linkindex: 12 + linkindex: 13 name: s2 -> h1 neighbors: - ifname: eth4 @@ -1037,7 +1101,7 @@ nodes: ifname: ethernet1/1/5 lag: _parentindex: 3 - linkindex: 17 + linkindex: 18 name: s2 -> h2 neighbors: - ifname: eth3 @@ -1049,7 +1113,7 @@ nodes: ifname: ethernet1/1/6 lag: _parentindex: 3 - linkindex: 18 + linkindex: 19 name: s2 -> h2 neighbors: - ifname: eth4 @@ -1061,7 +1125,7 @@ nodes: ifname: ethernet1/1/7 lag: _parentindex: 4 - linkindex: 20 + linkindex: 21 name: s2 -> h2 neighbors: - ifname: eth6 @@ -1073,7 +1137,7 @@ nodes: ifname: ethernet1/1/8 lag: _parentindex: 5 - linkindex: 23 + linkindex: 25 name: s2 -> s3 neighbors: - ifname: ethernet1/1/3 @@ -1085,7 +1149,7 @@ nodes: ifname: ethernet1/1/9 lag: _parentindex: 5 - linkindex: 24 + linkindex: 26 name: s2 -> s4 neighbors: - ifname: ethernet1/1/3 @@ -1097,7 +1161,7 @@ nodes: ifname: ethernet1/1/10 lag: _parentindex: 5 - linkindex: 25 + linkindex: 27 name: s2 -> s4 neighbors: - ifname: ethernet1/1/4 @@ -1123,6 +1187,20 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: virtual-network1002 + ipv4: 172.16.1.2/24 + name: VLAN peervlan_1 (1002) -> [s1] + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.1.1/24 + node: s1 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 lag: lacp: fast lacp_mode: active @@ -1143,8 +1221,16 @@ nodes: mtu: 1500 name: s2 vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_1: + _mlag_peer: true + bridge_group: 2 + id: 1002 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: bridge_group: 1 id: 1000 @@ -1162,22 +1248,32 @@ nodes: hostname: clab-input-s3 id: 3 interfaces: - - clab: - name: eth1 - ifindex: 1 - ifname: ethernet1/1/1 + - ifindex: 30000 + ifname: peerlink lag: + ifindex: 1000 + lacp: fast + lacp_mode: active mlag: + ifindex: 1000 mac: 02-00-01-A9-00-02 - peer: 10.0.0.4 + peer: 172.16.2.4 + peer_backup_ip: 10.0.0.4 peergroup: 2 - linkindex: 6 + vlan: 1002 name: s3 -> s4 neighbors: - - ifname: ethernet1/1/1 + - ifname: peerlink node: s4 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_2: {} + trunk_id: + - 1002 + - ifindex: 30001 ifname: port-channel5 lag: _mlag: true @@ -1195,13 +1291,25 @@ nodes: pool: l2only type: lag virtual_interface: true + - clab: + name: eth1 + ifindex: 1 + ifname: ethernet1/1/1 + lag: + _parentindex: 1000 + linkindex: 22 + name: s3 -> s4 + neighbors: + - ifname: ethernet1/1/1 + node: s4 + type: p2p - clab: name: eth2 ifindex: 2 ifname: ethernet1/1/2 lag: _parentindex: 5 - linkindex: 21 + linkindex: 23 name: s3 -> s1 neighbors: - ifname: ethernet1/1/10 @@ -1213,12 +1321,26 @@ nodes: ifname: ethernet1/1/3 lag: _parentindex: 5 - linkindex: 23 + linkindex: 25 name: s3 -> s2 neighbors: - ifname: ethernet1/1/8 node: s2 type: p2p + - bridge_group: 1 + ifindex: 40000 + ifname: virtual-network1002 + ipv4: 172.16.2.3/24 + name: VLAN peervlan_2 (1002) -> [s4] + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.2.4/24 + node: s4 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_2 lag: lacp: fast lacp_mode: active @@ -1238,6 +1360,17 @@ nodes: - vlan mtu: 1500 name: s3 + vlan: + max_bridge_group: 1 + vlans: + peervlan_2: + _mlag_peer: true + bridge_group: 1 + id: 1002 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 s4: af: ipv4: true @@ -1248,22 +1381,32 @@ nodes: hostname: clab-input-s4 id: 4 interfaces: - - clab: - name: eth1 - ifindex: 1 - ifname: ethernet1/1/1 + - ifindex: 30000 + ifname: peerlink lag: + ifindex: 1000 + lacp: fast + lacp_mode: active mlag: + ifindex: 1000 mac: 02-00-01-A9-00-02 - peer: 10.0.0.3 + peer: 172.16.2.3 + peer_backup_ip: 10.0.0.3 peergroup: 2 - linkindex: 6 + vlan: 1002 name: s4 -> s3 neighbors: - - ifname: ethernet1/1/1 + - ifname: peerlink node: s3 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_2: {} + trunk_id: + - 1002 + - ifindex: 30001 ifname: port-channel5 lag: _mlag: true @@ -1281,13 +1424,25 @@ nodes: pool: l2only type: lag virtual_interface: true + - clab: + name: eth1 + ifindex: 1 + ifname: ethernet1/1/1 + lag: + _parentindex: 1000 + linkindex: 22 + name: s4 -> s3 + neighbors: + - ifname: ethernet1/1/1 + node: s3 + type: p2p - clab: name: eth2 ifindex: 2 ifname: ethernet1/1/2 lag: _parentindex: 5 - linkindex: 22 + linkindex: 24 name: s4 -> s1 neighbors: - ifname: ethernet1/1/11 @@ -1299,7 +1454,7 @@ nodes: ifname: ethernet1/1/3 lag: _parentindex: 5 - linkindex: 24 + linkindex: 26 name: s4 -> s2 neighbors: - ifname: ethernet1/1/9 @@ -1311,12 +1466,26 @@ nodes: ifname: ethernet1/1/4 lag: _parentindex: 5 - linkindex: 25 + linkindex: 27 name: s4 -> s2 neighbors: - ifname: ethernet1/1/10 node: s2 type: p2p + - bridge_group: 1 + ifindex: 40000 + ifname: virtual-network1002 + ipv4: 172.16.2.4/24 + name: VLAN peervlan_2 (1002) -> [s3] + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.2.3/24 + node: s3 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_2 lag: lacp: fast lacp_mode: active @@ -1336,8 +1505,49 @@ nodes: - vlan mtu: 1500 name: s4 + vlan: + max_bridge_group: 1 + vlans: + peervlan_2: + _mlag_peer: true + bridge_group: 1 + id: 1002 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 provider: clab vlans: + peervlan_1: + _mlag_peer: true + host_count: 0 + id: 1002 + mode: irb + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.1.2/24 + node: s2 + - ifname: virtual-network1002 + ipv4: 172.16.1.1/24 + node: s1 + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 + peervlan_2: + _mlag_peer: true + host_count: 0 + id: 1002 + mode: irb + neighbors: + - ifname: virtual-network1002 + ipv4: 172.16.2.4/24 + node: s4 + - ifname: virtual-network1002 + ipv4: 172.16.2.3/24 + node: s3 + prefix: + allocation: id_based + ipv4: 172.16.2.0/24 red: host_count: 0 id: 1000 diff --git a/tests/topology/expected/node.clone-plugin-lag.yml b/tests/topology/expected/node.clone-plugin-lag.yml index ab92fa8754..02a37cc119 100644 --- a/tests/topology/expected/node.clone-plugin-lag.yml +++ b/tests/topology/expected/node.clone-plugin-lag.yml @@ -23,9 +23,8 @@ links: ifname: Ethernet1 node: r2 lag: - mlag: - peergroup: 1 - linkindex: 1 + _parentindex: 1 + linkindex: 8 node_count: 2 prefix: false type: p2p @@ -39,7 +38,7 @@ links: node: h-01 lag: _parentindex: 2 - linkindex: 8 + linkindex: 9 node_count: 2 prefix: false type: p2p @@ -53,7 +52,7 @@ links: node: h-01 lag: _parentindex: 2 - linkindex: 9 + linkindex: 10 node_count: 2 prefix: false type: p2p @@ -67,7 +66,7 @@ links: node: h-02 lag: _parentindex: 3 - linkindex: 10 + linkindex: 11 node_count: 2 prefix: false type: p2p @@ -81,7 +80,7 @@ links: node: h-02 lag: _parentindex: 3 - linkindex: 11 + linkindex: 12 node_count: 2 prefix: false type: p2p @@ -95,7 +94,7 @@ links: node: h-01 lag: _parentindex: 4 - linkindex: 12 + linkindex: 13 node_count: 2 prefix: false type: p2p @@ -109,7 +108,7 @@ links: node: h-01 lag: _parentindex: 4 - linkindex: 13 + linkindex: 14 node_count: 2 prefix: false type: p2p @@ -123,7 +122,7 @@ links: node: h-02 lag: _parentindex: 5 - linkindex: 14 + linkindex: 15 node_count: 2 prefix: false type: p2p @@ -137,7 +136,7 @@ links: node: h-02 lag: _parentindex: 5 - linkindex: 15 + linkindex: 16 node_count: 2 prefix: false type: p2p @@ -151,7 +150,7 @@ links: node: r1 lag: _parentindex: 6 - linkindex: 16 + linkindex: 17 node_count: 2 prefix: false type: p2p @@ -165,7 +164,7 @@ links: node: r2 lag: _parentindex: 6 - linkindex: 17 + linkindex: 18 node_count: 2 prefix: false type: p2p @@ -179,7 +178,7 @@ links: node: r1 lag: _parentindex: 7 - linkindex: 18 + linkindex: 19 node_count: 2 prefix: false type: p2p @@ -193,7 +192,7 @@ links: node: r2 lag: _parentindex: 7 - linkindex: 19 + linkindex: 20 node_count: 2 prefix: false type: p2p @@ -239,7 +238,7 @@ nodes: ifname: eth1 lag: _parentindex: 8 - linkindex: 8 + linkindex: 9 name: h-01 -> r1 neighbors: - ifname: Ethernet2 @@ -249,7 +248,7 @@ nodes: ifname: eth2 lag: _parentindex: 8 - linkindex: 9 + linkindex: 10 name: h-01 -> r1 neighbors: - ifname: Ethernet3 @@ -259,7 +258,7 @@ nodes: ifname: eth3 lag: _parentindex: 9 - linkindex: 12 + linkindex: 13 name: h-01 -> r2 neighbors: - ifname: Ethernet6 @@ -269,7 +268,7 @@ nodes: ifname: eth4 lag: _parentindex: 9 - linkindex: 13 + linkindex: 14 name: h-01 -> r2 neighbors: - ifname: Ethernet7 @@ -330,7 +329,7 @@ nodes: ifname: eth1 lag: _parentindex: 9 - linkindex: 10 + linkindex: 11 name: h-02 -> r1 neighbors: - ifname: Ethernet4 @@ -340,7 +339,7 @@ nodes: ifname: eth2 lag: _parentindex: 9 - linkindex: 11 + linkindex: 12 name: h-02 -> r1 neighbors: - ifname: Ethernet5 @@ -350,7 +349,7 @@ nodes: ifname: eth3 lag: _parentindex: 10 - linkindex: 14 + linkindex: 15 name: h-02 -> r2 neighbors: - ifname: Ethernet8 @@ -360,7 +359,7 @@ nodes: ifname: eth4 lag: _parentindex: 10 - linkindex: 15 + linkindex: 16 name: h-02 -> r2 neighbors: - ifname: Ethernet9 @@ -414,7 +413,7 @@ nodes: ifname: eth1 lag: _parentindex: 1 - linkindex: 16 + linkindex: 17 name: h2-01 -> r1 neighbors: - ifname: Ethernet6 @@ -424,7 +423,7 @@ nodes: ifname: eth2 lag: _parentindex: 1 - linkindex: 17 + linkindex: 18 name: h2-01 -> r2 neighbors: - ifname: Ethernet2 @@ -508,7 +507,7 @@ nodes: ifname: eth1 lag: _parentindex: 1 - linkindex: 18 + linkindex: 19 name: h2-02 -> r1 neighbors: - ifname: Ethernet7 @@ -518,7 +517,7 @@ nodes: ifname: eth2 lag: _parentindex: 1 - linkindex: 19 + linkindex: 20 name: h2-02 -> r2 neighbors: - ifname: Ethernet3 @@ -579,22 +578,27 @@ nodes: device: eos id: 1 interfaces: - - ifindex: 1 - ifname: Ethernet1 + - ifindex: 30000 + ifname: port-channel4094 lag: + ifindex: 4094 + lacp: fast + lacp_mode: active mlag: - ifindex: 4094 - peer: 169.254.127.1 peergroup: 1 - self: 169.254.127.0/31 - vlan: 4094 - linkindex: 1 name: r1 -> r2 neighbors: - - ifname: Ethernet1 + - ifname: port-channel4094 node: r2 - type: p2p - - ifindex: 30000 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel8 lag: ifindex: 8 @@ -607,7 +611,7 @@ nodes: pool: l2only type: lag virtual_interface: true - - ifindex: 30001 + - ifindex: 30002 ifname: port-channel9 lag: ifindex: 9 @@ -620,7 +624,7 @@ nodes: pool: l2only type: lag virtual_interface: true - - ifindex: 30002 + - ifindex: 30003 ifname: port-channel10 lag: _mlag: true @@ -640,7 +644,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30003 + - ifindex: 30004 ifname: port-channel11 lag: _mlag: true @@ -660,11 +664,21 @@ nodes: vlan: access: red access_id: 1000 + - ifindex: 1 + ifname: Ethernet1 + lag: + _parentindex: 4094 + linkindex: 8 + name: r1 -> r2 + neighbors: + - ifname: Ethernet1 + node: r2 + type: p2p - ifindex: 2 ifname: Ethernet2 lag: _parentindex: 8 - linkindex: 8 + linkindex: 9 name: r1 -> h-01 neighbors: - ifname: eth1 @@ -674,7 +688,7 @@ nodes: ifname: Ethernet3 lag: _parentindex: 8 - linkindex: 9 + linkindex: 10 name: r1 -> h-01 neighbors: - ifname: eth2 @@ -684,7 +698,7 @@ nodes: ifname: Ethernet4 lag: _parentindex: 9 - linkindex: 10 + linkindex: 11 name: r1 -> h-02 neighbors: - ifname: eth1 @@ -694,7 +708,7 @@ nodes: ifname: Ethernet5 lag: _parentindex: 9 - linkindex: 11 + linkindex: 12 name: r1 -> h-02 neighbors: - ifname: eth2 @@ -704,7 +718,7 @@ nodes: ifname: Ethernet6 lag: _parentindex: 10 - linkindex: 16 + linkindex: 17 name: r1 -> h2-01 neighbors: - ifname: eth1 @@ -714,7 +728,7 @@ nodes: ifname: Ethernet7 lag: _parentindex: 11 - linkindex: 18 + linkindex: 19 name: r1 -> h2-02 neighbors: - ifname: eth1 @@ -740,9 +754,27 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: Vlan4094 + ipv4: 172.16.1.1/24 + name: VLAN peervlan_1 (4094) -> [r2] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.2/24 + node: r2 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.1.2 + vlan: 4094 loopback: ifindex: 0 ifname: Loopback0 @@ -760,8 +792,16 @@ nodes: name: r1 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_1: + _mlag_peer: true + bridge_group: 2 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: bridge_group: 1 id: 1000 @@ -780,13 +820,8 @@ nodes: - ifindex: 1 ifname: Ethernet1 lag: - mlag: - ifindex: 4094 - peer: 169.254.127.0 - peergroup: 1 - self: 169.254.127.1/31 - vlan: 4094 - linkindex: 1 + _parentindex: 4094 + linkindex: 8 name: r2 -> r1 neighbors: - ifname: Ethernet1 @@ -796,7 +831,7 @@ nodes: ifname: Ethernet2 lag: _parentindex: 10 - linkindex: 17 + linkindex: 18 name: r2 -> h2-01 neighbors: - ifname: eth2 @@ -806,7 +841,7 @@ nodes: ifname: Ethernet3 lag: _parentindex: 11 - linkindex: 19 + linkindex: 20 name: r2 -> h2-02 neighbors: - ifname: eth2 @@ -830,7 +865,7 @@ nodes: ifname: Ethernet6 lag: _parentindex: 1 - linkindex: 12 + linkindex: 13 name: r2 -> h-01 neighbors: - ifname: eth3 @@ -840,7 +875,7 @@ nodes: ifname: Ethernet7 lag: _parentindex: 1 - linkindex: 13 + linkindex: 14 name: r2 -> h-01 neighbors: - ifname: eth4 @@ -850,7 +885,7 @@ nodes: ifname: Ethernet8 lag: _parentindex: 2 - linkindex: 14 + linkindex: 15 name: r2 -> h-02 neighbors: - ifname: eth3 @@ -860,13 +895,33 @@ nodes: ifname: Ethernet9 lag: _parentindex: 2 - linkindex: 15 + linkindex: 16 name: r2 -> h-02 neighbors: - ifname: eth4 node: h-02 type: p2p - ifindex: 30000 + ifname: port-channel4094 + lag: + ifindex: 4094 + lacp: fast + lacp_mode: active + mlag: + peergroup: 1 + name: r2 -> r1 + neighbors: + - ifname: port-channel4094 + node: r1 + type: lag + virtual_interface: true + vlan: + _allow_all: true + trunk: + peervlan_1: {} + trunk_id: + - 4094 + - ifindex: 30001 ifname: port-channel1 lag: ifindex: 1 @@ -879,7 +934,7 @@ nodes: pool: l2only type: lag virtual_interface: true - - ifindex: 30001 + - ifindex: 30002 ifname: port-channel2 lag: ifindex: 2 @@ -892,7 +947,7 @@ nodes: pool: l2only type: lag virtual_interface: true - - ifindex: 30002 + - ifindex: 30003 ifname: port-channel10 lag: _mlag: true @@ -912,7 +967,7 @@ nodes: vlan: access: red access_id: 1000 - - ifindex: 30003 + - ifindex: 30004 ifname: port-channel11 lag: _mlag: true @@ -952,9 +1007,27 @@ nodes: vlan: mode: irb name: red + - bridge_group: 2 + ifindex: 40001 + ifname: Vlan4094 + ipv4: 172.16.1.2/24 + name: VLAN peervlan_1 (4094) -> [r1] + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.1/24 + node: r1 + type: svi + virtual_interface: true + vlan: + mode: irb + name: peervlan_1 lag: lacp: fast lacp_mode: active + mlag: + ifindex: 4094 + peer: 172.16.1.1 + vlan: 4094 libvirt: nic_adapter_count: 10 loopback: @@ -974,8 +1047,16 @@ nodes: name: r2 role: router vlan: - max_bridge_group: 1 + max_bridge_group: 2 vlans: + peervlan_1: + _mlag_peer: true + bridge_group: 2 + id: 4094 + mode: irb + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: bridge_group: 1 id: 1000 @@ -987,6 +1068,21 @@ plugin: - node.clone provider: libvirt vlans: + peervlan_1: + _mlag_peer: true + host_count: 0 + id: 4094 + mode: irb + neighbors: + - ifname: Vlan4094 + ipv4: 172.16.1.2/24 + node: r2 + - ifname: Vlan4094 + ipv4: 172.16.1.1/24 + node: r1 + prefix: + allocation: id_based + ipv4: 172.16.1.0/24 red: host_count: 0 id: 1000