Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anta): Added the test case to verify the BGP route origin #813

Merged
merged 22 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1f33640
issue_811 Added TC for BGP route origin
Sep 3, 2024
0e0a8d3
Merge branch 'main' into issue_811
Sep 23, 2024
4046dfb
issue_811 Handling review comments: updated the variable name and inp…
Sep 23, 2024
1408772
issue_811 Handling review comments: updated the pylint ignore and doc…
Sep 25, 2024
3fb5245
Merge branch 'main' into issue_811
Sep 27, 2024
b9d1bea
issue_811 fix lintin issue
Sep 27, 2024
07d115f
issue_811 Handling review comments: updated vrf details in failure msg
Sep 30, 2024
2b615d7
Merge branch 'main' into issue_811
vitthalmagadum Sep 30, 2024
5c1a91a
Merge branch 'main' into issue_811
vitthalmagadum Oct 1, 2024
8a7fc6b
Merge branch 'main' into issue_811
vitthalmagadum Oct 7, 2024
18fbaa7
Merge branch 'main' into issue_811
gmuloc Oct 10, 2024
c6b80d5
Merge branch 'main' into issue_811
vitthalmagadum Oct 11, 2024
15d5964
issue_811 Handling review comments: updated the input model for route…
Oct 11, 2024
78c8ce9
Merge branch 'main' into issue_811
vitthalmagadum Dec 18, 2024
224b1e7
Added input models refactoring
vitthalmagadum Dec 18, 2024
b742646
Addressed review comment: updated doc, unit test eos data
vitthalmagadum Dec 19, 2024
c399bd3
Merge branch 'main' into issue_811
vitthalmagadum Dec 30, 2024
3981dd2
pre-commit changes after conflicts resolved
vitthalmagadum Dec 30, 2024
fbad6d7
Merge branch 'main' into issue_811
vitthalmagadum Jan 9, 2025
83ff9c9
Merge branch 'main' into issue_811
vitthalmagadum Jan 15, 2025
ba1d4db
Addressed review comments: updated docs, input model msg
vitthalmagadum Jan 15, 2025
5478535
Merge branch 'main' into issue_811
vitthalmagadum Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion anta/tests/routing/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from __future__ import annotations

from ipaddress import IPv4Address, IPv4Network, IPv6Address
from typing import Any, ClassVar
from typing import Any, ClassVar, Literal

from pydantic import BaseModel, Field, PositiveInt, model_validator
from pydantic.v1.utils import deep_update
Expand Down Expand Up @@ -1620,3 +1620,93 @@ def test(self) -> None:
self.result.is_success()
else:
self.result.is_failure(f"The following BGP peer(s) are not configured or maximum routes and maximum routes warning limit is not correct:\n{failures}")


class VerifyBGPRouteOrigin(AntaTest):
carl-baillargeon marked this conversation as resolved.
Show resolved Hide resolved
"""Verifies BGP route origin for the provided IPv4 Network(s).

Expected Results
----------------
* Success: The test will pass if the BGP route's origin matches expected origin type.
gmuloc marked this conversation as resolved.
Show resolved Hide resolved
* Failure: The test will fail if the BGP route's origin does not matches with expected origin type or BGP route entry(s) not found.

Examples
--------
```yaml
anta.tests.routing:
bgp:
- VerifyBGPRouteOrigin:
route_entries:
- prefix: 10.100.0.128/31
vrf: default
route_paths:
- nexthop: 10.100.0.10
origin: Igp
- nexthop: 10.100.4.5
origin: Incomplete
```
"""

name = "VerifyBGPRouteOrigin"
description = "Verifies BGP route origin for the provided IPv4 Network(s)."
categories: ClassVar[list[str]] = ["bgp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show ip bgp {prefix} vrf {vrf}", revision=3)]

class Input(AntaTest.Input):
"""Input model for the VerifyBGPRouteOrigin test."""

route_entries: list[BgpRoute]
"""List of BGP route(s)"""
carl-baillargeon marked this conversation as resolved.
Show resolved Hide resolved

class BgpRoute(BaseModel):
"""Model for a BGP route(s)."""

prefix: IPv4Network
"""IPv4 network address"""
vrf: str = "default"
"""Optional VRF. If not provided, it defaults to `default`."""
route_paths: list[dict[str, IPv4Address | Literal["Igp", "Egp", "Incomplete"]]]
"""A list of dictionaries represents a BGP path.
- `nexthop`: The next-hop IP address for the path.
- `origin`: The origin of the route."""
gmuloc marked this conversation as resolved.
Show resolved Hide resolved

