Merge pull request #15533 from opensourcerouting/fix/add_paths_limit_capability_test

bgpd: Add tests for Paths-Limit capability
This commit is contained in:
Russ White 2024-03-19 10:18:44 -04:00 committed by GitHub
commit 80c8e10f5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 180 additions and 91 deletions

View File

@ -25,7 +25,7 @@ struct bgp_paths_limit_capability {
uint16_t afi; uint16_t afi;
uint8_t safi; uint8_t safi;
uint16_t paths_limit; uint16_t paths_limit;
}; } __attribute__((packed));
#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1 #define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1

View File

@ -3240,11 +3240,13 @@ static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
safi_t safi; safi_t safi;
iana_afi_t pkt_afi; iana_afi_t pkt_afi;
iana_safi_t pkt_safi; iana_safi_t pkt_safi;
uint16_t paths_limit = 0;
struct bgp_paths_limit_capability bpl = {}; struct bgp_paths_limit_capability bpl = {};
memcpy(&bpl, data, sizeof(bpl)); memcpy(&bpl, data, sizeof(bpl));
pkt_afi = ntohs(bpl.afi); pkt_afi = ntohs(bpl.afi);
pkt_safi = safi_int2iana(bpl.safi); pkt_safi = safi_int2iana(bpl.safi);
paths_limit = ntohs(bpl.paths_limit);
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u",
@ -3252,8 +3254,7 @@ static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
lookup_msg(capcode_str, hdr->code, lookup_msg(capcode_str, hdr->code,
NULL), NULL),
iana_afi2str(pkt_afi), iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi), iana_safi2str(pkt_safi), paths_limit);
bpl.paths_limit);
if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi,
&safi)) { &safi)) {
@ -3275,7 +3276,7 @@ static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
SET_FLAG(peer->af_cap[afi][safi], SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV); PEER_CAP_PATHS_LIMIT_AF_RCV);
peer->addpath_paths_limit[afi][safi].receive = peer->addpath_paths_limit[afi][safi].receive =
bpl.paths_limit; paths_limit;
ignore: ignore:
data += CAPABILITY_CODE_PATHS_LIMIT_LEN; data += CAPABILITY_CODE_PATHS_LIMIT_LEN;
} }

View File

