diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 3096f47d5c2b..5215dca7f33f 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -292,6 +292,18 @@ 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 +899,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 +917,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.