summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c151
-rw-r--r--bfdd/bfd.h2
-rw-r--r--bgpd/bgp_fsm.c96
-rw-r--r--bgpd/bgp_route.c3
-rw-r--r--bgpd/bgp_vty.c49
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--doc/developer/topotests.rst2
-rw-r--r--isisd/isis_pdu.c3
-rw-r--r--tests/topotests/Dockerfile138
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py4
-rw-r--r--tests/topotests/bgp_peer_group/r1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_peer_group/r1/frr.conf21
-rw-r--r--tests/topotests/bgp_peer_group/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_peer_group/r2/bgpd.conf11
-rw-r--r--tests/topotests/bgp_peer_group/r2/frr.conf19
-rw-r--r--tests/topotests/bgp_peer_group/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_peer_group/r3/frr.conf (renamed from tests/topotests/bgp_peer_group/r3/bgpd.conf)5
-rw-r--r--tests/topotests/bgp_peer_group/r3/zebra.conf6
-rw-r--r--tests/topotests/bgp_peer_group/test_bgp_peer-group.py41
-rw-r--r--tests/topotests/docker/README.md2
-rwxr-xr-xtests/topotests/docker/frr-topotests.sh7
-rwxr-xr-xtests/topotests/docker/inner/compile_frr.sh5
-rwxr-xr-xtests/topotests/docker/inner/entrypoint.sh5
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py161
-rw-r--r--tests/topotests/ospfapi/test_ospf_clientapi.py2
-rw-r--r--zebra/dplane_fpm_nl.c34
27 files changed, 556 insertions, 244 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index eb9c300313..f32bc2598b 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -1172,6 +1172,9 @@ void bfd_set_echo(struct bfd_session *bs, bool echo)
if (bs->bdc == NULL)
ptm_bfd_echo_stop(bs);
}
+
+ if (bs->vrf && bs->vrf->info)
+ bfd_vrf_toggle_echo(bs->vrf->info);
}
void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
@@ -1800,6 +1803,69 @@ void bfd_profiles_remove(void)
bfd_profile_free(bp);
}
+struct __bfd_session_echo {
+ /* VRF peers must match */
+ struct vrf *vrf;
+ /* Echo enabled or not */
+ bool enabled;
+};
+
+static int __bfd_session_has_echo(struct hash_bucket *hb, void *arg)
+{
+ const struct bfd_session *session = hb->data;
+ struct __bfd_session_echo *has_echo = arg;
+
+ if (session->vrf != has_echo->vrf)
+ return HASHWALK_CONTINUE;
+ if (!CHECK_FLAG(session->flags, BFD_SESS_FLAG_ECHO))
+ return HASHWALK_CONTINUE;
+
+ has_echo->enabled = true;
+ return HASHWALK_ABORT;
+}
+
+void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf)
+{
+ struct __bfd_session_echo has_echo = {
+ .enabled = false,
+ .vrf = bfd_vrf->vrf,
+ };
+
+ /* Check for peers using echo */
+ hash_walk(bfd_id_hash, __bfd_session_has_echo, &has_echo);
+
+ /*
+ * No peers using echo, close all echo sockets.
+ */
+ if (!has_echo.enabled) {
+ if (bfd_vrf->bg_echo != -1) {
+ event_cancel(&bfd_vrf->bg_ev[4]);
+ close(bfd_vrf->bg_echo);
+ bfd_vrf->bg_echo = -1;
+ }
+
+ if (bfd_vrf->bg_echov6 != -1) {
+ event_cancel(&bfd_vrf->bg_ev[5]);
+ close(bfd_vrf->bg_echov6);
+ bfd_vrf->bg_echov6 = -1;
+ }
+ return;
+ }
+
+ /*
+ * At least one peer using echo, open echo sockets.
+ */
+ if (bfd_vrf->bg_echo == -1)
+ bfd_vrf->bg_echo = bp_echo_socket(bfd_vrf->vrf);
+ if (bfd_vrf->bg_echov6 == -1)
+ bfd_vrf->bg_echov6 = bp_echov6_socket(bfd_vrf->vrf);
+
+ if (bfd_vrf->bg_ev[4] == NULL && bfd_vrf->bg_echo != -1)
+ event_add_read(master, bfd_recv_cb, bfd_vrf, bfd_vrf->bg_echo, &bfd_vrf->bg_ev[4]);
+ if (bfd_vrf->bg_ev[5] == NULL && bfd_vrf->bg_echov6 != -1)
+ event_add_read(master, bfd_recv_cb, bfd_vrf, bfd_vrf->bg_echov6, &bfd_vrf->bg_ev[5]);
+}
+
/*
* Profile related hash functions.
*/
@@ -1842,9 +1908,23 @@ static void bfd_profile_detach(struct bfd_profile *bp)
*/
static int bfd_vrf_new(struct vrf *vrf)
{
+ struct bfd_vrf_global *bvrf;
+
if (bglobal.debug_zebra)
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
+ bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
+ bvrf->vrf = vrf;
+ vrf->info = bvrf;
+
+ /* Invalidate all sockets */
+ bvrf->bg_shop = -1;
+ bvrf->bg_mhop = -1;
+ bvrf->bg_shop6 = -1;
+ bvrf->bg_mhop6 = -1;
+ bvrf->bg_echo = -1;
+ bvrf->bg_echov6 = -1;
+
return 0;
}
@@ -1853,70 +1933,53 @@ static int bfd_vrf_delete(struct vrf *vrf)
if (bglobal.debug_zebra)
zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
+ XFREE(MTYPE_BFDD_VRF, vrf->info);
+
return 0;
}
static int bfd_vrf_enable(struct vrf *vrf)
{
- struct bfd_vrf_global *bvrf;
-
- /* a different name */
- if (!vrf->info) {
- bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
- bvrf->vrf = vrf;
- vrf->info = (void *)bvrf;
-
- /* Disable sockets if using data plane. */
- if (bglobal.bg_use_dplane) {
- bvrf->bg_shop = -1;
- bvrf->bg_mhop = -1;
- bvrf->bg_shop6 = -1;
- bvrf->bg_mhop6 = -1;
- bvrf->bg_echo = -1;
- bvrf->bg_echov6 = -1;
- }
- } else
- bvrf = vrf->info;
+ struct bfd_vrf_global *bvrf = vrf->info;
if (bglobal.debug_zebra)
zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
- if (!bvrf->bg_shop)
+ /* Don't open sockets when using data plane */
+ if (bglobal.bg_use_dplane)
+ goto skip_sockets;
+
+ if (bvrf->bg_shop == -1)
bvrf->bg_shop = bp_udp_shop(vrf);
- if (!bvrf->bg_mhop)
+ if (bvrf->bg_mhop == -1)
bvrf->bg_mhop = bp_udp_mhop(vrf);
- if (!bvrf->bg_shop6)
+ if (bvrf->bg_shop6 == -1)
bvrf->bg_shop6 = bp_udp6_shop(vrf);
- if (!bvrf->bg_mhop6)
+ if (bvrf->bg_mhop6 == -1)
bvrf->bg_mhop6 = bp_udp6_mhop(vrf);
- if (!bvrf->bg_echo)
- bvrf->bg_echo = bp_echo_socket(vrf);
- if (!bvrf->bg_echov6)
- bvrf->bg_echov6 = bp_echov6_socket(vrf);
- if (!bvrf->bg_ev[0] && bvrf->bg_shop != -1)
+ if (bvrf->bg_ev[0] == NULL && bvrf->bg_shop != -1)
event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
&bvrf->bg_ev[0]);
- if (!bvrf->bg_ev[1] && bvrf->bg_mhop != -1)
+ if (bvrf->bg_ev[1] == NULL && bvrf->bg_mhop != -1)
event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
&bvrf->bg_ev[1]);
- if (!bvrf->bg_ev[2] && bvrf->bg_shop6 != -1)
+ if (bvrf->bg_ev[2] == NULL && bvrf->bg_shop6 != -1)
event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
&bvrf->bg_ev[2]);
- if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1)
+ if (bvrf->bg_ev[3] == NULL && bvrf->bg_mhop6 != -1)
event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
&bvrf->bg_ev[3]);
- if (!bvrf->bg_ev[4] && bvrf->bg_echo != -1)
- event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
- &bvrf->bg_ev[4]);
- if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1)
- event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
- &bvrf->bg_ev[5]);
+ /* Toggle echo if VRF was disabled. */
+ bfd_vrf_toggle_echo(bvrf);
+
+skip_sockets:
if (vrf->vrf_id != VRF_DEFAULT) {
bfdd_zclient_register(vrf->vrf_id);
bfdd_sessions_enable_vrf(vrf);
}
+
return 0;
}
@@ -1948,17 +2011,9 @@ static int bfd_vrf_disable(struct vrf *vrf)
socket_close(&bvrf->bg_echo);
socket_close(&bvrf->bg_shop);
socket_close(&bvrf->bg_mhop);
- if (bvrf->bg_shop6 != -1)
- socket_close(&bvrf->bg_shop6);
- if (bvrf->bg_mhop6 != -1)
- socket_close(&bvrf->bg_mhop6);
- socket_close(&bvrf->bg_echo);
- if (bvrf->bg_echov6 != -1)
- socket_close(&bvrf->bg_echov6);
-
- /* free context */
- XFREE(MTYPE_BFDD_VRF, bvrf);
- vrf->info = NULL;
+ socket_close(&bvrf->bg_shop6);
+ socket_close(&bvrf->bg_mhop6);
+ socket_close(&bvrf->bg_echov6);
return 0;
}
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 2f83b245eb..d4d14ffce6 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -610,6 +610,8 @@ void bfd_sessions_remove_manual(void);
void bfd_profiles_remove(void);
void bfd_rtt_init(struct bfd_session *bfd);
+extern void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf);
+
/**
* Set the BFD session echo state.
*
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 4ac8201f74..490451f193 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -2726,33 +2726,55 @@ static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp,
struct listnode *node = {0};
struct listnode *nnode = {0};
enum peer_mode peer_old_state = PEER_INVALID;
-
- /* TODO: Need to handle peer-groups. */
+ struct peer_group *group;
+ struct peer *member;
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- peer_old_state = bgp_peer_gr_mode_get(peer);
- if (peer_old_state != PEER_GLOBAL_INHERIT)
- continue;
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_old_state = bgp_peer_gr_mode_get(peer);
+ if (peer_old_state != PEER_GLOBAL_INHERIT)
+ continue;
- bgp_peer_inherit_global_gr_mode(peer, global_new_state);
- bgp_peer_gr_flags_update(peer);
+ bgp_peer_inherit_global_gr_mode(peer, global_new_state);
+ bgp_peer_gr_flags_update(peer);
- if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
- zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64
- "...resetting session",
- peer, peer->peer_gr_new_status_flag,
- peer->flags);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64
+ "...resetting session",
+ peer, peer->peer_gr_new_status_flag, peer->flags);
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- /* Reset session to match with behavior for other peer
- * configs that require the session to be re-setup.
- */
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
- bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset_safe(peer, &nnode);
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
+ bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset_safe(peer, &nnode);
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, member)) {
+ peer_old_state = bgp_peer_gr_mode_get(member);
+ if (peer_old_state != PEER_GLOBAL_INHERIT)
+ continue;
+
+ bgp_peer_inherit_global_gr_mode(member, global_new_state);
+ bgp_peer_gr_flags_update(member);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64
+ "...resetting session",
+ member, member->peer_gr_new_status_flag,
+ member->flags);
+
+ member->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status))
+ bgp_notify_send(member->connection, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(member);
+ }
+ }
}
}
@@ -2911,6 +2933,9 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state,
{
enum global_mode global_gr_mode;
bool session_reset = true;
+ struct peer_group *group;
+ struct peer *member;
+ struct listnode *node, *nnode;
if (old_state == new_state)
return BGP_GR_NO_OPERATION;
@@ -2945,16 +2970,27 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state,
bgp_peer_move_to_gr_mode(peer, new_state);
if (session_reset) {
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- /* Reset session to match with behavior for other peer
- * configs that require the session to be re-setup.
- */
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
- bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
+ bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, member)) {
+ member->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ bgp_peer_move_to_gr_mode(member, new_state);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status))
+ bgp_notify_send(member->connection, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(member);
+ }
+ }
}
return BGP_GR_SUCCESS;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 72e798a7e2..5feda71837 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -12318,8 +12318,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
} else {
if (incremental_print) {
vty_out(vty, "\"prefix\": \"%pFX\",\n", p);
- vty_out(vty, "\"version\": \"%" PRIu64 "\",",
- dest->version);
+ vty_out(vty, "\"version\": %" PRIu64 ",", dest->version);
} else {
json_object_string_addf(json, "prefix", "%pFX",
p);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index cba1cdaf1a..d1238bc8de 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -3519,11 +3519,6 @@ DEFUN (bgp_neighbor_graceful_restart_set,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
if (result == BGP_GR_SUCCESS) {
@@ -3554,11 +3549,6 @@ DEFUN (no_bgp_neighbor_graceful_restart,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
if (ret == BGP_GR_SUCCESS) {
@@ -3588,11 +3578,6 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
if (ret == BGP_GR_SUCCESS) {
@@ -3623,11 +3608,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD);
if (ret == BGP_GR_SUCCESS) {
@@ -3657,11 +3637,6 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD);
if (ret == BGP_GR_SUCCESS) {
@@ -3693,11 +3668,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable,
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- vty_out(vty,
- "Per peer-group graceful-restart configuration is not yet supported\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
if (ret == BGP_GR_SUCCESS) {
@@ -14927,22 +14897,31 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) &&
- CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
json_object_string_add(
json_cap, "gracefulRestart",
"advertisedAndReceived");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_ADV))
+ } else if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
+ json_object_string_add(json_cap, "gracefulRestart",
+ "advertised");
+#if CONFDATE > 20250525
+CPP_NOTICE("Remove `gracefulRestartCapability` JSON field")
+#endif
json_object_string_add(
json_cap,
"gracefulRestartCapability",
"advertised");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_RCV))
+ } else if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+ json_object_string_add(json_cap, "gracefulRestart",
+ "received");
+#if CONFDATE > 20250525
+CPP_NOTICE("Remove `gracefulRestartCapability` JSON field")
+#endif
json_object_string_add(
json_cap,
"gracefulRestartCapability",
"received");
+ }
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
int restart_af_count = 0;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index a8431bee97..258fc87f96 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3022,6 +3022,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
PEER_ATTR_INHERIT(peer, group, local_role);
/* Update GR flags for the peer. */
+ PEER_ATTR_INHERIT(peer, group, peer_gr_new_status_flag);
bgp_peer_gr_flags_update(peer);
/* Apply BFD settings from group to peer if it exists. */
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 5077745a15..9e05a99474 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -881,7 +881,7 @@ commands:
.. code:: console
make topotests-build
- TOPOTEST_PULL=0 make topotests
+ make topotests
.. _topotests-guidelines:
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 23238d314a..c2ada459eb 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -231,7 +231,8 @@ static int process_p2p_hello(struct iih_info *iih)
return ISIS_OK;
}
}
- if (!adj || adj->level != iih->calculated_type) {
+ if (!adj || adj->level != iih->calculated_type ||
+ !(iih->circuit->is_type & iih->circ_type)) {
if (!adj) {
adj = isis_new_adj(iih->sys_id, NULL,
iih->calculated_type, iih->circuit);
diff --git a/tests/topotests/Dockerfile b/tests/topotests/Dockerfile
index 1503e67d31..d55827fe6c 100644
--- a/tests/topotests/Dockerfile
+++ b/tests/topotests/Dockerfile
@@ -1,60 +1,98 @@
-FROM ubuntu:18.04
+FROM ubuntu:22.04
-RUN export DEBIAN_FRONTEND=noninteractive \
- && apt-get update \
- && apt-get install -y \
- autoconf \
- binutils \
- bison \
- ca-certificates \
- flex \
+ARG DEBIAN_FRONTEND=noninteractive
+ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+
+RUN apt update -y && apt upgrade -y && \
+ # Basic build requirements from documentation
+ apt-get install -y \
+ autoconf \
+ automake \
+ bison \
+ build-essential \
+ flex \
+ git \
+ install-info \
+ libc-ares-dev \
+ libcap-dev \
+ libelf-dev \
+ libjson-c-dev \
+ libpam0g-dev \
+ libreadline-dev \
+ libsnmp-dev \
+ libsqlite3-dev \
+ lsb-release \
+ libtool \
+ lcov \
+ make \
+ perl \
+ pkg-config \
+ python3-dev \
+ python3-sphinx \
+ screen \
+ texinfo \
+ tmux \
+ && \
+ # Protobuf build requirements
+ apt-get install -y \
+ libprotobuf-c-dev \
+ protobuf-c-compiler \
+ && \
+ # Libyang2 extra build requirements
+ apt-get install -y \
+ cmake \
+ libpcre2-dev \
+ && \
+ # GRPC extra build requirements
+ apt-get install -y \
+ libgrpc-dev \
+ libgrpc++-dev \
+ protobuf-compiler-grpc \
+ && \
+ # Runtime/triage/testing requirements
+ apt-get install -y \
+ rsync \
+ curl \
gdb \
- git \
- gpg \
- install-info \
- iputils-ping \
+ kmod \
iproute2 \
- less \
- libtool \
- libjson-c-dev \
- libpcre3-dev \
- libpython-dev \
- libpython3-dev \
- libreadline-dev \
- libc-ares-dev \
- libcap-dev \
- libelf-dev \
- man \
- mininet \
- pkg-config \
- python-pip \
+ iputils-ping \
+ liblua5.3-dev \
+ libssl-dev \
+ lua5.3 \
+ net-tools \
python3 \
- python3-dev \
- python3-sphinx \
- python3-pytest \
- rsync \
+ python3-pip \
+ snmp \
+ snmp-mibs-downloader \
+ snmpd \
+ sudo \
+ time \
+ tshark \
+ valgrind \
+ yodl \
strace \
tcpdump \
- texinfo \
- tmux \
- valgrind \
- vim \
- wget \
- x11-xserver-utils \
- xterm \
- && pip install \
- exabgp==3.4.17 \
- "scapy>=2.4.2" \
- ipaddr \
- pytest \
- && rm -rf /var/lib/apt/lists/*
+ && \
+ download-mibs && \
+ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/iana/IANA-IPPM-METRICS-REGISTRY-MIB -O /usr/share/snmp/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB && \
+ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/SNMPv2-PDU -O /usr/share/snmp/mibs/ietf/SNMPv2-PDU && \
+ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/IPATM-IPMC-MIB -O /usr/share/snmp/mibs/ietf/IPATM-IPMC-MIB && \
+ python3 -m pip install wheel && \
+ python3 -m pip install 'protobuf<4' grpcio grpcio-tools && \
+ python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0' && \
+ python3 -m pip install 'scapy>=2.4.5' && \
+ python3 -m pip install xmltodict && \
+ python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311
+
+# Install FRR built packages
+RUN mkdir -p /etc/apt/keyrings && \
+ curl -s -o /etc/apt/keyrings/frrouting.gpg https://deb.frrouting.org/frr/keys.gpg && \
+ echo deb '[signed-by=/etc/apt/keyrings/frrouting.gpg]' https://deb.frrouting.org/frr \
+ $(lsb_release -s -c) "frr-stable" > /etc/apt/sources.list.d/frr.list && \
+ apt-get update && apt-get install -y librtr-dev libyang2-dev libyang2-tools
-RUN export DEBIAN_FRONTEND=noninteractive \
- && wget -qO- https://deb.frrouting.org/frr/keys.asc | apt-key add - \
- && echo "deb https://deb.frrouting.org/frr bionic frr-stable" > /etc/apt/sources.list.d/frr.list \
- && apt-get update \
- && apt-get install -y libyang-dev \
- && rm -rf /var/lib/apt/lists/*
+RUN apt install -y openvswitch-switch
RUN groupadd -r -g 92 frr \
&& groupadd -r -g 85 frrvty \
diff --git a/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
index 41bf96344a..14f90b859d 100644
--- a/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
+++ b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
@@ -1,6 +1,6 @@
!
router bgp 65001
- bgp max-med on-startup 5 777
+ bgp max-med on-startup 30 777
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
neighbor 192.168.255.2 timers 3 10
diff --git a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
index 545d7bd245..12ec88249a 100644
--- a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
+++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
@@ -82,12 +82,12 @@ def test_bgp_max_med_on_startup():
# Check session is established
test_func = functools.partial(_bgp_converge, router2)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1.0)
assert result is None, "Failed bgp convergence on r2"
# Check metric has value of max-med
test_func = functools.partial(_bgp_has_routes, router2, 777)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1.0)
assert result is None, "r2 does not receive routes with metric 777"
# Check that when the max-med timer expires, metric is updated
diff --git a/tests/topotests/bgp_peer_group/r1/bgpd.conf b/tests/topotests/bgp_peer_group/r1/bgpd.conf
deleted file mode 100644
index 68d8e61a59..0000000000
--- a/tests/topotests/bgp_peer_group/r1/bgpd.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-router bgp 65001
- neighbor PG peer-group
- neighbor PG remote-as external
- neighbor PG timers 3 10
- neighbor 192.168.255.3 peer-group PG
- neighbor r1-eth0 interface peer-group PG
- neighbor PG1 peer-group
- neighbor PG1 remote-as external
- neighbor PG1 timers 3 20
- neighbor 192.168.251.2 peer-group PG1
-!
diff --git a/tests/topotests/bgp_peer_group/r1/frr.conf b/tests/topotests/bgp_peer_group/r1/frr.conf
new file mode 100644
index 0000000000..035c8e4cf1
--- /dev/null
+++ b/tests/topotests/bgp_peer_group/r1/frr.conf
@@ -0,0 +1,21 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+interface r1-eth1
+ ip address 192.168.251.1/30
+!
+ip forwarding
+!
+router bgp 65001
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG timers 3 10
+ neighbor 192.168.255.3 peer-group PG
+ neighbor r1-eth0 interface peer-group PG
+ neighbor PG1 peer-group
+ neighbor PG1 remote-as external
+ neighbor PG1 timers 3 20
+ neighbor PG1 graceful-restart-disable
+ neighbor 192.168.251.2 peer-group PG1
+!
diff --git a/tests/topotests/bgp_peer_group/r1/zebra.conf b/tests/topotests/bgp_peer_group/r1/zebra.conf
deleted file mode 100644
index 16fd8c538c..0000000000
--- a/tests/topotests/bgp_peer_group/r1/zebra.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-!
-interface r1-eth0
- ip address 192.168.255.1/24
-!
-interface r1-eth1
- ip address 192.168.251.1/30
-!
-ip forwarding
-!
diff --git a/tests/topotests/bgp_peer_group/r2/bgpd.conf b/tests/topotests/bgp_peer_group/r2/bgpd.conf
deleted file mode 100644
index d0e8f017d1..0000000000
--- a/tests/topotests/bgp_peer_group/r2/bgpd.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-!
-router bgp 65002
- neighbor PG peer-group
- neighbor PG remote-as external
- neighbor PG timers 3 10
- neighbor r2-eth0 interface peer-group PG
- neighbor PG1 peer-group
- neighbor PG1 remote-as external
- neighbor PG1 timers 3 20
- neighbor 192.168.251.1 peer-group PG1
-!
diff --git a/tests/topotests/bgp_peer_group/r2/frr.conf b/tests/topotests/bgp_peer_group/r2/frr.conf
new file mode 100644
index 0000000000..4713789f15
--- /dev/null
+++ b/tests/topotests/bgp_peer_group/r2/frr.conf
@@ -0,0 +1,19 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+interface r2-eth1
+ ip address 192.168.251.2/30
+!
+ip forwarding
+!
+router bgp 65002
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG timers 3 10
+ neighbor r2-eth0 interface peer-group PG
+ neighbor PG1 peer-group
+ neighbor PG1 remote-as external
+ neighbor PG1 timers 3 20
+ neighbor 192.168.251.1 peer-group PG1
+!
diff --git a/tests/topotests/bgp_peer_group/r2/zebra.conf b/tests/topotests/bgp_peer_group/r2/zebra.conf
deleted file mode 100644
index c2ad956c9c..0000000000
--- a/tests/topotests/bgp_peer_group/r2/zebra.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-!
-interface r2-eth0
- ip address 192.168.255.2/24
-!
-interface r2-eth1
- ip address 192.168.251.2/30
-!
-ip forwarding
-!
diff --git a/tests/topotests/bgp_peer_group/r3/bgpd.conf b/tests/topotests/bgp_peer_group/r3/frr.conf
index 5a1340fb0b..e8bffaab51 100644
--- a/tests/topotests/bgp_peer_group/r3/bgpd.conf
+++ b/tests/topotests/bgp_peer_group/r3/frr.conf
@@ -1,4 +1,9 @@
!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
router bgp 65003
no bgp ebgp-requires-policy
neighbor PG peer-group
diff --git a/tests/topotests/bgp_peer_group/r3/zebra.conf b/tests/topotests/bgp_peer_group/r3/zebra.conf
deleted file mode 100644
index e9fdfb70c5..0000000000
--- a/tests/topotests/bgp_peer_group/r3/zebra.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-!
-interface r3-eth0
- ip address 192.168.255.3/24
-!
-ip forwarding
-!
diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py
index 7d476b0538..45f713b8a2 100644
--- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py
+++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py
@@ -2,12 +2,14 @@
# SPDX-License-Identifier: ISC
#
-# Copyright (c) 2021 by
+# Copyright (c) 2021-2024 by
# Donatas Abraitis <donatas.abraitis@gmail.com>
+# Donatas Abraitis <donatas@opensourcerouting.org>
#
"""
-Test if peer-group works for numbered and unnumbered configurations.
+Test if various random settings with peer-group works for
+numbered and unnumbered configurations.
"""
import os
@@ -21,7 +23,7 @@ sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
-from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topogen import Topogen, get_topogen
from lib.topolog import logger
pytestmark = [pytest.mark.bgpd]
@@ -48,12 +50,7 @@ def setup_module(mod):
router_list = tgen.routers()
for _, (rname, router) in enumerate(router_list.items(), 1):
- router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
- )
- router.load_config(
- TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
- )
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
tgen.start_router()
@@ -72,14 +69,26 @@ def test_bgp_peer_group():
def _bgp_peer_group_configured():
output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor json"))
expected = {
- "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"},
- "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"},
- "192.168.251.2": {"peerGroup": "PG1", "bgpState": "Established"},
+ "r1-eth0": {
+ "peerGroup": "PG",
+ "bgpState": "Established",
+ "neighborCapabilities": {"gracefulRestart": "advertisedAndReceived"},
+ },
+ "192.168.255.3": {
+ "peerGroup": "PG",
+ "bgpState": "Established",
+ "neighborCapabilities": {"gracefulRestart": "advertisedAndReceived"},
+ },
+ "192.168.251.2": {
+ "peerGroup": "PG1",
+ "bgpState": "Established",
+ "neighborCapabilities": {"gracefulRestart": "received"},
+ },
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_peer_group_configured)
- _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed bgp convergence in r1"
def _bgp_peer_group_check_advertised_routes():
@@ -97,7 +106,7 @@ def test_bgp_peer_group():
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_peer_group_check_advertised_routes)
- _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed checking advertised routes from r3"
@@ -122,7 +131,7 @@ def test_bgp_peer_group_remote_as_del_readd():
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_peer_group_remoteas_del)
- _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed bgp convergence in r1"
logger.info("Re-add bgp peer-group PG1 remote-as neighbor should be established")
@@ -139,7 +148,7 @@ def test_bgp_peer_group_remote_as_del_readd():
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_peer_group_remoteas_add)
- _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed bgp convergence in r1"
diff --git a/tests/topotests/docker/README.md b/tests/topotests/docker/README.md
index 2b40994cf6..2bd58a15b8 100644
--- a/tests/topotests/docker/README.md
+++ b/tests/topotests/docker/README.md
@@ -68,5 +68,5 @@ without pulling from the registry using the following commands:
```console
make topotests-build
-TOPOTEST_PULL=0 make topotests
+make topotests
```
diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh
index ce373d9bd0..bd37055147 100755
--- a/tests/topotests/docker/frr-topotests.sh
+++ b/tests/topotests/docker/frr-topotests.sh
@@ -45,9 +45,6 @@ if [[ "$1" = "-h" ]] || [[ "$1" = "--help" ]]; then
TOPOTEST_OPTIONS These options are appended to the docker-run
command for starting the tests.
- TOPOTEST_PULL If set to 0, don't try to pull the most recent
- version of the docker image from dockerhub.
-
TOPOTEST_SANITIZER Controls whether to use the address sanitizer.
Enabled by default, set to 0 to disable.
@@ -122,10 +119,6 @@ if [ -z "$TOPOTEST_BUILDCACHE" ]; then
|| docker volume create "${TOPOTEST_BUILDCACHE}"
fi
-if [ "${TOPOTEST_PULL:-1}" = "1" ]; then
- docker pull frrouting/topotests:latest
-fi
-
if [[ -n "$TMUX" ]]; then
TMUX_OPTIONS="-v $(dirname $TMUX):$(dirname $TMUX) -e TMUX=$TMUX -e TMUX_PANE=$TMUX_PANE"
fi
diff --git a/tests/topotests/docker/inner/compile_frr.sh b/tests/topotests/docker/inner/compile_frr.sh
index 4a88dc677f..e943c385c7 100755
--- a/tests/topotests/docker/inner/compile_frr.sh
+++ b/tests/topotests/docker/inner/compile_frr.sh
@@ -58,9 +58,6 @@ if [ ! -e Makefile ]; then
fi
bash configure >&3 \
- --enable-static-bin \
- --enable-static \
- --enable-shared \
--enable-dev-build \
--with-moduledir=/usr/lib/frr/modules \
--prefix=/usr \
@@ -69,6 +66,8 @@ if [ ! -e Makefile ]; then
--sbindir=/usr/lib/frr \
--enable-multipath=0 \
--enable-fpm \
+ --enable-grpc \
+ --enable-scripting \
--enable-sharpd \
$EXTRA_CONFIGURE \
--with-pkg-extra-version=-topotests \
diff --git a/tests/topotests/docker/inner/entrypoint.sh b/tests/topotests/docker/inner/entrypoint.sh
index 44e16db4b9..b92217440b 100755
--- a/tests/topotests/docker/inner/entrypoint.sh
+++ b/tests/topotests/docker/inner/entrypoint.sh
@@ -20,6 +20,11 @@ cd "${FRR_BUILD_DIR}/tests/topotests"
log_info "Setting permissions on /tmp so we can generate logs"
chmod 1777 /tmp
+# This is a MUST, otherwise we have:
+# AddressSanitizer:DEADLYSIGNAL
+# Segmentation fault
+sysctl -w vm.mmap_rnd_bits=28
+
if [ $# -eq 0 ] || ([[ "$1" != /* ]] && [[ "$1" != ./* ]]); then
export TOPOTESTS_CHECK_MEMLEAK=/tmp/memleak_
export TOPOTESTS_CHECK_STDERR=Yes
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index fe3d865565..e02fb07daf 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -12,6 +12,7 @@
"""
test_isis_topo1.py: Test ISIS topology.
"""
+import time
import datetime
import functools
import json
@@ -314,6 +315,107 @@ def test_isis_neighbor_json():
), assertmsg
+def test_isis_neighbor_state():
+ "Check that the neighbor states remain normal when the ISIS type is switched."
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking 'show isis neighbor state on a p2p link'")
+
+ # Establish a P2P link
+ # When the IS-IS type of r3 is set to level-1-2 and the IS-IS type of r5 is set to level-1,
+ # it is expected that all neighbors exist and are in the Up state
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no redistribute ipv4 connected level-1
+ no redistribute ipv4 connected level-2
+ no redistribute ipv6 connected level-1
+ no redistribute ipv6 connected level-2
+ interface r3-eth1
+ no isis circuit-type
+ isis network point-to-point
+ end
+ """
+ )
+ r5 = tgen.gears["r5"]
+ r5.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no redistribute ipv4 connected level-1
+ no redistribute ipv6 connected level-1
+ no redistribute ipv4 table 20 level-1
+ interface r5-eth0
+ no isis circuit-type
+ isis network point-to-point
+ end
+ """
+ )
+ result = _check_isis_neighbor_json("r3", "r5", True, "Up")
+ assert result is True, result
+ result = _check_isis_neighbor_json("r5", "r3", True, "Up")
+ assert result is True, result
+
+ # Remove the configuration that affects the switch of IS-IS type.
+ # Configure the IS-IS type of r3 to transition from level-1-2 to level-2-only,
+ # while maintaining the IS-IS type of r5 as level-1.
+ # In this scenario,
+ # the expectation is that some neighbors do not exist or are in the Initializing state
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ is-type level-2-only
+ end
+ """
+ )
+ result = _check_isis_neighbor_json("r3", "r5", False, "Initializing")
+ assert result is True, result
+ result = _check_isis_neighbor_json("r5", "r3", False, "Initializing")
+ assert result is True, result
+
+ # Restore to initial configuration
+ logger.info("Checking 'restore to initial configuration'")
+ r3.vtysh_cmd(
+ """
+ configure
+ interface r3-eth1
+ isis circuit-type level-1
+ no isis network point-to-point
+ router isis 1
+ no is-type
+ redistribute ipv4 connected level-1
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-1
+ redistribute ipv6 connected level-2
+ end
+ """
+ )
+ r5.vtysh_cmd(
+ """
+ configure
+ interface r5-eth0
+ isis circuit-type level-1
+ no isis network point-to-point
+ router isis 1
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ redistribute ipv4 table 20 level-1
+ end
+ """
+ )
+ result = _check_isis_neighbor_json("r3", "r5", True, "Up")
+ assert result is True, result
+ result = _check_isis_neighbor_json("r5", "r3", True, "Up")
+ assert result is True, result
+
+
def test_isis_database_json():
"Check json struct in show isis database json"
@@ -623,6 +725,65 @@ def test_isis_hello_padding_during_adjacency_formation():
assert result is True, result
+def _check_isis_neighbor_json(
+ self, neighbor, neighbor_expected, neighbor_state_expected
+):
+ tgen = get_topogen()
+ router = tgen.gears[self]
+ logger.info(
+ f"check_isis_neighbor_json {router} {neighbor} {neighbor_expected} {neighbor_state_expected}"
+ )
+
+ result = _check_isis_neighbor_exist(self, neighbor)
+ if result == True:
+ return _check_isis_neighbor_state(self, neighbor, neighbor_state_expected)
+ elif neighbor_expected == True:
+ return "{} with expected neighbor {} got none ".format(router.name, neighbor)
+ else:
+ return True
+
+
+@retry(retry_timeout=60)
+def _check_isis_neighbor_exist(self, neighbor):
+ tgen = get_topogen()
+ router = tgen.gears[self]
+ logger.info(f"check_isis_neighbor_exist {router} {neighbor}")
+ neighbor_json = router.vtysh_cmd("show isis neighbor json", isjson=True)
+
+ circuits = neighbor_json.get("areas", [])[0].get("circuits", [])
+ for circuit in circuits:
+ if "adj" in circuit and circuit["adj"] == neighbor:
+ return True
+
+ return "The neighbor {} of router {} has not been learned yet ".format(
+ neighbor, router.name
+ )
+
+
+@retry(retry_timeout=5)
+def _check_isis_neighbor_state(self, neighbor, neighbor_state_expected):
+ tgen = get_topogen()
+ router = tgen.gears[self]
+ logger.info(
+ f"check_isis_neighbor_state {router} {neighbor} {neighbor_state_expected}"
+ )
+ neighbor_json = router.vtysh_cmd(
+ "show isis neighbor {} json".format(neighbor), isjson=True
+ )
+
+ circuits = neighbor_json.get("areas", [])[0].get("circuits", [])
+ for circuit in circuits:
+ interface = circuit.get("interface", {})
+ if "state" in interface:
+ neighbor_state = interface["state"]
+ if neighbor_state == neighbor_state_expected:
+ return True
+
+ return "{} peer with expected neighbor_state {} got {} ".format(
+ router.name, neighbor_state_expected, neighbor_state
+ )
+
+
@retry(retry_timeout=10)
def check_last_iih_packet_for_padding(router, expect_padding):
logfilename = "{}/{}".format(router.gearlogdir, "isisd.log")
diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py
index 89a34ff9b5..9e00fcf11f 100644
--- a/tests/topotests/ospfapi/test_ospf_clientapi.py
+++ b/tests/topotests/ospfapi/test_ospf_clientapi.py
@@ -218,10 +218,12 @@ def _test_router_id(tgen, testbin):
step("router id: check for modified router id")
r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.1.1.1")
+ r1.vtysh_multicmd("clear ip ospf process")
_wait_output(p, "SUCCESS: {}".format(waitlist[1]))
step("router id: check for restored router id")
r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.0.0.0")
+ r1.vtysh_multicmd("clear ip ospf process")
_wait_output(p, "SUCCESS: {}".format(waitlist[2]))
except Exception as error:
logging.error("ERROR: %s", error)
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index e6b4af3674..3ec1c9d657 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -68,6 +68,8 @@
static const char *prov_name = "dplane_fpm_nl";
+static atomic_bool fpm_cleaning_up;
+
struct fpm_nl_ctx {
/* data plane connection. */
int socket;
@@ -524,6 +526,16 @@ static void fpm_connect(struct event *t);
static void fpm_reconnect(struct fpm_nl_ctx *fnc)
{
+ bool cleaning_p = false;
+
+ /* This is being called in the FPM pthread: ensure we don't deadlock
+ * with similar code that may be run in the main pthread.
+ */
+ if (!atomic_compare_exchange_strong_explicit(
+ &fpm_cleaning_up, &cleaning_p, true, memory_order_seq_cst,
+ memory_order_seq_cst))
+ return;
+
/* Cancel all zebra threads first. */
event_cancel_async(zrouter.master, &fnc->t_lspreset, NULL);
event_cancel_async(zrouter.master, &fnc->t_lspwalk, NULL);
@@ -551,6 +563,12 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc)
EVENT_OFF(fnc->t_read);
EVENT_OFF(fnc->t_write);
+ /* Reset the barrier value */
+ cleaning_p = true;
+ atomic_compare_exchange_strong_explicit(
+ &fpm_cleaning_up, &cleaning_p, false, memory_order_seq_cst,
+ memory_order_seq_cst);
+
/* FPM is disabled, don't attempt to connect. */
if (fnc->disabled)
return;
@@ -1624,6 +1642,16 @@ static int fpm_nl_start(struct zebra_dplane_provider *prov)
static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
{
+ bool cleaning_p = false;
+
+ /* This is being called in the main pthread: ensure we don't deadlock
+ * with similar code that may be run in the FPM pthread.
+ */
+ if (!atomic_compare_exchange_strong_explicit(
+ &fpm_cleaning_up, &cleaning_p, true, memory_order_seq_cst,
+ memory_order_seq_cst))
+ return 0;
+
/* Disable all events and close socket. */
EVENT_OFF(fnc->t_lspreset);
EVENT_OFF(fnc->t_lspwalk);
@@ -1644,6 +1672,12 @@ static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
fnc->socket = -1;
}
+ /* Reset the barrier value */
+ cleaning_p = true;
+ atomic_compare_exchange_strong_explicit(
+ &fpm_cleaning_up, &cleaning_p, false, memory_order_seq_cst,
+ memory_order_seq_cst);
+
return 0;
}