diff options
48 files changed, 2149 insertions, 1322 deletions
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 11e9344d1c..f1bdcc8bb4 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,667 +41,391 @@ #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; + struct peer *peer = arg; + + if (BGP_DEBUG(bfd, BFD_LIB)) + 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)); + + 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(bfd, BFD_LIB)) + 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); + } - /* 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; + 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); + BGP_EVENT_ADD(peer, BGP_Start); + } + } } -/* - * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single - * hop. - */ -bool bgp_bfd_is_peer_multihop(struct peer *peer) +void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) { - struct bfd_info *bfd_info; + struct listnode *n; + struct peer *pn; + struct peer *gconfig; + + /* 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; + } - bfd_info = (struct bfd_info *)peer->bfd_info; + /* 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; + } - if (!bfd_info) - return false; + /* + * Check if the group configuration was overwritten or apply group + * configuration. + */ + gconfig = pg->conf; + + /* + * 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 ((bfd_info->type == BFD_TYPE_MULTIHOP) - || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network) - || is_ebgp_multihop_configured(peer)) - return true; + /* 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 - return false; + 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); } -/* - * 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) +void bgp_peer_bfd_update_source(struct peer *p) { - 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) + 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; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* 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(bfd, BFD_LIB)) + 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(bfd, BFD_LIB)) + 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; + } + } - vrf_id = peer->bgp->vrf_id; + /* Update interface. */ + if (p->nexthop.ifp && bfd_sess_interface(session) == NULL) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: interface none to %s", __func__, + p->nexthop.ifp->name); - 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); + bfd_sess_set_interface(session, p->nexthop.ifp->name); + changed = true; } - /* while graceful restart with fwd path preserved - * and bfd controlplane check not configured is not kept - * keep bfd independent controlplane bit set to 1 + + /* + * 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 (!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_IS_MULTIHOP(p) && bfd_sess_hop_count(session) > 1) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: TTL %d to 1", __func__, + bfd_sess_hop_count(session)); - 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); + bfd_sess_set_hop_count(session, 1); + changed = true; } + if (PEER_IS_MULTIHOP(p) && p->ttl != bfd_sess_hop_count(session)) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: TTL %d to %d", __func__, + bfd_sess_hop_count(session), p->ttl); - if (peer->nexthop.ifp) { - arg.ifnamelen = strlen(peer->nexthop.ifp->name); - strlcpy(arg.ifname, peer->nexthop.ifp->name, - sizeof(arg.ifname)); + bfd_sess_set_hop_count(session, p->ttl); + changed = true; } - if (bfd_info->profile[0]) { - arg.profilelen = strlen(bfd_info->profile); - strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile)); + /* Update VRF. */ + if (bfd_sess_vrf_id(session) != p->bgp->vrf_id) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug( + "%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; } - 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); + if (changed) + bfd_sess_install(session); } -/* - * bgp_bfd_register_peer - register a peer with BFD through zebra - * for monitoring the peer rechahability. +/** + * Reset BFD configuration data structure to its defaults settings. */ -void bgp_bfd_register_peer(struct peer *peer) +static void bgp_peer_bfd_reset(struct peer *p) { - 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); + /* 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; } -/** - * 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) +void bgp_peer_configure_bfd(struct peer *p, bool manual) { - struct bfd_info *bfd_info; + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (!peer->bfd_info) - return; - 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; - /* 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; + /* Allocate memory for configuration overrides. */ + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); + p->bfd_config->manual = manual; - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Create new session and assign callback. */ + p->bfd_config->session = bfd_sess_new(bfd_session_status_update, p); + bgp_peer_bfd_reset(p); - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; + /* 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); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE); -} + 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); -/** - * 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; + if (p->nexthop.ifp) + bfd_sess_set_interface(p->bfd_config->session, + p->nexthop.ifp->name); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); + bfd_sess_enable(p->bfd_config->session, true); } -/* - * bgp_bfd_update_type - update session type with BFD through zebra. - */ -static void bgp_bfd_update_type(struct peer *peer) +static void bgp_peer_remove_bfd(struct peer *p) { - struct bfd_info *bfd_info; - int multihop; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) + /* + * 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; - - 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; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Zebra: BFD Dest replay request"); - - /* 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; + bfd_sess_free(&p->bfd_config->session); + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); } -/* - * 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) +static void bgp_group_configure_bfd(struct peer *p) { - struct bfd_info *bfd_info; - int old_status; + struct listnode *n; + struct peer *pn; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (bfd_info->status == status) + /* Already allocated: do nothing. */ + if (p->bfd_config) return; - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); - bfd_info->last_update = bgp_clock(); + /* 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; - 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); - return; - } - peer->last_reset = PEER_DOWN_BFD_DOWN; - BGP_EVENT_ADD(peer, BGP_Stop); - } - if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN) - && peer->status != Established) { - if (!BGP_PEER_START_SUPPRESSED(peer)) { - bgp_fsm_nht_update(peer, true); - BGP_EVENT_ADD(peer, BGP_Start); - } - } + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) + bgp_peer_configure_bfd(pn, false); } -/* - * 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) +static void bgp_group_remove_bfd(struct peer *p) { - struct interface *ifp; - struct prefix dp; - struct prefix sp; - int status; - int remote_cbit; + struct listnode *n; + struct peer *pn; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, - &remote_cbit, vrf_id); + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (BGP_DEBUG(zebra, ZEBRA)) { - struct vrf *vrf; + /* Already freed: do nothing. */ + if (p->bfd_config == NULL) + return; - vrf = vrf_lookup_by_id(vrf_id); + /* Free configuration and point to `NULL`. */ + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); - if (ifp) - 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)" : ""); + /* 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 - 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)" : ""); - } - - /* 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; -} - -/* - * 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)); + bgp_peer_remove_bfd(pn); } - 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) +void bgp_peer_remove_bfd_config(struct peer *p) { - 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. - */ -static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile) -{ - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - struct bfd_info *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; - - /* 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 0; + 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 +437,17 @@ 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); + + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } @@ -745,89 +471,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; - - 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 <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>", - 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; + 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); - 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; - - ret = bgp_bfd_peer_param_type_set(peer, type); - if (ret != 0) - return bgp_vty_return(vty, ret); + bgp_peer_configure_bfd(peer, true); - 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; + 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); - 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 <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure", @@ -840,9 +507,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 +517,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 +549,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 <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>", - 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 +573,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 +601,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..9dca48a437 100644 --- a/bgpd/bgp_bfd.h +++ b/bgpd/bgp_bfd.h @@ -23,22 +23,58 @@ #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); +/** + * 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 void bgp_bfd_reset_peer(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); -extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, - char *addr); +/** + * Allocates and configure BFD session for peer. If it is already configured, + * then it does nothing. + * + * Always call `bgp_peer_config_apply` afterwards if you need the changes + * immediately applied. + */ +extern void bgp_peer_configure_bfd(struct peer *p, bool manual); -extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json, - json_object *json_neigh); +/** + * Removes BFD configuration from either peer or peer group. + */ +extern void bgp_peer_remove_bfd_config(struct peer *p); -extern bool bgp_bfd_is_peer_multihop(struct peer *peer); +/** + * 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_debug.c b/bgpd/bgp_debug.c index 3afa6eaf09..ce1b7b552b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -21,6 +21,7 @@ #include <zebra.h> #include <lib/version.h> +#include "lib/bfd.h" #include "lib/printfrr.h" #include "prefix.h" #include "linklist.h" @@ -67,6 +68,7 @@ unsigned long conf_bgp_debug_labelpool; unsigned long conf_bgp_debug_pbr; unsigned long conf_bgp_debug_graceful_restart; unsigned long conf_bgp_debug_evpn_mh; +unsigned long conf_bgp_debug_bfd; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_neighbor_events; @@ -86,6 +88,7 @@ unsigned long term_bgp_debug_labelpool; unsigned long term_bgp_debug_pbr; unsigned long term_bgp_debug_graceful_restart; unsigned long term_bgp_debug_evpn_mh; +unsigned long term_bgp_debug_bfd; struct list *bgp_debug_neighbor_events_peers = NULL; struct list *bgp_debug_keepalive_peers = NULL; @@ -2093,6 +2096,31 @@ DEFUN (no_debug_bgp_labelpool, return CMD_SUCCESS; } +DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd, + "[no] debug bgp bfd", + NO_STR + DEBUG_STR + BGP_STR + "Bidirection Forwarding Detection\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) { + DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + } else { + DEBUG_ON(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(true); + } + } else { + if (no) + TERM_DEBUG_OFF(bfd, BFD_LIB); + else + TERM_DEBUG_ON(bfd, BFD_LIB); + } + + return CMD_SUCCESS; +} + DEFUN (no_debug_bgp, no_debug_bgp_cmd, "no debug bgp", @@ -2136,6 +2164,7 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES); TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT); + TERM_DEBUG_OFF(bfd, BFD_LIB); vty_out(vty, "All possible debugging has been turned off\n"); @@ -2225,6 +2254,9 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) vty_out(vty, " BGP EVPN-MH route debugging is on\n"); + if (BGP_DEBUG(bfd, BFD_LIB)) + vty_out(vty, " BGP BFD library debugging is on\n"); + vty_out(vty, "\n"); return CMD_SUCCESS; } @@ -2350,6 +2382,11 @@ static int bgp_config_write_debug(struct vty *vty) write++; } + if (CONF_BGP_DEBUG(bfd, BFD_LIB)) { + vty_out(vty, "debug bgp bfd\n"); + write++; + } + return write; } @@ -2478,6 +2515,10 @@ void bgp_debug_init(void) install_element(ENABLE_NODE, &debug_bgp_evpn_mh_cmd); install_element(CONFIG_NODE, &debug_bgp_evpn_mh_cmd); + + /* debug bgp bfd */ + install_element(ENABLE_NODE, &debug_bgp_bfd_cmd); + install_element(CONFIG_NODE, &debug_bgp_bfd_cmd); } /* Return true if this prefix is on the per_prefix_list of prefixes to debug diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index f16cfee4f2..fa8da1c345 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -78,6 +78,7 @@ extern unsigned long conf_bgp_debug_labelpool; extern unsigned long conf_bgp_debug_pbr; extern unsigned long conf_bgp_debug_graceful_restart; extern unsigned long conf_bgp_debug_evpn_mh; +extern unsigned long conf_bgp_debug_bfd; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_neighbor_events; @@ -95,6 +96,7 @@ extern unsigned long term_bgp_debug_labelpool; extern unsigned long term_bgp_debug_pbr; extern unsigned long term_bgp_debug_graceful_restart; extern unsigned long term_bgp_debug_evpn_mh; +extern unsigned long term_bgp_debug_bfd; extern struct list *bgp_debug_neighbor_events_peers; extern struct list *bgp_debug_keepalive_peers; @@ -139,6 +141,8 @@ struct bgp_debug_filter { #define BGP_DEBUG_GRACEFUL_RESTART 0x01 +#define BGP_DEBUG_BFD_LIB 0x01 + #define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) #define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ec71264081..cebc1c4d22 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2235,6 +2235,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) int ret; struct prefix_evpn p; + update_type1_routes_for_evi(bgp, vpn); + /* Update and advertise the type-3 route (only one) followed by the * locally learnt type-2 routes (MACIP) - for this VNI. * @@ -3136,7 +3138,7 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) return ret; ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 1); + 0); if (ret) return ret; diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 123c46f12f..826de21b9d 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -970,6 +970,48 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, return 0; } +/* + * This function is called when the export RT for a VNI changes. + * Update all type-1 local routes for this VNI from VNI/ES tables and the global + * table and advertise these routes to peers. + */ + +void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn) +{ + struct prefix_evpn p; + struct bgp_evpn_es *es; + struct bgp_evpn_es_evi *es_evi; + struct bgp_evpn_es_evi *es_evi_next; + + RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head, + &vpn->es_evi_rb_tree, es_evi_next) { + es = es_evi->es; + + /* Update EAD-ES */ + if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { + build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, + &es->esi, es->originator_ip); + if (bgp_evpn_type1_route_update(bgp, es, NULL, &p)) + flog_err(EC_BGP_EVPN_ROUTE_CREATE, + "%u: EAD-ES route update failure for ESI %s VNI %u", + bgp->vrf_id, es->esi_str, + es_evi->vpn->vni); + } + + /* Update EAD-EVI */ + if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) { + build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG, + &es->esi, es->originator_ip); + if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, + &p)) + flog_err(EC_BGP_EVPN_ROUTE_DELETE, + "%u: EAD-EVI route update failure for ESI %s VNI %u", + bgp->vrf_id, es->esi_str, + es_evi->vpn->vni); + } + } +} + /* Delete local Type-1 route */ static int bgp_evpn_type1_es_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, struct prefix_evpn *p) diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index 1053e3f022..8c66e391b6 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -335,6 +335,7 @@ extern int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es, afi_t afi, safi_t safi, struct prefix_evpn *evp, struct bgp_path_info *pi, int install); +extern void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn); int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi, struct attr *attr, uint8_t *pfx, int psize, uint32_t addpath_id); 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/bgp_zebra.c b/bgpd/bgp_zebra.c index afdd5123fb..0a12e719ce 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -283,20 +283,9 @@ static int bgp_ifp_down(struct interface *ifp) if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { -#if defined(HAVE_CUMULUS) - /* Take down directly connected EBGP peers as well as - * 1-hop BFD - * tracked (directly connected) IBGP peers. - */ - if ((peer->ttl != BGP_DEFAULT_TTL) - && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED) - && (!peer->bfd_info - || bgp_bfd_is_peer_multihop(peer))) -#else - /* Take down directly connected EBGP peers */ + /* Take down directly connected peers. */ if ((peer->ttl != BGP_DEFAULT_TTL) && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED)) -#endif continue; if (ifp == peer->nexthop.ifp) { 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; diff --git a/configure.ac b/configure.ac index 44d68f4845..f9516e559f 100755 --- a/configure.ac +++ b/configure.ac @@ -288,11 +288,17 @@ if test "$enable_clang_coverage" = "yes"; then fi if test "$enable_scripting" = "yes"; then - AX_PROG_LUA([5.3]) - AX_LUA_HEADERS + AX_PROG_LUA([5.3], [5.4], [], [ + AC_MSG_ERROR([Lua 5.3 is required to build with Lua support. No other version is supported.]) + ]) + AX_LUA_HEADERS([], [ + AC_MSG_ERROR([Lua 5.3 headers are required to build with Lua support. No other version is supported.]) + ]) AX_LUA_LIBS([ - AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting]) - LIBS="$LIBS $LUA_LIB" + AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting]) + LIBS="$LIBS $LUA_LIB" + ], [ + AC_MSG_ERROR([Lua 5.3 libraries are required to build with Lua support. No other version is supported.]) ]) fi diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 7d136b183e..6f797f7cc1 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -313,6 +313,11 @@ The following commands are available inside the interface configuration node. a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. +.. clicmd:: ip ospf bfd profile BFDPROF + + Same as command ``ip ospf bfd``, but applies the BFD profile to the sessions + it creates or that already exist. + .. _bfd-ospf6-peer-config: diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 6c0a4306f4..4433dc9e21 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2916,6 +2916,12 @@ Debugging Display Listen sockets and the vrf that created them. Useful for debugging of when listen is not working and this is considered a developer debug statement. +.. clicmd:: debug bgp bfd + + Enable or disable debugging for BFD events. This will show BFD integration + library messages and BGP BFD integration messages that are mostly state + transitions and validation problems. + .. clicmd:: debug bgp neighbor-events Enable or disable debugging for neighbor events. This provides general diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 00571487d7..607acd3706 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -229,7 +229,6 @@ Showing OSPF6 information Interface name can also be given. JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 spf tree [json] .. clicmd:: show ipv6 ospf6 spf tree [json] This commands shows the spf tree from the recent spf calculation with the @@ -237,7 +236,7 @@ Showing OSPF6 information tree in JSON format. Each area that the router belongs to has it's own JSON object, with each router having "cost", "isLeafNode" and "children" as arguments. - + OSPF6 Configuration Examples ============================ diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 8689bc4ccb..64ce85503e 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -733,23 +733,25 @@ Showing Information Json o/p of this command covers base route information i.e all LSAs except opaque lsa info. -.. clicmd:: show ip ospf database [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) self-originate [json] -.. clicmd:: show ip ospf database max-age [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database max-age [json] -.. clicmd:: show ip ospf database self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database self-originate [json] + + Show the OSPF database summary. .. clicmd:: show ip ospf route [json] @@ -780,17 +782,17 @@ Opaque LSA extensions that are used with MPLS-TE; it does not support a complete RSVP-TE solution. -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) self-originate Show Opaque LSA from the database. @@ -966,6 +968,12 @@ TI-LFA requires a proper Segment Routing configuration. Debugging OSPF ============== +.. clicmd:: debug ospf bfd + + Enable or disable debugging for BFD events. This will show BFD integration + library messages and OSPF BFD integration messages that are mostly state + transitions and validation problems. + .. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 039483b9b2..b108210686 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -392,7 +392,7 @@ void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, if (!yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); - vty_out(vty, " ip router isis %s ", + vty_out(vty, " ip router isis %s", yang_dnode_get_string(dnode, "../area-tag")); if (!strmatch(vrf, VRF_DEFAULT_NAME)) vty_out(vty, " vrf %s", vrf); @@ -27,6 +27,7 @@ #include "prefix.h" #include "thread.h" #include "stream.h" +#include "vrf.h" #include "zclient.h" #include "table.h" #include "vty.h" @@ -568,3 +569,640 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) return 0; } + +/** + * BFD protocol integration configuration. + */ + +/** Events definitions. */ +enum bfd_session_event { + /** Remove the BFD session configuration. */ + BSE_UNINSTALL, + /** Install the BFD session configuration. */ + BSE_INSTALL, +}; + +/** + * Data structure to do the necessary tricks to hide the BFD protocol + * integration internals. + */ +struct bfd_session_params { + /** Contains the session parameters and more. */ + struct bfd_session_arg args; + /** Contains the session state. */ + struct bfd_session_status bss; + /** Protocol implementation status update callback. */ + bsp_status_update updatecb; + /** Protocol implementation custom data pointer. */ + void *arg; + + /** + * Next event. + * + * This variable controls what action to execute when the command batch + * finishes. Normally we'd use `thread_add_event` value, however since + * that function is going to be called multiple times and the value + * might be different we'll use this variable to keep track of it. + */ + enum bfd_session_event lastev; + /** + * BFD session configuration event. + * + * Multiple actions might be asked during a command batch (either via + * configuration load or northbound batch), so we'll use this to + * install/uninstall the BFD session parameters only once. + */ + struct thread *installev; + + /** BFD session installation state. */ + bool installed; + /** BFD session enabled. */ + bool enabled; + + /** Global BFD paramaters list. */ + TAILQ_ENTRY(bfd_session_params) entry; +}; + +struct bfd_sessions_global { + /** + * Global BFD session parameters list for (re)installation and update + * without code duplication among daemons. + */ + TAILQ_HEAD(bsplist, bfd_session_params) bsplist; + + /** Pointer to FRR's event manager. */ + struct thread_master *tm; + /** Pointer to zebra client data structure. */ + struct zclient *zc; + + /** Debugging state. */ + bool debugging; + /** Is shutting down? */ + bool shutting_down; +}; + +/** Global configuration variable. */ +static struct bfd_sessions_global bsglobal; + +/** Global empty address for IPv4/IPv6. */ +static const struct in6_addr i6a_zero; + +struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg) +{ + struct bfd_session_params *bsp; + + bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp)); + + /* Save application data. */ + bsp->updatecb = updatecb; + bsp->arg = arg; + + /* Set defaults. */ + bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT; + bsp->args.ttl = BFD_SINGLE_HOP_TTL; + bsp->args.min_rx = BFD_DEF_MIN_RX; + bsp->args.min_tx = BFD_DEF_MIN_TX; + bsp->args.vrf_id = VRF_DEFAULT; + + /* Register in global list. */ + TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry); + + return bsp; +} + +static bool _bfd_sess_valid(const struct bfd_session_params *bsp) +{ + /* Peer/local address not configured. */ + if (bsp->args.family == 0) + return false; + + /* Address configured but invalid. */ + if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) { + if (bsglobal.debugging) + zlog_debug("%s: invalid session family: %d", __func__, + bsp->args.family); + return false; + } + + /* Invalid address. */ + if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) { + if (bsglobal.debugging) { + if (bsp->args.family == AF_INET) + zlog_debug("%s: invalid address: %pI4", + __func__, + (struct in_addr *)&bsp->args.dst); + else + zlog_debug("%s: invalid address: %pI6", + __func__, &bsp->args.dst); + } + return false; + } + + /* Multi hop requires local address. */ + if (bsp->args.mhop + && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) { + if (bsglobal.debugging) + zlog_debug( + "%s: multi hop but no local address provided", + __func__); + return false; + } + + /* Check VRF ID. */ + if (bsp->args.vrf_id == VRF_UNKNOWN) { + if (bsglobal.debugging) + zlog_debug("%s: asked for unknown VRF", __func__); + return false; + } + + return true; +} + +static int _bfd_sess_send(struct thread *t) +{ + struct bfd_session_params *bsp = THREAD_ARG(t); + int rv; + + /* Validate configuration before trying to send bogus data. */ + if (!_bfd_sess_valid(bsp)) + return 0; + + if (bsp->lastev == BSE_INSTALL) { + bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE + : ZEBRA_BFD_DEST_REGISTER; + } else + bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER; + + /* If not installed and asked for uninstall, do nothing. */ + if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) + return 0; + + rv = zclient_bfd_command(bsglobal.zc, &bsp->args); + /* Command was sent successfully. */ + if (rv == 0) { + /* Update installation status. */ + if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) + bsp->installed = false; + else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER) + bsp->installed = true; + } + + return 0; +} + +static void _bfd_sess_remove(struct bfd_session_params *bsp) +{ + /* Not installed, nothing to do. */ + if (!bsp->installed) + return; + + /* Cancel any pending installation request. */ + THREAD_OFF(bsp->installev); + + /* Send request to remove any session. */ + bsp->lastev = BSE_UNINSTALL; + thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); +} + +void bfd_sess_free(struct bfd_session_params **bsp) +{ + if (*bsp == NULL) + return; + + /* Remove any installed session. */ + _bfd_sess_remove(*bsp); + + /* Remove from global list. */ + TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry); + + /* Free the memory and point to NULL. */ + XFREE(MTYPE_BFD_INFO, (*bsp)); +} + +void bfd_sess_enable(struct bfd_session_params *bsp, bool enable) +{ + /* Remove the session when disabling. */ + if (!enable) + _bfd_sess_remove(bsp); + + bsp->enabled = enable; +} + +void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, + struct in_addr *src, struct in_addr *dst) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.family = AF_INET; + + /* Clean memory, set zero value and avoid static analyser warnings. */ + memset(&bsp->args.src, 0, sizeof(bsp->args.src)); + memset(&bsp->args.dst, 0, sizeof(bsp->args.dst)); + + /* Copy the equivalent of IPv4 to arguments structure. */ + if (src) + memcpy(&bsp->args.src, src, sizeof(struct in_addr)); + + assert(dst); + memcpy(&bsp->args.dst, dst, sizeof(struct in_addr)); +} + +void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, + struct in6_addr *src, struct in6_addr *dst) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.family = AF_INET6; + + /* Clean memory, set zero value and avoid static analyser warnings. */ + memset(&bsp->args.src, 0, sizeof(bsp->args.src)); + + if (src) + bsp->args.src = *src; + + assert(dst); + bsp->args.dst = *dst; +} + +void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + if (ifname == NULL) { + bsp->args.ifname[0] = 0; + bsp->args.ifnamelen = 0; + return; + } + + if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname)) + > sizeof(bsp->args.ifname)) + zlog_warn("%s: interface name truncated: %s", __func__, ifname); + + bsp->args.ifnamelen = strlen(bsp->args.ifname); +} + +void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile) +{ + if (profile == NULL) { + bsp->args.profile[0] = 0; + bsp->args.profilelen = 0; + return; + } + + if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile)) + > sizeof(bsp->args.profile)) + zlog_warn("%s: profile name truncated: %s", __func__, profile); + + bsp->args.profilelen = strlen(bsp->args.profile); +} + +void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.vrf_id = vrf_id; +} + +void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) +{ + assert(min_ttl != 0); + + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + /* Invert TTL value: protocol expects number of hops. */ + min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl; + bsp->args.ttl = min_ttl; + bsp->args.mhop = (min_ttl > 1); +} + +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.ttl = min_ttl; + bsp->args.mhop = (min_ttl > 1); +} + + +void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable) +{ + bsp->args.cbit = enable; +} + +void bfd_sess_set_timers(struct bfd_session_params *bsp, + uint8_t detection_multiplier, uint32_t min_rx, + uint32_t min_tx) +{ + bsp->args.detection_multiplier = detection_multiplier; + bsp->args.min_rx = min_rx; + bsp->args.min_tx = min_tx; +} + +void bfd_sess_install(struct bfd_session_params *bsp) +{ + /* Don't attempt to install/update when disabled. */ + if (!bsp->enabled) + return; + + bsp->lastev = BSE_INSTALL; + thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); +} + +void bfd_sess_uninstall(struct bfd_session_params *bsp) +{ + bsp->lastev = BSE_UNINSTALL; + thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); +} + +enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp) +{ + return bsp->bss.state; +} + +uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp) +{ + return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl); +} + +uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp) +{ + return bsp->args.ttl; +} + +const char *bfd_sess_profile(const struct bfd_session_params *bsp) +{ + return bsp->args.profilelen ? bsp->args.profile : NULL; +} + +void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family, + struct in6_addr *src, struct in6_addr *dst) +{ + *family = bsp->args.family; + if (src) + *src = bsp->args.src; + if (dst) + *dst = bsp->args.dst; +} + +const char *bfd_sess_interface(const struct bfd_session_params *bsp) +{ + if (bsp->args.ifnamelen) + return bsp->args.ifname; + + return NULL; +} + +const char *bfd_sess_vrf(const struct bfd_session_params *bsp) +{ + return vrf_id_to_name(bsp->args.vrf_id); +} + +vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp) +{ + return bsp->args.vrf_id; +} + +bool bfd_sess_cbit(const struct bfd_session_params *bsp) +{ + return bsp->args.cbit; +} + +void bfd_sess_timers(const struct bfd_session_params *bsp, + uint8_t *detection_multiplier, uint32_t *min_rx, + uint32_t *min_tx) +{ + *detection_multiplier = bsp->args.detection_multiplier; + *min_rx = bsp->args.min_rx; + *min_tx = bsp->args.min_tx; +} + +void bfd_sess_show(struct vty *vty, struct json_object *json, + struct bfd_session_params *bsp) +{ + json_object *json_bfd = NULL; + char time_buf[64]; + + /* Show type. */ + if (json) { + json_bfd = json_object_new_object(); + if (bsp->args.mhop) + json_object_string_add(json_bfd, "type", "multi hop"); + else + json_object_string_add(json_bfd, "type", "single hop"); + } else + vty_out(vty, " BFD: Type: %s\n", + bsp->args.mhop ? "multi hop" : "single hop"); + + /* Show configuration. */ + if (json) { + json_object_int_add(json_bfd, "detectMultiplier", + bsp->args.detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + bsp->args.min_rx); + json_object_int_add(json_bfd, "txMinInterval", + bsp->args.min_tx); + } else { + vty_out(vty, + " Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + bsp->args.detection_multiplier, bsp->args.min_rx, + bsp->args.min_tx); + } + + bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf)); + if (json) { + json_object_string_add(json_bfd, "status", + bfd_get_status_str(bsp->bss.state)); + json_object_string_add(json_bfd, "lastUpdate", time_buf); + } else + vty_out(vty, " Status: %s, Last update: %s\n", + bfd_get_status_str(bsp->bss.state), time_buf); + + if (json) + json_object_object_add(json, "peerBfdInfo", json_bfd); + else + vty_out(vty, "\n"); +} + +/* + * Zebra communication related. + */ + +/** + * Callback for reinstallation of all registered BFD sessions. + * + * Use this as `zclient` `bfd_dest_replay` callback. + */ +static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) +{ + struct bfd_session_params *bsp; + + /* Do nothing when shutting down. */ + if (bsglobal.shutting_down) + return 0; + + if (bsglobal.debugging) + zlog_debug("%s: sending all sessions registered", __func__); + + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); + + /* Replay all activated peers. */ + TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { + /* Skip disabled sessions. */ + if (!bsp->enabled) + continue; + + /* We are reconnecting, so we must send installation. */ + bsp->installed = false; + + /* Cancel any pending installation request. */ + THREAD_OFF(bsp->installev); + + /* Ask for installation. */ + bsp->lastev = BSE_INSTALL; + thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); + } + + return 0; +} + +static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) +{ + struct bfd_session_params *bsp; + size_t sessions_updated = 0; + struct interface *ifp; + int remote_cbit = false; + int state = BFD_STATUS_UNKNOWN; + time_t now; + size_t addrlen; + struct prefix dp; + struct prefix sp; + char ifstr[128], cbitstr[32]; + + /* Do nothing when shutting down. */ + if (bsglobal.shutting_down) + return 0; + + ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, + vrf_id); + + if (bsglobal.debugging) { + ifstr[0] = 0; + if (ifp) + snprintf(ifstr, sizeof(ifstr), " (interface %s)", + ifp->name); + + snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)", + remote_cbit ? "yes" : "no"); + + zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp, + &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr, + bfd_get_status_str(state)); + } + + switch (dp.family) { + case AF_INET: + addrlen = sizeof(struct in_addr); + break; + case AF_INET6: + addrlen = sizeof(struct in6_addr); + break; + + default: + /* Unexpected value. */ + assert(0); + break; + } + + /* Cache current time to avoid multiple monotime clock calls. */ + now = monotime(NULL); + + /* Notify all matching sessions about update. */ + TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { + /* Skip disabled or not installed entries. */ + if (!bsp->enabled || !bsp->installed) + continue; + /* Skip different VRFs. */ + if (bsp->args.vrf_id != vrf_id) + continue; + /* Skip different families. */ + if (bsp->args.family != dp.family) + continue; + /* Skip different interface. */ + if (bsp->args.ifnamelen && ifp + && strcmp(bsp->args.ifname, ifp->name) != 0) + continue; + /* Skip non matching destination addresses. */ + if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0) + continue; + /* + * Source comparison test: + * We will only compare source if BFD daemon provided the + * source address and the protocol set a source address in + * the configuration otherwise we'll just skip it. + */ + if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0 + && memcmp(&sp.u, &i6a_zero, addrlen) != 0 + && memcmp(&bsp->args.src, &sp.u, addrlen) != 0) + continue; + /* No session state change. */ + if ((int)bsp->bss.state == state) + continue; + + bsp->bss.last_event = now; + bsp->bss.previous_state = bsp->bss.state; + bsp->bss.state = state; + bsp->bss.remote_cbit = remote_cbit; + bsp->updatecb(bsp, &bsp->bss, bsp->arg); + sessions_updated++; + } + + if (bsglobal.debugging) + zlog_debug("%s: sessions updated: %zu", __func__, + sessions_updated); + + return 0; +} + +void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm) +{ + /* Initialize data structure. */ + TAILQ_INIT(&bsglobal.bsplist); + + /* Copy pointers. */ + bsglobal.zc = zc; + bsglobal.tm = tm; + + /* Install our callbacks. */ + zc->interface_bfd_dest_update = zclient_bfd_session_update; + zc->bfd_dest_replay = zclient_bfd_session_reply; + + /* Send the client registration */ + bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); +} + +void bfd_protocol_integration_set_debug(bool enable) +{ + bsglobal.debugging = enable; +} + +void bfd_protocol_integration_set_shutdown(bool enable) +{ + bsglobal.shutting_down = enable; +} + +bool bfd_protocol_integration_debug(void) +{ + return bsglobal.debugging; +} + +bool bfd_protocol_integration_shutting_down(void) +{ + return bsglobal.shutting_down; +} @@ -128,6 +128,305 @@ extern void bfd_gbl_exit(void); * BFD new API. */ +/* Forward declaration of argument struct. */ +struct bfd_session_params; + +/** Session state definitions. */ +enum bfd_session_state { + /** Session state is unknown or not initialized. */ + BSS_UNKNOWN = BFD_STATUS_UNKNOWN, + /** Local or remote peer administratively shutdown the session. */ + BSS_ADMIN_DOWN = BFD_STATUS_ADMIN_DOWN, + /** Session is down. */ + BSS_DOWN = BFD_STATUS_DOWN, + /** Session is up and working correctly. */ + BSS_UP = BFD_STATUS_UP, +}; + +/** BFD session status information */ +struct bfd_session_status { + /** Current session state. */ + enum bfd_session_state state; + /** Previous session state. */ + enum bfd_session_state previous_state; + /** Remote Control Plane Independent bit state. */ + bool remote_cbit; + /** Last event occurrence. */ + time_t last_event; +}; + +/** + * Session status update callback. + * + * \param bsp BFD session parameters. + * \param bss BFD session status. + * \param arg application independent data. + */ +typedef void (*bsp_status_update)(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg); + +/** + * Allocates and initializes the session parameters. + * + * \param updatedb status update notification callback. + * \param args application independent data. + * + * \returns pointer to configuration storage. + */ +struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args); + +/** + * Uninstall session if installed and free resources allocated by the + * parameters. Already sets pointer to `NULL` to avoid dangling references. + * + * \param bsp session parameters. + */ +void bfd_sess_free(struct bfd_session_params **bsp); + +/** + * Enable/disable session installation. + * + * \param bsp session parameters. + * \param enable knob variable. + */ +void bfd_sess_enable(struct bfd_session_params *bsp, bool enable); + +/** + * Set the local and peer address of the BFD session. + * + * \param bsp BFD session parameters. + * \param src local address (optional, can be `NULL`). + * \param dst remote address (mandatory). + */ +void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, + struct in_addr *src, struct in_addr *dst); + +/** + * Set the local and peer address of the BFD session. + * + * \param bsp BFD session parameters. + * \param src local address (optional, can be `NULL`). + * \param dst remote address (mandatory). + */ +void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, + struct in6_addr *src, struct in6_addr *dst); + +/** + * Configure the BFD session interface. + * + * \param bsp BFD session parameters. + * \param ifname interface name (or `NULL` to remove it). + */ +void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname); + +/** + * Configure the BFD session profile name. + * + * \param bsp BFD session parameters. + * \param profile profile name (or `NULL` to remove it). + */ +void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile); + +/** + * Configure the BFD session VRF. + * + * \param bsp BFD session parameters. + * \param vrf_id the VRF identification number. + */ +void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id); + +/** + * Configure the BFD session single/multi hop setting. + * + * \param bsp BFD session parameters. + * \param min_ttl minimum TTL value expected (255 for single hop, 254 for + * multi hop with single hop, 253 for multi hop with two hops + * and so on). See `BFD_SINGLE_HOP_TTL` and + * `BFD_MULTI_HOP_MIN_TTL` for defaults. + * + * To simplify things if your protocol only knows the amount of hops it is + * better to use `bfd_sess_set_hops` instead. + */ +void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl); + +/** To use single hop the minimum TTL must be set to this. */ +#define BFD_SINGLE_HOP_TTL 255 +/** To use multi hop the minimum TTL must be set to this or less. */ +#define BFD_MULTI_HOP_MIN_TTL 254 + +/** + * This function is the inverted version of `bfd_sess_set_minimum_ttl`. + * Instead of receiving the minimum expected TTL, it receives the amount of + * hops the protocol will jump. + * + * \param bsp BFD session parameters. + * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or + * more for multi hop). + */ +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl); + +/** + * Configure the BFD session to set the Control Plane Independent bit. + * + * \param bsp BFD session parameters. + * \param enable BFD Control Plane Independent state. + */ +void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable); + +/** + * DEPRECATED: please avoid using timers directly and use profiles instead. + * + * Configures the BFD session timers to use. This is specially useful with + * `ptm-bfd` which does not support timers. + * + * \param bsp BFD session parameters. + * \param detection_multiplier the detection multiplier value. + * \param min_rx minimum required receive period. + * \param min_tx minimum required transmission period. + */ +void bfd_sess_set_timers(struct bfd_session_params *bsp, + uint8_t detection_multiplier, uint32_t min_rx, + uint32_t min_tx); + +/** + * Installs or updates the BFD session based on the saved session arguments. + * + * \param bsp session parameters. + */ +void bfd_sess_install(struct bfd_session_params *bsp); + +/** + * Uninstall the BFD session based on the saved session arguments. + * + * \param bsp session parameters. + */ +void bfd_sess_uninstall(struct bfd_session_params *bsp); + +/** + * Get BFD session current status. + * + * \param bsp session parameters. + * + * \returns BFD session status data structure. + */ +enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp); + +/** + * Get BFD session minimum TTL configured value. + * + * \param bsp session parameters. + * + * \returns configured minimum TTL. + */ +uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp); + +/** + * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the + * way to the peer. + * + * \param bsp session parameters. + * + * \returns configured amount of hops. + */ +uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp); + +/** + * Get BFD session profile configured value. + * + * \param bsp session parameters. + * + * \returns configured profile name (or `NULL` if empty). + */ +const char *bfd_sess_profile(const struct bfd_session_params *bsp); + +/** + * Get BFD session addresses. + * + * \param bsp session parameters. + * \param family the address family being used (AF_INET or AF_INET6). + * \param src source address (optional, may be `NULL`). + * \param dst peer address (optional, may be `NULL`). + */ +void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family, + struct in6_addr *src, struct in6_addr *dst); +/** + * Get BFD session interface name. + * + * \param bsp session parameters. + * + * \returns `NULL` if not set otherwise the interface name. + */ +const char *bfd_sess_interface(const struct bfd_session_params *bsp); + +/** + * Get BFD session VRF name. + * + * \param bsp session parameters. + * + * \returns the VRF name. + */ +const char *bfd_sess_vrf(const struct bfd_session_params *bsp); + +/** + * Get BFD session VRF ID. + * + * \param bsp session parameters. + * + * \returns the VRF name. + */ +vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp); + +/** + * Get BFD session control plane independent bit configuration state. + * + * \param bsp session parameters. + * + * \returns `true` if enabled otherwise `false`. + */ +bool bfd_sess_cbit(const struct bfd_session_params *bsp); + +/** + * DEPRECATED: please avoid using timers directly and use profiles instead. + * + * Gets the configured timers. + * + * \param bsp BFD session parameters. + * \param detection_multiplier the detection multiplier value. + * \param min_rx minimum required receive period. + * \param min_tx minimum required transmission period. + */ +void bfd_sess_timers(const struct bfd_session_params *bsp, + uint8_t *detection_multiplier, uint32_t *min_rx, + uint32_t *min_tx); + +/** + * Show BFD session configuration and status. If `json` is provided (e.g. not + * `NULL`) then information will be inserted in object, otherwise printed to + * `vty`. + * + * \param vty Pointer to `vty` for outputting text. + * \param json (optional) JSON object pointer. + * \param bsp session parameters. + */ +void bfd_sess_show(struct vty *vty, struct json_object *json, + struct bfd_session_params *bsp); + +/** + * Initializes the BFD integration library. This function executes the + * following actions: + * + * - Copy the `struct thread_master` pointer to use as "thread" to execute + * the BFD session parameters installation. + * - Copy the `struct zclient` pointer to install its callbacks. + * - Initializes internal data structures. + * + * \param tm normally the daemon main thread event manager. + * \param zc the zebra client of the daemon. + */ +void bfd_protocol_integration_init(struct zclient *zc, + struct thread_master *tm); + /** * BFD session registration arguments. */ @@ -205,6 +504,34 @@ struct bfd_session_arg { */ extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg); +/** + * Enables or disables BFD protocol integration API debugging. + * + * \param enable new API debug state. + */ +extern void bfd_protocol_integration_set_debug(bool enable); + +/** + * Sets shutdown mode so no more events are processed. + * + * This is useful to avoid the event storm that happens caused by network, + * interfaces or VRFs removal. It should also avoid some crashes due hanging + * pointers left overs by protocol. + * + * \param enable new API shutdown state. + */ +extern void bfd_protocol_integration_set_shutdown(bool enable); + +/** + * Get API debugging state. + */ +extern bool bfd_protocol_integration_debug(void); + +/** + * Get API shutdown state. + */ +extern bool bfd_protocol_integration_shutting_down(void); + #ifdef __cplusplus } #endif diff --git a/lib/log_vty.c b/lib/log_vty.c index 7dadca8059..c26621ae99 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -532,6 +532,28 @@ DEFUN (no_config_log_timestamp_precision, return CMD_SUCCESS; } +DEFPY (config_log_ec, + config_log_ec_cmd, + "[no] log error-category", + NO_STR + "Logging control\n" + "Prefix log message text with [EC 9999] code\n") +{ + zlog_set_prefix_ec(!no); + return CMD_SUCCESS; +} + +DEFPY (config_log_xid, + config_log_xid_cmd, + "[no] log unique-id", + NO_STR + "Logging control\n" + "Prefix log message text with [XXXXX-XXXXX] identifier\n") +{ + zlog_set_prefix_xid(!no); + return CMD_SUCCESS; +} + DEFPY (config_log_filterfile, config_log_filterfile_cmd, "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]", @@ -699,6 +721,11 @@ void log_config_write(struct vty *vty) if (zt_file.ts_subsec > 0) vty_out(vty, "log timestamp precision %d\n", zt_file.ts_subsec); + + if (!zlog_get_prefix_ec()) + vty_out(vty, "no log error-category\n"); + if (!zlog_get_prefix_xid()) + vty_out(vty, "no log unique-id\n"); } static int log_vty_init(const char *progname, const char *protoname, @@ -707,6 +734,9 @@ static int log_vty_init(const char *progname, const char *protoname, zlog_progname = progname; zlog_protoname = protoname; + zlog_set_prefix_ec(true); + zlog_set_prefix_xid(true); + zlog_filterfile_init(&zt_filterfile); zlog_file_set_fd(&zt_stdout, STDOUT_FILENO); @@ -737,6 +767,8 @@ void log_cmd_init(void) install_element(CONFIG_NODE, &no_config_log_record_priority_cmd); install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd); install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd); + install_element(CONFIG_NODE, &config_log_ec_cmd); + install_element(CONFIG_NODE, &config_log_xid_cmd); install_element(VIEW_NODE, &show_log_filter_cmd); install_element(CONFIG_NODE, &log_filter_cmd); diff --git a/lib/northbound.c b/lib/northbound.c index 27ba632c9d..34ad5dbfa9 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -1260,27 +1260,36 @@ static int nb_callback_configuration(struct nb_context *context, } if (ret != NB_OK) { - int priority; - enum lib_log_refs ref; - yang_dnode_get_path(dnode, xpath, sizeof(xpath)); switch (event) { case NB_EV_VALIDATE: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_VALIDATE; + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_PREPARE: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_PREPARE; + flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_ABORT: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_ABORT; + flog_warn(EC_LIB_NB_CB_CONFIG_ABORT, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_APPLY: - priority = LOG_ERR; - ref = EC_LIB_NB_CB_CONFIG_APPLY; + flog_err(EC_LIB_NB_CB_CONFIG_APPLY, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; default: flog_err(EC_LIB_DEVELOPMENT, @@ -1288,15 +1297,6 @@ static int nb_callback_configuration(struct nb_context *context, event, xpath); exit(1); } - - flog(priority, ref, - "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]", - nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath); - if (strlen(errmsg) > 0) - flog(priority, ref, - "error processing configuration change: %s", - errmsg); } return ret; diff --git a/lib/printfrr.h b/lib/printfrr.h index a775e1517b..418e839d97 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -160,6 +160,30 @@ void printfrr_ext_reg(const struct printfrr_ext *); } \ /* end */ +/* fbuf helper functions */ + +static inline ssize_t bputs(struct fbuf *buf, const char *str) +{ + size_t len = strlen(str); + size_t ncopy; + + if (!buf) + return len; + + ncopy = MIN(len, (size_t)(buf->buf + buf->len - buf->pos)); + memcpy(buf->pos, str, ncopy); + buf->pos += ncopy; + + return len; +} + +static inline ssize_t bputch(struct fbuf *buf, char ch) +{ + if (buf && buf->pos < buf->buf + buf->len) + *buf->pos++ = ch; + return 1; +} + #ifdef __cplusplus } #endif diff --git a/lib/xref.c b/lib/xref.c index 40efe51363..a41f91a228 100644 --- a/lib/xref.c +++ b/lib/xref.c @@ -93,8 +93,6 @@ static void xref_add_one(const struct xref *xref) q = memrchr(filename, '/', p - filename); if (q) filename = q + 1; - else - filename = p + 1; } SHA256_Init(&sha); diff --git a/lib/zlog.c b/lib/zlog.c index 7304854648..f546709328 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -68,6 +68,8 @@ char zlog_prefix[128]; size_t zlog_prefixsz; int zlog_tmpdirfd = -1; +static atomic_bool zlog_ec = true, zlog_xid = true; + /* these are kept around because logging is initialized (and directories * & files created) before zprivs code switches to the FRR user; therefore * we need to chown() things so we don't get permission errors later when @@ -530,12 +532,54 @@ const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen) { if (!msg->text) { va_list args; + bool do_xid, do_ec; + size_t need = 0, hdrlen; + struct fbuf fb = { + .buf = msg->stackbuf, + .pos = msg->stackbuf, + .len = msg->stackbufsz, + }; + + do_ec = atomic_load_explicit(&zlog_ec, memory_order_relaxed); + do_xid = atomic_load_explicit(&zlog_xid, memory_order_relaxed); + + if (msg->xref && do_xid && msg->xref->xref.xrefdata->uid[0]) { + need += bputch(&fb, '['); + need += bputs(&fb, msg->xref->xref.xrefdata->uid); + need += bputch(&fb, ']'); + } + if (msg->xref && do_ec && msg->xref->ec) + need += bprintfrr(&fb, "[EC %u]", msg->xref->ec); + if (need) + need += bputch(&fb, ' '); + + hdrlen = need; + assert(hdrlen < msg->stackbufsz); va_copy(args, msg->args); - msg->text = vasnprintfrr(MTYPE_LOG_MESSAGE, msg->stackbuf, - msg->stackbufsz, msg->fmt, args); - msg->textlen = strlen(msg->text); + need += vbprintfrr(&fb, msg->fmt, args); va_end(args); + + msg->textlen = need; + need += bputch(&fb, '\0'); + + if (need <= msg->stackbufsz) + msg->text = msg->stackbuf; + else { + msg->text = XMALLOC(MTYPE_LOG_MESSAGE, need); + + memcpy(msg->text, msg->stackbuf, hdrlen); + + fb.buf = msg->text; + fb.len = need; + fb.pos = msg->text + hdrlen; + + va_copy(args, msg->args); + vbprintfrr(&fb, msg->fmt, args); + va_end(args); + + bputch(&fb, '\0'); + } } if (textlen) *textlen = msg->textlen; @@ -619,6 +663,26 @@ size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz, } } +void zlog_set_prefix_ec(bool enable) +{ + atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed); +} + +bool zlog_get_prefix_ec(void) +{ + return atomic_load_explicit(&zlog_ec, memory_order_relaxed); +} + +void zlog_set_prefix_xid(bool enable) +{ + atomic_store_explicit(&zlog_xid, enable, memory_order_relaxed); +} + +bool zlog_get_prefix_xid(void) +{ + return atomic_load_explicit(&zlog_xid, memory_order_relaxed); +} + /* setup functions */ struct zlog_target *zlog_target_clone(struct memtype *mt, diff --git a/lib/zlog.h b/lib/zlog.h index 140392bae6..66d8f1e5d7 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -85,31 +85,6 @@ static inline void zlog_ref(const struct xref_logmsg *xref, va_end(ap); } -#define _zlog_ref(prio, msg, ...) \ - do { \ - static struct xrefdata _xrefdata = { \ - .xref = NULL, \ - .uid = {}, \ - .hashstr = (msg), \ - .hashu32 = {(prio), 0}, \ - }; \ - static const struct xref_logmsg _xref __attribute__( \ - (used)) = { \ - .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \ - .fmtstring = (msg), \ - .priority = (prio), \ - .args = (#__VA_ARGS__), \ - }; \ - XREF_LINK(_xref.xref); \ - zlog_ref(&_xref, (msg), ##__VA_ARGS__); \ - } while (0) - -#define zlog_err(...) _zlog_ref(LOG_ERR, __VA_ARGS__) -#define zlog_warn(...) _zlog_ref(LOG_WARNING, __VA_ARGS__) -#define zlog_info(...) _zlog_ref(LOG_INFO, __VA_ARGS__) -#define zlog_notice(...) _zlog_ref(LOG_NOTICE, __VA_ARGS__) -#define zlog_debug(...) _zlog_ref(LOG_DEBUG, __VA_ARGS__) - #define _zlog_ecref(ec_, prio, msg, ...) \ do { \ static struct xrefdata _xrefdata = { \ @@ -127,18 +102,22 @@ static inline void zlog_ref(const struct xref_logmsg *xref, .args = (#__VA_ARGS__), \ }; \ XREF_LINK(_xref.xref); \ - zlog_ref(&_xref, "[EC %u] " msg, ec_, ##__VA_ARGS__); \ + zlog_ref(&_xref, (msg), ##__VA_ARGS__); \ } while (0) +#define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__) +#define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__) +#define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__) +#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__) +#define zlog_debug(...) _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__) + #define flog_err(ferr_id, format, ...) \ _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ _zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ - flog_err(ferr_id, format, ##__VA_ARGS__) -#define flog(priority, ferr_id, format, ...) \ - zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__) + _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__) extern void zlog_sigsafe(const char *text, size_t len); @@ -252,6 +231,11 @@ DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname, extern void zlog_fini(void); DECLARE_KOOH(zlog_fini, (), ()); +extern void zlog_set_prefix_ec(bool enable); +extern bool zlog_get_prefix_ec(void); +extern void zlog_set_prefix_xid(bool enable); +extern bool zlog_get_prefix_xid(void); + /* for tools & test programs, i.e. anything not a daemon. * (no cleanup needed at exit) */ diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index a9bc9069d2..b202cd01f1 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -23,6 +23,7 @@ #include <zebra.h> #include "command.h" +#include "json.h" #include "linklist.h" #include "memory.h" #include "prefix.h" @@ -44,48 +45,7 @@ #include "ospf_dump.h" #include "ospf_vty.h" -extern struct zclient *zclient; - -/* - * ospf_bfd_info_free - Free BFD info structure - */ -void ospf_bfd_info_free(void **bfd_info) -{ - bfd_info_free((struct bfd_info **)bfd_info); -} - -/* - * ospf_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through - * zebra for starting/stopping the monitoring of - * the neighbor rechahability. - */ -static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) -{ - struct ospf_interface *oi = nbr->oi; - 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); - - /* Check if BFD is enabled */ - if (!params->bfd_info) - return; - bfd_info = (struct bfd_info *)params->bfd_info; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("%s nbr (%pI4) with BFD. OSPF vrf %s", - bfd_get_command_dbg_str(command), - &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, cbit, command, 0, oi->ospf->vrf_id); -} +DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data"); /* * ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when @@ -94,293 +54,155 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state) { if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay)) - ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER); + bfd_sess_install(nbr->bfd_session); else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay)) - ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER); + bfd_sess_uninstall(nbr->bfd_session); } -/* - * ospf_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated - * with a interface with BFD through - * zebra for starting/stopping the monitoring of - * the neighbor rechahability. - */ -static int ospf_bfd_reg_dereg_all_nbr(struct interface *ifp, int command) +static void ospf_bfd_session_change(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg) { - struct ospf_interface *oi; - struct route_table *nbrs; - struct ospf_neighbor *nbr; - struct route_node *irn; - struct route_node *nrn; - - for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) { - if ((oi = irn->info) == NULL) - continue; + struct ospf_neighbor *nbr = arg; - if ((nbrs = oi->nbrs) == NULL) - continue; - - for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) { - if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self) - continue; - - if (command != ZEBRA_BFD_DEST_DEREGISTER) - ospf_bfd_info_nbr_create(oi, nbr); - else - bfd_info_free( - (struct bfd_info **)&nbr->bfd_info); - - if (nbr->state < NSM_TwoWay) - continue; + /* BFD peer went down. */ + if (bss->state == BFD_STATUS_DOWN + && bss->previous_state == BFD_STATUS_UP) { + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); - ospf_bfd_reg_dereg_nbr(nbr, command); - } + OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); } - return 0; + /* BFD peer went up. */ + if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN) + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); } -/* - * ospf_bfd_nbr_replay - Replay all the neighbors that have BFD enabled - * to zebra - */ -static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) +void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr) { - struct listnode *inode, *node, *onode; - struct ospf *ospf; - struct ospf_interface *oi; - struct route_table *nbrs; - struct route_node *rn; - struct ospf_neighbor *nbr; - struct ospf_if_params *params; + struct ospf_interface *oi = nbr->oi; + struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp); - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) { - zlog_debug("Zebra: BFD Dest replay request"); + /* BFD configuration was removed. */ + if (oip->bfd_config == NULL) { + bfd_sess_free(&nbr->bfd_session); + return; } - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - /* Replay the neighbor, if BFD is enabled in OSPF */ - for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) { - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) { - if ((nbrs = oi->nbrs) == NULL) - continue; - - params = IF_DEF_PARAMS(oi->ifp); - if (!params->bfd_info) - continue; - - for (rn = route_top(nbrs); rn; rn = route_next(rn)) { - if ((nbr = rn->info) == NULL - || nbr == oi->nbr_self) - continue; + /* New BFD session. */ + if (nbr->bfd_session == NULL) { + nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr); + bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src); + bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name); + bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id); + bfd_sess_enable(nbr->bfd_session, true); + } - if (nbr->state < NSM_TwoWay) - continue; + /* Set new configuration. */ + bfd_sess_set_timers(nbr->bfd_session, + oip->bfd_config->detection_multiplier, + oip->bfd_config->min_rx, oip->bfd_config->min_tx); + bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile); - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Replaying nbr (%pI4) to BFD", - &nbr->src); + /* Don't start sessions on down OSPF sessions. */ + if (nbr->state < NSM_TwoWay) + return; - ospf_bfd_reg_dereg_nbr(nbr, - ZEBRA_BFD_DEST_UPDATE); - } - } - } - return 0; + bfd_sess_install(nbr->bfd_session); } -/* - * ospf_bfd_interface_dest_update - Find the neighbor for which the BFD status - * has changed and bring down the neighbor - * connectivity if the BFD status changed to - * down. - */ -static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) +static void ospf_interface_bfd_apply(struct interface *ifp) { - struct interface *ifp; struct ospf_interface *oi; - struct ospf_if_params *params; - struct ospf_neighbor *nbr = NULL; - struct route_node *node; - struct route_node *n_node; - struct prefix p, src_p; - int status; - int old_status; - struct bfd_info *bfd_info; - struct timeval tv; - - ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL, - vrf_id); - - if ((ifp == NULL) || (p.family != AF_INET)) - return 0; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: interface %s bfd destination %pFX %s", - ifp->name, &p, bfd_get_status_str(status)); - - params = IF_DEF_PARAMS(ifp); - if (!params->bfd_info) - return 0; - - for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) { - if ((oi = node->info) == NULL) - continue; - - /* walk the neighbor list for point-to-point network */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT) { - for (n_node = route_top(oi->nbrs); n_node; - n_node = route_next(n_node)) { - nbr = n_node->info; - if (nbr) { - /* skip myself */ - if (nbr == oi->nbr_self) { - nbr = NULL; - continue; - } - - /* Found the matching neighbor */ - if (nbr->src.s_addr == - p.u.prefix4.s_addr) - break; - } - } - } else { - nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &p.u.prefix4); - } + struct route_table *nbrs; + struct ospf_neighbor *nbr; + struct route_node *irn; + struct route_node *nrn; - if (!nbr || !nbr->bfd_info) + /* Iterate over all interfaces and set neighbors BFD session. */ + for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) { + if ((oi = irn->info) == NULL) continue; - - bfd_info = (struct bfd_info *)nbr->bfd_info; - if (bfd_info->status == status) + if ((nbrs = oi->nbrs) == NULL) continue; + for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) { + if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self) + continue; - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - monotime(&tv); - bfd_info->last_update = tv.tv_sec; - - if ((status == BFD_STATUS_DOWN) - && (old_status == BFD_STATUS_UP)) { - if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%pI4]: BFD Down", - IF_NAME(nbr->oi), - &nbr->address.u.prefix4); - - OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); - } - if ((status == BFD_STATUS_UP) - && (old_status == BFD_STATUS_DOWN)) { - if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%pI4]: BFD Up", - IF_NAME(nbr->oi), - &nbr->address.u.prefix4); + ospf_neighbor_bfd_apply(nbr); } } - - return 0; } -/* - * ospf_bfd_info_nbr_create - Create/update BFD information for a neighbor. - */ -void ospf_bfd_info_nbr_create(struct ospf_interface *oi, - struct ospf_neighbor *nbr) +static void ospf_interface_enable_bfd(struct interface *ifp) { - struct bfd_info *oi_bfd_info; - struct bfd_info *nbr_bfd_info; - struct interface *ifp = oi->ifp; - struct ospf_if_params *params; - - /* Check if BFD is enabled */ - params = IF_DEF_PARAMS(ifp); + struct ospf_if_params *oip = IF_DEF_PARAMS(ifp); - /* Check if BFD is enabled */ - if (!params->bfd_info) + if (oip->bfd_config) return; - oi_bfd_info = (struct bfd_info *)params->bfd_info; - if (!nbr->bfd_info) - nbr->bfd_info = bfd_info_create(); + /* Allocate memory for configurations and set defaults. */ + oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config)); + oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + oip->bfd_config->min_rx = BFD_DEF_MIN_RX; + oip->bfd_config->min_tx = BFD_DEF_MIN_TX; +} - nbr_bfd_info = (struct bfd_info *)nbr->bfd_info; - nbr_bfd_info->detect_mult = oi_bfd_info->detect_mult; - nbr_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx; - nbr_bfd_info->required_min_rx = oi_bfd_info->required_min_rx; +void ospf_interface_disable_bfd(struct interface *ifp, + struct ospf_if_params *oip) +{ + XFREE(MTYPE_BFD_CONFIG, oip->bfd_config); + ospf_interface_bfd_apply(ifp); } /* * ospf_bfd_write_config - Write the interface BFD configuration. */ -void ospf_bfd_write_config(struct vty *vty, struct ospf_if_params *params) - +void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params + __attribute__((unused))) { #if HAVE_BFDD == 0 - struct bfd_info *bfd_info; -#endif /* ! HAVE_BFDD */ - - if (!params->bfd_info) - return; - -#if HAVE_BFDD == 0 - bfd_info = (struct bfd_info *)params->bfd_info; - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - vty_out(vty, " ip ospf bfd %d %d %d\n", bfd_info->detect_mult, - bfd_info->required_min_rx, bfd_info->desired_min_tx); + vty_out(vty, " ip ospf bfd %d %d %d\n", + params->bfd_config->detection_multiplier, + params->bfd_config->min_rx, params->bfd_config->min_tx); else #endif /* ! HAVE_BFDD */ vty_out(vty, " ip ospf bfd\n"); -} -/* - * ospf_bfd_show_info - Show BFD info structure - */ -void ospf_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj, - bool use_json, int param_only) -{ - if (param_only) - bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json, - json_obj); - else - bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json, - json_obj); + if (params->bfd_config->profile[0]) + vty_out(vty, " ip ospf bfd profile %s\n", + params->bfd_config->profile); } -/* - * ospf_bfd_interface_show - Show the interface BFD configuration. - */ -void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp, - json_object *json_interface_sub, bool use_json) +void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp, + struct json_object *json) { - struct ospf_if_params *params; - - params = IF_DEF_PARAMS(ifp); + struct ospf_if_params *params = IF_DEF_PARAMS(ifp); + struct bfd_configuration *bfd_config = params->bfd_config; + struct json_object *json_bfd; - ospf_bfd_show_info(vty, params->bfd_info, json_interface_sub, use_json, - 1); -} - -/* - * ospf_bfd_if_param_set - Set the configured BFD paramter values for - * interface. - */ -static void ospf_bfd_if_param_set(struct interface *ifp, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, - int defaults) -{ - struct ospf_if_params *params; - int command = 0; - - params = IF_DEF_PARAMS(ifp); + if (bfd_config == NULL) + return; - bfd_set_param((struct bfd_info **)&(params->bfd_info), min_rx, min_tx, - detect_mult, NULL, defaults, &command); - if (command) - ospf_bfd_reg_dereg_all_nbr(ifp, command); + if (json) { + json_bfd = json_object_new_object(); + json_object_int_add(json_bfd, "detectionMultiplier", + bfd_config->detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + bfd_config->min_rx); + json_object_int_add(json_bfd, "txMinInterval", + bfd_config->min_tx); + json_object_object_add(json, "peerBfdInfo", json_bfd); + } else + vty_out(vty, + " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + bfd_config->detection_multiplier, bfd_config->min_rx, + bfd_config->min_tx); } DEFUN (ip_ospf_bfd, @@ -391,17 +213,8 @@ DEFUN (ip_ospf_bfd, "Enables BFD support\n") { VTY_DECLVAR_CONTEXT(interface, ifp); - struct ospf_if_params *params; - struct bfd_info *bfd_info; - - assert(ifp); - params = IF_DEF_PARAMS(ifp); - bfd_info = params->bfd_info; - - if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - ospf_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); - + ospf_interface_enable_bfd(ifp); + ospf_interface_bfd_apply(ifp); return CMD_SUCCESS; } @@ -421,23 +234,63 @@ DEFUN( "Desired min transmit interval\n") { VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; int idx_number = 3; int idx_number_2 = 4; int idx_number_3 = 5; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; - assert(ifp); + ospf_interface_enable_bfd(ifp); + + params = IF_DEF_PARAMS(ifp); + params->bfd_config->detection_multiplier = + strtol(argv[idx_number]->arg, NULL, 10); + params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10); + params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10); + + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} - if ((ret = bfd_validate_param( - vty, argv[idx_number]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) - return ret; +DEFUN (ip_ospf_bfd_prof, + ip_ospf_bfd_prof_cmd, + "ip ospf bfd profile BFDPROF", + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + int idx_prof = 4; - ospf_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0); + ospf_interface_enable_bfd(ifp); + params = IF_DEF_PARAMS(ifp); + strlcpy(params->bfd_config->profile, argv[idx_prof]->arg, + sizeof(params->bfd_config->profile)); + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_bfd_prof, + no_ip_ospf_bfd_prof_cmd, + "no ip ospf bfd profile [BFDPROF]", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + ospf_interface_enable_bfd(ifp); + params = IF_DEF_PARAMS(ifp); + params->bfd_config->profile[0] = 0; + ospf_interface_bfd_apply(ifp); return CMD_SUCCESS; } @@ -461,29 +314,18 @@ DEFUN (no_ip_ospf_bfd, ) { VTY_DECLVAR_CONTEXT(interface, ifp); - struct ospf_if_params *params; - - assert(ifp); - - params = IF_DEF_PARAMS(ifp); - if (params->bfd_info) { - ospf_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER); - bfd_info_free(&(params->bfd_info)); - } - + ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp)); return CMD_SUCCESS; } -void ospf_bfd_init(void) +void ospf_bfd_init(struct thread_master *tm) { - bfd_gbl_init(); - - /* Initialize BFD client functions */ - zclient->interface_bfd_dest_update = ospf_bfd_interface_dest_update; - zclient->bfd_dest_replay = ospf_bfd_nbr_replay; + bfd_protocol_integration_init(zclient, tm); /* Install BFD command */ install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd); install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd); + install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd); + install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd); } diff --git a/ospfd/ospf_bfd.h b/ospfd/ospf_bfd.h index 74385d3268..9393c839f5 100644 --- a/ospfd/ospf_bfd.h +++ b/ospfd/ospf_bfd.h @@ -23,27 +23,34 @@ #ifndef _ZEBRA_OSPF_BFD_H #define _ZEBRA_OSPF_BFD_H +#include "ospfd/ospf_interface.h" #include "json.h" -extern void ospf_bfd_init(void); +extern void ospf_bfd_init(struct thread_master *tm); extern void ospf_bfd_write_config(struct vty *vty, - struct ospf_if_params *params); + const struct ospf_if_params *params); extern void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state); -extern void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp, - json_object *json_interface_sub, - bool use_json); - -extern void ospf_bfd_info_nbr_create(struct ospf_interface *oi, - struct ospf_neighbor *nbr); +/** + * Legacy information: it is the peers who actually have this information + * and the protocol should not need to know about timers. + */ +extern void ospf_interface_bfd_show(struct vty *vty, + const struct interface *ifp, + struct json_object *json); -extern void ospf_bfd_show_info(struct vty *vty, void *bfd_info, - json_object *json_obj, bool use_json, - int param_only); +/** + * Disables interface BFD configuration and remove settings from all peers. + */ +extern void ospf_interface_disable_bfd(struct interface *ifp, + struct ospf_if_params *oip); -extern void ospf_bfd_info_free(void **bfd_info); +/** + * Create/update BFD session for this OSPF neighbor. + */ +extern void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr); #endif /* _ZEBRA_OSPF_BFD_H */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 19829d4546..2442f2e781 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -21,6 +21,7 @@ #include <zebra.h> +#include "lib/bfd.h" #include "monotime.h" #include "linklist.h" #include "thread.h" @@ -60,6 +61,7 @@ unsigned long conf_debug_ospf_ti_lfa = 0; unsigned long conf_debug_ospf_defaultinfo = 0; unsigned long conf_debug_ospf_ldp_sync = 0; unsigned long conf_debug_ospf_gr = 0; +unsigned long conf_debug_ospf_bfd; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -76,6 +78,7 @@ unsigned long term_debug_ospf_ti_lfa = 0; unsigned long term_debug_ospf_defaultinfo; unsigned long term_debug_ospf_ldp_sync; unsigned long term_debug_ospf_gr = 0; +unsigned long term_debug_ospf_bfd; const char *ospf_redist_string(unsigned int route_type) { @@ -1563,6 +1566,31 @@ DEFPY (debug_ospf_gr, return CMD_SUCCESS; } +DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd, + "[no] debug ospf bfd", + NO_STR + DEBUG_STR + OSPF_STR + "Bidirection Forwarding Detection\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) { + bfd_protocol_integration_set_debug(false); + CONF_DEBUG_OFF(bfd, BFD_LIB); + } else { + bfd_protocol_integration_set_debug(true); + CONF_DEBUG_ON(bfd, BFD_LIB); + } + } + + if (no) + TERM_DEBUG_OFF(bfd, BFD_LIB); + else + TERM_DEBUG_ON(bfd, BFD_LIB); + + return CMD_SUCCESS; +} + DEFUN (no_debug_ospf, no_debug_ospf_cmd, "no debug ospf", @@ -1594,6 +1622,10 @@ DEFUN (no_debug_ospf, DEBUG_OFF(defaultinfo, DEFAULTINFO); DEBUG_OFF(ldp_sync, LDP_SYNC); + /* BFD debugging is two parts: OSPF and library. */ + DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + for (i = 0; i < 5; i++) DEBUG_PACKET_OFF(i, flag); } @@ -1621,6 +1653,7 @@ DEFUN (no_debug_ospf, TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE); TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO); TERM_DEBUG_OFF(ldp_sync, LDP_SYNC); + TERM_DEBUG_OFF(bfd, BFD_LIB); return CMD_SUCCESS; } @@ -1730,6 +1763,10 @@ static int show_debugging_ospf_common(struct vty *vty) if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER) vty_out(vty, " OSPF Graceful Restart Helper debugging is on\n"); + if (IS_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) + vty_out(vty, + " OSPF BFD integration library debugging is on\n"); + vty_out(vty, "\n"); return CMD_SUCCESS; @@ -1917,6 +1954,11 @@ static int config_write_debug(struct vty *vty) write = 1; } + if (IS_CONF_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) { + vty_out(vty, "debug ospf%s bfd\n", str); + write = 1; + } + return write; } @@ -1949,6 +1991,7 @@ void ospf_debug_init(void) install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd); install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd); install_element(ENABLE_NODE, &debug_ospf_gr_cmd); + install_element(ENABLE_NODE, &debug_ospf_bfd_cmd); install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd); install_element(ENABLE_NODE, &debug_ospf_packet_cmd); @@ -1992,6 +2035,7 @@ void ospf_debug_init(void) install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd); install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd); install_element(CONFIG_NODE, &debug_ospf_gr_cmd); + install_element(CONFIG_NODE, &debug_ospf_bfd_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd); diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index c4c5606663..b1c1d02a51 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -67,6 +67,8 @@ #define OSPF_DEBUG_GR_HELPER 0x01 #define OSPF_DEBUG_GR 0x03 +#define OSPF_DEBUG_BFD_LIB 0x01 + /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) #define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) @@ -140,6 +142,7 @@ extern unsigned long term_debug_ospf_ti_lfa; extern unsigned long term_debug_ospf_defaultinfo; extern unsigned long term_debug_ospf_ldp_sync; extern unsigned long term_debug_ospf_gr; +extern unsigned long term_debug_ospf_bfd; /* Message Strings. */ extern char *ospf_lsa_type_str[]; diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 0161f05d71..d494f0fbce 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -35,6 +35,7 @@ #include "ldp_sync.h" #include "ospfd/ospfd.h" +#include "ospfd/ospf_bfd.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" @@ -545,10 +546,11 @@ static struct ospf_if_params *ospf_new_if_params(void) return oip; } -void ospf_del_if_params(struct ospf_if_params *oip) +static void ospf_del_if_params(struct interface *ifp, + struct ospf_if_params *oip) { list_delete(&oip->auth_crypt); - bfd_info_free(&(oip->bfd_info)); + ospf_interface_disable_bfd(ifp, oip); ldp_sync_info_free(&(oip->ldp_sync_info)); XFREE(MTYPE_OSPF_IF_PARAMS, oip); } @@ -582,7 +584,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) && !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && listcount(oip->auth_crypt) == 0) { - ospf_del_if_params(oip); + ospf_del_if_params(ifp, oip); rn->info = NULL; route_unlock_node(rn); } @@ -696,10 +698,10 @@ static int ospf_if_delete_hook(struct interface *ifp) for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) if (rn->info) - ospf_del_if_params(rn->info); + ospf_del_if_params(ifp, rn->info); route_table_finish(IF_OIFS_PARAMS(ifp)); - ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp)); + ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp)); XFREE(MTYPE_OSPF_IF_INFO, ifp->info); return rc; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 2f146c06f3..a9534f543d 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -22,6 +22,7 @@ #ifndef _ZEBRA_OSPF_INTERFACE_H #define _ZEBRA_OSPF_INTERFACE_H +#include "lib/bfd.h" #include "qobj.h" #include "hook.h" #include "ospfd/ospf_packet.h" @@ -104,7 +105,16 @@ struct ospf_if_params { uint32_t network_lsa_seqnum; /* Network LSA seqnum */ /* BFD configuration */ - struct bfd_info *bfd_info; + struct bfd_configuration { + /** BFD session detection multiplier. */ + uint8_t detection_multiplier; + /** BFD session minimum required receive interval. */ + uint32_t min_rx; + /** BFD session minimum required transmission interval. */ + uint32_t min_tx; + /** BFD profile. */ + char profile[BFD_PROFILE_NAME_LEN]; + } *bfd_config; /* MPLS LDP-IGP Sync configuration */ struct ldp_sync_info *ldp_sync_info; @@ -285,7 +295,6 @@ extern struct ospf_if_params *ospf_lookup_if_params(struct interface *, struct in_addr); extern struct ospf_if_params *ospf_get_if_params(struct interface *, struct in_addr); -extern void ospf_del_if_params(struct ospf_if_params *); extern void ospf_free_if_params(struct interface *, struct in_addr); extern void ospf_if_update_params(struct interface *, struct in_addr); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 9ae2e8b043..d23dea0ca1 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -22,6 +22,7 @@ #include <zebra.h> #include <lib/version.h> +#include "bfd.h" #include "getopt.h" #include "thread.h" #include "prefix.h" @@ -98,6 +99,7 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); + bfd_protocol_integration_set_shutdown(true); ospf_terminate(); exit(0); } @@ -214,7 +216,7 @@ int main(int argc, char **argv) ospf_vty_clear_init(); /* OSPF BFD init */ - ospf_bfd_init(); + ospf_bfd_init(master); /* OSPF LDP IGP Sync init */ ospf_ldp_sync_init(); diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 2fa43923ab..a1b35b2fcd 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -21,6 +21,7 @@ #include <zebra.h> +#include "lib/bfd.h" #include "linklist.h" #include "prefix.h" #include "memory.h" @@ -99,8 +100,6 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->crypt_seqnum = 0; - ospf_bfd_info_nbr_create(oi, nbr); - /* Initialize GR Helper info*/ nbr->gr_helper_info.recvd_grace_period = 0; nbr->gr_helper_info.actual_grace_period = 0; @@ -149,7 +148,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) /* Cancel all events. */ /* Thread lookup cost would be negligible. */ thread_cancel_event(master, nbr); - ospf_bfd_info_free(&nbr->bfd_info); + bfd_sess_free(&nbr->bfd_session); OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer); @@ -458,6 +457,9 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi, if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC) nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + /* Configure BFD if interface has it. */ + ospf_neighbor_bfd_apply(nbr); + if (IS_DEBUG_OSPF_EVENT) zlog_debug("NSM[%s:%pI4]: start", IF_NAME(oi), &nbr->router_id); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 758693e289..2ce6d6755c 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -88,7 +88,7 @@ struct ospf_neighbor { uint32_t state_change; /* NSM state change counter */ /* BFD information */ - void *bfd_info; + struct bfd_session_params *bfd_session; /* ospf graceful restart HELPER info */ struct ospf_helper_info gr_helper_info; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index ca33fd4e18..006c4888ae 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -761,7 +761,8 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (state == NSM_Down) nbr->crypt_seqnum = 0; - ospf_bfd_trigger_event(nbr, old_state, state); + if (nbr->bfd_session) + ospf_bfd_trigger_event(nbr, old_state, state); /* Preserve old status? */ } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 6e42169b3a..e6835ffc72 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3776,7 +3776,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, " Neighbor Count is %d, Adjacent neighbor count is %d\n", ospf_nbr_count(oi, 0), ospf_nbr_count(oi, NSM_Full)); - ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json); + + ospf_interface_bfd_show(vty, ifp, json_interface_sub); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); @@ -5282,7 +5283,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, .helper_exit_reason)); } - ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0); + bfd_sess_show(vty, json_neigh, nbr->bfd_session); if (use_json) json_object_array_add(json_neigh_array, json_neigh); @@ -7109,14 +7110,14 @@ DEFUN (show_ip_ospf_database_max, return ret; } -DEFUN (show_ip_ospf_instance_database, - show_ip_ospf_instance_database_cmd, - "show ip ospf [{(1-65535)|vrf NAME}] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", +ALIAS (show_ip_ospf_database_max, + show_ip_ospf_database_cmd, + "show ip ospf [vrf <NAME|all>] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", SHOW_STR IP_STR "OSPF information\n" - "Instance ID\n" VRF_CMD_HELP_STR + "All VRFs\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" @@ -7124,78 +7125,6 @@ DEFUN (show_ip_ospf_instance_database, "Advertising Router link states\n" "Advertising Router (as an IP address)\n" JSON_STR) -{ - struct ospf *ospf; - unsigned short instance = 0; - struct listnode *node = NULL; - char *vrf_name = NULL; - bool all_vrf = false; - int ret = CMD_SUCCESS; - int inst = 0; - int idx = 0; - uint8_t use_vrf = 0; - bool uj = use_json(argc, argv); - json_object *json = NULL; - - if (uj) - json = json_object_new_object(); - - if (argv_find(argv, argc, "(1-65535)", &idx)) { - instance = strtoul(argv[idx]->arg, NULL, 10); - if (instance != ospf_instance) - return CMD_NOT_MY_INSTANCE; - - ospf = ospf_lookup_instance(instance); - if (!ospf || !ospf->oi_running) - return CMD_SUCCESS; - - return (show_ip_ospf_database_common( - vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj)); - } else if (argv_find(argv, argc, "vrf", &idx)) { - vrf_name = argv[++idx]->arg; - all_vrf = strmatch(vrf_name, "all"); - } - - if (vrf_name) { - use_vrf = 1; - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { - if (!ospf->oi_running) - continue; - ret = (show_ip_ospf_database_common( - vty, ospf, idx ? 2 : 0, argc, argv, - use_vrf, json, uj)); - } - } else { - ospf = ospf_lookup_by_inst_name(inst, vrf_name); - if ((ospf == NULL) || !ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); - return CMD_SUCCESS; - } - - ret = (show_ip_ospf_database_common( - vty, ospf, idx ? 2 : 0, argc, argv, use_vrf, - json, uj)); - } - } else { - /* Display default ospf (instance 0) info */ - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL || !ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); - return CMD_SUCCESS; - } - - ret = (show_ip_ospf_database_common(vty, ospf, 0, argc, argv, - use_vrf, json, uj)); - } - - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string(json)); - json_object_free(json); - } - - return ret; -} DEFUN (show_ip_ospf_instance_database_max, show_ip_ospf_instance_database_max_cmd, @@ -7238,6 +7167,20 @@ DEFUN (show_ip_ospf_instance_database_max, return CMD_SUCCESS; } +ALIAS (show_ip_ospf_instance_database_max, + show_ip_ospf_instance_database_cmd, + "show ip ospf (1-65535) database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", + SHOW_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Self-originated link states\n" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n" + JSON_STR) static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, struct ospf *ospf, @@ -7327,14 +7270,14 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, return CMD_SUCCESS; } -DEFUN (show_ip_ospf_instance_database_type_adv_router, - show_ip_ospf_instance_database_type_adv_router_cmd, - "show ip ospf [{(1-65535)|vrf NAME}] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", +DEFUN (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_adv_router_cmd, + "show ip ospf [vrf <NAME|all>] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", SHOW_STR IP_STR "OSPF information\n" - "Instance ID\n" VRF_CMD_HELP_STR + "All VRFs\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Advertising Router link states\n" @@ -7343,7 +7286,6 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, JSON_STR) { struct ospf *ospf = NULL; - unsigned short instance = 0; struct listnode *node = NULL; char *vrf_name = NULL; bool all_vrf = false; @@ -7357,19 +7299,6 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, if (uj) json = json_object_new_object(); - if (argv_find(argv, argc, "(1-65535)", &idx)) { - instance = strtoul(argv[idx]->arg, NULL, 10); - if (instance != ospf_instance) - return CMD_NOT_MY_INSTANCE; - - ospf = ospf_lookup_instance(instance); - if (!ospf || !ospf->oi_running) - return CMD_SUCCESS; - - return (show_ip_ospf_database_type_adv_router_common( - vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj)); - } - OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (vrf_name) { @@ -7416,8 +7345,50 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, } return ret; - /*return (show_ip_ospf_database_type_adv_router_common( - vty, ospf, idx ? 1 : 0, argc, argv));*/ +} + +DEFUN (show_ip_ospf_instance_database_type_adv_router, + show_ip_ospf_instance_database_type_adv_router_cmd, + "show ip ospf (1-65535) database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", + SHOW_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n" + "Self-originated link states\n" + JSON_STR) +{ + int idx_number = 3; + struct ospf *ospf; + unsigned short instance = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); + + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; + + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) + return CMD_SUCCESS; + + show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv, + 0, json, uj); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; } DEFUN (ip_ospf_authentication_args, @@ -11716,7 +11687,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) } /* bfd print. */ - if (params && params->bfd_info) + if (params && params->bfd_config) ospf_bfd_write_config(vty, params); /* MTU ignore print. */ @@ -12375,8 +12346,10 @@ void ospf_vty_show_init(void) install_element(VIEW_NODE, &show_ip_ospf_instance_cmd); /* "show ip ospf database" commands. */ + install_element(VIEW_NODE, &show_ip_ospf_database_cmd); install_element(VIEW_NODE, &show_ip_ospf_database_max_cmd); - + install_element(VIEW_NODE, + &show_ip_ospf_database_type_adv_router_cmd); install_element(VIEW_NODE, &show_ip_ospf_instance_database_type_adv_router_cmd); install_element(VIEW_NODE, &show_ip_ospf_instance_database_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1a1861fc58..9856e60130 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -42,6 +42,7 @@ #include "ldp_sync.h" #include "ospfd/ospfd.h" +#include "ospfd/ospf_bfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" @@ -1931,6 +1932,9 @@ static void ospf_nbr_nbma_add(struct ospf_nbr_nbma *nbr_nbma, nbr_nbma->nbr = nbr; + /* Configure BFD if interface has it. */ + ospf_neighbor_bfd_apply(nbr); + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_Start); } } diff --git a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json index bab24c4fa0..86a7e5139c 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json @@ -6,14 +6,14 @@ "interface": "r1-eth1", "multihop": false, "peer": "172.16.100.2", - "receive-interval": 300, + "receive-interval": 800, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", "remote-receive-interval": 300, "remote-transmit-interval": 300, "status": "up", - "transmit-interval": 300, + "transmit-interval": 800, "uptime": "*", "vrf": "default" }, diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf index 4798d17c40..fcea5d48fc 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf +++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf @@ -2,7 +2,7 @@ interface r1-eth1 ip ospf area 0 ip ospf hello-interval 2 ip ospf dead-interval 10 - ip ospf bfd + ip ospf bfd profile slowtx ! router ospf ospf router-id 10.254.254.1 diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json index 4e6fa869ba..ec973eb365 100644 --- a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json @@ -10,8 +10,8 @@ "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", - "remote-receive-interval": 300, - "remote-transmit-interval": 300, + "remote-receive-interval": 800, + "remote-transmit-interval": 800, "status": "up", "transmit-interval": 300, "uptime": "*", diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index ac7ee44b25..464d6eb475 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -115,7 +115,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -215,6 +215,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index c6e1792e84..10cf1c6ae8 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -71,7 +71,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -164,6 +164,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py index 6ab78c385e..ae904ba69e 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -40,6 +40,8 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.topotest import iproute2_is_vrf_capable +from lib.common_config import required_linux_kernel_version from mininet.topo import Topo @@ -193,18 +195,21 @@ def test_isis_route_installation(): def test_isis_linux_route_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf routes in OS") # Check for routes in `ip route show vrf {}-cust1` for rname, router in tgen.routers().items(): @@ -236,18 +241,21 @@ def test_isis_route6_installation(): def test_isis_linux_route6_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS") # Check for routes in `ip -6 route show vrf {}-cust1` for rname, router in tgen.routers().items(): diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 5cc1a6981d..70b2cfd648 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -516,6 +516,44 @@ def normalize_text(text): return text +def is_linux(): + """ + Parses unix name output to check if running on GNU/Linux. + + Returns True if running on Linux, returns False otherwise. + """ + + if os.uname()[0] == "Linux": + return True + return False + + +def iproute2_is_vrf_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling VRFs by interpreting the output of the 'ip' utility found in PATH. + + Returns True if capability can be detected, returns False otherwise. + """ + + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "route", "show", "vrf"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + encoding="utf-8" + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def module_present_linux(module, load): """ Returns whether `module` is present. diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index e68b819767..82529663ba 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -201,19 +201,6 @@ lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys( struct nb_cb_get_keys_args *args); -int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args); -int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args); -const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args); -int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args); -const void * -lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args); -const void * -lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args); -int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args); -const void * -lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args); -struct yang_data * -lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args); const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys( diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index d5c9f7183d..283a3e52d6 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2564,10 +2564,8 @@ DEFUN (default_vrf_vni_mapping, "VNI-ID\n" "Prefix routes only \n") { - int ret = 0; - char err[ERR_STR_SZ]; + char xpath[XPATH_MAXLEN]; struct zebra_vrf *zvrf = NULL; - vni_t vni = strtoul(argv[1]->arg, NULL, 10); int filter = 0; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -2577,25 +2575,35 @@ DEFUN (default_vrf_vni_mapping, if (argc == 3) filter = 1; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - filter, 1); - if (ret != 0) { - vty_out(vty, "%s\n", err); - return CMD_WARNING; + snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg); + + if (filter) { + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); } - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_default_vrf_vni_mapping, no_default_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE, + "no vni " CMD_VNI_RANGE "[prefix-routes-only]", NO_STR "VNI corresponding to DEFAULT VRF\n" - "VNI-ID") + "VNI-ID\n" + "Prefix routes only \n") { - int ret = 0; - char err[ERR_STR_SZ]; + char xpath[XPATH_MAXLEN]; + int filter = 0; vni_t vni = strtoul(argv[2]->arg, NULL, 10); struct zebra_vrf *zvrf = NULL; @@ -2603,13 +2611,32 @@ DEFUN (no_default_vrf_vni_mapping, if (!zvrf) return CMD_WARNING; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0); - if (ret != 0) { - vty_out(vty, "%s\n", err); + if (argc == 4) + filter = 1; + + if (zvrf->l3vni != vni) { + vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, + zvrf->vrf->name); return CMD_WARNING; } - return CMD_SUCCESS; + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg); + + if (filter) { + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true"); + } + + snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (vrf_vni_mapping, @@ -2637,9 +2664,7 @@ DEFUN (vrf_vni_mapping, nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", NB_OP_MODIFY, "true"); - nb_cli_apply_changes(vty, NULL); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_vrf_vni_mapping, @@ -2676,9 +2701,7 @@ DEFUN (no_vrf_vni_mapping, nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL); - nb_cli_apply_changes(vty, NULL); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } /* show vrf */ |
