-
Notifications
You must be signed in to change notification settings - Fork 29
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 BGP NLRI prefixes #792
Draft
vitthalmagadum
wants to merge
12
commits into
aristanetworks:main
Choose a base branch
from
vitthalmagadum:issue_786
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
7f3b715
issue_786 Added TC for BGP NLRIs
9902512
issue_786 handling review comment: added support for AFI
4c8a17e
issue_786 Handling review comments: updated specific peer check
d8439a9
issue_786 Handling review comments: updated helper function
92fc165
Merge branch 'main' into issue_786
202f508
Merge branch 'main' into issue_786
2545e65
issue_786 Handling review comments: updated tests.yaml
2d8ee8d
issue_786 fixed the sonarlint issues
7d567ab
issue_786 Handling review comments: updated conditional statement
7594a4c
Merge branch 'main' into issue_786
gmuloc 4ca04d6
Merge branch 'main' into issue_786
vitthalmagadum c7f8822
Merge branch 'main' into issue_786
vitthalmagadum File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -26,6 +26,9 @@ | |||||||
else: | ||||||||
from typing_extensions import Self | ||||||||
|
||||||||
# pylint: disable=C0302 | ||||||||
# TODO: Refactor to reduce the number of lines in this module later | ||||||||
|
||||||||
|
||||||||
def _add_bgp_failures(failures: dict[tuple[str, str | None], dict[str, Any]], afi: Afi, safi: Safi | None, vrf: str, issue: str | dict[str, Any]) -> None: | ||||||||
"""Add a BGP failure entry to the given `failures` dictionary. | ||||||||
|
@@ -171,6 +174,43 @@ def _add_bgp_routes_failure( | |||||||
return failure_routes | ||||||||
|
||||||||
|
||||||||
def _get_inconsistent_peers(peer_details: dict[Any, Any], bgp_peers: list[IPv4Address] | None) -> dict[Any, Any]: | ||||||||
"""Identify BGP peers with inconsistency of prefix(s) received and accepted in a BGP session. | ||||||||
|
||||||||
Parameters | ||||||||
---------- | ||||||||
peer_details: dict[Any, Any] | ||||||||
The BGP peer data dictionary. | ||||||||
bgp_peers: list[IPv4Address] | None | ||||||||
List of IPv4 address of a BGP peer to be verified. If not provided, test will verifies all the BGP peers. | ||||||||
|
||||||||
Returns | ||||||||
------- | ||||||||
dict[Any, Any]: A dictionary containing the BGP peer(s) with inconsistent prefix(s). | ||||||||
|
||||||||
""" | ||||||||
failure: dict[Any, Any] = {} | ||||||||
|
||||||||
# Update the peer details as per input peer addresses for verification. | ||||||||
if bgp_peers: | ||||||||
input_peers_detail: dict[Any, Any] = {} | ||||||||
for peer in bgp_peers: | ||||||||
if not (peer_detail := peer_details.get(str(peer))): | ||||||||
failure[str(peer)] = "Not Configured" | ||||||||
else: | ||||||||
input_peers_detail[str(peer)] = peer_detail | ||||||||
peer_details = input_peers_detail | ||||||||
|
||||||||
# Iterate over each peer and verify the prefix(s) consistency. | ||||||||
for peer, peer_detail in peer_details.items(): | ||||||||
prefix_rcv = peer_detail.get("prefixReceived", "Not Found") | ||||||||
prefix_acc = peer_detail.get("prefixAccepted", "Not Found") | ||||||||
if (prefix_acc and prefix_rcv) == "Not Found" or prefix_rcv != prefix_acc: | ||||||||
failure[peer] = {"prefix received": prefix_rcv, "prefix accepted": prefix_acc} | ||||||||
|
||||||||
return failure | ||||||||
|
||||||||
|
||||||||
class VerifyBGPPeerCount(AntaTest): | ||||||||
"""Verifies the count of BGP peers for a given address family. | ||||||||
|
||||||||
|
@@ -1628,3 +1668,144 @@ 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 VerifyBGPPeerPrefixes(AntaTest): | ||||||||
"""Verifies BGP IPv4 peer(s) consistency of prefix(s) received and accepted in a BGP session. | ||||||||
|
||||||||
Expected Results | ||||||||
---------------- | ||||||||
* Success: The test will pass if the `PfxRcd` equals `PfxAcc`, indicating that all received prefix(s) were accepted. | ||||||||
* Failure: The test will fail if the `PfxRcd` is not equal to `PfxAcc`, indicating that some prefix(s) were rejected/filtered out or | ||||||||
peer(s) are not configured. | ||||||||
|
||||||||
Examples | ||||||||
-------- | ||||||||
```yaml | ||||||||
anta.tests.routing: | ||||||||
bgp: | ||||||||
- VerifyBGPPeerPrefixes: | ||||||||
address_families: | ||||||||
- afi: ipv4 | ||||||||
safi: unicast | ||||||||
peers: | ||||||||
- 10.100.0.8 | ||||||||
- 10.100.0.10 | ||||||||
- afi: ipv4 | ||||||||
safi: multicast | ||||||||
- afi: evpn | ||||||||
- afi: vpn-ipv4 | ||||||||
- afi: ipv4 | ||||||||
safi: labeled-unicast | ||||||||
``` | ||||||||
""" | ||||||||
|
||||||||
name = "VerifyBGPPeerPrefixes" | ||||||||
description = "Verifies the prefix(s) received and accepted of a BGP IPv4 peer." | ||||||||
categories: ClassVar[list[str]] = ["bgp"] | ||||||||
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [ | ||||||||
AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}", revision=3), | ||||||||
AntaTemplate(template="show bgp {afi} summary", revision=3), | ||||||||
] | ||||||||
|
||||||||
class Input(AntaTest.Input): | ||||||||
"""Input model for the VerifyBGPPeerPrefixes test.""" | ||||||||
|
||||||||
address_families: list[BgpAfi] | ||||||||
"""List of BGP address families (BgpAfi).""" | ||||||||
|
||||||||
class BgpAfi(BaseModel): | ||||||||
"""Model for a BGP address family (AFI) and subsequent address family (SAFI).""" | ||||||||
|
||||||||
afi: Afi | ||||||||
"""BGP address family (AFI).""" | ||||||||
safi: Safi | None = None | ||||||||
"""Optional BGP subsequent service family (SAFI). | ||||||||
|
||||||||
If the input `afi` is `ipv4` or `ipv6`, a valid `safi` must be provided. | ||||||||
""" | ||||||||
vrf: str = "default" | ||||||||
""" | ||||||||
Optional VRF for IPv4 and IPv6. If not provided, it defaults to `default`. | ||||||||
|
||||||||
If the input `afi` is not `ipv4` or `ipv6`, e.g. `evpn`, `vrf` must be `default`. | ||||||||
""" | ||||||||
peers: list[IPv4Address] | None = None | ||||||||
"""Optional list of IPv4 address of a BGP peer to be verified. If not provided, test will verifies all the BGP peers.""" | ||||||||
|
||||||||
@model_validator(mode="after") | ||||||||
def validate_inputs(self: BaseModel) -> BaseModel: | ||||||||
"""Validate the inputs provided to the BgpAfi class. | ||||||||
|
||||||||
If afi is either ipv4 or ipv6, safi must be provided. | ||||||||
|
||||||||
If afi is not ipv4 or ipv6, safi must not be provided and vrf must be default. | ||||||||
""" | ||||||||
if self.afi in ["ipv4", "ipv6"]: | ||||||||
if self.safi is None: | ||||||||
msg = "'safi' must be provided when afi is ipv4 or ipv6" | ||||||||
raise ValueError(msg) | ||||||||
elif self.safi is not None: | ||||||||
msg = "'safi' must not be provided when afi is not ipv4 or ipv6" | ||||||||
raise ValueError(msg) | ||||||||
elif self.vrf != "default": | ||||||||
msg = "'vrf' must be default when afi is not ipv4 or ipv6" | ||||||||
raise ValueError(msg) | ||||||||
return self | ||||||||
|
||||||||
def render(self, template: AntaTemplate) -> list[AntaCommand]: | ||||||||
"""Render the template for each BGP address family in the input list.""" | ||||||||
commands = [] | ||||||||
for afi in self.inputs.address_families: | ||||||||
if template == VerifyBGPPeerPrefixes.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi != "sr-te": | ||||||||
commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf)) | ||||||||
|
||||||||
# For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6 | ||||||||
elif template == VerifyBGPPeerPrefixes.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi == "sr-te": | ||||||||
commands.append(template.render(afi=afi.safi, safi=afi.afi, vrf=afi.vrf)) | ||||||||
elif template == VerifyBGPPeerPrefixes.commands[1] and afi.afi not in ["ipv4", "ipv6"]: | ||||||||
commands.append(template.render(afi=afi.afi)) | ||||||||
return commands | ||||||||
|
||||||||
@AntaTest.anta_test | ||||||||
def test(self) -> None: | ||||||||
"""Main test function for VerifyBGPPeerPrefixes.""" | ||||||||
self.result.is_success() | ||||||||
failures: dict[Any, Any] = {} | ||||||||
|
||||||||
for command, input_entry in zip(self.instance_commands, self.inputs.address_families): | ||||||||
command_output = command.json_output | ||||||||
afi = input_entry.afi | ||||||||
safi = input_entry.safi | ||||||||
afi_vrf = input_entry.vrf | ||||||||
input_peers = input_entry.peers | ||||||||
|
||||||||
# Update failures dictionary for `afi`, later on removing the same if no failure found. | ||||||||
if not failures.get(afi): | ||||||||
failures[afi] = {} | ||||||||
Comment on lines
+1784
to
+1785
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
# Verify peer details. | ||||||||
if not (peer_details := get_value(command_output, f"vrfs..{afi_vrf}..peers", separator="..")): | ||||||||
failures[afi].update({safi: "Peers not configured"}) | ||||||||
if not safi: | ||||||||
failures[afi] = "Peers not configured" | ||||||||
continue | ||||||||
|
||||||||
# Verify the received and accepted prefix(s). | ||||||||
failure_logs = _get_inconsistent_peers(peer_details, input_peers) | ||||||||
|
||||||||
# Update failures if any. | ||||||||
if failure_logs and safi: | ||||||||
failures[afi].update({safi: failure_logs}) | ||||||||
elif failure_logs: | ||||||||
failures[afi].update(failure_logs) | ||||||||
|
||||||||
# Remove AFI from failures if empty. | ||||||||
if not failures.get(afi): | ||||||||
failures.pop(afi, None) | ||||||||
|
||||||||
# Check if any failures | ||||||||
if failures: | ||||||||
self.result.is_failure( | ||||||||
f"The following BGP address family(s), peers are not configured or prefix(s) received and accepted are not consistent:\n{failures}" | ||||||||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we have to check for specific peer for specific AFI/SAFI. Please recheck.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. Thanks!