diff --git a/docs/module/stp.md b/docs/module/stp.md index 6b7a45476..10f59f1f3 100644 --- a/docs/module/stp.md +++ b/docs/module/stp.md @@ -12,7 +12,8 @@ The following table describes per-platform support of individual STP features: | Operating system | STP | MSTP | RSTP | Per-VLAN (R)STP | Enable per port | Port type | ------------------ |:---:|:---:|:---:|:---:|:---:|:---:| | Arista EOS[^EOS] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| Cumulus Linux[^CL] | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | +| Cumulus Linux 4.x[^CL] | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | +| Cumulus 5.x (NVUE)[^CL] | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | | Dell OS10[^OS10] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | FRR[^FRR] | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | @@ -28,7 +29,7 @@ MSTP/RSTP ports fall back to regular STP upon receiving a plain STP BPDU. ## Global Parameters * **stp.protocol** (one of stp, mstp, rstp or pvrst) -- Global STP flavor to run on supporting nodes, default **stp** -* **stp.host_edge_port** (bool) -- Configure ports with only hosts connected as 'edge' port_type on platforms that support it, default **True** +* **stp.stub_port_type** (one of 'normal','edge','network','auto' or 'none') -- Port type to configure on ports with only hosts connected, default **'edge'** ## Global, Node, Link, Interface, and VLAN Parameters @@ -41,9 +42,9 @@ You can set the **‌stp.enable** parameter in the **‌vlans** dictionary to en ## Node Parameters (global or per VLAN) * **stp.priority** (int 0..61440 in increments of 1024) -- STP priority for root election, by default, all nodes have equal priority 32656. In case of equal priority, the bridge with the lowest MAC address becomes root; note that MAC addresses are assigned randomly in Netlab -* **stp.port_type** (one of 'normal','edge','network') -- STP port type for all interfaces connected to this link +* **stp.port_type** (one of 'normal','edge','network' or 'auto') -- STP port type for all interfaces connected to this link ## Interface Parameters * **stp.port_priority** (int 0..15) -- STP port priority for selecting between multiple ports; ports are blocked based on priority (lower value = higher priority). The priority is sent over the wire (4 bits) as the most significant part of the port ID; it is used by the node *receiving* it (!) to decide which port(s) to unblock. Note that on many platforms, the value that ends up in the configuration is a multiple (x16) of this attribute -* **stp.port_type** (one of 'normal','edge','network') -- STP port type for this interface, default 'normal' +* **stp.port_type** (one of 'normal','edge','network' or 'auto') -- STP port type for this interface, default 'normal' diff --git a/netsim/ansible/templates/stp/cumulus.j2 b/netsim/ansible/templates/stp/cumulus.j2 index dcf5db748..ce57b5808 100644 --- a/netsim/ansible/templates/stp/cumulus.j2 +++ b/netsim/ansible/templates/stp/cumulus.j2 @@ -38,7 +38,7 @@ iface {{ ifdata.ifname }} {% endif %} {% set port_type = ifdata.stp.port_type|default("normal") %} mstpctl-portadminedge {{ 'yes' if port_type=='edge' else 'no' }} - mstpctl-portautoedge {{ 'yes' if port_type=='normal' else 'no' }} + mstpctl-portautoedge {{ 'yes' if port_type in ['normal','auto'] else 'no' }} {% endfor %} CONFIG diff --git a/netsim/ansible/templates/stp/cumulus_nvue.j2 b/netsim/ansible/templates/stp/cumulus_nvue.j2 index e683a9251..970c38748 100644 --- a/netsim/ansible/templates/stp/cumulus_nvue.j2 +++ b/netsim/ansible/templates/stp/cumulus_nvue.j2 @@ -47,7 +47,7 @@ {% endif %} {% set port_type = ifdata.stp.port_type|default("normal") %} admin-edge: {{ 'on' if port_type=='edge' else 'off' }} - auto-edge: {{ 'on' if port_type=='normal' else 'off' }} + auto-edge: {{ 'on' if port_type in ['normal','auto'] else 'off' }} {% elif ifdata.vlan.trunk_id is defined %} {% for id in ifdata.vlan.trunk_id %} {% if loop.first %} diff --git a/netsim/ansible/templates/stp/dellos10.j2 b/netsim/ansible/templates/stp/dellos10.j2 index c2a7c7920..b6c11c977 100644 --- a/netsim/ansible/templates/stp/dellos10.j2 +++ b/netsim/ansible/templates/stp/dellos10.j2 @@ -28,7 +28,7 @@ spanning-tree vlan {{ vdata.id }} priority {{ vdata.stp.priority }} {% for ifdata in interfaces if 'stp' in ifdata or ifdata.vlan.trunk|default({})|dict2items|map(attribute='value')|selectattr('stp','defined') %} interface {{ ifdata.ifname }} {% if 'stp' in ifdata %} -{% set _no = "" if ifdata.stp.port_type|default("")=='edge' else "no " %} +{% set _no = "" if ifdata.stp.port_type|default("normal")=='edge' else "no " %} {{ _no }}spanning-tree port type edge {% if not ifdata.stp.enable|default(True) %} spanning-tree disable diff --git a/netsim/ansible/templates/stp/eos.j2 b/netsim/ansible/templates/stp/eos.j2 index dc2e8ff43..7f1d3fe9c 100644 --- a/netsim/ansible/templates/stp/eos.j2 +++ b/netsim/ansible/templates/stp/eos.j2 @@ -36,5 +36,5 @@ interface {{ ifdata.ifname }} # {% endif %} {% endif %} - spanning-tree portfast {{ ifdata.stp.port_type|default('auto') }} + spanning-tree portfast {{ ifdata.stp.port_type|default('normal') }} {% endfor %} diff --git a/netsim/modules/stp.py b/netsim/modules/stp.py index 3d60a853d..bfb247617 100644 --- a/netsim/modules/stp.py +++ b/netsim/modules/stp.py @@ -9,9 +9,9 @@ from . import _Module """ -configure_host_edge_port - for a L2 interface where all devices connected are hosts, sets the stp.port_type as 'edge' +configure_stub_port_type - for a L2 interface where all devices connected are hosts, sets the stp.port_type as """ -def configure_host_edge_port(intf: Box, topology: Box) -> None: +def configure_stub_port_type(intf: Box, stub_port_type: str, topology: Box) -> None: if not (intf.get('neighbors',[]) or intf.get('_vlan_saved_neighbors',[])): # Skip interfaces with no neighbors return if 'ipv4' in intf or 'ipv6' in intf: # Skip IP interfaces @@ -22,7 +22,7 @@ def configure_host_edge_port(intf: Box, topology: Box) -> None: neighbor = topology.nodes[n.node] if neighbor.get('role',None) != 'host': return - intf.stp.port_type = 'edge' # All neighbors are hosts + intf.stp.port_type = stub_port_type # All neighbors are hosts class STP(_Module): @@ -47,7 +47,7 @@ def node_post_transform(self, node: Box, topology: Box) -> None: log.IncorrectValue, 'stp') - set_host_edge_port = topology.get('stp.host_edge_port',True) and features.get('stp.port_type',False) + stub_port_type = topology.get('stp.stub_port_type','edge') if features.get('stp.port_type',False) else 'none' for intf in node.get('interfaces',[]): if 'stp' in intf: if 'ipv4' in intf or 'ipv6' in intf: @@ -65,8 +65,8 @@ def node_post_transform(self, node: Box, topology: Box) -> None: f'node {node.name} (device {node.device}) does not support configuration of STP port_type on ({intf.ifname})', log.IncorrectValue, 'stp') - if set_host_edge_port and not intf.get('stp.port_type',None): - configure_host_edge_port(intf,topology) + if stub_port_type != 'none' and not intf.get('stp.port_type',None): + configure_stub_port_type(intf,stub_port_type,topology) # Check if per-VLAN priority is being used for vname,vdata in node.get('vlans',{}).items(): diff --git a/netsim/modules/stp.yml b/netsim/modules/stp.yml index 642b7065a..2d1dd94ba 100644 --- a/netsim/modules/stp.yml +++ b/netsim/modules/stp.yml @@ -4,16 +4,16 @@ requires: [ vlan ] # Perhaps not on all platforms transform_after: [ vlan ] config_after: [ vlan ] -no_propagate: [ host_edge_port ] +no_propagate: [ stub_port_type ] enable: True # By default, enable STP on all devices where this module is activated protocol: "stp" # Default to basic 802.1D STP protocol, users may explicitly enable fancier newer flavors -host_edge_port: True # Whether to auto-configure port_type as 'edge' for ports with only hosts connected, default True +stub_port_type: "edge" # Port type to configure on ports with only hosts connected, default 'edge' attributes: global: enable: bool - host_edge_port: bool + stub_port_type: { type: str, valid_values: [ 'normal', 'edge', 'network', 'auto', 'none' ] } protocol: { type: str, valid_values: [ stp, rstp, mstp, pvrst ] } # mstp = IEEE 802.1s, pvrst = Per-VLAN Rapid Spanning Tree (802.1w) node: @@ -25,12 +25,12 @@ attributes: link: enable: copy: global - port_type: { type: str, valid_values: [ normal, edge, network ] } # Apply this port_type to all connected interfaces + port_type: { type: str, valid_values: [ normal, edge, network, auto ] } # Apply this port_type to all connected interfaces interface: enable: bool port_priority: { type: int, min_value: 0, max_value: 15 } # 4-bit value, default '8' if not set - port_type: { type: str, valid_values: [ normal, edge, network ] } + port_type: { type: str, valid_values: [ normal, edge, network, auto ] } _top: # Modification of global defaults attributes: