diff --git a/netsim/augment/links.py b/netsim/augment/links.py index ed9646501e..5d7a2fb5bb 100644 --- a/netsim/augment/links.py +++ b/netsim/augment/links.py @@ -209,7 +209,7 @@ def get_unique_ifindex( idx_list = [ # Build a list of already-used ifindex values intf.ifindex for intf in node.interfaces - if iftype == intf.type or (iftype is None and intf.type not in VIRTUAL_INTERFACE_TYPES) ] + if iftype == intf._type or (iftype is None and intf._type not in VIRTUAL_INTERFACE_TYPES) ] ifindex = start while ifindex < stop: # Iterate through ifindex values if ifindex not in idx_list: # ... returning the first one that is not used @@ -266,7 +266,7 @@ def create_regular_interface(node: Box, ifdata: Box, defaults: Box) -> None: ifdata[provider] = pdata def create_virtual_interface(node: Box, ifdata: Box, defaults: Box) -> None: - devtype = ifdata.get('type','loopback') # Get virtual interface type, default to loopback interface + devtype = ifdata.get('_type','loopback') # Get virtual interface type, default to loopback interface ifindex_offset = ( devices.get_device_attribute(node,f'{devtype}_offset',defaults) or 1 if devtype == 'loopback' else 0) # Loopback interfaces have to start with 1 to prevent overlap with built-in loopback @@ -308,7 +308,7 @@ def create_virtual_interface(node: Box, ifdata: Box, defaults: Box) -> None: module='links') def add_node_interface(node: Box, ifdata: Box, defaults: Box) -> Box: - if ifdata.get('type',None) in VIRTUAL_INTERFACE_TYPES: + if ifdata.get('_type',None) in VIRTUAL_INTERFACE_TYPES: create_virtual_interface(node,ifdata,defaults) else: create_regular_interface(node,ifdata,defaults) @@ -326,7 +326,7 @@ def add_node_interface(node: Box, ifdata: Box, defaults: Box) -> Box: if not sys_mtu: # .. does the device support system MTU? ifdata.mtu = node.mtu # .... no, copy node MTU to interface MTU - if ifdata.get('type',None) == 'loopback': + if ifdata.get('_type',None) == 'loopback': ifdata.pop('mtu',None) # Remove MTU from loopback interfaces node.interfaces.append(ifdata) @@ -776,6 +776,8 @@ def create_node_interfaces(link: Box, addr_pools: Box, ndict: Box, defaults: Box set_interface_name(ifdata,link,intf_cnt) set_parent_interface(ifdata,ndict[node]) ifdata.pop('node',None) # Remove the node name (not needed within the node) + if 'type' in ifdata: + ifdata._type = ifdata.pop('type',None) # rename 'type' (from link) to '_type' node_intf = add_node_interface(ndict[node],ifdata,defaults) # Attach new interface to its node value.ifindex = node_intf.ifindex # Save ifindex and ifname in link interface data value.ifname = node_intf.ifname # ... needed for things like Graph output module that works with links @@ -1183,8 +1185,6 @@ def transform(link_list: typing.Optional[Box], defaults: Box, nodes: Box, pools: return link_list def cleanup(topology: Box) -> None: - if not 'links' in topology: - return - -# for link in topology.links: -# link.pop('_linkname',None) + for link in topology.get('links',[]): + # link.pop('_linkname',None) + data.cleanup_interface_type(link) diff --git a/netsim/augment/nodes.py b/netsim/augment/nodes.py index b0c61df99a..848647c1ee 100644 --- a/netsim/augment/nodes.py +++ b/netsim/augment/nodes.py @@ -460,6 +460,13 @@ def cleanup(topology: Box) -> None: n.config = [ cfg for cfg in n.config if cfg in plugin_config ] + \ [ cfg for cfg in n.config if cfg not in plugin_config ] + data.cleanup_interface_type(n) + if 'vrfs' in n: + for vname,vdata in n.vrfs.items(): + for igp in ['ospf','isis']: + if vdata.get(f'{igp}.interfaces',[]): + data.cleanup_interface_type(vdata[igp]) + topology.pop('_plugin_config',None) ''' diff --git a/netsim/data/__init__.py b/netsim/data/__init__.py index 26b1a5c145..cd48fa3f22 100644 --- a/netsim/data/__init__.py +++ b/netsim/data/__init__.py @@ -181,3 +181,11 @@ def kw_list_transform(lookup_table: typing.Union[dict,Box], kw_list: list) -> li xf_list.append(lookup_kw) return xf_list + +""" +cleanup_interface_type - rename '_type' back to 'type' for all interfaces in the given obj +""" +def cleanup_interface_type(obj: Box) -> None: + for intf in obj.get('interfaces',[]): + if '_type' in intf: + intf.type = intf.pop('_type',None) diff --git a/netsim/modules/_routing.py b/netsim/modules/_routing.py index 26587ab8dc..b616055190 100644 --- a/netsim/modules/_routing.py +++ b/netsim/modules/_routing.py @@ -151,11 +151,11 @@ def passive( return role = intf.get('role',"") - if role in ["passive","external"] or intf.type == 'stub': # Passive/external role or stub link ==> must be passive + if role in ["passive","external"] or intf._type == 'stub': # Passive/external role or stub link ==> must be passive intf[proto].passive = True return - if role != "stub": # Not a stub role ==> not passive + if role != "stub": # Not a stub role ==> not passive intf[proto].passive = False return diff --git a/netsim/modules/bgp.py b/netsim/modules/bgp.py index 32cf147e3d..059dac5326 100644 --- a/netsim/modules/bgp.py +++ b/netsim/modules/bgp.py @@ -467,7 +467,7 @@ def bgp_set_advertise(node: Box, topology: Box) -> None: continue role = l.get("role",None) # Get interface/link role - if l.get("type",None) in stub_roles or role in stub_roles: + if l.get("_type",None) in stub_roles or role in stub_roles: # We have a potential stub link according to advertised_roles, but we still have to check for true stub # if role != "stub": @@ -476,7 +476,7 @@ def bgp_set_advertise(node: Box, topology: Box) -> None: l.bgp.advertise = _routing.is_true_stub(l,topology) continue # And move on - if l.get('type',None) == 'loopback' and node.bgp.advertise_loopback: + if l.get('_type',None) == 'loopback' and node.bgp.advertise_loopback: l.bgp.advertise = True # ... also advertise loopback prefixes if bgp.advertise_loopback is set """ diff --git a/netsim/modules/lag.py b/netsim/modules/lag.py index 73f8e033e8..5185a8033c 100644 --- a/netsim/modules/lag.py +++ b/netsim/modules/lag.py @@ -38,11 +38,11 @@ def populate_peerlink_id_set(topology: Box) -> None: create_l2_link_base - Create a L2 P2P link as base for member links """ def create_l2_link_base(l: Box, topology: Box) -> Box: - l2_ifdata = data.get_box({ 'type': "p2p", 'prefix': False, 'lag': {} }) # Construct an L2 member link - for a in list(topology.defaults.lag.attributes.lag_l2_ifattr): + l2_linkdata = data.get_box({ 'type': "p2p", 'prefix': False, 'lag': {} }) # Construct an L2 member link + for a in list(topology.defaults.lag.attributes.lag_l2_linkattr): if a in l: - l2_ifdata[a] = l[a] - return l2_ifdata + l2_linkdata[a] = l[a] + return l2_linkdata """ check_lag_config - check if the given node supports lag and has the module enabled @@ -209,7 +209,7 @@ def analyze_lag(members: list, node_count: dict) -> tuple[bool,bool,str]: l.interfaces = [] # Build interface list for lag link skip_atts = list(topology.defaults.lag.attributes.lag_no_propagate) for node in node_count: - ifatts = data.get_box({ 'node': node }) + ifatts = data.get_box({ 'node': node, '_type': 'lag' }) for m in members: # Collect attributes from member links if node in [ i.node for i in m.interfaces ]:# ...in which is involved ifatts = ifatts + { k:v for k,v in m.items() if k not in skip_atts } @@ -385,7 +385,7 @@ def node_post_transform(self, node: Box, topology: Box) -> None: 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': + elif i._type=='lag': i.lag = node.get('lag',{}) + i.lag # Merge node level settings with interface overrides lacp_mode = i.get('lag.lacp_mode') # Inheritance copying is done elsewhere if lacp_mode=='passive' and not features.lag.get('passive',False): diff --git a/netsim/modules/lag.yml b/netsim/modules/lag.yml index e6f2955444..a05da58524 100644 --- a/netsim/modules/lag.yml +++ b/netsim/modules/lag.yml @@ -36,7 +36,7 @@ attributes: # _mlag: bool # Copy only these L2 attributes into LAG physical link members - lag_l2_ifattr: + lag_l2_linkattr: mtu: bandwidth: diff --git a/netsim/modules/vlan.py b/netsim/modules/vlan.py index 650606c566..96e567a3bb 100644 --- a/netsim/modules/vlan.py +++ b/netsim/modules/vlan.py @@ -800,7 +800,7 @@ def create_svi_interfaces(node: Box, topology: Box) -> dict: continue # ... good, move on routed_intf = get_vlan_interface_mode(ifdata) == 'route' # Identify routed VLAN interfaces - vlan_subif = routed_intf and ifdata.get('type','') == 'vlan_member' # ... and VLAN-based subinterfaces + vlan_subif = routed_intf and ifdata.get('_type','') == 'vlan_member' # ... and VLAN-based subinterfaces vlan_data = create_node_vlan(node,access_vlan,topology) if vlan_data is None: # pragma: no-cover @@ -856,7 +856,7 @@ def create_svi_interfaces(node: Box, topology: Box) -> dict: ifname=ifdata.ifname) vlan_ifdata.name = f'VLAN {access_vlan} ({vlan_data.id})' vlan_ifdata.virtual_interface = True # Mark interface as virtual - vlan_ifdata.type = "svi" + vlan_ifdata._type = "svi" vlan_ifdata.neighbors = [] # No neighbors so far # Overwrite interface settings with VLAN settings vlan_ifdata = vlan_ifdata + { @@ -976,12 +976,12 @@ def rename_vlan_subinterfaces(node: Box, topology: Box) -> None: features = devices.get_device_features(node,topology.defaults) if 'switch' in features.vlan.model: # No need for VLAN subinterfaces, remove non-routed vlan_member interfaces node.interfaces = [ intf for intf in node.interfaces \ - if intf.type != 'vlan_member' or intf.vlan.get('mode','') == 'route' ] + if intf._type != 'vlan_member' or intf.vlan.get('mode','') == 'route' ] subif_name = features.vlan.routed_subif_name # Just in case: try to get interface name pattern for routed subinterface has_vlan_loopbacks = False for intf in node.interfaces: # Now loop over remaining vlan_member interfaces - if intf.type != 'vlan_member': + if intf._type != 'vlan_member': continue if not 'router' in features.vlan.model and not 'l3-switch' in features.vlan.model: @@ -1086,7 +1086,7 @@ def check_mixed_trunks(node: Box, topology: Box) -> None: err_ifmap = {} for intf in node.interfaces: - if not intf.get('parent_ifindex') or intf.type != 'vlan_member': # Skip everything that is not a VLAN subinterface + if not intf.get('parent_ifindex') or intf._type != 'vlan_member': # Skip everything that is not a VLAN subinterface continue parent_intf_list = [ x for x in node.interfaces if x.ifindex == intf.parent_ifindex ] @@ -1131,7 +1131,7 @@ def check_mixed_native_trunk(node: Box, topology: Box) -> None: f'Device type {node.device} (node {node.name}) cannot have a routed native VLAN with a bridged trunk', category=log.IncorrectValue, module='vlan', - more_data=f'Found on interface {intf.ifname} ({intf.name})') + more_data=f'Found on interface {intf.ifname} ({intf.name}) ({intf})') """ fix_vlan_gateways -- set VLAN-wide gateway IP diff --git a/netsim/modules/vlan.yml b/netsim/modules/vlan.yml index 7608a8bea1..b8c67fb943 100644 --- a/netsim/modules/vlan.yml +++ b/netsim/modules/vlan.yml @@ -50,7 +50,7 @@ attributes: parentindex: ifname: linkindex: - type: + _type: vlan: mtu: bandwidth: @@ -65,7 +65,7 @@ attributes: vlan: ifindex: ifname: - type: + _type: virtual_interface: features: diff --git a/netsim/modules/vrf.py b/netsim/modules/vrf.py index 79e7ed0e65..b3d9ccdc7f 100644 --- a/netsim/modules/vrf.py +++ b/netsim/modules/vrf.py @@ -323,7 +323,7 @@ def vrf_loopbacks(node : Box, topology: Box) -> None: # Note: set interface ifindex to v.vrfidx if you want to have VRF-numbered loopbacks # ifdata = data.get_box({ # Create interface data structure - 'type': "loopback", + '_type': "loopback", 'name': f'VRF Loopback {vrfname}', 'neighbors': [], 'vrf': vrfname,}) @@ -374,7 +374,7 @@ def vrf_loopbacks(node : Box, topology: Box) -> None: """ def get_vrf_loopback(node: Box, vrf: str) -> typing.Optional[Box]: for intf in node.interfaces: # Loop over all interfaces - if intf.type != 'loopback': # Not a loopback interface? Move on... + if intf._type != 'loopback': # Not a loopback interface? Move on... continue if intf.get('vrf',None) != vrf: # Not in the correct VRF? Move on continue diff --git a/netsim/modules/vxlan.py b/netsim/modules/vxlan.py index 1aef265a5b..0c94e9bc23 100644 --- a/netsim/modules/vxlan.py +++ b/netsim/modules/vxlan.py @@ -102,7 +102,7 @@ def node_set_vtep(node: Box, topology: Box) -> bool: # Search for additional loopback interfaces with vxlan.vtep' flag, and use the first one for intf in node.interfaces: - if intf.get('type', '') == 'loopback' and 'vxlan' in intf and intf.vxlan.get('vtep', False): + if intf.get('_type', '') == 'loopback' and 'vxlan' in intf and intf.vxlan.get('vtep', False): vtep_interface = intf loopback_name = intf.ifname break diff --git a/tests/topology/expected/lag-l2.yml b/tests/topology/expected/lag-l2.yml index 0499a8fa2a..e92e3b571a 100644 --- a/tests/topology/expected/lag-l2.yml +++ b/tests/topology/expected/lag-l2.yml @@ -14,11 +14,13 @@ links: lag: ifindex: 1 node: r1 + type: lag - ifindex: 30000 ifname: port-channel1 lag: ifindex: 1 node: r2 + type: lag lag: {} linkindex: 1 mtu: 1600 diff --git a/tests/topology/expected/lag-l3-access-vlan.yml b/tests/topology/expected/lag-l3-access-vlan.yml index 3e2d8927ac..334a1c333c 100644 --- a/tests/topology/expected/lag-l3-access-vlan.yml +++ b/tests/topology/expected/lag-l3-access-vlan.yml @@ -16,6 +16,7 @@ links: lag: ifindex: 1 node: r1 + type: lag vlan: access: v1 - _vlan_mode: irb @@ -25,6 +26,7 @@ links: lag: ifindex: 1 node: r2 + type: lag vlan: access: v1 lag: diff --git a/tests/topology/expected/lag-l3-vlan-trunk.yml b/tests/topology/expected/lag-l3-vlan-trunk.yml index f85f9de2ed..3d71d434ed 100644 --- a/tests/topology/expected/lag-l3-vlan-trunk.yml +++ b/tests/topology/expected/lag-l3-vlan-trunk.yml @@ -14,6 +14,7 @@ links: lag: ifindex: 1 node: r1 + type: lag vlan: trunk: v1: {} @@ -23,6 +24,7 @@ links: lag: ifindex: 1 node: r2 + type: lag vlan: trunk: v1: {} diff --git a/tests/topology/expected/lag-l3.yml b/tests/topology/expected/lag-l3.yml index 22342110cf..edfd1db769 100644 --- a/tests/topology/expected/lag-l3.yml +++ b/tests/topology/expected/lag-l3.yml @@ -15,12 +15,14 @@ links: lag: ifindex: 1 node: r1 + type: lag - ifindex: 30000 ifname: port-channel1 ipv4: 10.1.0.2/30 lag: ifindex: 1 node: r2 + type: lag lag: {} linkindex: 1 node_count: 2 diff --git a/tests/topology/expected/lag-mlag-m_to_m.yml b/tests/topology/expected/lag-mlag-m_to_m.yml index cbd4a94997..7c22af418a 100644 --- a/tests/topology/expected/lag-mlag-m_to_m.yml +++ b/tests/topology/expected/lag-mlag-m_to_m.yml @@ -60,6 +60,7 @@ links: lag: _mlag: true node: a2 + type: lag vlan: trunk: red: {} @@ -68,6 +69,7 @@ links: lag: _mlag: true node: b2 + type: lag vlan: trunk: red: {} @@ -88,6 +90,7 @@ links: lag: _mlag: true node: a1 + type: lag vlan: trunk: red: {} @@ -96,6 +99,7 @@ links: lag: _mlag: true node: b1 + type: lag vlan: trunk: red: {} diff --git a/tests/topology/expected/lag-mlag.yml b/tests/topology/expected/lag-mlag.yml index 3ae998882b..547d94c668 100644 --- a/tests/topology/expected/lag-mlag.yml +++ b/tests/topology/expected/lag-mlag.yml @@ -42,6 +42,7 @@ links: lag: ifindex: 1 node: h1 + type: lag vlan: access: red - _vlan_mode: irb @@ -51,6 +52,7 @@ links: lag: _mlag: true node: s1 + type: lag vlan: access: red - _vlan_mode: irb @@ -60,6 +62,7 @@ links: lag: _mlag: true node: s2 + type: lag vlan: access: red lag: @@ -80,11 +83,13 @@ links: lag: ifindex: 2 node: h1 + type: lag - ifindex: 30001 ifname: port-channel2 lag: ifindex: 2 node: s1 + type: lag lag: {} linkindex: 3 node_count: 2 @@ -100,6 +105,7 @@ links: lag: ifindex: 1 node: h2 + type: lag vlan: access: red - _vlan_mode: irb @@ -109,6 +115,7 @@ links: lag: _mlag: true node: s1 + type: lag vlan: access: red - _vlan_mode: irb @@ -118,6 +125,7 @@ links: lag: _mlag: true node: s2 + type: lag vlan: access: red lag: @@ -140,6 +148,7 @@ links: lag: ifindex: 2 node: h2 + type: lag vlan: access: red - _vlan_mode: irb @@ -149,6 +158,7 @@ links: lag: _mlag: true node: s1 + type: lag vlan: access: red - _vlan_mode: irb @@ -158,6 +168,7 @@ links: lag: _mlag: true node: s2 + type: lag vlan: access: red lag: diff --git a/tests/topology/expected/node.clone-plugin-lag.yml b/tests/topology/expected/node.clone-plugin-lag.yml index e71c82dc35..8a6882b67a 100644 --- a/tests/topology/expected/node.clone-plugin-lag.yml +++ b/tests/topology/expected/node.clone-plugin-lag.yml @@ -36,9 +36,11 @@ links: - ifindex: 30000 ifname: port-channel8 node: r1 + type: lag - ifindex: 30000 ifname: bond8 node: h-01 + type: lag lag: ifindex: 8 linkindex: 2 @@ -51,9 +53,11 @@ links: - ifindex: 30001 ifname: port-channel9 node: r1 + type: lag - ifindex: 30000 ifname: bond9 node: h-02 + type: lag lag: ifindex: 9 linkindex: 3 @@ -68,11 +72,13 @@ links: lag: ifindex: 1 node: r2 + type: lag - ifindex: 30001 ifname: bond9 lag: ifindex: 9 node: h-01 + type: lag lag: {} linkindex: 4 node_count: 2 @@ -86,11 +92,13 @@ links: lag: ifindex: 2 node: r2 + type: lag - ifindex: 30001 ifname: bond10 lag: ifindex: 10 node: h-02 + type: lag lag: {} linkindex: 5 node_count: 2 @@ -106,6 +114,7 @@ links: lag: ifindex: 1 node: h2-01 + type: lag vlan: access: red - _vlan_mode: irb @@ -115,6 +124,7 @@ links: lag: _mlag: true node: r1 + type: lag vlan: access: red - _vlan_mode: irb @@ -124,6 +134,7 @@ links: lag: _mlag: true node: r2 + type: lag vlan: access: red lag: @@ -146,6 +157,7 @@ links: lag: ifindex: 1 node: h2-02 + type: lag vlan: access: red - _vlan_mode: irb @@ -155,6 +167,7 @@ links: lag: _mlag: true node: r1 + type: lag vlan: access: red - _vlan_mode: irb @@ -164,6 +177,7 @@ links: lag: _mlag: true node: r2 + type: lag vlan: access: red lag: