From 7555dc6116a4fc51631b2c26ecb5b63a5c574674 Mon Sep 17 00:00:00 2001 From: SumitAgarwal123 Date: Sun, 20 Oct 2019 22:53:01 -0700 Subject: [PATCH] bfdd: Handling local and remote admin-down Scenarios where this code change is required: 1. BFD is un-configured from BGP at remote end. Neighbour BFD sends ADMIN_DOWN state, but BFD on local side will send DOWN to BGP, resulting in BGP session DOWN. Removing BFD session administratively shouldn't bring DOWN BGP session at local or remote. 2. BFD is un-configured from BGP or shutdown locally. BFD will send state DOWN to BGP resulting in BGP session DOWN. (This is akin to saying do not use BFD for BGP) Removing BFD session administratively shouldn't bring DOWN BGP session at local or remote. Signed-off-by: Sayed Mohd Saquib sayed.saquib@broadcom.com --- bfdd/bfd.c | 46 ++++++++++++++++++++++++++++++++++++++---- bfdd/bfd.h | 4 ++-- bfdd/bfdd_northbound.c | 4 ++-- bfdd/control.c | 4 ++-- bfdd/ptm_adapter.c | 13 +++++++++--- bgpd/bgp_bfd.c | 3 ++- isisd/isis_bfd.c | 3 ++- lib/bfd.c | 2 ++ lib/bfd.h | 14 ++++++++++--- ospf6d/ospf6_bfd.c | 2 +- ospfd/ospf_bfd.c | 2 +- pimd/pim_bfd.c | 2 +- 12 files changed, 78 insertions(+), 21 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index feb9827ce1..50c46fbd3d 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -49,6 +49,8 @@ static void bs_admin_down_handler(struct bfd_session *bs, int nstate); static void bs_down_handler(struct bfd_session *bs, int nstate); static void bs_init_handler(struct bfd_session *bs, int nstate); static void bs_up_handler(struct bfd_session *bs, int nstate); +static void bs_neighbour_admin_down_handler(struct bfd_session *bfd, + uint8_t diag); /* Zeroed array with the size of an IPv6 address. */ struct in6_addr zero_addr; @@ -307,7 +309,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) /* Start sending control packets with poll bit immediately. */ ptm_bfd_snd(bfd, 0); - control_notify(bfd); + control_notify(bfd, bfd->ses_state); if (old_state != bfd->ses_state) { bfd->stats.session_up++; @@ -335,7 +337,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) - control_notify(bfd); + control_notify(bfd, PTM_BFD_DOWN); /* Stop echo packet transmission if they are active */ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) @@ -570,7 +572,7 @@ skip_echo: /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs); + control_notify(bs, bs->ses_state); /* Don't try to send packets with a disabled session. */ if (bs->sock != -1) @@ -584,7 +586,7 @@ skip_echo: /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs); + control_notify(bs, bs->ses_state); /* Enable all timers. */ bfd_recvtimer_update(bs); @@ -856,10 +858,46 @@ static void bs_init_handler(struct bfd_session *bs, int nstate) } } +static void bs_neighbour_admin_down_handler(struct bfd_session *bfd, + uint8_t diag) +{ + int old_state = bfd->ses_state; + + bfd->local_diag = diag; + bfd->discrs.remote_discr = 0; + bfd->ses_state = PTM_BFD_DOWN; + bfd->polling = 0; + bfd->demand_mode = 0; + monotime(&bfd->downtime); + + /* Slow down the control packets, the connection is down. */ + bs_set_slow_timers(bfd); + + /* only signal clients when going from up->down state */ + if (old_state == PTM_BFD_UP) + control_notify(bfd, PTM_BFD_ADM_DOWN); + + /* Stop echo packet transmission if they are active */ + if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) + ptm_bfd_echo_stop(bfd); + + if (old_state != bfd->ses_state) { + bfd->stats.session_down++; + + log_info("state-change: [%s] %s -> %s reason:%s", + bs_to_string(bfd), state_list[old_state].str, + state_list[bfd->ses_state].str, + get_diag_str(bfd->local_diag)); + } +} + static void bs_up_handler(struct bfd_session *bs, int nstate) { switch (nstate) { case PTM_BFD_ADM_DOWN: + bs_neighbour_admin_down_handler(bs, BD_ADMIN_DOWN); + break; + case PTM_BFD_DOWN: /* Peer lost or asked to shutdown connection. */ ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN); diff --git a/bfdd/bfd.h b/bfdd/bfd.h index cdec78d122..89f97d2e30 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -369,7 +369,7 @@ TAILQ_HEAD(bcslist, bfd_control_socket); int control_init(const char *path); void control_shutdown(void); -int control_notify(struct bfd_session *bs); +int control_notify(struct bfd_session *bs, uint8_t notify_state); int control_notify_config(const char *op, struct bfd_session *bs); int control_accept(struct thread *t); @@ -632,7 +632,7 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf); void bfdd_sessions_disable_vrf(struct vrf *vrf); void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf); -int ptm_bfd_notify(struct bfd_session *bs); +int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state); /* diff --git a/bfdd/bfdd_northbound.c b/bfdd/bfdd_northbound.c index 7cd2fb6b9a..b8a7e95553 100644 --- a/bfdd/bfdd_northbound.c +++ b/bfdd/bfdd_northbound.c @@ -405,7 +405,7 @@ static int bfdd_bfd_sessions_single_hop_administrative_down_modify( /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs); + control_notify(bs, bs->ses_state); /* Enable all timers. */ bfd_recvtimer_update(bs); @@ -428,7 +428,7 @@ static int bfdd_bfd_sessions_single_hop_administrative_down_modify( /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs); + control_notify(bs, bs->ses_state); ptm_bfd_snd(bs, 0); } diff --git a/bfdd/control.c b/bfdd/control.c index c308d647d8..5c5421c041 100644 --- a/bfdd/control.c +++ b/bfdd/control.c @@ -774,13 +774,13 @@ static void _control_notify(struct bfd_control_socket *bcs, control_queue_enqueue(bcs, bcm); } -int control_notify(struct bfd_session *bs) +int control_notify(struct bfd_session *bs, uint8_t notify_state) { struct bfd_control_socket *bcs; struct bfd_notify_peer *bnp; /* Notify zebra listeners as well. */ - ptm_bfd_notify(bs); + ptm_bfd_notify(bs, notify_state); /* * PERFORMANCE: reuse the bfd_control_msg allocated data for diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index ae6d04e77d..2677eb31f2 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -153,7 +153,7 @@ static int _ptm_msg_address(struct stream *msg, int family, const void *addr) return 0; } -int ptm_bfd_notify(struct bfd_session *bs) +int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state) { struct stream *msg; @@ -204,12 +204,15 @@ int ptm_bfd_notify(struct bfd_session *bs) _ptm_msg_address(msg, bs->key.family, &bs->key.peer); /* BFD status */ - switch (bs->ses_state) { + switch (notify_state) { case PTM_BFD_UP: stream_putl(msg, BFD_STATUS_UP); break; case PTM_BFD_ADM_DOWN: + stream_putl(msg, BFD_STATUS_ADMIN_DOWN); + break; + case PTM_BFD_DOWN: case PTM_BFD_INIT: stream_putl(msg, BFD_STATUS_DOWN); @@ -432,7 +435,7 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) return; } - ptm_bfd_notify(bs); + ptm_bfd_notify(bs, bs->ses_state); } static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) @@ -461,6 +464,10 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) if (bs->refcount || BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) return; + + bs->ses_state = PTM_BFD_ADM_DOWN; + ptm_bfd_snd(bs, 0); + ptm_bfd_sess_del(&bpc); } diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 57fef8e913..0ed6057eac 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -282,7 +282,8 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status, return; old_status = bfd_info->status; - bfd_info->status = status; + BFD_SET_CLIENT_STATUS(bfd_info->status, status); + bfd_info->last_update = bgp_clock(); if (status != old_status) { diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index 8fc7997d79..cf4b841798 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -118,7 +118,8 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, int old_status = adj->bfd_session->status; - adj->bfd_session->status = new_status; + BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status); + if (old_status == new_status) return; diff --git a/lib/bfd.c b/lib/bfd.c index 00dbd1b3d1..ffb3cbc1f8 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -315,6 +315,8 @@ const char *bfd_get_status_str(int status) return "Down"; case BFD_STATUS_UP: return "Up"; + case BFD_STATUS_ADMIN_DOWN: + return "Admin Down"; case BFD_STATUS_UNKNOWN: default: return "Unknown"; diff --git a/lib/bfd.h b/lib/bfd.h index e4781f4eaf..7f5d111504 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -51,9 +51,17 @@ struct bfd_gbl { #define BFD_FLAG_BFD_CBIT_ON (1 << 3) /* Peer registered with CBIT set to on */ #define BFD_FLAG_BFD_CHECK_CONTROLPLANE (1 << 4) /* BFD and controlplane daemon are linked */ -#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */ -#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */ -#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */ +#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */ +#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */ +#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */ +#define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */ + +#define BFD_SET_CLIENT_STATUS(current_status, new_status) \ + do { \ + (current_status) = \ + (((new_status) == BFD_STATUS_ADMIN_DOWN) ? \ + BFD_STATUS_DOWN : (new_status));\ + } while (0) enum bfd_sess_type { BFD_TYPE_NOT_CONFIGURED, diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index f0500601b0..4e7a0050aa 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -236,7 +236,7 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) continue; old_status = bfd_info->status; - bfd_info->status = status; + BFD_SET_CLIENT_STATUS(bfd_info->status, status); monotime(&tv); bfd_info->last_update = tv.tv_sec; diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index a17975270a..73802ce13e 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -240,7 +240,7 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) continue; old_status = bfd_info->status; - bfd_info->status = status; + BFD_SET_CLIENT_STATUS(bfd_info->status, status); monotime(&tv); bfd_info->last_update = tv.tv_sec; diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 87d0f9fa22..01a7980858 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -270,7 +270,7 @@ static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) continue; } old_status = bfd_info->status; - bfd_info->status = status; + BFD_SET_CLIENT_STATUS(bfd_info->status, status); monotime(&tv); bfd_info->last_update = tv.tv_sec; -- 2.39.5