Split BGP global activate discover by neighbor IP family.

IPv4/IPv6 neighbor in/out keep AF peers and peer-group expand, while top-level global activate is routed to ipv4 or ipv6 discover by address literal.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-22 21:06:37 +08:00
parent 262082ef08
commit 4c5738e48e
5 changed files with 167 additions and 25 deletions

View file

@ -438,27 +438,29 @@ class ZteConfigIntentTests(unittest.TestCase):
"loopback400",
)
self.assertNotIn(("64900", "l2vpn-evpn", "", "444::2", ""), by)
# AS 64580: top-level activate only → global row
# AS 64580: top-level activate only → global row with activate=enable
self.assertIn(("64580", "global", "", "22:22:22::22", ""), by)
self.assertEqual(
by[("64580", "global", "", "22:22:22::22", "")]["update_source"],
"loopback0",
)
# AS 100: peer-group expand on EVPN
self.assertIn(("100", "l2vpn-evpn", "", "", "MAR_GROUP_V6_1"), by)
self.assertIn(
("100", "l2vpn-evpn", "", "2408:8121:8400:1:1000::4:0", "MAR_GROUP_V6_1"),
by,
)
self.assertEqual(
by[
("100", "l2vpn-evpn", "", "2408:8121:8400:1:1000::4:0", "MAR_GROUP_V6_1")
]["route_map_out"],
"TO_MAR_EVPN_SRV6_GROUP_1",
by[("64580", "global", "", "22:22:22::22", "")]["activate"], "enable"
)
# AS 100: top-level activate → global (legacy ≈ ipv4) plus vpnv4 AF row
self.assertEqual(
by[("100", "global", "", "100.0.0.2", "")]["activate"], "enable"
)
self.assertEqual(
by[("100", "vpnv4", "", "100.0.0.2", "")]["remote_as"], "100"
)
# Top-level activate disable must not look like enable
self.assertEqual(
by[("100", "global", "", "2408:8121:8400:1:1000::4:0", "MAR_GROUP_V6_1")][
"activate"
],
"disable",
)
# Peer-group members must not leak across local AS
self.assertNotIn(
("64900", "l2vpn-evpn", "", "2408:8121:8400:1:1000::4:0", "MAR_GROUP_V6_1"),

View file

@ -812,8 +812,10 @@ $
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_filter_contains, "ipv4,global")
self.assertEqual(glob_ipv4.placeholders[0].discover_require_empty, "vrf")
self.assertEqual(glob_ipv4.placeholders[0].discover_equals, "activate=enable")
self.assertEqual(glob_ipv4.placeholders[0].discover_global_ip_family, "ipv4")
peer_recs = [
{
@ -822,6 +824,7 @@ $
"vrf": "",
"neighbor": "10.0.0.1",
"remote_as": "65001",
"activate": "enable",
},
{
"local_as": "64900",
@ -830,6 +833,7 @@ $
"neighbor": "",
"peer_group": "CORE_RR",
"remote_as": "65009",
"activate": "enable",
},
{
"local_as": "64900",
@ -838,6 +842,7 @@ $
"neighbor": "10.0.0.9",
"peer_group": "CORE_RR",
"remote_as": "65019",
"activate": "enable",
},
{
"local_as": "64900",
@ -845,6 +850,7 @@ $
"vrf": "",
"neighbor": "FC00::1",
"remote_as": "65002",
"activate": "enable",
},
{
"local_as": "64900",
@ -852,6 +858,7 @@ $
"vrf": "CUST_A",
"neighbor": "10.0.0.2",
"remote_as": "65003",
"activate": "enable",
},
{
"local_as": "64900",
@ -859,6 +866,39 @@ $
"vrf": "",
"neighbor": "10.0.0.8",
"remote_as": "65004",
"activate": "enable",
},
{
"local_as": "64900",
"afi": "global",
"vrf": "",
"neighbor": "10.0.0.7",
"remote_as": "65007",
"activate": "enable",
},
{
"local_as": "64900",
"afi": "global",
"vrf": "",
"neighbor": "FC00::7",
"remote_as": "65017",
"activate": "enable",
},
{
"local_as": "64900",
"afi": "ipv4",
"vrf": "",
"neighbor": "10.0.0.88",
"remote_as": "65088",
"activate": "disable",
},
{
"local_as": "64900",
"afi": "ipv4",
"vrf": "",
"neighbor": "10.0.0.99",
"remote_as": "65099",
"activate": "",
},
{
"local_as": "64900",
@ -866,20 +906,48 @@ $
"vrf": "CUST_B",
"neighbor": "FC00::2",
"remote_as": "65005",
"activate": "enable",
},
{
"local_as": "64900",
"afi": "ipv6",
"vrf": "",
"neighbor": "FC00::8",
"remote_as": "65006",
"activate": "enable",
},
{
"local_as": "64900",
"afi": "ipv6",
"vrf": "",
"neighbor": "172.16.0.8",
"remote_as": "65018",
"activate": "enable",
},
]
self.assertEqual(
filter_discover_records(peer_recs, glob_v4.placeholders[0]),
["10.0.0.1", "10.0.0.9"],
)
# vpnv4: direct AF neighbor + peer-group member (membership at global,
# already expanded onto afi=vpnv4 by config_bgp_peer).
self.assertEqual(
filter_discover_records(peer_recs, glob_v6.placeholders[0]),
["FC00::1"],
)
# Global ipv4: only empty-vrf peers (not VRF CE)
# IPv4: ipv4 AF + global activate only for IPv4 literals
self.assertEqual(
filter_discover_records(peer_recs, glob_ipv4.placeholders[0]),
["10.0.0.8"],
["10.0.0.8", "10.0.0.7"],
)
glob_ipv6 = get_profile("zte.bgp_ipv6_neighbor_in")
assert glob_ipv6 is not None
self.assertEqual(glob_ipv6.placeholders[0].discover_filter_contains, "ipv6,global")
self.assertEqual(glob_ipv6.placeholders[0].discover_global_ip_family, "ipv6")
# IPv6 AF (any IP under AF) + global activate only for IPv6 literals
self.assertEqual(
set(filter_discover_records(peer_recs, glob_ipv6.placeholders[0])),
{"FC00::8", "172.16.0.8", "FC00::7"},
)
# afi filter is exact: ipv4 must not match vpnv4
vrf_nei = get_profile("zte.bgp_vpnv4_vrf_neighbor_in")