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,