diff --git a/netsim/validate/ospf/frr.py b/netsim/validate/ospf/frr.py index 9bcb5a9f3c..eb3e8f0fb0 100644 --- a/netsim/validate/ospf/frr.py +++ b/netsim/validate/ospf/frr.py @@ -17,9 +17,9 @@ def show_ospf_neighbor(id: str, present: bool = True, vrf: str = 'default') -> str: try: ipaddress.IPv4Address(id) - except: - raise Exception(f'OSPF router ID {id} is not a valid IPv4 address') - return f'ip ospf ' + (f'vrf {vrf} ' if vrf != 'default' else '') + f'neighbor {id} json' + except Exception as exc: + raise Exception(f'OSPF router ID {id} is not a valid IPv4 address') from exc + return f'ip ospf vrf {vrf} neighbor {id} json' def valid_ospf_neighbor(id: str, present: bool = True, vrf: str = 'default') -> bool: _result = global_vars.get_result_dict('_result') @@ -31,7 +31,7 @@ def valid_ospf_neighbor(id: str, present: bool = True, vrf: str = 'default') -> if not present: return True raise Exception(f'There is no OSPFv2 neighbor {id}') - + n_state = _result[id][0] if not present: raise Exception(f'Unexpected OSPFv2 neighbor {id} in state {n_state.nbrState}') @@ -42,15 +42,16 @@ def valid_ospf_neighbor(id: str, present: bool = True, vrf: str = 'default') -> else: raise log.Result(exit_msg) -def show_ospf6_neighbor(id: str, **kwargs: typing.Any) -> str: +def show_ospf6_neighbor(id: str, present: bool = True, vrf: str = 'default', **kwargs: typing.Any) -> str: try: ipaddress.IPv4Address(id) - except: - raise Exception(f'OSPF router ID {id} is not a valid IPv4 address') - return f'ipv6 ospf6 neighbor {id} json' + except Exception as exc: + raise Exception(f'OSPF router ID {id} is not a valid IPv4 address') from exc + return f'ipv6 ospf6 vrf {vrf} neighbor {id} json' -def valid_ospf6_neighbor(id: str, present: bool = True) -> bool: +def valid_ospf6_neighbor(id: str, present: bool = True, vrf: str = 'default') -> bool: _result = global_vars.get_result_dict('_result') + vrf_name = '' if vrf == 'default' else f' in VRF {vrf}' n_state = None for n_idx in _result.keys(): @@ -62,18 +63,18 @@ def valid_ospf6_neighbor(id: str, present: bool = True) -> bool: if n_state is None: if not present: return True - raise Exception(f'There is no OSPFv3 neighbor {id}') - else: + raise Exception(f'There is no OSPFv3 neighbor {id}{vrf_name}') + else: if not present: - raise Exception(f'Unexpected OSPFv3 neighbor {id} in state {n_state.neighborState}') + raise Exception(f'Unexpected OSPFv3 neighbor {id}{vrf_name} in state {n_state.neighborState}') if n_state.neighborState != 'Full': - raise Exception(f'OSPFv3 neighbor {id} is in state {n_state.neighborState}') + raise Exception(f'OSPFv3 neighbor {id}{vrf_name} is in state {n_state.neighborState}') return True def show_ospf_prefix(pfx: str, **kwargs: typing.Any) -> str: - return f'ip ospf route json' + return 'ip ospf route json' def get_ospf_prefix(pfx: str, data: Box, **kwargs: typing.Any) -> typing.Optional[Box]: return data.get(pfx,None) @@ -108,7 +109,7 @@ def valid_ospf_prefix( names = OSPF_PREFIX_NAMES) def show_ospf6_prefix(pfx: str, **kwargs: typing.Any) -> str: - return f'ipv6 ospf6 route detail json' + return 'ipv6 ospf6 route detail json' def get_ospf6_prefix(pfx: str, data: Box) -> typing.Optional[Box]: return data.get('routes').get(pfx,None) @@ -122,8 +123,6 @@ def check_ospf6_cost(data: list, value: typing.Any, **kwargs: typing.Any) -> lis return m_value - return [ p for p in data if p.metricCost == value ] - def check_ospf6_rt(data: list, value: typing.Any, **kwargs: typing.Any) -> list: return [ p for p in data if p.pathType == value ] @@ -157,10 +156,10 @@ def valid_ipv6_route( if not _result: raise Exception(f'The routing table has no {proto} routes') - + if not pfx in _result: raise Exception(f'The prefix {pfx} is not in the routing table or not a {proto} route') - + pfx_data = _result[pfx][0] if cost is not None and cost != pfx_data.metric: raise Exception(f'Invalid OSPF end-to-end cost for prefix {pfx}: expected {cost} actual {pfx_data.metric}') diff --git a/tests/integration/vlan/52-vlan-vrf-lite.yml b/tests/integration/vlan/52-vlan-vrf-lite.yml index ebd101fa8b..dd65aabfd1 100644 --- a/tests/integration/vlan/52-vlan-vrf-lite.yml +++ b/tests/integration/vlan/52-vlan-vrf-lite.yml @@ -2,19 +2,19 @@ # # * Routed VLAN interfaces # * VRFs -# * OSPF in VRFs +# * OSPF and OSPFv3 in VRFs # --- message: | - VRF lite implementation with VLAN trunks + VRF lite implementation with dual-stack VLAN trunks - * h1, h2, and h5 should be able to ping each other - * h3 and h4 should be able to ping each other + * h1, h2, and h5 should be able to ping each other using IPv4 and IPv6 + * h3 and h4 should be able to ping each other using IPv4 and IPv6 Please note it might take a while for the lab to work due to - STP and OSPF setup phase + STP, OSPF, and OSPFv3 setup phase -defaults.sources.extra: [ ../wait_times.yml, ../warnings.yml ] +defaults.sources.extra: [ ../vrf/defaults-ipv6-only.yml, ../wait_times.yml, ../warnings.yml ] groups: _auto_create: True @@ -54,43 +54,83 @@ links: vlan.trunk: [ red, blue ] validate: - adj_r1_b: - description: Check OSPF adjacencies (R2-R1) - wait_msg: Waiting for OSPF adjacencies to form + adj_v2_r1_b: + description: Check OSPFv2 adjacencies (R2-R1) + wait_msg: Waiting for OSPFv2 adjacencies to form wait: ospfv2_adj_stp nodes: [ r2 ] plugin: ospf_neighbor(nodes.r1.vrfs.blue.ospf.router_id,vrf='blue') - adj_r1_r: - description: Check OSPF adjacencies (R2-R1) - wait_msg: Waiting for OSPF adjacencies to form + adj_v2_r1_r: + description: Check OSPFv2 adjacencies (R2-R1) + wait_msg: Waiting for OSPFv2 adjacencies to form wait: ospfv2_adj_lan nodes: [ r2 ] plugin: ospf_neighbor(nodes.r1.vrfs.red.ospf.router_id,vrf='red') - adj_r3_b: - description: Check OSPF adjacencies (R2-R3) - wait_msg: Waiting for OSPF adjacencies to form + adj_v2_r3_b: + description: Check OSPFv2 adjacencies (R2-R3) + wait_msg: Waiting for OSPFv2 adjacencies to form wait: ospfv2_adj_lan nodes: [ r2 ] plugin: ospf_neighbor(nodes.r3.vrfs.blue.ospf.router_id,vrf='blue') - adj_r3_r: - description: Check OSPF adjacencies (R2-R3) - wait_msg: Waiting for OSPF adjacencies to form + adj_v2_r3_r: + description: Check OSPFv2 adjacencies (R2-R3) + wait_msg: Waiting for OSPFv2 adjacencies to form wait: ospfv2_adj_lan nodes: [ r2 ] plugin: ospf_neighbor(nodes.r3.vrfs.red.ospf.router_id,vrf='red') - red: - description: Intra-VLAN reachability (red) + adj_v3_r1_b: + description: Check OSPFv3 adjacencies (R2-R1) + wait_msg: Waiting for OSPFv3 adjacencies to form + wait: ospfv3_adj_stp + nodes: [ r2 ] + plugin: ospf6_neighbor(nodes.r1.vrfs.blue.ospf.router_id,vrf='blue') + adj_v3_r1_r: + description: Check OSPFv3 adjacencies (R2-R1) + wait_msg: Waiting for OSPFv3 adjacencies to form + wait: ospfv3_adj_lan + nodes: [ r2 ] + plugin: ospf6_neighbor(nodes.r1.vrfs.red.ospf.router_id,vrf='red') + adj_v3_r3_b: + description: Check OSPFv3 adjacencies (R2-R3) + wait_msg: Waiting for OSPFv3 adjacencies to form + wait: ospfv3_adj_lan + nodes: [ r2 ] + plugin: ospf6_neighbor(nodes.r3.vrfs.blue.ospf.router_id,vrf='blue') + adj_v3_r3_r: + description: Check OSPFv3 adjacencies (R2-R3) + wait_msg: Waiting for OSPFv3 adjacencies to form + wait: ospfv3_adj_lan + nodes: [ r2 ] + plugin: ospf6_neighbor(nodes.r3.vrfs.red.ospf.router_id,vrf='red') + red_v4: + description: IPv4 intra-VLAN reachability (red) wait_msg: Waiting for STP forwarding state wait: ping_stp nodes: [ h1, h2 ] - plugin: ping('h5') - blue: - description: Intra-VLAN reachability (blue) + plugin: ping('h5',af='ipv4') + red_v6: + description: IPv6 intra-VLAN reachability (red) + wait_msg: Waiting for STP forwarding state + wait: ping_stp + nodes: [ h1, h2 ] + plugin: ping('h5',af='ipv6') + blue_v4: + description: IPv4 intra-VLAN reachability (blue) + nodes: [ h3 ] + wait: ping_long + devices: [ linux ] + plugin: ping('h4',af='ipv4') + blue_v6: + description: IPv6 intra-VLAN reachability (blue) nodes: [ h3 ] wait: ping_long devices: [ linux ] - plugin: ping('h4') - filter: - description: Inter-VLAN isolation (red - blue) + plugin: ping('h4',af='ipv6') + filter_v4: + description: IPv4 inter-VLAN isolation (red - blue) + nodes: [ h1, h2 ] + plugin: ping('h3',af='ipv4',expect='fail') + filter_v6: + description: IPv6 inter-VLAN isolation (red - blue) nodes: [ h1, h2 ] - plugin: ping('h3',expect='fail') + plugin: ping('h3',af='ipv6',expect='fail')