From 95b007447d84f4f0a93a9145c773d7707d487682 Mon Sep 17 00:00:00 2001 From: Lokesh Dhoundiyal Date: Tue, 21 Nov 2023 14:41:29 +1300 Subject: [PATCH] bfdd: Add bfd session params to dest register msg Allow protocols to generate bfd session id and set the bfd session enable status for bfd sessions via the ZEBRA_BFD_DEST_REGISTER message. This is useful in case of "Stacking" when the Active(session enabled) and Standby(session disabled) switches run the same BFD session and if the Active fails and the Standby becomes Active but the session remains UP without affecting the routing protocols with the DOWN event. Signed-off-by: Lokesh Dhoundiyal --- bfdd/bfd.c | 21 ++++++++++++++++++++- bfdd/bfd.h | 4 ++++ bfdd/bfdctl.h | 4 ++++ bfdd/ptm_adapter.c | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 3096f47d5c2b..0efa58a6c407 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -292,6 +292,19 @@ int bfd_session_enable(struct bfd_session *bs) if (bs->bdc) return 0; + /* Wait for the session to be enabled. We keep the session in INIT state + * to avoid triggering a DOWN event on the remote end if the session + * was UP earlier. This is particularly useful in case of "Stacking" when + * the Active(session enabled) and Standby(session disabled) switches run + * the same BFD session and if the Active fails and the Standby becomes + * Active but the session remains UP without affecting the routing protocols + * with the DOWN event. + */ + if (bs->ses_disable) { + bs->ses_state = PTM_BFD_INIT; + return 0; + } + /* * If the interface or VRF doesn't exist, then we must register * the session but delay its start. @@ -887,6 +900,11 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) bfd->key.mhop = bpc->bpc_mhop; + /* Get the protocol instructions to disable the bfd session */ + bfd->ses_disable = bpc->bpc_session_disable; + + /* Get the session id(my discriminator) from the protocol */ + bfd->session_id = bpc->bpc_session_id; if (bs_registrate(bfd) == NULL) return NULL; @@ -900,7 +918,8 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd) { /* Registrate session into data structures. */ bfd_key_insert(bfd); - bfd->discrs.my_discr = ptm_bfd_gen_ID(); + /* If the session id is generated by the protocol then use it, otherwise generate one */ + bfd->discrs.my_discr = bfd->session_id ? bfd->session_id : ptm_bfd_gen_ID(); bfd_id_insert(bfd); /* Try to enable session and schedule for packet receive/send. */ diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 6c5a1e921618..fa65a15a401e 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -258,6 +258,10 @@ struct bfd_config_timers { */ struct bfd_session { + /* protocol parameters */ + bool ses_disable; + uint32_t session_id; + /* protocol state per RFC 5880*/ uint8_t ses_state; struct bfd_discrs discrs; diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index f1f8185c3bbf..e92771fd281b 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -88,6 +88,10 @@ struct bfd_peer_cfg { bool bpc_has_profile; char bpc_profile[64]; + /* protocol parameters */ + uint32_t bpc_session_id; + bool bpc_session_disable; + /* Status information */ enum bfd_peer_status bpc_bps; uint32_t bpc_id; diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index e6c2fb71f0cf..55f5c0e74760 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -352,6 +352,32 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, * - c: profile name length. * - X bytes: profile name. * + * New format (with session id and status): + * - header: Command, VRF + * - l: pid + * - w: family + * - AF_INET: + * - l: destination IPv4 address + * - AF_INET6: + * - 16 bytes: destination IPv6 address + * - l: min_rx + * - l: min_tx + * - c: detect multiplier + * - c: is_multihop? + * - w: family + * - AF_INET: + * - l: source IPv4 address + * - AF_INET6: + * - 16 bytes: source IPv6 address + * - c: ttl + * - c: ifname length + * - X bytes: interface name + * - c: bfd_cbit + * - c: profile name length. + * - X bytes: profile name. + * - l: session id + * - c: session disabled? + * * q(64), l(32), w(16), c(8) */ @@ -443,6 +469,12 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, bpc->bpc_profile[ifnamelen] = 0; } + /* Get the session id */ + STREAM_GETL(msg, bpc->bpc_session_id); + + /* Get the session disable state. */ + STREAM_GETC(msg, bpc->bpc_session_disable); + /* Sanity check: peer and local address must match IP types. */ if (bpc->bpc_local.sa_sin.sin_family != AF_UNSPEC && (bpc->bpc_local.sa_sin.sin_family @@ -480,6 +512,11 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) return; } } else { + /* Existing BFD session has been enabled */ + if (!bpc.bpc_session_disable && bpc.bpc_session_disable != bs->ses_disable) { + bs->ses_disable = bpc.bpc_session_disable; + bfd_session_enable(bs); + } /* * BFD session was already created, we are just updating the * current peer.