From 6ee2c081b3c1937712eb474a17ffb97af8e8424d Mon Sep 17 00:00:00 2001 From: vitthalmagadum <122079046+vitthalmagadum@users.noreply.github.com> Date: Thu, 19 Dec 2024 03:18:22 +0530 Subject: [PATCH] fix(anta.tests): Cleaning up AVT tests module (VerifyAVTSpecificPath) (#939) --- anta/input_models/avt.py | 36 ++++ anta/tests/avt.py | 125 +++++--------- docs/api/tests.avt.md | 18 ++ examples/tests.yaml | 2 +- tests/units/anta_tests/test_avt.py | 259 +++++++++++++++++++---------- 5 files changed, 276 insertions(+), 164 deletions(-) create mode 100644 anta/input_models/avt.py diff --git a/anta/input_models/avt.py b/anta/input_models/avt.py new file mode 100644 index 000000000..9219c2fc8 --- /dev/null +++ b/anta/input_models/avt.py @@ -0,0 +1,36 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +"""Module containing input models for AVT tests.""" + +from __future__ import annotations + +from ipaddress import IPv4Address + +from pydantic import BaseModel, ConfigDict + + +class AVTPath(BaseModel): + """AVT (Adaptive Virtual Topology) model representing path details and associated information.""" + + model_config = ConfigDict(extra="forbid") + vrf: str = "default" + """VRF context. Defaults to `default`.""" + avt_name: str + """The name of the Adaptive Virtual Topology (AVT).""" + destination: IPv4Address + """The IPv4 address of the destination peer in the AVT.""" + next_hop: IPv4Address + """The IPv4 address of the next hop used to reach the AVT peer.""" + path_type: str | None = None + """Specifies the type of path for the AVT. If not specified, both types 'direct' and 'multihop' are considered.""" + + def __str__(self) -> str: + """Return a human-readable string representation of the AVTPath for reporting. + + Examples + -------- + AVT CONTROL-PLANE-PROFILE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1) + + """ + return f"AVT {self.avt_name} VRF: {self.vrf} (Destination: {self.destination}, Next-hop: {self.next_hop})" diff --git a/anta/tests/avt.py b/anta/tests/avt.py index 66b30babe..b0f1a465b 100644 --- a/anta/tests/avt.py +++ b/anta/tests/avt.py @@ -7,12 +7,10 @@ # mypy: disable-error-code=attr-defined from __future__ import annotations -from ipaddress import IPv4Address from typing import ClassVar -from pydantic import BaseModel - from anta.decorators import skip_on_platforms +from anta.input_models.avt import AVTPath from anta.models import AntaCommand, AntaTemplate, AntaTest from anta.tools import get_value @@ -71,14 +69,22 @@ def test(self) -> None: class VerifyAVTSpecificPath(AntaTest): - """Verifies the status and type of an Adaptive Virtual Topology (AVT) path for a specified VRF. + """Verifies the Adaptive Virtual Topology (AVT) path. + + This test performs the following checks for each specified LLDP neighbor: + + 1. Confirming that the AVT paths are associated with the specified VRF. + 2. Verifying that each AVT path is active and valid. + 3. Ensuring that the AVT path matches the specified type (direct/multihop) if provided. Expected Results ---------------- - * Success: The test will pass if all AVT paths for the specified VRF are active, valid, and match the specified type (direct/multihop) if provided. - If multiple paths are configured, the test will pass only if all the paths are valid and active. - * Failure: The test will fail if no AVT paths are configured for the specified VRF, or if any configured path is not active, valid, - or does not match the specified type. + * Success: The test will pass if all of the following conditions are met: + - All AVT paths for the specified VRF are active, valid, and match the specified path type (direct/multihop), if provided. + - If multiple paths are configured, the test will pass only if all paths meet these criteria. + * Failure: The test will fail if any of the following conditions are met: + - No AVT paths are configured for the specified VRF. + - Any configured path is inactive, invalid, or does not match the specified type. Examples -------- @@ -94,35 +100,16 @@ class VerifyAVTSpecificPath(AntaTest): ``` """ - description = "Verifies the status and type of an AVT path for a specified VRF." categories: ClassVar[list[str]] = ["avt"] - commands: ClassVar[list[AntaCommand | AntaTemplate]] = [ - AntaTemplate(template="show adaptive-virtual-topology path vrf {vrf} avt {avt_name} destination {destination}") - ] + commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show adaptive-virtual-topology path", revision=1)] class Input(AntaTest.Input): """Input model for the VerifyAVTSpecificPath test.""" - avt_paths: list[AVTPaths] + avt_paths: list[AVTPath] """List of AVT paths to verify.""" - - class AVTPaths(BaseModel): - """Model for the details of AVT paths.""" - - vrf: str = "default" - """The VRF for the AVT path. Defaults to 'default' if not provided.""" - avt_name: str - """Name of the adaptive virtual topology.""" - destination: IPv4Address - """The IPv4 address of the AVT peer.""" - next_hop: IPv4Address - """The IPv4 address of the next hop for the AVT peer.""" - path_type: str | None = None - """The type of the AVT path. If not provided, both 'direct' and 'multihop' paths are considered.""" - - def render(self, template: AntaTemplate) -> list[AntaCommand]: - """Render the template for each input AVT path/peer.""" - return [template.render(vrf=path.vrf, avt_name=path.avt_name, destination=path.destination) for path in self.inputs.avt_paths] + AVTPaths: ClassVar[type[AVTPath]] = AVTPath + """To maintain backward compatibility.""" @skip_on_platforms(["cEOSLab", "vEOS-lab"]) @AntaTest.anta_test @@ -131,59 +118,39 @@ def test(self) -> None: # Assume the test is successful until a failure is detected self.result.is_success() - # Process each command in the instance - for command, input_avt in zip(self.instance_commands, self.inputs.avt_paths): - # Extract the command output and parameters - vrf = command.params.vrf - avt_name = command.params.avt_name - peer = str(command.params.destination) - - command_output = command.json_output.get("vrfs", {}) - - # If no AVT is configured, mark the test as failed and skip to the next command - if not command_output: - self.result.is_failure(f"AVT configuration for peer '{peer}' under topology '{avt_name}' in VRF '{vrf}' is not found.") - continue - - # Extract the AVT paths - avt_paths = get_value(command_output, f"{vrf}.avts.{avt_name}.avtPaths") - next_hop, input_path_type = str(input_avt.next_hop), input_avt.path_type + command_output = self.instance_commands[0].json_output + for avt_path in self.inputs.avt_paths: + if (path_output := get_value(command_output, f"vrfs.{avt_path.vrf}.avts.{avt_path.avt_name}.avtPaths")) is None: + self.result.is_failure(f"{avt_path} - No AVT path configured") + return - nexthop_path_found = path_type_found = False + path_found = path_type_found = False # Check each AVT path - for path, path_data in avt_paths.items(): - # If the path does not match the expected next hop, skip to the next path - if path_data.get("nexthopAddr") != next_hop: - continue - - nexthop_path_found = True + for path, path_data in path_output.items(): + dest = path_data.get("destination") + nexthop = path_data.get("nexthopAddr") path_type = "direct" if get_value(path_data, "flags.directPath") else "multihop" - # If the path type does not match the expected path type, skip to the next path - if input_path_type and path_type != input_path_type: - continue - - path_type_found = True - valid = get_value(path_data, "flags.valid") - active = get_value(path_data, "flags.active") - - # Check the path status and type against the expected values - if not all([valid, active]): - failure_reasons = [] - if not get_value(path_data, "flags.active"): - failure_reasons.append("inactive") - if not get_value(path_data, "flags.valid"): - failure_reasons.append("invalid") - # Construct the failure message prefix - failed_log = f"AVT path '{path}' for topology '{avt_name}' in VRF '{vrf}'" - self.result.is_failure(f"{failed_log} is {', '.join(failure_reasons)}.") - - # If no matching next hop or path type was found, mark the test as failed - if not nexthop_path_found or not path_type_found: - self.result.is_failure( - f"No '{input_path_type}' path found with next-hop address '{next_hop}' for AVT peer '{peer}' under topology '{avt_name}' in VRF '{vrf}'." - ) + if not avt_path.path_type: + path_found = all([dest == str(avt_path.destination), nexthop == str(avt_path.next_hop)]) + + else: + path_type_found = all([dest == str(avt_path.destination), nexthop == str(avt_path.next_hop), path_type == avt_path.path_type]) + if path_type_found: + path_found = True + # Check the path status and type against the expected values + valid = get_value(path_data, "flags.valid") + active = get_value(path_data, "flags.active") + if not all([valid, active]): + self.result.is_failure(f"{avt_path} - Incorrect path {path} - Valid: {valid}, Active: {active}") + + # If no matching path found, mark the test as failed + if not path_found: + if avt_path.path_type and not path_type_found: + self.result.is_failure(f"{avt_path} Path Type: {avt_path.path_type} - Path not found") + else: + self.result.is_failure(f"{avt_path} - Path not found") class VerifyAVTRole(AntaTest): diff --git a/docs/api/tests.avt.md b/docs/api/tests.avt.md index f9e1acfdd..a55fcce14 100644 --- a/docs/api/tests.avt.md +++ b/docs/api/tests.avt.md @@ -7,7 +7,10 @@ anta_title: ANTA catalog for Adaptive Virtual Topology (AVT) tests ~ that can be found in the LICENSE file. --> +# Tests + ::: anta.tests.avt + options: show_root_heading: false show_root_toc_entry: false @@ -18,3 +21,18 @@ anta_title: ANTA catalog for Adaptive Virtual Topology (AVT) tests filters: - "!test" - "!render" + +# Input models + +::: anta.input_models.avt + + options: + show_root_heading: false + show_root_toc_entry: false + show_bases: false + anta_hide_test_module_description: true + merge_init_into_class: false + show_labels: true + filters: + - "!^__init__" + - "!^__str__" diff --git a/examples/tests.yaml b/examples/tests.yaml index d2a029986..86ed117a3 100644 --- a/examples/tests.yaml +++ b/examples/tests.yaml @@ -63,7 +63,7 @@ anta.tests.avt: # Verifies the AVT role of a device. role: edge - VerifyAVTSpecificPath: - # Verifies the status and type of an AVT path for a specified VRF. + # Verifies the Adaptive Virtual Topology (AVT) path. avt_paths: - avt_name: CONTROL-PLANE-PROFILE vrf: default diff --git a/tests/units/anta_tests/test_avt.py b/tests/units/anta_tests/test_avt.py index 80fbce036..d9cdaa1fa 100644 --- a/tests/units/anta_tests/test_avt.py +++ b/tests/units/anta_tests/test_avt.py @@ -361,48 +361,63 @@ "avts": { "DEFAULT-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - } - } - } - } - } - }, - { - "vrfs": { - "data": { - "avts": { - "DATA-AVT-POLICY-CONTROL-PLANE": { - "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:8": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + "multihop:1": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + "multihop:3": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, } } - } - } - } - }, - { - "vrfs": { + }, + }, "data": { "avts": { "DATA-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:8": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.1", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.1", + }, + "direct:8": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, + "multihop:1": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, + "multihop:3": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, } - } + }, } - } + }, } }, ], @@ -420,36 +435,85 @@ "test": VerifyAVTSpecificPath, "eos_data": [ {"vrfs": {}}, + ], + "inputs": { + "avt_paths": [ + {"avt_name": "MGMT-AVT-POLICY-DEFAULT", "vrf": "default", "destination": "10.101.255.2", "next_hop": "10.101.255.1", "path_type": "multihop"}, + {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.2", "path_type": "multihop"}, + ] + }, + "expected": { + "result": "failure", + "messages": ["AVT MGMT-AVT-POLICY-DEFAULT VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1) - No AVT path configured"], + }, + }, + { + "name": "failure-path_type_check_true", + "test": VerifyAVTSpecificPath, + "eos_data": [ { "vrfs": { + "default": { + "avts": { + "DEFAULT-AVT-POLICY-CONTROL-PLANE": { + "avtPaths": { + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + } + } + }, + }, "data": { "avts": { "DATA-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.3", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.3", + }, } - } + }, } - } + }, } }, ], "inputs": { "avt_paths": [ - {"avt_name": "MGMT-AVT-POLICY-DEFAULT", "vrf": "default", "destination": "10.101.255.2", "next_hop": "10.101.255.1", "path_type": "multihop"}, - {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.2", "path_type": "multihop"}, + { + "avt_name": "DEFAULT-AVT-POLICY-CONTROL-PLANE", + "vrf": "default", + "destination": "10.101.255.2", + "next_hop": "10.101.255.11", + "path_type": "multihop", + }, + {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21", "path_type": "direct"}, ] }, "expected": { "result": "failure", - "messages": ["AVT configuration for peer '10.101.255.2' under topology 'MGMT-AVT-POLICY-DEFAULT' in VRF 'default' is not found."], + "messages": [ + "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.11) Path Type: multihop - Path not found", + "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.21) Path Type: direct - Path not found", + ], }, }, { - "name": "failure-no-path-with-correct-next-hop", + "name": "failure-path_type_check_false", "test": VerifyAVTSpecificPath, "eos_data": [ { @@ -458,30 +522,38 @@ "avts": { "DEFAULT-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, } } - } - } - } - }, - { - "vrfs": { + }, + }, "data": { "avts": { "DATA-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, + "direct:10": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.3", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.3", + }, } - } + }, } - } + }, } }, ], @@ -492,18 +564,15 @@ "vrf": "default", "destination": "10.101.255.2", "next_hop": "10.101.255.11", - "path_type": "multihop", }, - {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21", "path_type": "direct"}, + {"avt_name": "DATA-AVT-POLICY-CONTROL-PLANE", "vrf": "data", "destination": "10.101.255.1", "next_hop": "10.101.255.21"}, ] }, "expected": { "result": "failure", "messages": [ - "No 'multihop' path found with next-hop address '10.101.255.11' for AVT peer '10.101.255.2' under " - "topology 'DEFAULT-AVT-POLICY-CONTROL-PLANE' in VRF 'default'.", - "No 'direct' path found with next-hop address '10.101.255.21' for AVT peer '10.101.255.1' under " - "topology 'DATA-AVT-POLICY-CONTROL-PLANE' in VRF 'data'.", + "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.11) - Path not found", + "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.21) - Path not found", ], }, }, @@ -517,30 +586,48 @@ "avts": { "DEFAULT-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "direct:9": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:1": {"flags": {"directPath": True, "valid": False, "active": False}, "nexthopAddr": "10.101.255.1"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": False}, "nexthopAddr": "10.101.255.1"}, + "multihop:3": { + "flags": {"directPath": False, "valid": False, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.2", + }, } } - } - } - } - }, - { - "vrfs": { + }, + }, "data": { "avts": { "DATA-AVT-POLICY-CONTROL-PLANE": { "avtPaths": { - "direct:10": {"flags": {"directPath": True, "valid": True, "active": True}, "nexthopAddr": "10.101.255.1"}, - "direct:9": {"flags": {"directPath": True, "valid": False, "active": True}, "nexthopAddr": "10.101.255.1"}, - "multihop:1": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, - "multihop:3": {"flags": {"directPath": False, "valid": True, "active": True}, "nexthopAddr": "10.101.255.2"}, + "direct:10": { + "flags": {"directPath": True, "valid": False, "active": True}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.1", + }, + "direct:9": { + "flags": {"directPath": True, "valid": True, "active": False}, + "nexthopAddr": "10.101.255.1", + "destination": "10.101.255.1", + }, + "direct:8": { + "flags": {"directPath": True, "valid": False, "active": False}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, + "multihop:1": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, + "multihop:3": { + "flags": {"directPath": False, "valid": True, "active": True}, + "nexthopAddr": "10.101.255.2", + "destination": "10.101.255.1", + }, } - } + }, } - } + }, } }, ], @@ -559,8 +646,12 @@ "expected": { "result": "failure", "messages": [ - "AVT path 'multihop:3' for topology 'DEFAULT-AVT-POLICY-CONTROL-PLANE' in VRF 'default' is inactive.", - "AVT path 'direct:9' for topology 'DATA-AVT-POLICY-CONTROL-PLANE' in VRF 'data' is invalid.", + "AVT DEFAULT-AVT-POLICY-CONTROL-PLANE VRF: default (Destination: 10.101.255.2, Next-hop: 10.101.255.1) - " + "Incorrect path multihop:3 - Valid: False, Active: True", + "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.1) - " + "Incorrect path direct:10 - Valid: False, Active: True", + "AVT DATA-AVT-POLICY-CONTROL-PLANE VRF: data (Destination: 10.101.255.1, Next-hop: 10.101.255.1) - " + "Incorrect path direct:9 - Valid: True, Active: False", ], }, },