@ -9253,7 +9253,7 @@ DEFPY (no_neighbor_addpath_paths_limit,
peer->addpath_paths_limit[afi][safi].send = 0; peer->addpath_paths_limit[afi][safi].send = 0;
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
CAPABILITY_ACTION_UNSET); CAPABILITY_ACTION_SET);
return ret; return ret;
} }
@ -14111,33 +14111,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
CHECK_FLAG( CHECK_FLAG(
p->af_cap[afi][safi], p->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_RCV)) { PEER_CAP_ADDPATH_AF_TX_RCV)) {
if (CHECK_FLAG( json_object_boolean_add(
p->af_cap[afi] json_sub,
[safi], "txAdvertisedAndReceived",
PEER_CAP_ADDPATH_AF_TX_ADV) && CHECK_FLAG(p->af_cap[afi]
CHECK_FLAG( [safi],
p->af_cap[afi] PEER_CAP_ADDPATH_AF_TX_ADV) &&
[safi], CHECK_FLAG(
PEER_CAP_ADDPATH_AF_TX_RCV)) p->af_cap[afi]
json_object_boolean_true_add( [safi],
json_sub, PEER_CAP_ADDPATH_AF_TX_RCV));
"txAdvertisedAndReceived");
else if ( json_object_boolean_add(
CHECK_FLAG( json_sub, "txAdvertised",
p->af_cap[afi] CHECK_FLAG(p->af_cap[afi]
[safi], [safi],
PEER_CAP_ADDPATH_AF_TX_ADV)) PEER_CAP_ADDPATH_AF_TX_ADV));
json_object_boolean_true_add(
json_sub, json_object_boolean_add(
"txAdvertised"); json_sub, "txReceived",
else if ( CHECK_FLAG(p->af_cap[afi]
CHECK_FLAG( [safi],
p->af_cap[afi] PEER_CAP_ADDPATH_AF_TX_RCV));
[safi],
PEER_CAP_ADDPATH_AF_TX_RCV))
json_object_boolean_true_add(
json_sub,
"txReceived");
} }
if (CHECK_FLAG( if (CHECK_FLAG(
@ -14146,33 +14141,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
CHECK_FLAG( CHECK_FLAG(
p->af_cap[afi][safi], p->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_RX_RCV)) { PEER_CAP_ADDPATH_AF_RX_RCV)) {
if (CHECK_FLAG( json_object_boolean_add(
p->af_cap[afi] json_sub,
[safi], "rxAdvertisedAndReceived",
PEER_CAP_ADDPATH_AF_RX_ADV) && CHECK_FLAG(p->af_cap[afi]
CHECK_FLAG( [safi],
p->af_cap[afi] PEER_CAP_ADDPATH_AF_RX_ADV) &&
[safi], CHECK_FLAG(
PEER_CAP_ADDPATH_AF_RX_RCV)) p->af_cap[afi]
json_object_boolean_true_add( [safi],
json_sub, PEER_CAP_ADDPATH_AF_RX_RCV));
"rxAdvertisedAndReceived");
else if ( json_object_boolean_add(
CHECK_FLAG( json_sub, "rxAdvertised",
p->af_cap[afi] CHECK_FLAG(p->af_cap[afi]
[safi], [safi],
PEER_CAP_ADDPATH_AF_RX_ADV)) PEER_CAP_ADDPATH_AF_RX_ADV));
json_object_boolean_true_add(
json_sub, json_object_boolean_add(
"rxAdvertised"); json_sub, "rxReceived",
else if ( CHECK_FLAG(p->af_cap[afi]
CHECK_FLAG( [safi],
p->af_cap[afi] PEER_CAP_ADDPATH_AF_RX_RCV));
[safi],
PEER_CAP_ADDPATH_AF_RX_RCV))
json_object_boolean_true_add(
json_sub,
"rxReceived");
} }
if (CHECK_FLAG( if (CHECK_FLAG(

View File

@ -15,6 +15,7 @@ router bgp 65001
! !
address-family ipv4 unicast address-family ipv4 unicast
neighbor 192.168.1.2 addpath-tx-all-paths neighbor 192.168.1.2 addpath-tx-all-paths
neighbor 192.168.1.2 addpath-rx-paths-limit 10
exit-address-family exit-address-family
! !
ip prefix-list r2 seq 5 permit 10.10.10.10/32 ip prefix-list r2 seq 5 permit 10.10.10.10/32

View File

@ -16,6 +16,7 @@ router bgp 65002
neighbor 192.168.1.1 timers 1 3 neighbor 192.168.1.1 timers 1 3
neighbor 192.168.1.1 timers connect 1 neighbor 192.168.1.1 timers connect 1
neighbor 192.168.1.1 capability dynamic neighbor 192.168.1.1 capability dynamic
neighbor 192.168.1.1 addpath-rx-paths-limit 20
! !
address-family ipv4 unicast address-family ipv4 unicast
redistribute connected redistribute connected

View File

@ -6,7 +6,11 @@
# #
""" """
Test if Addpath capability is adjusted dynamically. Test if Addpath/Paths-Limit capabilities are adjusted dynamically.
T1: Enable Addpath/Paths-Limit capabilities and check if they are exchanged dynamically
T2: Disable paths limit and check if it's exchanged dynamically
T3: Disable Addpath capability RX and check if it's exchanged dynamically
T4: Disable Addpath capability and check if it's exchanged dynamically
""" """
import os import os
@ -24,7 +28,6 @@ sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413 # pylint: disable=C0413
from lib import topotest from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.common_config import step
pytestmark = [pytest.mark.bgpd] pytestmark = [pytest.mark.bgpd]
@ -47,7 +50,7 @@ def teardown_module(mod):
tgen.stop_topology() tgen.stop_topology()
def test_bgp_dynamic_capability_addpath(): def test_bgp_addpath_paths_limit():
tgen = get_topogen() tgen = get_topogen()
if tgen.routers_have_failure(): if tgen.routers_have_failure():
@ -56,7 +59,7 @@ def test_bgp_dynamic_capability_addpath():
r1 = tgen.gears["r1"] r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"] r2 = tgen.gears["r2"]
def _bgp_converge(): def _converge():
output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
expected = { expected = {
"192.168.1.2": { "192.168.1.2": {
@ -65,8 +68,19 @@ def test_bgp_dynamic_capability_addpath():
"dynamic": "advertisedAndReceived", "dynamic": "advertisedAndReceived",
"addPath": { "addPath": {
"ipv4Unicast": { "ipv4Unicast": {
"txAdvertisedAndReceived": False,
"txAdvertised": True, "txAdvertised": True,
"txReceived": False,
"rxAdvertisedAndReceived": True, "rxAdvertisedAndReceived": True,
"rxAdvertised": True,
"rxReceived": True,
}
},
"pathsLimit": {
"ipv4Unicast": {
"advertisedAndReceived": True,
"advertisedPathsLimit": 10,
"receivedPathsLimit": 20,
} }
}, },
}, },
@ -80,26 +94,26 @@ def test_bgp_dynamic_capability_addpath():
return topotest.json_cmp(output, expected) return topotest.json_cmp(output, expected)
test_func = functools.partial( test_func = functools.partial(
_bgp_converge, _converge,
) )
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Can't converge" assert result is None, "Can't converge"
step("Enable Addpath capability and check if it's exchanged dynamically") ####
# T1: Enable Addpath/Paths-Limit capabilities and check if they are exchanged dynamically
# Clear message stats to check if we receive a notification or not after we ####
# change the settings fo LLGR.
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
r2.vtysh_cmd( r2.vtysh_cmd(
""" """
configure terminal configure terminal
router bgp router bgp
address-family ipv4 unicast address-family ipv4 unicast
neighbor 192.168.1.1 addpath-tx-all-paths neighbor 192.168.1.1 addpath-tx-all-paths
neighbor 192.168.1.1 addpath-rx-paths-limit 21
""" """
) )
def _bgp_check_if_addpath_rx_tx_and_session_not_reset(): def _enable_addpath_paths_limit():
output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
expected = { expected = {
"192.168.1.2": { "192.168.1.2": {
@ -109,7 +123,18 @@ def test_bgp_dynamic_capability_addpath():
"addPath": { "addPath": {
"ipv4Unicast": { "ipv4Unicast": {
"txAdvertisedAndReceived": True, "txAdvertisedAndReceived": True,
"txAdvertised": True,
"txReceived": True,
"rxAdvertisedAndReceived": True, "rxAdvertisedAndReceived": True,
"rxAdvertised": True,
"rxReceived": True,
}
},
"pathsLimit": {
"ipv4Unicast": {
"advertisedAndReceived": True,
"advertisedPathsLimit": 10,
"receivedPathsLimit": 21,
} }
}, },
}, },
@ -120,23 +145,76 @@ def test_bgp_dynamic_capability_addpath():
}, },
"messageStats": { "messageStats": {
"notificationsRecv": 0, "notificationsRecv": 0,
"capabilityRecv": 1, "notificationsSent": 0,
"capabilityRecv": 2,
}, },
} }
} }
return topotest.json_cmp(output, expected) return topotest.json_cmp(output, expected)
test_func = functools.partial( test_func = functools.partial(
_bgp_check_if_addpath_rx_tx_and_session_not_reset, _enable_addpath_paths_limit,
) )
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Session was reset after enabling Addpath capability" assert (
result is None
), "Something went wrong when enabling Addpath/Paths-Limit capabilities"
step("Disable Addpath capability RX and check if it's exchanged dynamically") ###
# T2: Disable paths limit and check if it's exchanged dynamically
###
r2.vtysh_cmd(
"""
configure terminal
router bgp
address-family ipv4 unicast
no neighbor 192.168.1.1 addpath-rx-paths-limit
"""
)
# Clear message stats to check if we receive a notification or not after we def _disable_paths_limit():
# disable addpath-rx. output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") expected = {
"192.168.1.2": {
"bgpState": "Established",
"neighborCapabilities": {
"dynamic": "advertisedAndReceived",
"addPath": {
"ipv4Unicast": {
"txAdvertisedAndReceived": True,
"txAdvertised": True,
"txReceived": True,
"rxAdvertisedAndReceived": True,
"rxAdvertised": True,
"rxReceived": True,
}
},
"pathsLimit": {
"ipv4Unicast": {
"advertisedAndReceived": True,
"advertisedPathsLimit": 10,
"receivedPathsLimit": 0,
}
},
},
"messageStats": {
"notificationsRecv": 0,
"notificationsSent": 0,
"capabilityRecv": 3,
},
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(
_disable_paths_limit,
)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Something went wrong after disabling paths limit"
###
# T3: Disable Addpath capability RX and check if it's exchanged dynamically
###
r2.vtysh_cmd( r2.vtysh_cmd(
""" """
configure terminal configure terminal
@ -146,7 +224,7 @@ def test_bgp_dynamic_capability_addpath():
""" """
) )
def _bgp_check_if_addpath_tx_and_session_not_reset(): def _disable_addpath_rx():
output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
expected = { expected = {
"192.168.1.2": { "192.168.1.2": {
@ -156,27 +234,39 @@ def test_bgp_dynamic_capability_addpath():
"addPath": { "addPath": {
"ipv4Unicast": { "ipv4Unicast": {
"txAdvertisedAndReceived": True, "txAdvertisedAndReceived": True,
"txAdvertised": True,
"txReceived": True,
"rxAdvertisedAndReceived": False,
"rxAdvertised": True, "rxAdvertised": True,
"rxReceived": False,
}
},
"pathsLimit": {
"ipv4Unicast": {
"advertisedAndReceived": True,
"advertisedPathsLimit": 10,
"receivedPathsLimit": 0,
} }
}, },
}, },
"messageStats": { "messageStats": {
"notificationsRecv": 0, "notificationsRecv": 0,
"capabilityRecv": 1, "notificationsSent": 0,
"capabilityRecv": 4,
}, },
} }
} }
return topotest.json_cmp(output, expected) return topotest.json_cmp(output, expected)
test_func = functools.partial( test_func = functools.partial(
_bgp_check_if_addpath_tx_and_session_not_reset, _disable_addpath_rx,
) )
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Session was reset after disabling Addpath RX flags" assert result is None, "Something went wrong after disabling Addpath RX flags"
# Clear message stats to check if we receive a notification or not after we ###
# disable Addpath capability. # T4: Disable Addpath capability and check if it's exchanged dynamically
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") ###
r1.vtysh_cmd( r1.vtysh_cmd(
""" """
configure terminal configure terminal
@ -186,7 +276,7 @@ def test_bgp_dynamic_capability_addpath():
""" """
) )
def _bgp_check_if_addpath_capability_is_absent(): def _disable_addpath():
output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
expected = { expected = {
"192.168.1.2": { "192.168.1.2": {
@ -195,24 +285,30 @@ def test_bgp_dynamic_capability_addpath():
"dynamic": "advertisedAndReceived", "dynamic": "advertisedAndReceived",
"addPath": { "addPath": {
"ipv4Unicast": { "ipv4Unicast": {
"txAdvertisedAndReceived": None, "txAdvertisedAndReceived": False,
"txAdvertised": None, "txAdvertised": False,
"txReceived": True,
"rxAdvertisedAndReceived": False,
"rxAdvertised": True, "rxAdvertised": True,
"rxReceived": False,
} }
}, },
}, },
"messageStats": { "messageStats": {
"notificationsRecv": 0, "notificationsRecv": 0,
"notificationsSent": 0,
"capabilitySent": 1,
"capabilityRecv": 4,
}, },
} }
} }
return topotest.json_cmp(output, expected) return topotest.json_cmp(output, expected)
test_func = functools.partial( test_func = functools.partial(
_bgp_check_if_addpath_capability_is_absent, _disable_addpath,
) )
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed to disable Addpath capability" assert result is None, "Something went wrong when disabling Addpath capability"
if __name__ == "__main__": if __name__ == "__main__":