Skip to content

Commit

Permalink
feat(anta): Added the test case to verify BGP NLRI prefixes (#792)
Browse files Browse the repository at this point in the history
* issue_786 Added TC for BGP NLRIs

* issue_786 handling review comment: added support for AFI

* issue_786 Handling review comments: updated specific peer check

* issue_786 Handling review comments: updated helper function

* issue_786 Handling review comments: updated tests.yaml

* issue_786 fixed the sonarlint issues

* issue_786 Handling review comments: updated conditional statement

* Updated input model refactoring

* Addressed review comments: updated input to BgpPeer

* Update error message

---------

Co-authored-by: VitthalMagadum <yvitthal.magadum-ext@arista.com>
Co-authored-by: Guillaume Mulocher <gmulocher@arista.com>
Co-authored-by: Carl Baillargeon <carl.baillargeon@arista.com>
  • Loading branch information
4 people authored Jan 15, 2025
1 parent 529e997 commit ba15a4a
Show file tree
Hide file tree
Showing 5 changed files with 375 additions and 1 deletion.
2 changes: 1 addition & 1 deletion anta/input_models/routing/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class BgpPeer(BaseModel):
received_routes: list[IPv4Network] | None = None
"""List of received routes in CIDR format. Required field in the `VerifyBGPExchangedRoutes` test."""
capabilities: list[MultiProtocolCaps] | None = None
"""List of BGP multiprotocol capabilities. Required field in the `VerifyBGPPeerMPCaps` test."""
"""List of BGP multiprotocol capabilities. Required field in the `VerifyBGPPeerMPCaps`, `VerifyBGPNlriAcceptance` tests."""
strict: bool = False
"""If True, requires exact match of the provided BGP multiprotocol capabilities.
Expand Down
75 changes: 75 additions & 0 deletions anta/tests/routing/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1544,3 +1544,78 @@ def test(self) -> None:
outq = peer["peerTcpInfo"]["outputQueueLength"]
if self.inputs.check_tcp_queues and (inq != 0 or outq != 0):
self.result.is_failure(f"Peer: {peer['peerAddress']} VRF: {vrf} - Session has non-empty message queues - InQ: {inq}, OutQ: {outq}")


class VerifyBGPNlriAcceptance(AntaTest):
"""Verifies that all received NLRI are accepted for all AFI/SAFI configured for BGP IPv4 peer(s).
This test performs the following checks for each specified peer:
1. Verifies that the peer is found in its VRF in the BGP configuration.
2. Verifies that all received NLRI were accepted by comparing `nlrisReceived` with `nlrisAccepted`.
Expected Results
----------------
* Success: If `nlrisReceived` equals `nlrisAccepted`, indicating all NLRI were accepted.
* Failure: If any of the following occur:
- The specified VRF is not configured.
- `nlrisReceived` does not equal `nlrisAccepted`, indicating some NLRI were rejected or filtered.
Examples
--------
```yaml
anta.tests.routing:
bgp:
- VerifyBGPNlriAcceptance:
bgp_peers:
- peer_address: 10.100.0.128
vrf: default
capabilities:
- ipv4Unicast
```
"""

categories: ClassVar[list[str]] = ["bgp"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp summary vrf all", revision=1)]

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

bgp_peers: list[BgpPeer]
"""List of BGP IPv4 peers."""

@field_validator("bgp_peers")
@classmethod
def validate_bgp_peers(cls, bgp_peers: list[T]) -> list[T]:
"""Validate that 'capabilities' field is provided in each BGP peer."""
for peer in bgp_peers:
if peer.capabilities is None:
msg = f"{peer} 'capabilities' field missing in the input"
raise ValueError(msg)
return bgp_peers

@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyBGPNlriAcceptance."""
self.result.is_success()

output = self.instance_commands[0].json_output

for peer in self.inputs.bgp_peers:
# Check if the peer is found
if not (peer_data := get_value(output, f"vrfs..{peer.vrf}..peers..{peer.peer_address}", separator="..")):
self.result.is_failure(f"{peer} - Not found")
continue

# Fetching the multiprotocol capabilities
for capability in peer.capabilities:
# Check if the capability is found
if (capability_status := get_value(peer_data, capability)) is None:
self.result.is_failure(f"{peer} - {capability} not found")
continue

if capability_status["afiSafiState"] != "negotiated":
self.result.is_failure(f"{peer} - {capability} not negotiated")

if (received := capability_status.get("nlrisReceived")) != (accepted := capability_status.get("nlrisAccepted")):
self.result.is_failure(f"{peer} AFI/SAFI: {capability} - some NLRI were filtered or rejected - Accepted: {accepted} Received: {received}")
7 changes: 7 additions & 0 deletions examples/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,13 @@ anta.tests.routing.bgp:
- 192.0.254.5/32
received_routes:
- 192.0.254.3/32
- VerifyBGPNlriAcceptance:
# Verifies that all received NLRI are accepted for all AFI/SAFI configured for BGP IPv4 peer(s).
bgp_peers:
- peer_address: 10.100.0.128
vrf: default
capabilities:
- ipv4Unicast
- VerifyBGPPeerASNCap:
# Verifies the four octet ASN capability of BGP IPv4 peer(s).
bgp_peers:
Expand Down
266 changes: 266 additions & 0 deletions tests/units/anta_tests/routing/test_bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from anta.tests.routing.bgp import (
VerifyBGPAdvCommunities,
VerifyBGPExchangedRoutes,
VerifyBGPNlriAcceptance,
VerifyBGPPeerASNCap,
VerifyBGPPeerCount,
VerifyBGPPeerDropStats,
Expand Down Expand Up @@ -4609,4 +4610,269 @@ def test_check_bgp_neighbor_capability(input_dict: dict[str, bool], expected: bo
],
},
},
{
"name": "success",
"test": VerifyBGPNlriAcceptance,
"eos_data": [
{
"vrfs": {
"default": {
"vrf": "default",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.0.8": {
"peerState": "Established",
"peerAsn": "65100",
"ipv4Unicast": {"afiSafiState": "negotiated", "nlrisReceived": 17, "nlrisAccepted": 17},
"l2VpnEvpn": {"afiSafiState": "negotiated", "nlrisReceived": 56, "nlrisAccepted": 56},
},
},
},
"MGMT": {
"vrf": "MGMT",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.4.5": {
"peerState": "Established",
"peerAsn": "65102",
"ipv4Unicast": {"afiSafiState": "negotiated", "nlrisReceived": 14, "nlrisAccepted": 14},
"l2VpnEvpn": {"afiSafiState": "negotiated", "nlrisReceived": 56, "nlrisAccepted": 56},
}
},
},
}
}
],
"inputs": {
"bgp_peers": [
{
"peer_address": "10.100.0.8",
"vrf": "default",
"capabilities": ["Ipv4 Unicast", "L2vpnEVPN"],
},
{
"peer_address": "10.100.4.5",
"vrf": "MGMT",
"capabilities": ["ipv4 Unicast", "L2vpnEVPN"],
},
]
},
"expected": {"result": "success"},
},
{
"name": "failure-vrf-not-configured",
"test": VerifyBGPNlriAcceptance,
"eos_data": [
{
"vrfs": {
"default": {
"vrf": "default",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {},
},
"MGMT": {
"vrf": "MGMT",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {},
},
}
}
],
"inputs": {
"bgp_peers": [
{
"peer_address": "10.100.0.8",
"vrf": "default",
"capabilities": ["Ipv4 Unicast", "L2vpnEVPN"],
},
{
"peer_address": "10.100.4.5",
"vrf": "MGMT",
"capabilities": ["ipv4 Unicast", "L2vpnEVPN"],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Peer: 10.100.0.8 VRF: default - Not found",
"Peer: 10.100.4.5 VRF: MGMT - Not found",
],
},
},
{
"name": "failure-capability-not-found",
"test": VerifyBGPNlriAcceptance,
"eos_data": [
{
"vrfs": {
"default": {
"vrf": "default",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.0.8": {
"peerState": "Established",
"peerAsn": "65100",
"ipv4Unicast": {"afiSafiState": "negotiated", "nlrisReceived": 17, "nlrisAccepted": 17},
},
},
},
"MGMT": {
"vrf": "MGMT",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.4.5": {
"peerState": "Established",
"peerAsn": "65102",
"l2VpnEvpn": {"afiSafiState": "negotiated", "nlrisReceived": 56, "nlrisAccepted": 56},
}
},
},
}
}
],
"inputs": {
"bgp_peers": [
{
"peer_address": "10.100.0.8",
"vrf": "default",
"capabilities": ["Ipv4 Unicast", "L2vpnEVPN"],
},
{
"peer_address": "10.100.4.5",
"vrf": "MGMT",
"capabilities": ["ipv4 Unicast", "L2vpnEVPN"],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Peer: 10.100.0.8 VRF: default - l2VpnEvpn not found",
"Peer: 10.100.4.5 VRF: MGMT - ipv4Unicast not found",
],
},
},
{
"name": "failure-capability-not-negotiated",
"test": VerifyBGPNlriAcceptance,
"eos_data": [
{
"vrfs": {
"default": {
"vrf": "default",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.0.8": {
"peerState": "Established",
"peerAsn": "65100",
"ipv4Unicast": {"afiSafiState": "configured", "nlrisReceived": 17, "nlrisAccepted": 17},
},
},
},
"MGMT": {
"vrf": "MGMT",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.4.5": {
"peerState": "Established",
"peerAsn": "65102",
"l2VpnEvpn": {"afiSafiState": "configured", "nlrisReceived": 56, "nlrisAccepted": 56},
}
},
},
}
}
],
"inputs": {
"bgp_peers": [
{
"peer_address": "10.100.0.8",
"vrf": "default",
"capabilities": ["Ipv4 Unicast", "L2vpnEVPN"],
},
{
"peer_address": "10.100.4.5",
"vrf": "MGMT",
"capabilities": ["ipv4 Unicast", "L2vpnEVPN"],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Peer: 10.100.0.8 VRF: default - ipv4Unicast not negotiated",
"Peer: 10.100.0.8 VRF: default - l2VpnEvpn not found",
"Peer: 10.100.4.5 VRF: MGMT - ipv4Unicast not found",
"Peer: 10.100.4.5 VRF: MGMT - l2VpnEvpn not negotiated",
],
},
},
{
"name": "failure-nlris-not-accepted",
"test": VerifyBGPNlriAcceptance,
"eos_data": [
{
"vrfs": {
"default": {
"vrf": "default",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.0.8": {
"peerState": "Established",
"peerAsn": "65100",
"ipv4Unicast": {"afiSafiState": "negotiated", "nlrisReceived": 17, "nlrisAccepted": 16},
"l2VpnEvpn": {"afiSafiState": "negotiated", "nlrisReceived": 58, "nlrisAccepted": 56},
},
},
},
"MGMT": {
"vrf": "MGMT",
"routerId": "10.100.1.5",
"asn": "65102",
"peers": {
"10.100.4.5": {
"peerState": "Established",
"peerAsn": "65102",
"ipv4Unicast": {"afiSafiState": "negotiated", "nlrisReceived": 15, "nlrisAccepted": 14},
"l2VpnEvpn": {"afiSafiState": "negotiated", "nlrisReceived": 59, "nlrisAccepted": 56},
}
},
},
}
}
],
"inputs": {
"bgp_peers": [
{
"peer_address": "10.100.0.8",
"vrf": "default",
"capabilities": ["Ipv4 Unicast", "L2vpnEVPN"],
},
{
"peer_address": "10.100.4.5",
"vrf": "MGMT",
"capabilities": ["ipv4 Unicast", "L2vpnEVPN"],
},
]
},
"expected": {
"result": "failure",
"messages": [
"Peer: 10.100.0.8 VRF: default AFI/SAFI: ipv4Unicast - some NLRI were filtered or rejected - Accepted: 16 Received: 17",
"Peer: 10.100.0.8 VRF: default AFI/SAFI: l2VpnEvpn - some NLRI were filtered or rejected - Accepted: 56 Received: 58",
"Peer: 10.100.4.5 VRF: MGMT AFI/SAFI: ipv4Unicast - some NLRI were filtered or rejected - Accepted: 14 Received: 15",
"Peer: 10.100.4.5 VRF: MGMT AFI/SAFI: l2VpnEvpn - some NLRI were filtered or rejected - Accepted: 56 Received: 59",
],
},
},
]
Loading

0 comments on commit ba15a4a

Please sign in to comment.