Merge pull request #4144 from pguibert6WIND/bfd_cbit

BFD CBIT
This commit is contained in:
Russ White 2019-05-16 10:13:26 -04:00 committed by GitHub
commit ace430f0db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 964 additions and 27 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -1115,8 +1115,6 @@ int bgp_stop(struct peer *peer)
/* Reset peer synctime */
peer->synctime = 0;
bgp_bfd_deregister_peer(peer);
}
/* stop keepalives */

View File

@ -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:

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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
}
]
}
]
}
}

View File

@ -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
!

View File

@ -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"
}
]
}
]
}

View File

@ -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
}
]

View File

@ -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
}
]

View File

@ -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

View File

@ -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
!

View File

@ -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
}
]
}
]
}
}

View File

@ -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
!

View File

@ -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"
}
]
}
]
}

View File

@ -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
}
]

View File

@ -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
}
]

View File

@ -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

View File

@ -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"];
}

View File

@ -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))

View File

@ -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,