summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_bfd.c1053
-rw-r--r--bgpd/bgp_bfd.h56
-rw-r--r--bgpd/bgp_debug.c41
-rw-r--r--bgpd/bgp_debug.h4
-rw-r--r--bgpd/bgp_evpn.c4
-rw-r--r--bgpd/bgp_evpn_mh.c42
-rw-r--r--bgpd/bgp_evpn_mh.h1
-rw-r--r--bgpd/bgp_fsm.c10
-rw-r--r--bgpd/bgp_main.c3
-rw-r--r--bgpd/bgp_vty.c10
-rw-r--r--bgpd/bgp_zebra.c13
-rw-r--r--bgpd/bgpd.c19
-rw-r--r--bgpd/bgpd.h27
-rwxr-xr-xconfigure.ac14
-rw-r--r--doc/user/bfd.rst5
-rw-r--r--doc/user/bgp.rst6
-rw-r--r--doc/user/ospf6d.rst3
-rw-r--r--doc/user/ospfd.rst38
-rw-r--r--isisd/isis_cli.c2
-rw-r--r--lib/bfd.c638
-rw-r--r--lib/bfd.h327
-rw-r--r--lib/log_vty.c32
-rw-r--r--lib/northbound.c40
-rw-r--r--lib/printfrr.h24
-rw-r--r--lib/xref.c2
-rw-r--r--lib/zlog.c70
-rw-r--r--lib/zlog.h42
-rw-r--r--ospfd/ospf_bfd.c474
-rw-r--r--ospfd/ospf_bfd.h31
-rw-r--r--ospfd/ospf_dump.c44
-rw-r--r--ospfd/ospf_dump.h3
-rw-r--r--ospfd/ospf_interface.c12
-rw-r--r--ospfd/ospf_interface.h13
-rw-r--r--ospfd/ospf_main.c4
-rw-r--r--ospfd/ospf_neighbor.c8
-rw-r--r--ospfd/ospf_neighbor.h2
-rw-r--r--ospfd/ospf_nsm.c3
-rw-r--r--ospfd/ospf_vty.c173
-rw-r--r--ospfd/ospfd.c4
-rw-r--r--tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json4
-rw-r--r--tests/topotests/bfd-profiles-topo1/r1/ospfd.conf2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json4
-rw-r--r--tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py6
-rw-r--r--tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py6
-rw-r--r--tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py32
-rw-r--r--tests/topotests/lib/topotest.py38
-rw-r--r--zebra/zebra_nb.h13
-rw-r--r--zebra/zebra_vty.c69
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);
diff --git a/lib/bfd.c b/lib/bfd.c
index b780ae43eb..176269cc5b 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -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;
+}
diff --git a/lib/bfd.h b/lib/bfd.h
index ceab4628b6..1325f86a30 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -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 */