mirror of
https://github.com/hansjone/netx.git
synced 2026-10-08 22:20:58 +08:00
Add BGP IPv4/IPv6 unicast neighbor in/out monitor profiles.
Catalog previously only had VPNv4/VPNv6 route items; global ipv4/ipv6 discover requires empty vrf so VRF CE peers are not mixed in. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6b35add5a4
commit
586ca69d3f
4 changed files with 180 additions and 5 deletions
|
|
@ -147,6 +147,9 @@ def _record_passes_discover_filter(rec: dict[str, Any], ph: PlaceholderDef) -> b
|
|||
require = str(ph.discover_require_nonempty or "").strip()
|
||||
if require and not str(rec.get(require) or "").strip():
|
||||
return False
|
||||
require_empty = str(getattr(ph, "discover_require_empty", "") or "").strip()
|
||||
if require_empty and str(rec.get(require_empty) or "").strip():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class PlaceholderDef:
|
|||
discover_filter_contains: str = ""
|
||||
# Skip rows where this field is empty (e.g. CE peers require non-empty vrf).
|
||||
discover_require_nonempty: str = ""
|
||||
# Skip rows where this field is non-empty (e.g. global AF peers require empty vrf).
|
||||
discover_require_empty: str = ""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -324,6 +326,7 @@ _BGP_NEIGHBOR_VPNV4 = PlaceholderDef(
|
|||
discover_label_field="neighbor",
|
||||
discover_filter_field="afi",
|
||||
discover_filter_contains="vpnv4",
|
||||
discover_require_empty="vrf",
|
||||
)
|
||||
|
||||
_BGP_NEIGHBOR_VPNV6 = PlaceholderDef(
|
||||
|
|
@ -336,6 +339,33 @@ _BGP_NEIGHBOR_VPNV6 = PlaceholderDef(
|
|||
discover_label_field="neighbor",
|
||||
discover_filter_field="afi",
|
||||
discover_filter_contains="vpnv6",
|
||||
discover_require_empty="vrf",
|
||||
)
|
||||
|
||||
_BGP_NEIGHBOR_IPV4 = PlaceholderDef(
|
||||
name="neighbor",
|
||||
schema_field="neighbor",
|
||||
required=True,
|
||||
bind_mode="discover_select",
|
||||
discover_profile_id="zte.config_bgp_peer",
|
||||
discover_value_field="neighbor",
|
||||
discover_label_field="neighbor",
|
||||
discover_filter_field="afi",
|
||||
discover_filter_contains="ipv4",
|
||||
discover_require_empty="vrf",
|
||||
)
|
||||
|
||||
_BGP_NEIGHBOR_IPV6 = PlaceholderDef(
|
||||
name="neighbor",
|
||||
schema_field="neighbor",
|
||||
required=True,
|
||||
bind_mode="discover_select",
|
||||
discover_profile_id="zte.config_bgp_peer",
|
||||
discover_value_field="neighbor",
|
||||
discover_label_field="neighbor",
|
||||
discover_filter_field="afi",
|
||||
discover_filter_contains="ipv6",
|
||||
discover_require_empty="vrf",
|
||||
)
|
||||
|
||||
# Per-VRF CE peers live under address-family ipv4/ipv6 vrf <name>.
|
||||
|
|
@ -1075,6 +1105,120 @@ def _zte_status_profiles() -> list[ParseProfile]:
|
|||
),
|
||||
],
|
||||
),
|
||||
ParseProfile(
|
||||
profile_id="zte.bgp_ipv4_neighbor_in",
|
||||
vendor_key="zte",
|
||||
metric_id="bgp_route",
|
||||
parser_id="bgp_route",
|
||||
title="BGP IPv4 Neighbor In",
|
||||
command_template="show bgp ipv4 unicast neighbor in <neighbor> | one-line",
|
||||
match=r"(?i)^\s*show\s+bgp\s+ipv4\s+unicast\s+neighbor\s+(?P<direction>in)\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
|
||||
textfsm_command="show bgp ipv4 unicast neighbor in",
|
||||
description=(
|
||||
"Routes learned from IPv4 unicast neighbor; discover from BGP peer intent "
|
||||
"(direct + peer-group members); aux: show running-config bgp."
|
||||
),
|
||||
placeholders=[_BGP_NEIGHBOR_IPV4],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "ipv4", "route"],
|
||||
sort_order=428,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
enrich_joins=[
|
||||
EnrichJoin(
|
||||
from_aux="config_bgp_peer",
|
||||
left_on="afi,neighbor",
|
||||
right_on="afi,neighbor",
|
||||
take=("remote_as", "activate", "route_map_in", "route_map_out"),
|
||||
),
|
||||
],
|
||||
),
|
||||
ParseProfile(
|
||||
profile_id="zte.bgp_ipv4_neighbor_out",
|
||||
vendor_key="zte",
|
||||
metric_id="bgp_route",
|
||||
parser_id="bgp_route",
|
||||
title="BGP IPv4 Neighbor Out",
|
||||
command_template="show bgp ipv4 unicast neighbor out <neighbor> | one-line",
|
||||
match=r"(?i)^\s*show\s+bgp\s+ipv4\s+unicast\s+neighbor\s+(?P<direction>out)\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
|
||||
textfsm_command="show bgp ipv4 unicast neighbor out",
|
||||
description=(
|
||||
"Routes advertised to IPv4 unicast neighbor; discover from BGP peer intent; "
|
||||
"aux: show running-config bgp."
|
||||
),
|
||||
placeholders=[_BGP_NEIGHBOR_IPV4],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "ipv4", "route"],
|
||||
sort_order=429,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
collect_lane="heavy",
|
||||
enrich_joins=[
|
||||
EnrichJoin(
|
||||
from_aux="config_bgp_peer",
|
||||
left_on="afi,neighbor",
|
||||
right_on="afi,neighbor",
|
||||
take=("remote_as", "activate", "route_map_in", "route_map_out"),
|
||||
),
|
||||
],
|
||||
),
|
||||
ParseProfile(
|
||||
profile_id="zte.bgp_ipv6_neighbor_in",
|
||||
vendor_key="zte",
|
||||
metric_id="bgp_route",
|
||||
parser_id="bgp_route",
|
||||
title="BGP IPv6 Neighbor In",
|
||||
command_template="show bgp ipv6 unicast neighbor in <neighbor> | one-line",
|
||||
match=r"(?i)^\s*show\s+bgp\s+ipv6\s+unicast\s+neighbor\s+(?P<direction>in)\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
|
||||
textfsm_command="show bgp ipv6 unicast neighbor in",
|
||||
description=(
|
||||
"Routes learned from IPv6 unicast neighbor; discover from BGP peer intent "
|
||||
"(direct + peer-group members); aux: show running-config bgp."
|
||||
),
|
||||
placeholders=[_BGP_NEIGHBOR_IPV6],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "ipv6", "route"],
|
||||
sort_order=430,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
enrich_joins=[
|
||||
EnrichJoin(
|
||||
from_aux="config_bgp_peer",
|
||||
left_on="afi,neighbor",
|
||||
right_on="afi,neighbor",
|
||||
take=("remote_as", "activate", "route_map_in", "route_map_out"),
|
||||
),
|
||||
],
|
||||
),
|
||||
ParseProfile(
|
||||
profile_id="zte.bgp_ipv6_neighbor_out",
|
||||
vendor_key="zte",
|
||||
metric_id="bgp_route",
|
||||
parser_id="bgp_route",
|
||||
title="BGP IPv6 Neighbor Out",
|
||||
command_template="show bgp ipv6 unicast neighbor out <neighbor> | one-line",
|
||||
match=r"(?i)^\s*show\s+bgp\s+ipv6\s+unicast\s+neighbor\s+(?P<direction>out)\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
|
||||
textfsm_command="show bgp ipv6 unicast neighbor out",
|
||||
description=(
|
||||
"Routes advertised to IPv6 unicast neighbor; discover from BGP peer intent; "
|
||||
"aux: show running-config bgp."
|
||||
),
|
||||
placeholders=[_BGP_NEIGHBOR_IPV6],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "ipv6", "route"],
|
||||
sort_order=431,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
collect_lane="heavy",
|
||||
enrich_joins=[
|
||||
EnrichJoin(
|
||||
from_aux="config_bgp_peer",
|
||||
left_on="afi,neighbor",
|
||||
right_on="afi,neighbor",
|
||||
take=("remote_as", "activate", "route_map_in", "route_map_out"),
|
||||
),
|
||||
],
|
||||
),
|
||||
ParseProfile(
|
||||
profile_id="zte.bgp_vpnv4_vrf_neighbor_in",
|
||||
vendor_key="zte",
|
||||
|
|
@ -1094,7 +1238,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
|
|||
placeholders=[_BGP_VRF_PEER_IPV4, _BGP_NEIGHBOR_IPV4_VRF],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "vpnv4", "vrf", "route"],
|
||||
sort_order=430,
|
||||
sort_order=440,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
enrich_joins=[
|
||||
|
|
@ -1125,7 +1269,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
|
|||
placeholders=[_BGP_VRF_PEER_IPV4, _BGP_NEIGHBOR_IPV4_VRF],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "vpnv4", "vrf", "route"],
|
||||
sort_order=435,
|
||||
sort_order=445,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
collect_lane="heavy",
|
||||
|
|
@ -1157,7 +1301,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
|
|||
placeholders=[_BGP_VRF_PEER_IPV6, _BGP_NEIGHBOR_IPV6_VRF],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "vpnv6", "vrf", "route"],
|
||||
sort_order=440,
|
||||
sort_order=450,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
enrich_joins=[
|
||||
|
|
@ -1188,7 +1332,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
|
|||
placeholders=[_BGP_VRF_PEER_IPV6, _BGP_NEIGHBOR_IPV6_VRF],
|
||||
fields=list(_BGP_ROUTE_FIELDS),
|
||||
tags=["bgp", "vpnv6", "vrf", "route"],
|
||||
sort_order=445,
|
||||
sort_order=455,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
collect_lane="heavy",
|
||||
|
|
@ -1707,6 +1851,7 @@ def profile_to_public_dict(p: ParseProfile, *, overrides: dict[str, Any] | None
|
|||
"discover_filter_field": ph.discover_filter_field,
|
||||
"discover_filter_contains": ph.discover_filter_contains,
|
||||
"discover_require_nonempty": ph.discover_require_nonempty,
|
||||
"discover_require_empty": ph.discover_require_empty,
|
||||
}
|
||||
for ph in p.placeholders
|
||||
],
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ class BizStateProfileTests(unittest.TestCase):
|
|||
"zte.bgp_vpnv4_neighbor_out",
|
||||
"zte.bgp_vpnv6_neighbor_in",
|
||||
"zte.bgp_vpnv6_neighbor_out",
|
||||
"zte.bgp_ipv4_neighbor_in",
|
||||
"zte.bgp_ipv4_neighbor_out",
|
||||
"zte.bgp_ipv6_neighbor_in",
|
||||
"zte.bgp_ipv6_neighbor_out",
|
||||
"zte.bgp_vpnv4_vrf_neighbor_in",
|
||||
"zte.bgp_vpnv4_vrf_neighbor_out",
|
||||
"zte.bgp_vpnv6_vrf_neighbor_in",
|
||||
|
|
|
|||
|
|
@ -677,6 +677,10 @@ $
|
|||
self.assertIsNotNone(get_profile("zte.l2vpn_pw_detail"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_vpnv6_neighbor_in"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_vpnv6_neighbor_out"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_ipv4_neighbor_in"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_ipv4_neighbor_out"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_ipv6_neighbor_in"))
|
||||
self.assertIsNotNone(get_profile("zte.bgp_ipv6_neighbor_out"))
|
||||
|
||||
p = get_profile("zte.bgp_vpnv4_vrf_neighbor_in")
|
||||
assert p is not None
|
||||
|
|
@ -757,13 +761,18 @@ $
|
|||
assert glob_v6 is not None
|
||||
self.assertEqual(glob_v6.placeholders[0].discover_filter_contains, "vpnv6")
|
||||
|
||||
glob_ipv4 = get_profile("zte.bgp_ipv4_neighbor_in")
|
||||
assert glob_ipv4 is not None
|
||||
self.assertEqual(glob_ipv4.placeholders[0].discover_filter_contains, "ipv4")
|
||||
self.assertEqual(glob_ipv4.placeholders[0].discover_require_empty, "vrf")
|
||||
|
||||
peer_recs = [
|
||||
{"afi": "vpnv4", "vrf": "", "neighbor": "10.0.0.1", "remote_as": "65001"},
|
||||
{"afi": "vpnv4", "vrf": "", "neighbor": "", "peer_group": "CORE_RR", "remote_as": "65009"},
|
||||
{"afi": "vpnv4", "vrf": "", "neighbor": "10.0.0.9", "peer_group": "CORE_RR", "remote_as": "65019"},
|
||||
{"afi": "vpnv6", "vrf": "", "neighbor": "FC00::1", "remote_as": "65002"},
|
||||
{"afi": "ipv4", "vrf": "CUST_A", "neighbor": "10.0.0.2", "remote_as": "65003"},
|
||||
{"afi": "ipv4", "vrf": "", "neighbor": "10.0.0.9", "remote_as": "65004"},
|
||||
{"afi": "ipv4", "vrf": "", "neighbor": "10.0.0.8", "remote_as": "65004"},
|
||||
{"afi": "ipv6", "vrf": "CUST_B", "neighbor": "FC00::2", "remote_as": "65005"},
|
||||
]
|
||||
self.assertEqual(
|
||||
|
|
@ -774,6 +783,11 @@ $
|
|||
filter_discover_records(peer_recs, glob_v6.placeholders[0]),
|
||||
["FC00::1"],
|
||||
)
|
||||
# Global ipv4: only empty-vrf peers (not VRF CE)
|
||||
self.assertEqual(
|
||||
filter_discover_records(peer_recs, glob_ipv4.placeholders[0]),
|
||||
["10.0.0.8"],
|
||||
)
|
||||
# afi filter is exact: ipv4 must not match vpnv4
|
||||
vrf_nei = get_profile("zte.bgp_vpnv4_vrf_neighbor_in")
|
||||
assert vrf_nei is not None
|
||||
|
|
@ -926,6 +940,15 @@ gei-0/0/0/2 is up, ifindex: 2
|
|||
self.assertEqual(routes[0]["afi"], "vpnv6")
|
||||
self.assertEqual(routes[0]["direction"], "in")
|
||||
|
||||
hit4 = match_command(
|
||||
vendor_key="zte",
|
||||
command="show bgp ipv4 unicast neighbor in 10.0.0.1 | one-line",
|
||||
)
|
||||
self.assertIsNotNone(hit4)
|
||||
assert hit4 is not None
|
||||
self.assertEqual(hit4.profile.profile_id, "zte.bgp_ipv4_neighbor_in")
|
||||
self.assertEqual(hit4.params.get("neighbor"), "10.0.0.1")
|
||||
|
||||
# IPv4 neighbor routes: same wrap join as vpnv6
|
||||
v4_wrap = normalize_bgp_route(
|
||||
raw_text="""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue