diff options
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; } |
