From cb135cc94303d2581987645f124bd6d4cecd80a6 Mon Sep 17 00:00:00 2001 From: Karen Schoener Date: Tue, 8 Dec 2020 09:44:27 -0500 Subject: [PATCH] isisd, ospfd: IGPs detect LDP down via zapi client close message When ldp-sync is configured, IGPs take action if the LDP process goes down. Currently, IGPs detect the LDP process is down if they do not receive a periodic 'hello' message from LDP within 1 second. Intermittently, this heartbeat mechanism causes false topotest failures. When the failure occurs, LDP is busy receiving messages from zebra for a few seconds. During this time, LDP does not send the expected periodic message. With this change, IGPs detect LDP down via zapi client close message. Signed-off-by: Karen Schoener --- isisd/isis_ldp_sync.c | 40 +++++++++++++++++++++++++++++++++++++++- isisd/isis_ldp_sync.h | 4 ++++ isisd/isis_zebra.c | 16 ++++++++++++++++ ospfd/ospf_ldp_sync.c | 29 ++++++++++++++++++++++++++++- ospfd/ospf_ldp_sync.h | 2 ++ ospfd/ospf_zebra.c | 16 ++++++++++++++++ 6 files changed, 105 insertions(+), 2 deletions(-) diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 3b1faffe53..c9d29871ae 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -293,7 +293,7 @@ void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit) ldp_sync_info = circuit->ldp_sync_info; - /* LDP failed to send hello: + /* LDP client close detected: * stop holddown timer * set cost of interface to LSInfinity so traffic will use different * interface until LDP restarts and has learned all labels from peer @@ -521,6 +521,44 @@ void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit) &ldp_sync_info->t_holddown); } +/* + * LDP-SYNC handle client close routine + */ +void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info) +{ + struct isis_area *area; + struct listnode *node; + struct isis_circuit *circuit; + struct interface *ifp; + struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + /* if isis is not enabled or LDP-SYNC is not configured ignore */ + if (!isis + || !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) + return; + + /* Check if the LDP main client session closed */ + if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0) + return; + + /* Handle the zebra notification that the LDP client session closed. + * set cost to LSInfinity + * send request to LDP for LDP-SYNC state for each interface + */ + zlog_err("ldp_sync: LDP down"); + + FOR_ALL_INTERFACES (vrf, ifp) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + circuit = + circuit_lookup_by_ifp(ifp, area->circuit_list); + if (circuit == NULL) + continue; + isis_ldp_sync_if_start(circuit, true); + } + } +} + /* * LDP-SYNC hello timer routines */ diff --git a/isisd/isis_ldp_sync.h b/isisd/isis_ldp_sync.h index 61ac946078..1b6058c5c9 100644 --- a/isisd/isis_ldp_sync.h +++ b/isisd/isis_ldp_sync.h @@ -20,6 +20,8 @@ #ifndef _ZEBRA_ISIS_LDP_SYNC_H #define _ZEBRA_ISIS_LDP_SYNC_H +#include "zclient.h" + /* Macro to log debug message */ #define ils_debug(...) \ do { \ @@ -36,6 +38,8 @@ extern void isis_ldp_sync_if_start(struct isis_circuit *circuit, extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove); extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit); extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit); +extern void +isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info); extern void isis_ldp_sync_hello_timer_add(void); extern void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit); extern int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 1b4b0c8f2f..d51a4db939 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -699,6 +699,20 @@ stream_failure: return ret; } +static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS) +{ + int ret = 0; + + struct zapi_client_close_info info; + + if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0) + return -1; + + isis_ldp_sync_handle_client_close(&info); + + return ret; +} + void isis_zebra_init(struct thread_master *master, int instance) { /* Initialize asynchronous zclient. */ @@ -727,6 +741,8 @@ void isis_zebra_init(struct thread_master *master, int instance) zclient_sync->privs = &isisd_privs; zclient->opaque_msg_handler = isis_opaque_msg_handler; + + zclient->zebra_client_close_notify = isis_zebra_client_close_notify; } void isis_zebra_stop(void) diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 68792ebcc2..bca15304b1 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -253,6 +253,33 @@ void ospf_ldp_sync_if_complete(struct interface *ifp) } } +void ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info) +{ + struct ospf *ospf; + struct vrf *vrf; + struct interface *ifp; + + /* if ospf is not enabled or LDP-SYNC is not configured ignore */ + ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + if (ospf == NULL + || !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) + return; + + /* Check if the LDP main client session closed */ + if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0) + return; + + /* Handle the zebra notification that the LDP client session closed. + * set cost to LSInfinity + * send request to LDP for LDP-SYNC state for each interface + */ + zlog_err("ldp_sync: LDP down"); + + vrf = vrf_lookup_by_id(ospf->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) + ospf_ldp_sync_if_start(ifp, true); +} + void ospf_ldp_sync_ldp_fail(struct interface *ifp) { struct ospf_if_params *params; @@ -264,7 +291,7 @@ void ospf_ldp_sync_ldp_fail(struct interface *ifp) params = IF_DEF_PARAMS(ifp); ldp_sync_info = params->ldp_sync_info; - /* LDP failed to send hello: + /* LDP client close detected: * stop holddown timer * set cost of interface to LSInfinity so traffic will use different * interface until LDP has learned all labels from peer diff --git a/ospfd/ospf_ldp_sync.h b/ospfd/ospf_ldp_sync.h index d4efa55311..418ca4e5b6 100644 --- a/ospfd/ospf_ldp_sync.h +++ b/ospfd/ospf_ldp_sync.h @@ -50,6 +50,8 @@ extern void ospf_ldp_sync_if_write_config(struct vty *vty, extern int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state); extern int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce); extern int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello); +extern void +ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info); extern void ospf_ldp_sync_state_req_msg(struct interface *ifp); extern void ospf_ldp_sync_init(void); extern void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index e7dbdbd9af..93d4ee0ec7 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1986,6 +1986,20 @@ stream_failure: return ret; } +static int ospf_zebra_client_close_notify(ZAPI_CALLBACK_ARGS) +{ + int ret = 0; + + struct zapi_client_close_info info; + + if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0) + return -1; + + ospf_ldp_sync_handle_client_close(&info); + + return ret; +} + void ospf_zebra_init(struct thread_master *master, unsigned short instance) { /* Allocate zebra structure. */ @@ -2021,6 +2035,8 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance) prefix_list_delete_hook(ospf_prefix_list_update); zclient->opaque_msg_handler = ospf_opaque_msg_handler; + + zclient->zebra_client_close_notify = ospf_zebra_client_close_notify; } void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p) -- 2.39.5