From 21bfce982771b791c9f52d6de784f5370895c85b Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Fri, 26 Feb 2021 16:50:51 -0300 Subject: [PATCH] bgpd: rework BFD integration Remove old BFD API usage and replace it with the new one. Highlights: - More shared code: the daemon gets notified with callbacks instead of having to roll its own code to find the notified sessions. - Less code to integrate with BFD. - Remove hidden commands to configure single / multi hop. Use protocol data instead. BGP can determine if a peer is single/multi hop according to the following criteria: a. If the IP address is a link-local address (single hop) b. The network is shared with peer (single hop) c. BGP is configured for eBGP multi hop / TTL security (multi hop) - Respect the configuration hierarchy: a. Peer configuration take precendence over peer-group configuration. b. When peer group configuration is removed, reset peer BFD configurations to defaults (unless peer had specific configs). Example: neighbor foo peer-group neighbor foo bfd profile X neighbor 192.168.0.2 peer-group foo neighbor 192.168.0.2 bfd ! If peer-group is removed the profile configuration gets ! removed from peer 192.168.0.2, but BFD will still enabled ! because of the neighbor specific bfd configuration. Signed-off-by: Rafael Zalamena --- bgpd/bgp_bfd.c | 1120 ++++++++++++++++------------------------------- bgpd/bgp_bfd.h | 57 ++- bgpd/bgp_fsm.c | 10 +- bgpd/bgp_main.c | 3 + bgpd/bgp_vty.c | 10 +- bgpd/bgpd.c | 19 +- bgpd/bgpd.h | 27 +- 7 files changed, 473 insertions(+), 773 deletions(-) diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 11e9344d1c..b618fa28e7 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -29,6 +29,7 @@ #include "thread.h" #include "buffer.h" #include "stream.h" +#include "vrf.h" #include "zclient.h" #include "bfd.h" #include "lib/json.h" @@ -40,325 +41,37 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_vty.h" +DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data"); + extern struct zclient *zclient; -/* - * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group - * template - * to peer. - */ -void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer) +static void bfd_session_status_update(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg) { - struct bfd_info *bfd_info; - struct bfd_info *conf_bfd_info; - - if (!conf->bfd_info) - return; - - conf_bfd_info = (struct bfd_info *)conf->bfd_info; - if (!peer->bfd_info) - peer->bfd_info = bfd_info_create(); - - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Copy BFD parameter values */ - bfd_info->required_min_rx = conf_bfd_info->required_min_rx; - bfd_info->desired_min_tx = conf_bfd_info->desired_min_tx; - bfd_info->detect_mult = conf_bfd_info->detect_mult; - bfd_info->type = conf_bfd_info->type; -} - -/* - * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single - * hop. - */ -bool bgp_bfd_is_peer_multihop(struct peer *peer) -{ - struct bfd_info *bfd_info; - - bfd_info = (struct bfd_info *)peer->bfd_info; - - if (!bfd_info) - return false; - - if ((bfd_info->type == BFD_TYPE_MULTIHOP) - || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network) - || is_ebgp_multihop_configured(peer)) - return true; - else - return false; -} - -/* - * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister - * command to Zebra to be forwarded to BFD - */ -static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) -{ - struct bfd_session_arg arg = {}; - struct bfd_info *bfd_info; - int multihop; - vrf_id_t vrf_id; - size_t addrlen; - - /* - * XXX: some pointers are dangling during shutdown, so instead of - * trying to send a message during signal handlers lets just wait BGP - * to terminate zebra's connection and BFD will automatically find - * out that we are no longer expecting notifications. - * - * The pointer that is causing a crash here is `peer->nexthop.ifp`. - * That happens because at this point of the shutdown all interfaces are - * already `free()`d. - */ - if (bm->terminating) - return; - - bfd_info = (struct bfd_info *)peer->bfd_info; - - vrf_id = peer->bgp->vrf_id; - - if (command == ZEBRA_BFD_DEST_DEREGISTER) { - multihop = - CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); - UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); - } else { - multihop = bgp_bfd_is_peer_multihop(peer); - if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop) - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); - } - /* while graceful restart with fwd path preserved - * and bfd controlplane check not configured is not kept - * keep bfd independent controlplane bit set to 1 - */ - if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - /* Set all message arguments. */ - arg.family = peer->su.sa.sa_family; - addrlen = arg.family == AF_INET ? sizeof(struct in_addr) - : sizeof(struct in6_addr); - - if (arg.family == AF_INET) - memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen); - else - memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen); - - if (peer->su_local) { - if (arg.family == AF_INET) - memcpy(&arg.src, &peer->su_local->sin.sin_addr, - addrlen); - else - memcpy(&arg.src, &peer->su_local->sin6.sin6_addr, - addrlen); - } - - if (peer->nexthop.ifp) { - arg.ifnamelen = strlen(peer->nexthop.ifp->name); - strlcpy(arg.ifname, peer->nexthop.ifp->name, - sizeof(arg.ifname)); - } - - if (bfd_info->profile[0]) { - arg.profilelen = strlen(bfd_info->profile); - strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile)); - } - - arg.set_flag = 1; - arg.mhop = multihop; - arg.ttl = peer->ttl; - arg.vrf_id = vrf_id; - arg.command = command; - arg.bfd_info = bfd_info; - arg.min_tx = bfd_info->desired_min_tx; - arg.min_rx = bfd_info->required_min_rx; - arg.detection_multiplier = bfd_info->detect_mult; - arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - /* Send message. */ - zclient_bfd_command(zclient, &arg); -} - -/* - * bgp_bfd_register_peer - register a peer with BFD through zebra - * for monitoring the peer rechahability. - */ -void bgp_bfd_register_peer(struct peer *peer) -{ - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Check if BFD is enabled and peer has already been registered with BFD - */ - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); -} - -/** - * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra - * for stopping the monitoring of the peer - * rechahability. - */ -void bgp_bfd_deregister_peer(struct peer *peer) -{ - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Check if BFD is eanbled and peer has not been registered */ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; - - bfd_info->status = BFD_STATUS_DOWN; - bfd_info->last_update = bgp_clock(); - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); -} - -/* - * bgp_bfd_update_peer - update peer with BFD with new BFD paramters - * through zebra. - */ -static void bgp_bfd_update_peer(struct peer *peer) -{ - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE); -} - -/** - * bgp_bfd_reset_peer - reinitialise bfd - * ensures that bfd state machine is restarted - * to be synced with remote bfd - */ -void bgp_bfd_reset_peer(struct peer *peer) -{ - if (!peer->bfd_info) - return; - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); -} - -/* - * bgp_bfd_update_type - update session type with BFD through zebra. - */ -static void bgp_bfd_update_type(struct peer *peer) -{ - struct bfd_info *bfd_info; - int multihop; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; - - if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) { - multihop = bgp_bfd_is_peer_multihop(peer); - if ((multihop - && !CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP)) - || (!multihop && CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP))) { - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); - } - } else { - if ((bfd_info->type == BFD_TYPE_MULTIHOP - && !CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP)) - || (bfd_info->type == BFD_TYPE_SINGLEHOP - && CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP))) { - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); - } - } -} - -/* - * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled - * to zebra - */ -static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS) -{ - struct listnode *mnode, *node, *nnode; - struct bgp *bgp; - struct peer *peer; + struct peer *peer = arg; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Zebra: BFD Dest replay request"); + zlog_debug("%s: neighbor %s vrf %s(%u) bfd state %s -> %s", + __func__, peer->conf_if ? peer->conf_if : peer->host, + bfd_sess_vrf(bsp), bfd_sess_vrf_id(bsp), + bfd_get_status_str(bss->previous_state), + bfd_get_status_str(bss->state)); - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - /* Replay the peer, if BFD is enabled in BGP */ - - for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp)) - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - bgp_bfd_update_peer(peer); - } - - return 0; -} - -/* - * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring - * down the peer if the BFD session went down from - * * up. - */ -static void bgp_bfd_peer_status_update(struct peer *peer, int status, - int remote_cbit) -{ - struct bfd_info *bfd_info; - int old_status; - - bfd_info = (struct bfd_info *)peer->bfd_info; - - if (bfd_info->status == status) - return; - - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - - bfd_info->last_update = bgp_clock(); - - if (status != old_status) { - if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) - zlog_debug("[%s]: BFD %s", peer->host, - bfd_get_status_str(status)); - } - if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) { - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) && - CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) && - !remote_cbit) { - zlog_info("%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared", - peer->host); + if (bss->state == BSS_DOWN && bss->previous_state == BSS_UP) { + if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) + && bfd_sess_cbit(bsp) && !bss->remote_cbit) { + if (BGP_DEBUG(zebra, ZEBRA)) + 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); } - if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN) + + if (bss->state == BSS_UP && bss->previous_state != BSS_UP && peer->status != Established) { if (!BGP_PEER_START_SUPPRESSED(peer)) { bgp_fsm_nht_update(peer, true); @@ -367,340 +80,353 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status, } } -/* - * bgp_bfd_dest_update - Find the peer for which the BFD status - * has changed and bring down the peer - * connectivity if the BFD session went down. - */ -static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) +void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) { - struct interface *ifp; - struct prefix dp; - struct prefix sp; - int status; - int remote_cbit; + struct listnode *n; + struct peer *pn; + struct peer *gconfig; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, - &remote_cbit, vrf_id); + /* When called on a group, apply to all peers. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) { + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) + bgp_peer_config_apply(pn, pg); + return; + } - if (BGP_DEBUG(zebra, ZEBRA)) { - struct vrf *vrf; + /* No group, just use current configuration. */ + if (pg == NULL || pg->conf->bfd_config == NULL) { + bfd_sess_set_timers(p->bfd_config->session, + p->bfd_config->detection_multiplier, + p->bfd_config->min_rx, + p->bfd_config->min_tx); + bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit); + bfd_sess_set_profile(p->bfd_config->session, + p->bfd_config->profile); + bfd_sess_install(p->bfd_config->session); + return; + } - vrf = vrf_lookup_by_id(vrf_id); + /* + * Check if the group configuration was overwritten or apply group + * configuration. + */ + gconfig = pg->conf; - if (ifp) + /* + * If using default control plane independent configuration, + * then prefer group's (e.g. it means it wasn't manually configured). + */ + if (!p->bfd_config->cbit) + bfd_sess_set_cbit(p->bfd_config->session, + gconfig->bfd_config->cbit); + else + bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit); + + /* If no profile was specified in peer, then use the group profile. */ + if (p->bfd_config->profile[0] == 0) + bfd_sess_set_profile(p->bfd_config->session, + gconfig->bfd_config->profile); + else + bfd_sess_set_profile(p->bfd_config->session, + p->bfd_config->profile); + + /* If no specific timers were configured, then use the group timers. */ + if (p->bfd_config->detection_multiplier == BFD_DEF_DETECT_MULT + || p->bfd_config->min_rx == BFD_DEF_MIN_RX + || p->bfd_config->min_tx == BFD_DEF_MIN_TX) + bfd_sess_set_timers(p->bfd_config->session, + gconfig->bfd_config->detection_multiplier, + gconfig->bfd_config->min_rx, + gconfig->bfd_config->min_tx); + else + bfd_sess_set_timers(p->bfd_config->session, + p->bfd_config->detection_multiplier, + p->bfd_config->min_rx, + p->bfd_config->min_tx); + + bfd_sess_install(p->bfd_config->session); +} + +void bgp_peer_bfd_update_source(struct peer *p) +{ + struct bfd_session_params *session = p->bfd_config->session; + bool changed = false; + int family; + union { + struct in_addr v4; + struct in6_addr v6; + } src, dst; + + /* Nothing to do for groups. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) + return; + + /* Update peer's source/destination addresses. */ + bfd_sess_addresses(session, &family, &src.v6, &dst.v6); + if (family == AF_INET) { + if ((p->su_local + && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr) + || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: address [%pI4->%pI4] to [%pI4->%pI4]", + __func__, &src.v4, &dst.v4, + p->su_local ? &p->su_local->sin.sin_addr + : &src.v4, + &p->su.sin.sin_addr); + + bfd_sess_set_ipv4_addrs( + session, + p->su_local ? &p->su_local->sin.sin_addr : NULL, + &p->su.sin.sin_addr); + changed = true; + } + } else { + if ((p->su_local + && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6))) + || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: address [%pI6->%pI6] to [%pI6->%pI6]", + __func__, &src.v6, &dst.v6, + p->su_local + ? &p->su_local->sin6.sin6_addr + : &src.v6, + &p->su.sin6.sin6_addr); + + bfd_sess_set_ipv6_addrs( + session, + p->su_local ? &p->su_local->sin6.sin6_addr + : NULL, + &p->su.sin6.sin6_addr); + changed = true; + } + } + + /* Update interface. */ + if (p->nexthop.ifp && bfd_sess_interface(session) == NULL) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: interface none to %s", __func__, + p->nexthop.ifp->name); + + bfd_sess_set_interface(session, p->nexthop.ifp->name); + changed = true; + } + + /* + * Update TTL. + * + * Two cases: + * - We detected that the peer is a hop away from us (remove multi hop). + * (this happens when `p->shared_network` is set to `true`) + * - eBGP multi hop / TTL security changed. + */ + if (!PEER_IS_MULTIHOP(p) && bfd_sess_hop_count(session) > 1) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: TTL %d to 1", __func__, + bfd_sess_hop_count(session)); + + bfd_sess_set_hop_count(session, 1); + changed = true; + } + if (PEER_IS_MULTIHOP(p) && p->ttl != bfd_sess_hop_count(session)) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: TTL %d to %d", __func__, + bfd_sess_hop_count(session), p->ttl); + + bfd_sess_set_hop_count(session, p->ttl); + changed = true; + } + + /* Update VRF. */ + if (bfd_sess_vrf_id(session) != p->bgp->vrf_id) { + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug( - "Zebra: vrf %s(%u) interface %s bfd destination %pFX %s %s", - VRF_LOGNAME(vrf), vrf_id, ifp->name, &dp, - bfd_get_status_str(status), - remote_cbit ? "(cbit on)" : ""); - else - zlog_debug( - "Zebra: vrf %s(%u) source %pFX bfd destination %pFX %s %s", - VRF_LOGNAME(vrf), vrf_id, &sp, &dp, - bfd_get_status_str(status), - remote_cbit ? "(cbit on)" : ""); + "%s: VRF %s(%d) to %s(%d)", __func__, + bfd_sess_vrf(session), bfd_sess_vrf_id(session), + vrf_id_to_name(p->bgp->vrf_id), p->bgp->vrf_id); + + bfd_sess_set_vrf(session, p->bgp->vrf_id); + changed = true; } - /* Bring the peer down if BFD is enabled in BGP */ - { - struct listnode *mnode, *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp)) - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (!peer->bfd_info) - continue; - - if ((dp.family == AF_INET) - && (peer->su.sa.sa_family == AF_INET)) { - if (dp.u.prefix4.s_addr - != peer->su.sin.sin_addr.s_addr) - continue; - } else if ((dp.family == AF_INET6) - && (peer->su.sa.sa_family - == AF_INET6)) { - if (memcmp(&dp.u.prefix6, - &peer->su.sin6.sin6_addr, - sizeof(struct in6_addr))) - continue; - } else - continue; - - if (ifp && (ifp == peer->nexthop.ifp)) { - bgp_bfd_peer_status_update(peer, - status, - remote_cbit); - } else { - if (!peer->su_local) - continue; - - if ((sp.family == AF_INET) - && (peer->su_local->sa.sa_family - == AF_INET)) { - if (sp.u.prefix4.s_addr - != peer->su_local->sin - .sin_addr.s_addr) - continue; - } else if ((sp.family == AF_INET6) - && (peer->su_local->sa - .sa_family - == AF_INET6)) { - if (memcmp(&sp.u.prefix6, - &peer->su_local->sin6 - .sin6_addr, - sizeof(struct - in6_addr))) - continue; - } else - continue; - - if ((vrf_id != VRF_DEFAULT) - && (peer->bgp->vrf_id != vrf_id)) - continue; - - bgp_bfd_peer_status_update(peer, - status, - remote_cbit); - } - } - } - - return 0; + if (changed) + bfd_sess_install(session); } -/* - * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer. - */ -static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, - int defaults) -{ - struct bfd_info *bi; - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - - bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx, - detect_mult, NULL, defaults, &command); - - /* This command overrides profile if it was previously applied. */ - bi = peer->bfd_info; - bi->profile[0] = 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - min_rx, min_tx, detect_mult, NULL, - defaults, &command); - - /* - * This command overrides profile if it was previously - * applied. - */ - bi = peer->bfd_info; - bi->profile[0] = 0; - - if ((peer->status == Established) - && (command == ZEBRA_BFD_DEST_REGISTER)) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - } else { - if ((peer->status == Established) - && (command == ZEBRA_BFD_DEST_REGISTER)) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - return 0; -} - -/* - * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for - * peer. - */ -static int bgp_bfd_peer_param_unset(struct peer *peer) -{ - struct peer_group *group; - struct listnode *node, *nnode; - - if (!peer->bfd_info) - return 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - bfd_info_free(&(peer->bfd_info)); - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - bgp_bfd_deregister_peer(peer); - bfd_info_free(&(peer->bfd_info)); - } - } else { - bgp_bfd_deregister_peer(peer); - bfd_info_free(&(peer->bfd_info)); - } - return 0; -} - -/* - * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or - * singlehop) - */ -static int bgp_bfd_peer_param_type_set(struct peer *peer, - enum bfd_sess_type type) -{ - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - bfd_info->type = type; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - if (!peer->bfd_info) - bfd_set_param( - (struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - bfd_info->type = type; - - if (peer->status == Established) { - if (command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else - bgp_bfd_update_type(peer); - } - } - } else { - if (peer->status == Established) { - if (command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else - bgp_bfd_update_type(peer); - } - } - - return 0; -} - -#if HAVE_BFDD > 0 /** - * Set peer BFD profile configuration. + * Reset BFD configuration data structure to its defaults settings. */ -static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile) +static void bgp_peer_bfd_reset(struct peer *p) { - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - struct bfd_info *bfd_info; + /* Set defaults. */ + p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + p->bfd_config->min_rx = BFD_DEF_MIN_RX; + p->bfd_config->min_tx = BFD_DEF_MIN_TX; + p->bfd_config->cbit = false; + p->bfd_config->profile[0] = 0; +} - bfd_set_param((struct bfd_info **)&(peer->bfd_info), BFD_DEF_MIN_RX, - BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, NULL, 1, &command); +void bgp_peer_configure_bfd(struct peer *p, bool manual) +{ + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Already configured, skip it. */ + if (p->bfd_config) { + /* If manually active update flag. */ + if (!p->bfd_config->manual) + p->bfd_config->manual = manual; - /* If profile was specified, then copy string. */ - if (profile) - strlcpy(bfd_info->profile, profile, sizeof(bfd_info->profile)); - else /* Otherwise just initialize it empty. */ - bfd_info->profile[0] = 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* If profile was specified, then copy string. */ - if (profile) - strlcpy(bfd_info->profile, profile, - sizeof(bfd_info->profile)); - else /* Otherwise just initialize it empty. */ - bfd_info->profile[0] = 0; - - if (peer->status == Established - && command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - } else { - if (peer->status == Established - && command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); + return; } - return 0; + /* Allocate memory for configuration overrides. */ + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); + p->bfd_config->manual = manual; + + /* Create new session and assign callback. */ + p->bfd_config->session = bfd_sess_new(bfd_session_status_update, p); + bgp_peer_bfd_reset(p); + + /* Configure session with basic BGP peer data. */ + if (p->su.sa.sa_family == AF_INET) + bfd_sess_set_ipv4_addrs(p->bfd_config->session, + p->su_local ? &p->su_local->sin.sin_addr + : NULL, + &p->su.sin.sin_addr); + else + bfd_sess_set_ipv6_addrs( + p->bfd_config->session, + p->su_local ? &p->su_local->sin6.sin6_addr : NULL, + &p->su.sin6.sin6_addr); + + bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id); + bfd_sess_set_hop_count(p->bfd_config->session, + PEER_IS_MULTIHOP(p) ? p->ttl : 1); + + if (p->nexthop.ifp) + bfd_sess_set_interface(p->bfd_config->session, + p->nexthop.ifp->name); + + bfd_sess_enable(p->bfd_config->session, true); + bgp_peer_config_apply(p, p->group); +} + +static void bgp_peer_remove_bfd(struct peer *p) +{ + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); + + /* + * Peer configuration was removed, however we must check if there + * is still a group configuration to keep this running. + */ + if (p->group && p->group->conf->bfd_config) { + p->bfd_config->manual = false; + bgp_peer_bfd_reset(p); + bgp_peer_config_apply(p, p->group); + return; + } + + bfd_sess_free(&p->bfd_config->session); + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); +} + +static void bgp_group_configure_bfd(struct peer *p) +{ + struct listnode *n; + struct peer *pn; + + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); + + /* Already allocated: do nothing. */ + if (p->bfd_config) + return; + + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); + + /* Set defaults. */ + p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + p->bfd_config->min_rx = BFD_DEF_MIN_RX; + p->bfd_config->min_tx = BFD_DEF_MIN_TX; + + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) + bgp_peer_configure_bfd(pn, false); +} + +static void bgp_group_remove_bfd(struct peer *p) +{ + struct listnode *n; + struct peer *pn; + + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); + + /* Already freed: do nothing. */ + if (p->bfd_config == NULL) + return; + + /* Free configuration and point to `NULL`. */ + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); + + /* Now that it is `NULL` recalculate configuration for all peers. */ + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) { + if (pn->bfd_config->manual) + bgp_peer_config_apply(pn, NULL); + else + bgp_peer_remove_bfd(pn); + } +} + +void bgp_peer_remove_bfd_config(struct peer *p) +{ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) + bgp_group_remove_bfd(p); + else + bgp_peer_remove_bfd(p); } -#endif /* * bgp_bfd_peer_config_write - Write the peer BFD configuration. */ -void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr) +void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer, + const char *addr) { - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - - bfd_info = (struct bfd_info *)peer->bfd_info; - - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) + /* + * Always show group BFD configuration, but peer only when explicitly + * configured. + */ + if ((!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) + && peer->bfd_config->manual) + || CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { #if HAVE_BFDD > 0 vty_out(vty, " neighbor %s bfd\n", addr); #else vty_out(vty, " neighbor %s bfd %d %d %d\n", addr, - bfd_info->detect_mult, bfd_info->required_min_rx, - bfd_info->desired_min_tx); + peer->bfd_config->detection_multiplier, + peer->bfd_config->min_rx, peer->bfd_config->min_tx); #endif /* HAVE_BFDD */ - - if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED) - vty_out(vty, " neighbor %s bfd %s\n", addr, - (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop" - : "singlehop"); - - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG) - && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) { - vty_out(vty, " neighbor %s bfd", addr); - if (bfd_info->profile[0]) - vty_out(vty, " profile %s", bfd_info->profile); - vty_out(vty, "\n"); } - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) - vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr); + if (peer->bfd_config->profile[0]) + vty_out(vty, " neighbor %s bfd profile %s\n", addr, + peer->bfd_config->profile); + + if (peer->bfd_config->cbit) + vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", + addr); } /* * bgp_bfd_show_info - Show the peer BFD information. */ -void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json, +void bgp_bfd_show_info(struct vty *vty, const struct peer *peer, json_object *json_neigh) { - bfd_show_info(vty, (struct bfd_info *)peer->bfd_info, - bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh); + if (peer->bfd_config->session) + bfd_sess_show(vty, json_neigh, peer->bfd_config->session); } DEFUN (neighbor_bfd, @@ -712,16 +438,15 @@ DEFUN (neighbor_bfd, { int idx_peer = 1; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); return CMD_SUCCESS; } @@ -745,89 +470,30 @@ DEFUN( int idx_number_1 = 3; int idx_number_2 = 4; int idx_number_3 = 5; + long detection_multiplier, min_rx, min_tx; struct peer *peer; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if ((ret = bfd_validate_param( - vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) - return ret; + detection_multiplier = strtol(argv[idx_number_1]->arg, NULL, 10); + min_rx = strtol(argv[idx_number_2]->arg, NULL, 10); + min_tx = strtol(argv[idx_number_3]->arg, NULL, 10); - ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0); - if (ret != 0) - return bgp_vty_return(vty, ret); - - return CMD_SUCCESS; -} - -DEFUN_HIDDEN (neighbor_bfd_type, - neighbor_bfd_type_cmd, - "neighbor bfd ", - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Enables BFD support\n" - "Multihop session\n" - "Single hop session\n") -{ - int idx_peer = 1; - int idx_hop = 3; - struct peer *peer; - enum bfd_sess_type type; - int ret; - - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - if (strmatch(argv[idx_hop]->text, "singlehop")) - type = BFD_TYPE_SINGLEHOP; - else if (strmatch(argv[idx_hop]->text, "multihop")) - type = BFD_TYPE_MULTIHOP; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); else - return CMD_WARNING_CONFIG_FAILED; + bgp_peer_configure_bfd(peer, true); - ret = bgp_bfd_peer_param_type_set(peer, type); - if (ret != 0) - return bgp_vty_return(vty, ret); + peer->bfd_config->detection_multiplier = detection_multiplier; + peer->bfd_config->min_rx = min_rx; + peer->bfd_config->min_tx = min_tx; + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } -static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer, - const char *no) -{ - struct bfd_info *bfd_info; - - if (!peer->bfd_info) { - if (no) - return CMD_SUCCESS; - vty_out(vty, "%% Specify bfd command first\n"); - return CMD_WARNING_CONFIG_FAILED; - } - bfd_info = (struct bfd_info *)peer->bfd_info; - if (!no) { - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) { - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE); - bgp_bfd_update_peer(peer); - } - } else { - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) { - UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE); - bgp_bfd_update_peer(peer); - } - } - return CMD_SUCCESS; -} - - DEFUN (neighbor_bfd_check_controlplane_failure, neighbor_bfd_check_controlplane_failure_cmd, "[no] neighbor bfd check-control-plane-failure", @@ -840,9 +506,6 @@ DEFUN (neighbor_bfd_check_controlplane_failure, const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL; int idx_peer = 0; struct peer *peer; - struct peer_group *group; - struct listnode *node, *nnode; - int ret = CMD_SUCCESS; if (no) idx_peer = 2; @@ -853,19 +516,16 @@ DEFUN (neighbor_bfd_check_controlplane_failure, vty_out(vty, "%% Specify remote-as or peer-group commands first\n"); return CMD_WARNING_CONFIG_FAILED; } - if (!peer->bfd_info) { - if (no) - return CMD_SUCCESS; - vty_out(vty, "%% Specify bfd command first\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) - ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no); - } else - ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no); - return ret; + + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); + + peer->bfd_config->cbit = no == NULL; + bgp_peer_config_apply(peer, peer->group); + + return CMD_SUCCESS; } DEFUN (no_neighbor_bfd, @@ -888,44 +548,15 @@ DEFUN (no_neighbor_bfd, { int idx_peer = 2; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_param_unset(peer); - if (ret != 0) - return bgp_vty_return(vty, ret); - - return CMD_SUCCESS; -} - - -DEFUN_HIDDEN (no_neighbor_bfd_type, - no_neighbor_bfd_type_cmd, - "no neighbor bfd ", - NO_STR - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Disables BFD support\n" - "Multihop session\n" - "Singlehop session\n") -{ - int idx_peer = 2; - struct peer *peer; - int ret; - - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - if (!peer->bfd_info) - return 0; - - ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_remove_bfd(peer); + else + bgp_peer_remove_bfd(peer); return CMD_SUCCESS; } @@ -941,15 +572,19 @@ DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd, { int idx_peer = 1, idx_prof = 4; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_set_profile(peer, argv[idx_prof]->arg); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); + + strlcpy(peer->bfd_config->profile, argv[idx_prof]->arg, + sizeof(peer->bfd_config->profile)); + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } @@ -965,38 +600,33 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd, { int idx_peer = 2; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (!peer->bfd_info) - return 0; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); - ret = bgp_bfd_peer_set_profile(peer, NULL); - if (ret != 0) - return bgp_vty_return(vty, ret); + peer->bfd_config->profile[0] = 0; + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } #endif /* HAVE_BFDD */ -void bgp_bfd_init(void) +void bgp_bfd_init(struct thread_master *tm) { - bfd_gbl_init(); - /* Initialize BFD client functions */ - zclient->interface_bfd_dest_update = bgp_bfd_dest_update; - zclient->bfd_dest_replay = bgp_bfd_dest_replay; + bfd_protocol_integration_init(zclient, tm); /* "neighbor bfd" commands. */ install_element(BGP_NODE, &neighbor_bfd_cmd); install_element(BGP_NODE, &neighbor_bfd_param_cmd); - install_element(BGP_NODE, &neighbor_bfd_type_cmd); install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd); install_element(BGP_NODE, &no_neighbor_bfd_cmd); - install_element(BGP_NODE, &no_neighbor_bfd_type_cmd); #if HAVE_BFDD > 0 install_element(BGP_NODE, &neighbor_bfd_profile_cmd); diff --git a/bgpd/bgp_bfd.h b/bgpd/bgp_bfd.h index f2fa959b45..ec2772b69b 100644 --- a/bgpd/bgp_bfd.h +++ b/bgpd/bgp_bfd.h @@ -23,22 +23,55 @@ #ifndef _QUAGGA_BGP_BFD_H #define _QUAGGA_BGP_BFD_H -extern void bgp_bfd_init(void); +#define PEER_IS_MULTIHOP(peer) \ + ((((peer)->sort == BGP_PEER_IBGP) && !(peer)->shared_network) \ + || is_ebgp_multihop_configured((peer))) -extern void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer); +extern void bgp_bfd_init(struct thread_master *tm); -extern void bgp_bfd_register_peer(struct peer *peer); +extern void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer, + const char *addr); -extern void bgp_bfd_deregister_peer(struct peer *peer); - -extern void bgp_bfd_reset_peer(struct peer *peer); - -extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, - char *addr); - -extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json, +/** + * Show BFD information helper. + * + * \param vty the VTY pointer. + * \param peer the BGP configuration pointer. + * \param use_json unused. + * \param json_neigh JSON object when called as JSON command. + */ +extern void bgp_bfd_show_info(struct vty *vty, const struct peer *peer, json_object *json_neigh); -extern bool bgp_bfd_is_peer_multihop(struct peer *peer); +/** + * When called on a group it applies configuration to all peers in that group, + * otherwise just applies the configuration to a single peer. + * + * This function should be called when configuration changes either on group + * or peer. + * + * \param p the BGP peer pointer. + * \param pg the BGP group to copy configuration from (it is usually + * `p->group` exception when copying new group configuration + * see `peer_group2peer_config_copy` function case). + */ +extern void bgp_peer_config_apply(struct peer *p, struct peer_group *pg); + +/** + * Allocates and configure BFD session for peer. If it is already configured, + * then it does nothing. + */ +extern void bgp_peer_configure_bfd(struct peer *p, bool manual); + +/** + * Removes BFD configuration from either peer or peer group. + */ +extern void bgp_peer_remove_bfd_config(struct peer *p); + +/** + * Special function to handle the case of changing source address. This + * happens when the peer/group is configured with `neigbor X update-source Y`. + */ +extern void bgp_peer_bfd_update_source(struct peer *p); #endif /* _QUAGGA_BGP_BFD_H */ diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index f099309f97..45a856a459 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1215,8 +1215,9 @@ int bgp_stop(struct peer *peer) peer->nsf_af_count = 0; /* deregister peer */ - if (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) - bgp_bfd_deregister_peer(peer); + if (peer->bfd_config + && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) + bfd_sess_uninstall(peer->bfd_config->session); if (peer_dynamic_neighbor(peer) && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { @@ -2122,7 +2123,10 @@ static int bgp_establish(struct peer *peer) hash_release(peer->bgp->peerhash, peer); hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); - bgp_bfd_reset_peer(peer); + /* Start BFD peer if not already running. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); + return ret; } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 6b3df87515..2ddafd9a0c 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -162,6 +162,9 @@ __attribute__((__noreturn__)) void sigint(void) assert(bm->terminating == false); bm->terminating = true; /* global flag that shutting down */ + /* Disable BFD events to avoid wasting processing. */ + bfd_protocol_integration_set_shutdown(true); + bgp_terminate(); bgp_exit(0); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a6c00d5735..a016265d6e 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -14411,7 +14411,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "\n"); /* BFD information. */ - bgp_bfd_show_info(vty, p, use_json, json_neigh); + if (p->bfd_config) + bgp_bfd_show_info(vty, p, json_neigh); if (use_json) { if (p->conf_if) /* Configured interface name. */ @@ -16818,11 +16819,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, peer->rtt_expected, peer->rtt_keepalive_conf); /* bfd */ - if (peer->bfd_info) { - if (!peer_group_active(peer) || !g_peer->bfd_info) { - bgp_bfd_peer_config_write(vty, peer, addr); - } - } + if (peer->bfd_config) + bgp_bfd_peer_config_write(vty, peer, addr); /* password */ if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD)) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4eb9229b55..d37b9fa48c 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1161,7 +1161,9 @@ static void peer_free(struct peer *peer) XFREE(MTYPE_PEER_CONF_IF, peer->conf_if); - bfd_info_free(&(peer->bfd_info)); + /* Remove BFD configuration. */ + if (peer->bfd_config) + bgp_peer_remove_bfd_config(peer); FOREACH_AFI_SAFI (afi, safi) bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE); @@ -2394,7 +2396,9 @@ int peer_delete(struct peer *peer) SET_FLAG(peer->flags, PEER_FLAG_DELETE); - bgp_bfd_deregister_peer(peer); + /* Remove BFD settings. */ + if (peer->bfd_config) + bgp_peer_remove_bfd_config(peer); /* Delete peer route flap dampening configuration. This needs to happen * before removing the peer from peer groups. @@ -2678,7 +2682,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Update GR flags for the peer. */ bgp_peer_gr_flags_update(peer); - bgp_bfd_peer_group2peer_copy(conf, peer); + /* Apply BFD settings from group to peer if it exists. */ + if (conf->bfd_config) { + bgp_peer_configure_bfd(peer, false); + bgp_peer_config_apply(peer, group); + } } /* Peer group's remote AS configuration. */ @@ -2768,7 +2776,8 @@ int peer_group_delete(struct peer_group *group) XFREE(MTYPE_PEER_GROUP_HOST, group->name); group->name = NULL; - bfd_info_free(&(group->conf->bfd_info)); + if (group->conf->bfd_config) + bgp_peer_remove_bfd_config(group->conf); group->conf->group = NULL; peer_delete(group->conf); @@ -7700,7 +7709,7 @@ void bgp_init(unsigned short instance) bgp_clist = community_list_init(); /* BFD init */ - bgp_bfd_init(); + bgp_bfd_init(bm->master); bgp_lp_vty_init(); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 029019dd3c..6270542178 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -45,6 +45,8 @@ #include "bgp_nexthop.h" #include "bgp_damp.h" +#include "lib/bfd.h" + #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ #define BGP_PEER_MAX_HASH_SIZE 16384 @@ -1558,8 +1560,29 @@ struct peer { #define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */ #define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */ - /* peer specific BFD information */ - struct bfd_info *bfd_info; + /** Peer overwrite configuration. */ + struct bfd_session_config { + /** + * Manual configuration bit. + * + * This flag only makes sense for real peers (and not groups), + * it keeps track if the user explicitly configured BFD for a + * peer. + */ + bool manual; + /** Control Plane Independent. */ + bool cbit; + /** Detection multiplier. */ + uint8_t detection_multiplier; + /** Minimum required RX interval. */ + uint32_t min_rx; + /** Minimum required TX interval. */ + uint32_t min_tx; + /** Profile name. */ + char profile[BFD_PROFILE_NAME_LEN]; + /** Peer BFD session */ + struct bfd_session_params *session; + } * bfd_config; /* hostname and domainname advertised by host */ char *hostname;