From 9beff0bda93a1ab398647cfda6e5efc06222a46c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 15 Apr 2019 17:20:25 +0200 Subject: [PATCH] bfdd, lib, bgpd: add bfd cbit usage bfd cbit is a value carried out in bfd messages, that permit to keep or not, the independence between control plane and dataplane. In other words, while most of the cases plan to flush entries, when bfd goes down, there are some cases where that bfd event should be ignored. this is the case with non stop forwarding mechanisms where entries may be kept. this is the case for BGP, when graceful restart capability is used. If BFD event down happens, and bgp is in graceful restart mode, it is wished to ignore the BFD event while waiting for the remote router to restart. The changes take into account the following: - add a config flag across zebra layer so that daemon can set or not the cbit capability. - ability for daemons to read the remote bfd capability associated to a bfd notification. - in bfdd, according to the value, the cbit value is set - in bfdd, the received value is retrived and stored in the bfd session context. - by default, the local cbit announced to remote is set to 1 while preservation of the local path is not set. Signed-off-by: Philippe Guibert --- bfdd/bfd.c | 11 +++++++++++ bfdd/bfd.h | 8 ++++++++ bfdd/bfd_packet.c | 9 +++++++++ bfdd/bfdctl.h | 2 ++ bfdd/ptm_adapter.c | 13 +++++++++++-- bgpd/bgp_bfd.c | 44 +++++++++++++++++++++++++++++++++----------- isisd/isis_bfd.c | 5 ++++- lib/bfd.c | 14 ++++++++++++-- lib/bfd.h | 6 ++++-- ospf6d/ospf6_bfd.c | 10 +++++++--- ospfd/ospf_bfd.c | 8 ++++++-- pimd/pim_bfd.c | 10 ++++++++-- zebra/zebra_ptm.c | 6 ++++++ 13 files changed, 121 insertions(+), 25 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index a2e84e928d..d4e2834835 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -600,6 +600,17 @@ skip_echo: bfd_recvtimer_update(bs); bfd_xmttimer_update(bs, bs->xmt_TO); } + if (bpc->bpc_cbit) { + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT)) + return; + + BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); + } else { + if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT)) + return; + + BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); + } } static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 3f3d603832..213e905bf0 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -129,6 +129,12 @@ struct bfd_echo_pkt { flags |= (val & 0x3) << 6; \ } #define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) +#define BFD_SETCBIT(flags, val) \ + { \ + if ((val)) \ + flags |= val; \ + } +#define BFD_GETCBIT(flags) (flags & BFD_FBIT) #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) @@ -168,6 +174,7 @@ enum bfd_session_flags { */ BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */ BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */ + BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */ }; #define BFD_SET_FLAG(field, flag) (field |= flag) @@ -210,6 +217,7 @@ struct bfd_session { uint8_t detect_mult; uint8_t remote_detect_mult; uint8_t mh_ttl; + uint8_t remote_cbit; /* Timers */ struct bfd_timers timers; diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8edba05d12..f3acfa4167 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -221,6 +221,10 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) BFD_SETVER(cp.diag, BFD_VERSION); cp.flags = 0; BFD_SETSTATE(cp.flags, bfd->ses_state); + + if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_CBIT)) + BFD_SETCBIT(cp.flags, BFD_CBIT); + BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND); /* @@ -646,6 +650,11 @@ int bfd_recv_cb(struct thread *t) ntohl(cp->timers.required_min_echo); bfd->remote_detect_mult = cp->detect_mult; + if (BFD_GETCBIT(cp->flags)) + bfd->remote_cbit = 1; + else + bfd->remote_cbit = 0; + /* State switch from section 6.2. */ bs_state_handler(bfd, BFD_GETSTATE(cp->flags)); diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index 0da1ca8df6..4ce23a8f27 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -88,6 +88,8 @@ struct bfd_peer_cfg { bool bpc_createonly; bool bpc_shutdown; + bool bpc_cbit; + /* 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 a12a3c196b..3e2ace6ea6 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -89,6 +89,7 @@ static void debug_printbpc(const char *func, unsigned int line, { char addr[3][128]; char timers[3][128]; + char cbit_str[10]; addr[0][0] = addr[1][0] = addr[2][0] = timers[0][0] = timers[1][0] = timers[2][0] = 0; @@ -117,9 +118,11 @@ static void debug_printbpc(const char *func, unsigned int line, snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d", bpc->bpc_detectmultiplier); - log_debug("%s:%d: %s %s%s%s%s%s%s", func, line, + sprintf(cbit_str, "CB %x", bpc->bpc_cbit); + + log_debug("%s:%d: %s %s%s%s%s%s%s %s", func, line, bpc->bpc_mhop ? "multi-hop" : "single-hop", addr[0], addr[1], - addr[2], timers[0], timers[1], timers[2]); + addr[2], timers[0], timers[1], timers[2], cbit_str); } #define DEBUG_PRINTBPC(bpc) debug_printbpc(__FILE__, __LINE__, (bpc)) @@ -173,6 +176,7 @@ int ptm_bfd_notify(struct bfd_session *bs) * - AF_INET6: * - 16 bytes: ipv6 * - c: prefix length + * - c: cbit * * Commands: ZEBRA_BFD_DEST_REPLAY * @@ -219,6 +223,8 @@ int ptm_bfd_notify(struct bfd_session *bs) /* BFD source prefix information. */ _ptm_msg_address(msg, bs->key.family, &bs->key.local); + stream_putc(msg, bs->remote_cbit); + /* Write packet size. */ stream_putw_at(msg, 0, stream_get_endp(msg)); @@ -293,6 +299,7 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, * - 16 bytes: ipv6 address * - c: ifname length * - X bytes: interface name + * - c: bfd_cbit * * q(64), l(32), w(16), c(8) */ @@ -371,6 +378,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, } } + STREAM_GETC(msg, bpc->bpc_cbit); + /* Sanity check: peer and local address must match IP types. */ if (bpc->bpc_local.sa_sin.sin_family != 0 && (bpc->bpc_local.sa_sin.sin_family diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index a9c30acafb..cf17250931 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -96,7 +96,7 @@ int bgp_bfd_is_peer_multihop(struct peer *peer) static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) { struct bfd_info *bfd_info; - int multihop; + int multihop, cbit = 0; vrf_id_t vrf_id; bfd_info = (struct bfd_info *)peer->bfd_info; @@ -112,20 +112,28 @@ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop) SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); } + /* while graceful restart with fwd path preserved is not kept + * keep bfd independent controlplane bit set to 1 + */ + if (!bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART) + && !bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); + + cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); if (peer->su.sa.sa_family == AF_INET) bfd_peer_sendmsg( zclient, bfd_info, AF_INET, &peer->su.sin.sin_addr, (peer->su_local) ? &peer->su_local->sin.sin_addr : NULL, (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL, - peer->ttl, multihop, command, 1, vrf_id); + peer->ttl, multihop, cbit, command, 1, vrf_id); else if (peer->su.sa.sa_family == AF_INET6) bfd_peer_sendmsg( zclient, bfd_info, AF_INET6, &peer->su.sin6.sin6_addr, (peer->su_local) ? &peer->su_local->sin6.sin6_addr : NULL, (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL, - peer->ttl, multihop, command, 1, vrf_id); + peer->ttl, multihop, cbit, command, 1, vrf_id); } /* @@ -260,7 +268,8 @@ static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS) * down the peer if the BFD session went down from * * up. */ -static void bgp_bfd_peer_status_update(struct peer *peer, int status) +static void bgp_bfd_peer_status_update(struct peer *peer, int status, + int remote_cbit) { struct bfd_info *bfd_info; int old_status; @@ -280,6 +289,13 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status) bfd_get_status_str(status)); } if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) { + if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) && + !remote_cbit) { + zlog_info("%s BFD DOWN message ignored in the process" + " of graceful restart when C bit is cleared", + peer->host); + return; + } peer->last_reset = PEER_DOWN_BFD_DOWN; BGP_EVENT_ADD(peer, BGP_Stop); } @@ -303,23 +319,27 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) struct prefix dp; struct prefix sp; int status; + int remote_cbit; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, + &remote_cbit, vrf_id); if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][PREFIX2STR_BUFFER]; prefix2str(&dp, buf[0], sizeof(buf[0])); if (ifp) { zlog_debug( - "Zebra: vrf %u interface %s bfd destination %s %s", + "Zebra: vrf %u interface %s bfd destination %s %s %s", vrf_id, ifp->name, buf[0], - bfd_get_status_str(status)); + bfd_get_status_str(status), + remote_cbit ? "(cbit on)" : ""); } else { prefix2str(&sp, buf[1], sizeof(buf[1])); zlog_debug( - "Zebra: vrf %u source %s bfd destination %s %s", + "Zebra: vrf %u source %s bfd destination %s %s %s", vrf_id, buf[1], buf[0], - bfd_get_status_str(status)); + bfd_get_status_str(status), + remote_cbit ? "(cbit on)" : ""); } } @@ -351,7 +371,8 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) if (ifp && (ifp == peer->nexthop.ifp)) { bgp_bfd_peer_status_update(peer, - status); + status, + remote_cbit); } else { if (!peer->su_local) continue; @@ -381,7 +402,8 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) continue; bgp_bfd_peer_status_update(peer, - status); + status, + remote_cbit); } } } diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index fccef0169e..fa89c80049 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -98,7 +98,8 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct prefix dst_ip; int status; - ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, + NULL, vrf_id); if (!ifp || dst_ip.family != AF_INET) return 0; @@ -217,6 +218,7 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj) adj->circuit->interface->name, 0, /* ttl */ 0, /* multihop */ + 1, /* control plane independent bit is on */ ZEBRA_BFD_DEST_DEREGISTER, 0, /* set_flag */ VRF_DEFAULT); @@ -258,6 +260,7 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) circuit->interface->name, 0, /* ttl */ 0, /* multihop */ + 1, /* control plane independent bit is on */ command, 0, /* set flag */ VRF_DEFAULT); diff --git a/lib/bfd.c b/lib/bfd.c index a8956c315c..00dbd1b3d1 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -127,8 +127,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, */ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, int family, void *dst_ip, void *src_ip, char *if_name, - int ttl, int multihop, int command, int set_flag, - vrf_id_t vrf_id) + int ttl, int multihop, int cbit, int command, + int set_flag, vrf_id_t vrf_id) { struct stream *s; int ret; @@ -208,6 +208,11 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, stream_putc(s, 0); } } + /* cbit */ + if (cbit) + stream_putc(s, 1); + else + stream_putc(s, 0); stream_putw_at(s, 0, stream_get_endp(s)); @@ -253,11 +258,13 @@ const char *bfd_get_command_dbg_str(int command) */ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, struct prefix *sp, int *status, + int *remote_cbit, vrf_id_t vrf_id) { unsigned int ifindex; struct interface *ifp = NULL; int plen; + int local_remote_cbit; /* Get interface index. */ ifindex = stream_getl(s); @@ -292,6 +299,9 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, stream_get(&sp->u.prefix, s, plen); sp->prefixlen = stream_getc(s); } + local_remote_cbit = stream_getc(s); + if (remote_cbit) + *remote_cbit = local_remote_cbit; return ifp; } diff --git a/lib/bfd.h b/lib/bfd.h index d02110a997..7f376a2470 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -48,6 +48,7 @@ struct bfd_gbl { #define BFD_FLAG_PARAM_CFG (1 << 0) /* parameters have been configured */ #define BFD_FLAG_BFD_REG (1 << 1) /* Peer registered with BFD */ #define BFD_FLAG_BFD_TYPE_MULTIHOP (1 << 2) /* Peer registered with BFD as multihop */ +#define BFD_FLAG_BFD_CBIT_ON (1 << 3) /* Peer registered with CBIT set to on */ #define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */ #define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */ @@ -83,13 +84,14 @@ extern void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, int *command); extern void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, int family, void *dst_ip, void *src_ip, - char *if_name, int ttl, int multihop, int command, - int set_flag, vrf_id_t vrf_id); + char *if_name, int ttl, int multihop, int cbit, + int command, int set_flag, vrf_id_t vrf_id); extern const char *bfd_get_command_dbg_str(int command); extern struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, struct prefix *sp, int *status, + int *remote_cbit, vrf_id_t vrf_id); const char *bfd_get_status_str(int status); diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index 7a26af1f09..f0500601b0 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -74,6 +74,7 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command) struct interface *ifp = oi->interface; struct bfd_info *bfd_info; char src[64]; + int cbit; if (!oi->bfd_info || !on->bfd_info) return; @@ -85,9 +86,11 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command) bfd_get_command_dbg_str(command), src); } + cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); + bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr, - on->ospf6_if->linklocal_addr, ifp->name, 0, 0, command, - 0, VRF_DEFAULT); + on->ospf6_if->linklocal_addr, ifp->name, 0, 0, + cbit, command, 0, VRF_DEFAULT); if (command == ZEBRA_BFD_DEST_DEREGISTER) bfd_info_free((struct bfd_info **)&on->bfd_info); @@ -195,7 +198,8 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct bfd_info *bfd_info; struct timeval tv; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, + NULL, vrf_id); if ((ifp == NULL) || (dp.family != AF_INET6)) return 0; diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index c8ad6d04f4..a17975270a 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -65,6 +65,7 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) struct interface *ifp = oi->ifp; struct ospf_if_params *params; struct bfd_info *bfd_info; + int cbit; /* Check if BFD is enabled */ params = IF_DEF_PARAMS(ifp); @@ -80,8 +81,10 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) inet_ntoa(nbr->src), ospf_vrf_id_to_name(oi->ospf->vrf_id)); + cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); + bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->src, NULL, ifp->name, - 0, 0, command, 0, oi->ospf->vrf_id); + 0, 0, cbit, command, 0, oi->ospf->vrf_id); } /* @@ -207,7 +210,8 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct bfd_info *bfd_info; struct timeval tv; - ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, + NULL, vrf_id); if ((ifp == NULL) || (p.family != AF_INET)) return 0; diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 300261e5a9..87d0f9fa22 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -111,6 +111,7 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command) struct pim_interface *pim_ifp = NULL; struct bfd_info *bfd_info = NULL; struct zclient *zclient = NULL; + int cbit; zclient = pim_zebra_zclient_get(); @@ -127,8 +128,12 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command) zlog_debug("%s Nbr %s %s with BFD", __PRETTY_FUNCTION__, str, bfd_get_command_dbg_str(command)); } + + cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); + bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->source_addr, NULL, - nbr->interface->name, 0, 0, command, 0, VRF_DEFAULT); + nbr->interface->name, 0, 0, cbit, + command, 0, VRF_DEFAULT); } /* @@ -222,7 +227,8 @@ static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct listnode *neigh_nextnode = NULL; struct pim_neighbor *neigh = NULL; - ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, + NULL, vrf_id); if ((ifp == NULL) || (p.family != AF_INET)) return 0; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index d3ecd3695a..46f1385520 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -93,6 +93,7 @@ const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName"; const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt"; const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent"; const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName"; +const char ZEBRA_PTM_BFD_CBIT_FIELD[] = "bfdcbit"; static ptm_lib_handle_t *ptm_hdl; @@ -688,6 +689,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; unsigned int pid; + uint8_t cbit_set; if (hdr->command == ZEBRA_BFD_DEST_UPDATE) client->bfd_peer_upd8_cnt++; @@ -813,6 +815,10 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD, if_name); } + STREAM_GETC(s, cbit_set); + sprintf(tmp_buf, "%d", cbit_set); + ptm_lib_append_msg(ptm_hdl, out_ctxt, + ZEBRA_PTM_BFD_CBIT_FIELD, tmp_buf); sprintf(tmp_buf, "%d", 1); ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT, -- 2.39.5