def render(self, template: AntaTemplate) -> list[AntaCommand]:
"""Render the template for each BGP peer in the input list."""
return [template.render(prefix=route.prefix, vrf=route.vrf) for route in self.inputs.route_entries]

@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyBGPRouteOrigin."""
failures: dict[Any, Any] = {}

for command, input_entry in zip(self.instance_commands, self.inputs.route_entries):
prefix = str(command.params.prefix)
vrf = command.params.vrf
paths = input_entry.route_paths

# Verify if a BGP peer is configured with the provided vrf
if not (bgp_routes := get_value(command.json_output, f"vrfs..{vrf}..bgpRouteEntries..{prefix}..bgpRoutePaths", separator="..")):
failures[prefix] = {vrf: "Not configured"}
continue

# Iterating over each nexthop.
failure: dict[Any, Any] = {}
for path in paths:
nexthop = str(path["nexthop"])
origin = path["origin"]
if not (route_path := get_item(bgp_routes, "nextHop", nexthop)):
failure[nexthop] = "Path not found."
continue

if (actual_origin := route_path.get("routeDetail", {}).get("origin", "Not Found")) != origin:
failure[nexthop] = f"Expected `{origin}` as the origin, but found `{actual_origin}` instead."

# Updating failures.
if failure:
failures[prefix] = failure
gmuloc marked this conversation as resolved.
Show resolved Hide resolved

# Check if any failures
if not failures:
self.result.is_success()
else:
self.result.is_failure(f"Following BGP route entry(s) or nexthop path(s) not found or origin type is not correct:\n{failures}")
18 changes: 17 additions & 1 deletion examples/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,22 @@ anta.tests.routing:
vrf: default
maximum_routes: 12000
warning_limit: 10000
- VerifyBGPRouteOrigin:
route_entries:
- prefix: 10.100.0.128/31
vrf: default
route_paths:
- nexthop: 10.100.0.10
origin: Igp
- nexthop: 10.100.4.5
origin: Incomplete
- prefix: 10.100.0.130/31
vrf: default
route_paths:
- nexthop: 10.100.0.8
origin: Igp
- nexthop: 10.100.0.10
origin: Igp
ospf:
- VerifyOSPFNeighborState:
- VerifyOSPFNeighborCount:
Expand Down Expand Up @@ -678,4 +694,4 @@ anta.tests.routing:
- endpoint: 1.0.0.14/32
vias:
- type: ip
nexthop: 1.1.1.1
nexthop: 1.1.1.1
gmuloc marked this conversation as resolved.
Show resolved Hide resolved
241 changes: 241 additions & 0 deletions tests/units/anta_tests/routing/test_bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
VerifyBGPPeersHealth,
VerifyBGPPeerUpdateErrors,
VerifyBgpRouteMaps,
VerifyBGPRouteOrigin,
VerifyBGPSpecificPeers,
VerifyBGPTimers,
VerifyEVPNType2Route,
Expand Down Expand Up @@ -4836,4 +4837,244 @@
],
},
},
{
"name": "success",
"test": VerifyBGPRouteOrigin,
"eos_data": [
{
"vrfs": {
"default": {
"bgpRouteEntries": {
"10.100.0.128/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.10",
"routeDetail": {
"origin": "Igp",
},
},
{
"nextHop": "10.100.4.5",
"routeDetail": {
"origin": "Incomplete",
},
},
],
}
}
}
}
},
{
"vrfs": {
"MGMT": {
"bgpRouteEntries": {
"10.100.0.130/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.8",
"routeDetail": {
"origin": "Igp",
},
},
{
"nextHop": "10.100.0.10",
"routeDetail": {
"origin": "Igp",
},
},
],
}
}
}
}
},
],
"inputs": {
"route_entries": [
{
"prefix": "10.100.0.128/31",
"vrf": "default",
"route_paths": [{"nexthop": "10.100.0.10", "origin": "Igp"}, {"nexthop": "10.100.4.5", "origin": "Incomplete"}],
},
{
"prefix": "10.100.0.130/31",
"vrf": "MGMT",
"route_paths": [{"nexthop": "10.100.0.8", "origin": "Igp"}, {"nexthop": "10.100.0.10", "origin": "Igp"}],
},
]
},
"expected": {"result": "success"},
},
{
"name": "failure-origin-not-correct",
"test": VerifyBGPRouteOrigin,
"eos_data": [
{
"vrfs": {
"default": {
"bgpRouteEntries": {
"10.100.0.128/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.10",
"routeDetail": {
"origin": "Igp",
},
},
{
"nextHop": "10.100.4.5",
"routeDetail": {
"origin": "Incomplete",
},
},
],
}
}
}
}
},
{
"vrfs": {
"MGMT": {
"bgpRouteEntries": {
"10.100.0.130/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.8",
"routeDetail": {
"origin": "Igp",
},
},
{
"nextHop": "10.100.0.10",
"routeDetail": {
"origin": "Igp",
},
},
],
}
}
}
}
},
],
"inputs": {
"route_entries": [
{
"prefix": "10.100.0.128/31",
"vrf": "default",
"route_paths": [{"nexthop": "10.100.0.10", "origin": "Incomplete"}, {"nexthop": "10.100.4.5", "origin": "Igp"}],
},
{
"prefix": "10.100.0.130/31",
"vrf": "MGMT",
"route_paths": [{"nexthop": "10.100.0.8", "origin": "Incomplete"}, {"nexthop": "10.100.0.10", "origin": "Incomplete"}],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Following BGP route entry(s) or nexthop path(s) not found or origin type is not correct:\n"
"{'10.100.0.128/31': {'10.100.0.10': 'Expected `Incomplete` as the origin, but found `Igp` instead.', "
"'10.100.4.5': 'Expected `Igp` as the origin, but found `Incomplete` instead.'}, "
"'10.100.0.130/31': {'10.100.0.8': 'Expected `Incomplete` as the origin, but found `Igp` instead.', "
"'10.100.0.10': 'Expected `Incomplete` as the origin, but found `Igp` instead.'}}"
],
},
},
{
"name": "failure-path-not-found",
"test": VerifyBGPRouteOrigin,
"eos_data": [
{
"vrfs": {
"default": {
"bgpRouteEntries": {
"10.100.0.128/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.15",
"routeDetail": {
"origin": "Igp",
},
},
],
}
}
}
}
},
{
"vrfs": {
"MGMT": {
"bgpRouteEntries": {
"10.100.0.130/31": {
"bgpRoutePaths": [
{
"nextHop": "10.100.0.15",
"routeDetail": {
"origin": "Igp",
},
},
],
}
}
}
}
},
],
"inputs": {
"route_entries": [
{
"prefix": "10.100.0.128/31",
"vrf": "default",
"route_paths": [{"nexthop": "10.100.0.10", "origin": "Incomplete"}, {"nexthop": "10.100.4.5", "origin": "Igp"}],
},
{
"prefix": "10.100.0.130/31",
"vrf": "MGMT",
"route_paths": [{"nexthop": "10.100.0.8", "origin": "Incomplete"}, {"nexthop": "10.100.0.10", "origin": "Incomplete"}],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Following BGP route entry(s) or nexthop path(s) not found or origin type is not correct:\n"
"{'10.100.0.128/31': {'10.100.0.10': 'Path not found.', '10.100.4.5': 'Path not found.'}, "
"'10.100.0.130/31': {'10.100.0.8': 'Path not found.', '10.100.0.10': 'Path not found.'}}"
],
},
},
{
"name": "failure-route-not-found",
"test": VerifyBGPRouteOrigin,
"eos_data": [
{"vrfs": {"default": {"bgpRouteEntries": {}}}},
{"vrfs": {"MGMT": {"bgpRouteEntries": {}}}},
],
"inputs": {
"route_entries": [
{
"prefix": "10.100.0.128/31",
"vrf": "default",
"route_paths": [{"nexthop": "10.100.0.10", "origin": "Incomplete"}, {"nexthop": "10.100.4.5", "origin": "Igp"}],
},
{
"prefix": "10.100.0.130/31",
"vrf": "MGMT",
"route_paths": [{"nexthop": "10.100.0.8", "origin": "Incomplete"}, {"nexthop": "10.100.0.10", "origin": "Incomplete"}],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Following BGP route entry(s) or nexthop path(s) not found or origin type is not correct:\n"
"{'10.100.0.128/31': {'default': 'Not configured'}, '10.100.0.130/31': {'MGMT': 'Not configured'}}"
],
},
},
]
Loading