summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2019-05-16 16:13:26 +0200
committerGitHub <noreply@github.com>2019-05-16 16:13:26 +0200
commitace430f0db312f31e3aa4e925433e9418f74e28a (patch)
tree1fa803d8aa4a9e0c2118f768d97766978e870bd9
parentMerge pull request #4269 from donaldsharp/other_tables (diff)
parentbgpd: do not unregister bfd session when bgp session goes down (diff)
downloadfrr-ace430f0db312f31e3aa4e925433e9418f74e28a.tar.xz
frr-ace430f0db312f31e3aa4e925433e9418f74e28a.zip
Merge pull request #4144 from pguibert6WIND/bfd_cbit
BFD CBIT
-rw-r--r--bfdd/bfd.c11
-rw-r--r--bfdd/bfd.h8
-rw-r--r--bfdd/bfd_packet.c9
-rw-r--r--bfdd/bfdctl.h2
-rw-r--r--bfdd/ptm_adapter.c13
-rw-r--r--bgpd/bgp_bfd.c118
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--doc/user/bfd.rst15
-rw-r--r--isisd/isis_bfd.c5
-rw-r--r--lib/bfd.c14
-rw-r--r--lib/bfd.h7
-rw-r--r--ospf6d/ospf6_bfd.c10
-rw-r--r--ospfd/ospf_bfd.c8
-rw-r--r--pimd/pim_bfd.c10
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/__init__.py0
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json103
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf20
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/ipv6_routes.json80
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json16
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json14
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/zebra.conf8
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r2/zebra.conf9
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json55
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf25
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/ipv6_routes.json80
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json16
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json14
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/zebra.conf7
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.dot58
-rwxr-xr-xtests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py248
-rw-r--r--zebra/zebra_ptm.c6
31 files changed, 964 insertions, 27 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index 57d8ffa6d..435443182 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -600,6 +600,17 @@ skip_echo:
bfd_recvtimer_update(bs);
bfd_xmttimer_update(bs, bs->xmt_TO);
}
+ if (bpc->bpc_cbit) {
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT))
+ return;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
+ } else {
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT))
+ return;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
+ }
}
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 3f3d60383..213e905bf 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -129,6 +129,12 @@ struct bfd_echo_pkt {
flags |= (val & 0x3) << 6; \
}
#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3)
+#define BFD_SETCBIT(flags, val) \
+ { \
+ if ((val)) \
+ flags |= val; \
+ }
+#define BFD_GETCBIT(flags) (flags & BFD_FBIT)
#define BFD_ECHO_VERSION 1
#define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt)
@@ -168,6 +174,7 @@ enum bfd_session_flags {
*/
BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */
BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */
+ BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */
};
#define BFD_SET_FLAG(field, flag) (field |= flag)
@@ -210,6 +217,7 @@ struct bfd_session {
uint8_t detect_mult;
uint8_t remote_detect_mult;
uint8_t mh_ttl;
+ uint8_t remote_cbit;
/* Timers */
struct bfd_timers timers;
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 8edba05d1..f3acfa416 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -221,6 +221,10 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit)
BFD_SETVER(cp.diag, BFD_VERSION);
cp.flags = 0;
BFD_SETSTATE(cp.flags, bfd->ses_state);
+
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_CBIT))
+ BFD_SETCBIT(cp.flags, BFD_CBIT);
+
BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND);
/*
@@ -646,6 +650,11 @@ int bfd_recv_cb(struct thread *t)
ntohl(cp->timers.required_min_echo);
bfd->remote_detect_mult = cp->detect_mult;
+ if (BFD_GETCBIT(cp->flags))
+ bfd->remote_cbit = 1;
+ else
+ bfd->remote_cbit = 0;
+
/* State switch from section 6.2. */
bs_state_handler(bfd, BFD_GETSTATE(cp->flags));
diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h
index 0da1ca8df..4ce23a8f2 100644
--- a/bfdd/bfdctl.h
+++ b/bfdd/bfdctl.h
@@ -88,6 +88,8 @@ struct bfd_peer_cfg {
bool bpc_createonly;
bool bpc_shutdown;
+ bool bpc_cbit;
+
/* Status information */
enum bfd_peer_status bpc_bps;
uint32_t bpc_id;
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index a12a3c196..3e2ace6ea 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -89,6 +89,7 @@ static void debug_printbpc(const char *func, unsigned int line,
{
char addr[3][128];
char timers[3][128];
+ char cbit_str[10];
addr[0][0] = addr[1][0] = addr[2][0] = timers[0][0] = timers[1][0] =
timers[2][0] = 0;
@@ -117,9 +118,11 @@ static void debug_printbpc(const char *func, unsigned int line,
snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
bpc->bpc_detectmultiplier);
- log_debug("%s:%d: %s %s%s%s%s%s%s", func, line,
+ sprintf(cbit_str, "CB %x", bpc->bpc_cbit);
+
+ log_debug("%s:%d: %s %s%s%s%s%s%s %s", func, line,
bpc->bpc_mhop ? "multi-hop" : "single-hop", addr[0], addr[1],
- addr[2], timers[0], timers[1], timers[2]);
+ addr[2], timers[0], timers[1], timers[2], cbit_str);
}
#define DEBUG_PRINTBPC(bpc) debug_printbpc(__FILE__, __LINE__, (bpc))
@@ -173,6 +176,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
* - AF_INET6:
* - 16 bytes: ipv6
* - c: prefix length
+ * - c: cbit
*
* Commands: ZEBRA_BFD_DEST_REPLAY
*
@@ -219,6 +223,8 @@ int ptm_bfd_notify(struct bfd_session *bs)
/* BFD source prefix information. */
_ptm_msg_address(msg, bs->key.family, &bs->key.local);
+ stream_putc(msg, bs->remote_cbit);
+
/* Write packet size. */
stream_putw_at(msg, 0, stream_get_endp(msg));
@@ -293,6 +299,7 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
* - 16 bytes: ipv6 address
* - c: ifname length
* - X bytes: interface name
+ * - c: bfd_cbit
*
* q(64), l(32), w(16), c(8)
*/
@@ -371,6 +378,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
}
}
+ STREAM_GETC(msg, bpc->bpc_cbit);
+
/* Sanity check: peer and local address must match IP types. */
if (bpc->bpc_local.sa_sin.sin_family != 0
&& (bpc->bpc_local.sa_sin.sin_family
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index a9c30acaf..57fef8e91 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -96,7 +96,7 @@ int bgp_bfd_is_peer_multihop(struct peer *peer)
static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
{
struct bfd_info *bfd_info;
- int multihop;
+ int multihop, cbit = 0;
vrf_id_t vrf_id;
bfd_info = (struct bfd_info *)peer->bfd_info;
@@ -112,20 +112,30 @@ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop)
SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
}
+ /* while graceful restart with fwd path preserved
+ * and bfd controlplane check not configured is not kept
+ * keep bfd independent controlplane bit set to 1
+ */
+ if (!bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART)
+ && !bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD)
+ && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
+ SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
+
+ cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
if (peer->su.sa.sa_family == AF_INET)
bfd_peer_sendmsg(
zclient, bfd_info, AF_INET, &peer->su.sin.sin_addr,
(peer->su_local) ? &peer->su_local->sin.sin_addr : NULL,
(peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
- peer->ttl, multihop, command, 1, vrf_id);
+ peer->ttl, multihop, cbit, command, 1, vrf_id);
else if (peer->su.sa.sa_family == AF_INET6)
bfd_peer_sendmsg(
zclient, bfd_info, AF_INET6, &peer->su.sin6.sin6_addr,
(peer->su_local) ? &peer->su_local->sin6.sin6_addr
: NULL,
(peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL,
- peer->ttl, multihop, command, 1, vrf_id);
+ peer->ttl, multihop, cbit, command, 1, vrf_id);
}
/*
@@ -260,7 +270,8 @@ static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
* down the peer if the BFD session went down from
* * up.
*/
-static void bgp_bfd_peer_status_update(struct peer *peer, int status)
+static void bgp_bfd_peer_status_update(struct peer *peer, int status,
+ int remote_cbit)
{
struct bfd_info *bfd_info;
int old_status;
@@ -280,6 +291,14 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status)
bfd_get_status_str(status));
}
if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) &&
+ 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);
}
@@ -303,23 +322,27 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
struct prefix dp;
struct prefix sp;
int status;
+ int remote_cbit;
- ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, vrf_id);
+ ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
+ &remote_cbit, vrf_id);
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[2][PREFIX2STR_BUFFER];
prefix2str(&dp, buf[0], sizeof(buf[0]));
if (ifp) {
zlog_debug(
- "Zebra: vrf %u interface %s bfd destination %s %s",
+ "Zebra: vrf %u interface %s bfd destination %s %s %s",
vrf_id, ifp->name, buf[0],
- bfd_get_status_str(status));
+ bfd_get_status_str(status),
+ remote_cbit ? "(cbit on)" : "");
} else {
prefix2str(&sp, buf[1], sizeof(buf[1]));
zlog_debug(
- "Zebra: vrf %u source %s bfd destination %s %s",
+ "Zebra: vrf %u source %s bfd destination %s %s %s",
vrf_id, buf[1], buf[0],
- bfd_get_status_str(status));
+ bfd_get_status_str(status),
+ remote_cbit ? "(cbit on)" : "");
}
}
@@ -351,7 +374,8 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
if (ifp && (ifp == peer->nexthop.ifp)) {
bgp_bfd_peer_status_update(peer,
- status);
+ status,
+ remote_cbit);
} else {
if (!peer->su_local)
continue;
@@ -381,7 +405,8 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
continue;
bgp_bfd_peer_status_update(peer,
- status);
+ status,
+ remote_cbit);
}
}
}
@@ -534,6 +559,9 @@ void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)
&& (bfd_info->type == BFD_TYPE_NOT_CONFIGURED))
vty_out(vty, " neighbor %s bfd\n", addr);
+
+ if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
+ vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr);
}
/*
@@ -644,6 +672,73 @@ DEFUN_HIDDEN (neighbor_bfd_type,
return CMD_SUCCESS;
}
+static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer,
+ const char *no)
+{
+ struct bfd_info *bfd_info;
+
+ if (!peer->bfd_info) {
+ if (no)
+ return CMD_SUCCESS;
+ vty_out(vty, "%% Specify bfd command first\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ bfd_info = (struct bfd_info *)peer->bfd_info;
+ if (!no) {
+ if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
+ SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
+ bgp_bfd_update_peer(peer);
+ }
+ } else {
+ if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
+ UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
+ bgp_bfd_update_peer(peer);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (neighbor_bfd_check_controlplane_failure,
+ neighbor_bfd_check_controlplane_failure_cmd,
+ "[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "BFD support\n"
+ "Link dataplane status with BGP controlplane\n")
+{
+ 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;
+ else
+ idx_peer = 1;
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer) {
+ 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;
+ }
+
DEFUN (no_neighbor_bfd,
no_neighbor_bfd_cmd,
#if HAVE_BFDD > 0
@@ -718,6 +813,7 @@ void bgp_bfd_init(void)
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);
}
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 9e37a6018..12ae1f841 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1115,8 +1115,6 @@ int bgp_stop(struct peer *peer)
/* Reset peer synctime */
peer->synctime = 0;
-
- bgp_bfd_deregister_peer(peer);
}
/* stop keepalives */
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index a7c5cf28b..33bc77049 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -174,6 +174,21 @@ The following commands are available inside the BGP configuration node.
Removes any notification registration for this neighbor.
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
+
+ Allow to write CBIT independence in BFD outgoing packets. Also allow to
+ read both C-BIT value of BFD and lookup BGP peer status. This command is
+ useful when a BFD down event is caught, while the BGP peer requested that
+ local BGP keeps the remote BGP entries as staled if such issue is detected.
+ This is the case when graceful restart is enabled, and it is wished to
+ ignore the BD event while waiting for the remote router to restart.
+
+.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
+.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
+
+ Disallow to write CBIT independence in BFD outgoing packets. Also disallow
+ to ignore BFD down notification. This is the default behaviour.
.. _bfd-ospf-peer-config:
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index fccef0169..fa89c8004 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -98,7 +98,8 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
struct prefix dst_ip;
int status;
- ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, vrf_id);
+ ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status,
+ NULL, vrf_id);
if (!ifp || dst_ip.family != AF_INET)
return 0;
@@ -217,6 +218,7 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
adj->circuit->interface->name,
0, /* ttl */
0, /* multihop */
+ 1, /* control plane independent bit is on */
ZEBRA_BFD_DEST_DEREGISTER,
0, /* set_flag */
VRF_DEFAULT);
@@ -258,6 +260,7 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
circuit->interface->name,
0, /* ttl */
0, /* multihop */
+ 1, /* control plane independent bit is on */
command,
0, /* set flag */
VRF_DEFAULT);
diff --git a/lib/bfd.c b/lib/bfd.c
index a8956c315..00dbd1b3d 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -127,8 +127,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
*/
void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip, char *if_name,
- int ttl, int multihop, int command, int set_flag,
- vrf_id_t vrf_id)
+ int ttl, int multihop, int cbit, int command,
+ int set_flag, vrf_id_t vrf_id)
{
struct stream *s;
int ret;
@@ -208,6 +208,11 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
stream_putc(s, 0);
}
}
+ /* cbit */
+ if (cbit)
+ stream_putc(s, 1);
+ else
+ stream_putc(s, 0);
stream_putw_at(s, 0, stream_get_endp(s));
@@ -253,11 +258,13 @@ const char *bfd_get_command_dbg_str(int command)
*/
struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
struct prefix *sp, int *status,
+ int *remote_cbit,
vrf_id_t vrf_id)
{
unsigned int ifindex;
struct interface *ifp = NULL;
int plen;
+ int local_remote_cbit;
/* Get interface index. */
ifindex = stream_getl(s);
@@ -292,6 +299,9 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
stream_get(&sp->u.prefix, s, plen);
sp->prefixlen = stream_getc(s);
}
+ local_remote_cbit = stream_getc(s);
+ if (remote_cbit)
+ *remote_cbit = local_remote_cbit;
return ifp;
}
diff --git a/lib/bfd.h b/lib/bfd.h
index d02110a99..e4781f4ea 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -48,6 +48,8 @@ struct bfd_gbl {
#define BFD_FLAG_PARAM_CFG (1 << 0) /* parameters have been configured */
#define BFD_FLAG_BFD_REG (1 << 1) /* Peer registered with BFD */
#define BFD_FLAG_BFD_TYPE_MULTIHOP (1 << 2) /* Peer registered with BFD as multihop */
+#define BFD_FLAG_BFD_CBIT_ON (1 << 3) /* Peer registered with CBIT set to on */
+#define BFD_FLAG_BFD_CHECK_CONTROLPLANE (1 << 4) /* BFD and controlplane daemon are linked */
#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */
@@ -83,13 +85,14 @@ extern void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx,
int *command);
extern void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip,
- char *if_name, int ttl, int multihop, int command,
- int set_flag, vrf_id_t vrf_id);
+ char *if_name, int ttl, int multihop, int cbit,
+ int command, int set_flag, vrf_id_t vrf_id);
extern const char *bfd_get_command_dbg_str(int command);
extern struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
struct prefix *sp, int *status,
+ int *remote_cbit,
vrf_id_t vrf_id);
const char *bfd_get_status_str(int status);
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 7a26af1f0..f0500601b 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -74,6 +74,7 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command)
struct interface *ifp = oi->interface;
struct bfd_info *bfd_info;
char src[64];
+ int cbit;
if (!oi->bfd_info || !on->bfd_info)
return;
@@ -85,9 +86,11 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command)
bfd_get_command_dbg_str(command), src);
}
+ cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
+
bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr,
- on->ospf6_if->linklocal_addr, ifp->name, 0, 0, command,
- 0, VRF_DEFAULT);
+ on->ospf6_if->linklocal_addr, ifp->name, 0, 0,
+ cbit, command, 0, VRF_DEFAULT);
if (command == ZEBRA_BFD_DEST_DEREGISTER)
bfd_info_free((struct bfd_info **)&on->bfd_info);
@@ -195,7 +198,8 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
struct bfd_info *bfd_info;
struct timeval tv;
- ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, vrf_id);
+ ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
+ NULL, vrf_id);
if ((ifp == NULL) || (dp.family != AF_INET6))
return 0;
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index c8ad6d04f..a17975270 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -65,6 +65,7 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command)
struct interface *ifp = oi->ifp;
struct ospf_if_params *params;
struct bfd_info *bfd_info;
+ int cbit;
/* Check if BFD is enabled */
params = IF_DEF_PARAMS(ifp);
@@ -80,8 +81,10 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command)
inet_ntoa(nbr->src),
ospf_vrf_id_to_name(oi->ospf->vrf_id));
+ cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
+
bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->src, NULL, ifp->name,
- 0, 0, command, 0, oi->ospf->vrf_id);
+ 0, 0, cbit, command, 0, oi->ospf->vrf_id);
}
/*
@@ -207,7 +210,8 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
struct bfd_info *bfd_info;
struct timeval tv;
- ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, vrf_id);
+ ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status,
+ NULL, vrf_id);
if ((ifp == NULL) || (p.family != AF_INET))
return 0;
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 300261e5a..87d0f9fa2 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -111,6 +111,7 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command)
struct pim_interface *pim_ifp = NULL;
struct bfd_info *bfd_info = NULL;
struct zclient *zclient = NULL;
+ int cbit;
zclient = pim_zebra_zclient_get();
@@ -127,8 +128,12 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command)
zlog_debug("%s Nbr %s %s with BFD", __PRETTY_FUNCTION__, str,
bfd_get_command_dbg_str(command));
}
+
+ cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
+
bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->source_addr, NULL,
- nbr->interface->name, 0, 0, command, 0, VRF_DEFAULT);
+ nbr->interface->name, 0, 0, cbit,
+ command, 0, VRF_DEFAULT);
}
/*
@@ -222,7 +227,8 @@ static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
struct listnode *neigh_nextnode = NULL;
struct pim_neighbor *neigh = NULL;
- ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status, vrf_id);
+ ifp = bfd_get_peer_info(zclient->ibuf, &p, NULL, &status,
+ NULL, vrf_id);
if ((ifp == NULL) || (p.family != AF_INET))
return 0;
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/__init__.py b/tests/topotests/bfd-bgp-cbit-topo3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/__init__.py
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json
new file mode 100644
index 000000000..54ae57f7b
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json
@@ -0,0 +1,103 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "10.254.254.1",
+ "localAS": 101,
+ "routes":
+ {
+ "2001:db8:6::/64": [
+ {
+ "stale": true,
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:6::",
+ "prefixLen": 64,
+ "network": "2001:db8:6::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001:db8:4::1",
+ "origin": "IGP",
+ "nexthops": [
+ { "ip": "2001:db8:4::1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:7::/64": [
+ {
+ "stale": true,
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:7::",
+ "prefixLen": 64, "network":
+ "2001:db8:7::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001:db8:4::1",
+ "origin": "IGP",
+ "nexthops": [
+ {
+ "ip": "2001:db8:4::1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:8::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:8::",
+ "prefixLen": 64,
+ "network": "2001:db8:8::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "origin": "IGP",
+ "nexthops": [
+ {
+ "ip": "::",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:9::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:9::",
+ "prefixLen": 64,
+ "network": "2001:db8:9::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "origin": "IGP",
+ "nexthops": [
+ {
+ "ip": "::",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
+
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf
new file mode 100644
index 000000000..fa6d60a8f
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf
@@ -0,0 +1,20 @@
+debug bgp neighbor-events
+router bgp 101
+ bgp router-id 10.254.254.1
+ timers bgp 8 24
+ bgp graceful-restart
+ neighbor 2001:db8:4::1 remote-as 102
+ neighbor 2001:db8:4::1 remote-as external
+ neighbor 2001:db8:4::1 bfd
+ neighbor 2001:db8:4::1 bfd check-control-plane-failure
+ neighbor 2001:db8:4::1 update-source 2001:db8:1::1
+ neighbor 2001:db8:4::1 ebgp-multihop 5
+ address-family ipv4 unicast
+ no neighbor 2001:db8:4::1 activate
+ exit-address-family
+ address-family ipv6 unicast
+ network 2001:db8:8::/64
+ network 2001:db8:9::/64
+ neighbor 2001:db8:4::1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/ipv6_routes.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/ipv6_routes.json
new file mode 100644
index 000000000..8eea18328
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/ipv6_routes.json
@@ -0,0 +1,80 @@
+{
+ "2001:db8:1::/64": [{
+ "distance": 0,
+ "protocol": "connected",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [{
+ "directlyConnected": true,
+ "interfaceName": "r1-eth0",
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:4::/64": [{
+ "distance": 1,
+ "protocol": "static",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:4::/64",
+ "nexthops": [{
+ "interfaceName": "r1-eth0",
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "2001:db8:6::/64": [{
+ "distance": 20,
+ "protocol": "bgp",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:6::/64",
+ "nexthops": [{
+ "ip":"2001:db8:4::1",
+ "active": true,
+ "afi": "ipv6",
+ "recursive":true
+ },
+ {
+ "fib":true,
+ "ip":"2001:db8:1::2",
+ "afi": "ipv6",
+ "interfaceName": "r1-eth0"
+ }
+ ]
+ }
+ ],
+ "2001:db8:7::/64": [{
+ "distance": 20,
+ "protocol": "bgp",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:7::/64",
+ "nexthops": [{
+ "ip":"2001:db8:4::1",
+ "active": true,
+ "afi": "ipv6",
+ "recursive": true
+ },
+ {
+ "fib":true,
+ "ip":"2001:db8:1::2",
+ "afi": "ipv6",
+ "interfaceName":"r1-eth0"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json
new file mode 100644
index 000000000..d1927ae49
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json
@@ -0,0 +1,16 @@
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:4::1",
+ "local":"2001:db8:1::1",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json
new file mode 100644
index 000000000..25b47f18e
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json
@@ -0,0 +1,14 @@
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:4::1",
+ "local":"2001:db8:1::1",
+ "status":"up",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/zebra.conf b/tests/topotests/bfd-bgp-cbit-topo3/r1/zebra.conf
new file mode 100644
index 000000000..3a30cd42f
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/zebra.conf
@@ -0,0 +1,8 @@
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ipv6 address 2001:db8:1::1/64
+!
+ipv6 route 2001:db8:4::/64 2001:db8:1::2
+
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r2/zebra.conf b/tests/topotests/bfd-bgp-cbit-topo3/r2/zebra.conf
new file mode 100644
index 000000000..0f70be1bd
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r2/zebra.conf
@@ -0,0 +1,9 @@
+ip forwarding
+ipv6 forwarding
+!
+interface r2-eth0
+ ipv6 address 2001:db8:1::2/64
+!
+interface r2-eth1
+ ipv6 address 2001:db8:4::2/64
+!
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json
new file mode 100644
index 000000000..a3bb22250
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json
@@ -0,0 +1,55 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "10.254.254.3",
+ "localAS": 102,
+ "routes":
+ {
+ "2001:db8:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:6::",
+ "prefixLen": 64,
+ "network": "2001:db8:6::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "origin": "IGP",
+ "nexthops": [
+ {
+ "ip": "::",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:7::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "2001:db8:7::",
+ "prefixLen": 64,
+ "network": "2001:db8:7::\/64",
+ "med": 0,
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "origin": "IGP",
+ "nexthops": [
+ {
+ "ip": "::",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf
new file mode 100644
index 000000000..ea5334029
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf
@@ -0,0 +1,25 @@
+debug bgp neighbor-events
+router bgp 102
+ bgp router-id 10.254.254.3
+ timers bgp 20 60
+ bgp graceful-restart
+ ! simulate NSF machine
+ bgp graceful-restart preserve-fw-state
+ bgp graceful-restart stalepath-time 900
+ bgp graceful-restart restart-time 900
+ neighbor 2001:db8:1::1 remote-as 101
+ neighbor 2001:db8:1::1 remote-as external
+ neighbor 2001:db8:1::1 update-source 2001:db8:4::1
+ neighbor 2001:db8:1::1 bfd
+ neighbor 2001:db8:1::1 ebgp-multihop 5
+ !
+ address-family ipv4 unicast
+ no neighbor 2001:db8:1::1 activate
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ neighbor 2001:db8:1::1 activate
+ network 2001:db8:6::/64
+ network 2001:db8:7::/64
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/ipv6_routes.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/ipv6_routes.json
new file mode 100644
index 000000000..09808cc09
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/ipv6_routes.json
@@ -0,0 +1,80 @@
+{
+ "2001:db8:1::/64": [{
+ "distance": 1,
+ "protocol": "static",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [{
+ "interfaceName": "r3-eth0",
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "2001:db8:4::/64": [{
+ "distance": 0,
+ "protocol": "connected",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:4::/64",
+ "nexthops": [{
+ "directlyConnected": true,
+ "interfaceName": "r3-eth0",
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:8::/64": [{
+ "distance": 20,
+ "protocol": "bgp",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:8::/64",
+ "nexthops": [{
+ "ip":"2001:db8:1::1",
+ "active": true,
+ "afi": "ipv6",
+ "recursive":true
+ },
+ {
+ "fib":true,
+ "ip":"2001:db8:4::2",
+ "afi": "ipv6",
+ "interfaceName":"r3-eth0"
+ }
+ ]
+ }
+ ],
+ "2001:db8:9::/64": [{
+ "distance": 20,
+ "protocol": "bgp",
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:9::/64",
+ "nexthops": [{
+ "ip":"2001:db8:1::1",
+ "active": true,
+ "afi": "ipv6",
+ "recursive":true
+ },
+ {
+ "fib":true,
+ "ip":"2001:db8:4::2",
+ "afi": "ipv6",
+ "interfaceName":"r3-eth0"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json
new file mode 100644
index 000000000..5193f2a6e
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json
@@ -0,0 +1,16 @@
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:1::1",
+ "local":"2001:db8:4::1",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json
new file mode 100644
index 000000000..9e4bd2633
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json
@@ -0,0 +1,14 @@
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:1::1",
+ "local":"2001:db8:4::1",
+ "status":"down",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/zebra.conf b/tests/topotests/bfd-bgp-cbit-topo3/r3/zebra.conf
new file mode 100644
index 000000000..7759251dc
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/zebra.conf
@@ -0,0 +1,7 @@
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ipv6 address 2001:db8:4::1/64
+!
+ipv6 route 2001:db8:1::/64 2001:db8:4::2
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.dot b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.dot
new file mode 100644
index 000000000..270de829c
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.dot
@@ -0,0 +1,58 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+ r2 -- sw2 [label="eth1"];
+ r3 -- sw2 [label="eth0"];
+}
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
new file mode 100755
index 000000000..59858d6fd
--- /dev/null
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_bgp_cbit_topo3.py
+#
+# Copyright (c) 2019 6WIND
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_bgp_cbit_topo3.py: Test the FRR/Quagga BFD daemon with multihop and BGP
+unnumbered.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class BFDTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers.
+ for routern in range(1, 4):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BFDTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ )
+ router.load_config(
+ TopoRouter.RD_BFD,
+ os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Verify that we are using the proper version and that the BFD
+ # daemon exists.
+ for router in router_list.values():
+ # Check for Version
+ if router.has_version('<', '5.1'):
+ tgen.set_error('Unsupported FRR version')
+ break
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged before checking for the BFD
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv6 routing tables.
+ logger.info("Checking IPv6 routes for convergence")
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ipv6 route json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=40,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bfd peers to go up')
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+def test_bfd_loss_intermediate():
+ """
+ Assert that BFD notices the bfd link down failure.
+ but BGP entries should still be present
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('removing IPv6 address from r2 to simulate loss of connectivity')
+ # Disable r2-eth0 ipv6 address
+ cmd = 'vtysh -c \"configure terminal\" -c \"interface r2-eth1\" -c "no ipv6 address 2001:db8:4::2/64\"'
+ tgen.net['r2'].cmd(cmd)
+
+ # Wait the minimum time we can before checking that BGP/BFD
+ # converged.
+ logger.info('waiting for BFD converge down')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ json_file = '{}/{}/peers_down.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ logger.info('waiting for BGP entries to become stale')
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ json_file = '{}/{}/bgp_ipv6_routes_down.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bgp ipv6 json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=50, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ logger.info("Checking IPv6 routes on r1 should still be present")
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ if router.name == 'r3':
+ continue
+ json_file = '{}/r1/ipv6_routes.json'.format(CWD)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ipv6 route json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=30,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+def test_bfd_comes_back_again():
+ """
+ Assert that BFD notices the bfd link up
+ and that ipv6 entries appear back
+ """
+ tgen = get_topogen()
+ logger.info('re-adding IPv6 address from r2 to simulate connectivity is back')
+ # adds back r2-eth0 ipv6 address
+ cmd = 'vtysh -c \"configure terminal\" -c \"interface r2-eth1\" -c "ipv6 address 2001:db8:4::2/64\"'
+ tgen.net['r2'].cmd(cmd)
+
+ # Wait the minimum time we can before checking that BGP/BFD
+ # converged.
+ logger.info('waiting for BFD to converge up')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ if router.name == 'r2':
+ continue
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index d3ecd3695..46f138552 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -93,6 +93,7 @@ const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
+const char ZEBRA_PTM_BFD_CBIT_FIELD[] = "bfdcbit";
static ptm_lib_handle_t *ptm_hdl;
@@ -688,6 +689,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
char tmp_buf[64];
int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
unsigned int pid;
+ uint8_t cbit_set;
if (hdr->command == ZEBRA_BFD_DEST_UPDATE)
client->bfd_peer_upd8_cnt++;
@@ -813,6 +815,10 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
}
+ STREAM_GETC(s, cbit_set);
+ sprintf(tmp_buf, "%d", cbit_set);
+ ptm_lib_append_msg(ptm_hdl, out_ctxt,
+ ZEBRA_PTM_BFD_CBIT_FIELD, tmp_buf);
sprintf(tmp_buf, "%d", 1);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,