Merge pull request #6437 from opensourcerouting/bfd-profiles-bgp

bfdd,bgpd: profiles integration support
This commit is contained in:
Donald Sharp 2020-07-02 12:22:44 -04:00 committed by GitHub
commit 7799deeed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1189 additions and 107 deletions

View File

@ -115,7 +115,8 @@ struct bfd_profile *bfd_profile_new(const char *name)
void bfd_profile_free(struct bfd_profile *bp)
{
/* Detach from any session. */
bfd_profile_detach(bp);
if (bglobal.bg_shutdown == false)
bfd_profile_detach(bp);
/* Remove from global list. */
TAILQ_REMOVE(&bplist, bp, entry);
@ -765,6 +766,15 @@ static void _bfd_session_update(struct bfd_session *bs,
*/
bs->peer_profile.admin_shutdown = bpc->bpc_shutdown;
bfd_set_shutdown(bs, bpc->bpc_shutdown);
/*
* Apply profile last: it also calls `bfd_set_shutdown`.
*
* There is no problem calling `shutdown` twice if the value doesn't
* change or if it is overriden by peer specific configuration.
*/
if (bpc->bpc_has_profile)
bfd_profile_apply(bpc->bpc_profile, bs);
}
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)

View File

@ -429,6 +429,12 @@ struct bfd_global {
struct zebra_privs_t bfdd_privs;
/**
* Daemon is exit()ing? Use this to avoid actions that expect a
* running system or to avoid unnecessary operations when quitting.
*/
bool bg_shutdown;
/* Debug options. */
/* Show all peer state changes events. */
bool debug_peer_event;

View File

@ -90,6 +90,9 @@ struct bfd_peer_cfg {
bool bpc_cbit;
bool bpc_has_profile;
char bpc_profile[64];
/* Status information */
enum bfd_peer_status bpc_bps;
uint32_t bpc_id;

View File

@ -63,6 +63,8 @@ static void sigusr1_handler(void)
static void sigterm_handler(void)
{
bglobal.bg_shutdown = true;
/* Signalize shutdown. */
frr_early_fini();

View File

@ -85,6 +85,7 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
{
char timers[3][128] = {};
char addr[3][128] = {};
char profile[128] = {};
char cbit_str[32];
char msgbuf[256];
va_list vl;
@ -119,13 +120,17 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit);
if (bpc->bpc_has_profile)
snprintf(profile, sizeof(profile), " profile:%s",
bpc->bpc_profile);
va_start(vl, fmt);
vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl);
va_end(vl);
zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s]", msgbuf,
zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s]", msgbuf,
bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2],
timers[0], timers[1], timers[2], cbit_str);
timers[0], timers[1], timers[2], cbit_str, profile);
}
static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag)
@ -330,6 +335,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
* - c: ifname length
* - X bytes: interface name
* - c: bfd_cbit
* - c: profile name length.
* - X bytes: profile name.
*
* q(64), l(32), w(16), c(8)
*/
@ -410,6 +417,14 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
STREAM_GETC(msg, bpc->bpc_cbit);
/* Handle profile names. */
STREAM_GETC(msg, ifnamelen);
bpc->bpc_has_profile = ifnamelen > 0;
if (bpc->bpc_has_profile) {
STREAM_GET(bpc->bpc_profile, msg, ifnamelen);
bpc->bpc_profile[ifnamelen] = 0;
}
/* 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
@ -450,10 +465,18 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
/* Protocol created peers are 'no shutdown' by default. */
bs->peer_profile.admin_shutdown = false;
} else {
/* Don't try to change echo/shutdown state. */
bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
bpc.bpc_shutdown =
CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
/*
* BFD session was already created, we are just updating the
* current peer.
*
* `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
* that allow users to set peer specific timers via protocol.
* BFD daemon (this code) on the other hand only supports
* changing peer configuration manually (through `peer` node)
* or via profiles.
*/
if (bpc.bpc_has_profile)
bfd_profile_apply(bpc.bpc_profile, bs);
}
/* Create client peer notification register. */

View File

@ -95,9 +95,24 @@ bool bgp_bfd_is_peer_multihop(struct peer *peer)
*/
static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
{
struct bfd_session_arg arg = {};
struct bfd_info *bfd_info;
int multihop, cbit = 0;
int multihop;
vrf_id_t vrf_id;
size_t addrlen;
/*
* XXX: some pointers are dangling during shutdown, so instead of
* trying to send a message during signal handlers lets just wait BGP
* to terminate zebra's connection and BFD will automatically find
* out that we are no longer expecting notifications.
*
* The pointer that is causing a crash here is `peer->nexthop.ifp`.
* That happens because at this point of the shutdown all interfaces are
* already `free()`d.
*/
if (bm->terminating)
return;
bfd_info = (struct bfd_info *)peer->bfd_info;
@ -121,21 +136,49 @@ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
&& !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);
/* 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 (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, 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, cbit, command, 1, vrf_id);
if (arg.family == AF_INET)
memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen);
else
memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen);
if (peer->su_local) {
if (arg.family == AF_INET)
memcpy(&arg.src, &peer->su_local->sin.sin_addr,
addrlen);
else
memcpy(&arg.src, &peer->su_local->sin6.sin6_addr,
addrlen);
}
if (peer->nexthop.ifp) {
arg.ifnamelen = strlen(peer->nexthop.ifp->name);
strlcpy(arg.ifname, peer->nexthop.ifp->name,
sizeof(arg.ifname));
}
if (bfd_info->profile[0]) {
arg.profilelen = strlen(bfd_info->profile);
strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile));
}
arg.set_flag = 1;
arg.mhop = multihop;
arg.ttl = peer->ttl;
arg.vrf_id = vrf_id;
arg.command = command;
arg.bfd_info = bfd_info;
arg.min_tx = bfd_info->desired_min_tx;
arg.min_rx = bfd_info->required_min_rx;
arg.detection_multiplier = bfd_info->detect_mult;
arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
/* Send message. */
zclient_bfd_command(zclient, &arg);
}
/*
@ -438,6 +481,7 @@ 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;
@ -445,6 +489,10 @@ static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
detect_mult, 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)) {
@ -453,6 +501,13 @@ static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
min_rx, min_tx, detect_mult, 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);
@ -547,6 +602,61 @@ static int bgp_bfd_peer_param_type_set(struct peer *peer,
return 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, 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, 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;
}
/*
* bgp_bfd_peer_config_write - Write the peer BFD configuration.
*/
@ -574,8 +684,12 @@ void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
: "singlehop");
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);
&& (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);
@ -818,6 +932,58 @@ DEFUN_HIDDEN (no_neighbor_bfd_type,
return CMD_SUCCESS;
}
#if HAVE_BFDD > 0
DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"BFD integration\n"
BFD_PROFILE_STR
BFD_PROFILE_NAME_STR)
{
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);
return CMD_SUCCESS;
}
DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile [BFDPROF]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"BFD integration\n"
BFD_PROFILE_STR
BFD_PROFILE_NAME_STR)
{
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_set_profile(peer, NULL);
if (ret != 0)
return bgp_vty_return(vty, ret);
return CMD_SUCCESS;
}
#endif /* HAVE_BFDD */
void bgp_bfd_init(void)
{
bfd_gbl_init();
@ -833,4 +999,9 @@ void bgp_bfd_init(void)
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);
install_element(BGP_NODE, &no_neighbor_bfd_profile_cmd);
#endif /* HAVE_BFDD */
}

View File

@ -232,6 +232,20 @@ The following commands are available inside the BGP configuration node.
Disallow to write CBIT independence in BFD outgoing packets. Also disallow
to ignore BFD down notification. This is the default behaviour.
.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
Same as command ``neighbor <A.B.C.D|X:X::X:X|WORD> bfd``, but applies the
BFD profile to the sessions it creates or that already exist.
.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
Removes the BFD profile configuration from peer session(s).
.. _bfd-ospf-peer-config:
OSPF BFD Configuration

View File

@ -263,9 +263,10 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
ZEBRA_BFD_DEST_DEREGISTER);
bfd_peer_sendmsg(zclient, NULL, adj->bfd_session->family,
&adj->bfd_session->dst_ip,
&adj->bfd_session->src_ip,
adj->circuit->interface->name,
&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
(adj->circuit->interface)
? adj->circuit->interface->name
: NULL,
0, /* ttl */
0, /* multihop */
1, /* control plane independent bit is on */
@ -324,7 +325,9 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
bfd_peer_sendmsg(zclient, circuit->bfd_info, adj->bfd_session->family,
&adj->bfd_session->dst_ip,
&adj->bfd_session->src_ip,
circuit->interface->name,
(adj->circuit->interface)
? adj->circuit->interface->name
: NULL,
0, /* ttl */
0, /* multihop */
1, /* control plane independent bit is on */

193
lib/bfd.c
View File

@ -127,9 +127,8 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int ttl, int multihop, int cbit, int command,
int set_flag, vrf_id_t vrf_id)
{
struct stream *s;
int ret;
int len;
struct bfd_session_arg args = {};
size_t addrlen;
/* Individual reg/dereg messages are suppressed during shutdown. */
if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
@ -150,86 +149,32 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
return;
}
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, vrf_id);
stream_putl(s, getpid());
stream_putw(s, family);
switch (family) {
case AF_INET:
stream_put_in_addr(s, (struct in_addr *)dst_ip);
break;
case AF_INET6:
stream_put(s, dst_ip, 16);
break;
default:
break;
/* Fill in all arguments. */
args.ttl = ttl;
args.cbit = cbit;
args.family = family;
args.mhop = multihop;
args.vrf_id = vrf_id;
args.command = command;
args.set_flag = set_flag;
args.bfd_info = bfd_info;
if (args.bfd_info) {
args.min_rx = bfd_info->required_min_rx;
args.min_tx = bfd_info->desired_min_tx;
args.detection_multiplier = bfd_info->detect_mult;
}
if (command != ZEBRA_BFD_DEST_DEREGISTER) {
stream_putl(s, bfd_info->required_min_rx);
stream_putl(s, bfd_info->desired_min_tx);
stream_putc(s, bfd_info->detect_mult);
}
addrlen = family == AF_INET ? sizeof(struct in_addr)
: sizeof(struct in6_addr);
memcpy(&args.dst, dst_ip, addrlen);
if (src_ip)
memcpy(&args.src, src_ip, addrlen);
if (multihop) {
stream_putc(s, 1);
/* Multi-hop destination send the source IP address to BFD */
if (src_ip) {
stream_putw(s, family);
switch (family) {
case AF_INET:
stream_put_in_addr(s, (struct in_addr *)src_ip);
break;
case AF_INET6:
stream_put(s, src_ip, 16);
break;
default:
break;
}
}
stream_putc(s, ttl);
} else {
stream_putc(s, 0);
if ((family == AF_INET6) && (src_ip)) {
stream_putw(s, family);
stream_put(s, src_ip, 16);
}
if (if_name) {
len = strlen(if_name);
stream_putc(s, len);
stream_put(s, if_name, len);
} else {
stream_putc(s, 0);
}
}
/* cbit */
if (cbit)
stream_putc(s, 1);
else
stream_putc(s, 0);
if (if_name)
args.ifnamelen =
strlcpy(args.ifname, if_name, sizeof(args.ifname));
stream_putw_at(s, 0, stream_get_endp(s));
ret = zclient_send_message(zclient);
if (ret < 0) {
if (bfd_debug)
zlog_debug(
"bfd_peer_sendmsg: zclient_send_message() failed");
return;
}
if (set_flag) {
if (command == ZEBRA_BFD_DEST_REGISTER)
SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
else if (command == ZEBRA_BFD_DEST_DEREGISTER)
UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
}
return;
zclient_bfd_command(zclient, &args);
}
/*
@ -478,3 +423,93 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
return;
}
int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
{
struct stream *s;
size_t addrlen;
/* Check socket. */
if (!zc || zc->sock < 0) {
if (bfd_debug)
zlog_debug("%s: zclient unavailable", __func__);
return -1;
}
s = zc->obuf;
stream_reset(s);
/* Create new message. */
zclient_create_header(s, args->command, args->vrf_id);
stream_putl(s, getpid());
/* Encode destination address. */
stream_putw(s, args->family);
addrlen = (args->family == AF_INET) ? sizeof(struct in_addr)
: sizeof(struct in6_addr);
stream_put(s, &args->dst, addrlen);
/* Encode timers if this is a registration message. */
if (args->command != ZEBRA_BFD_DEST_DEREGISTER) {
stream_putl(s, args->min_rx);
stream_putl(s, args->min_tx);
stream_putc(s, args->detection_multiplier);
}
if (args->mhop) {
/* Multi hop indicator. */
stream_putc(s, 1);
/* Multi hop always sends the source address. */
stream_putw(s, args->family);
stream_put(s, &args->src, addrlen);
/* Send the expected TTL. */
stream_putc(s, args->ttl);
} else {
/* Multi hop indicator. */
stream_putc(s, 0);
/* Single hop only sends the source address when IPv6. */
if (args->family == AF_INET6) {
stream_putw(s, args->family);
stream_put(s, &args->src, addrlen);
}
/* Send interface name if any. */
stream_putc(s, args->ifnamelen);
if (args->ifnamelen)
stream_put(s, args->ifname, args->ifnamelen);
}
/* Send the C bit indicator. */
stream_putc(s, args->cbit);
/* `ptm-bfd` doesn't support profiles yet. */
#if HAVE_BFDD > 0
/* Send profile name if any. */
stream_putc(s, args->profilelen);
if (args->profilelen)
stream_put(s, args->profile, args->profilelen);
#endif /* HAVE_BFDD */
/* Finish the message by writing the size. */
stream_putw_at(s, 0, stream_get_endp(s));
/* Send message to zebra. */
if (zclient_send_message(zc) == -1) {
if (bfd_debug)
zlog_debug("%s: zclient_send_message failed", __func__);
return -1;
}
/* Write registration indicator into data structure. */
if (args->bfd_info && args->set_flag) {
if (args->command == ZEBRA_BFD_DEST_REGISTER)
SET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
else if (args->command == ZEBRA_BFD_DEST_DEREGISTER)
UNSET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
}
return 0;
}

View File

@ -56,6 +56,8 @@ struct bfd_gbl {
#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */
#define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */
#define BFD_PROFILE_NAME_LEN 64
#define BFD_SET_CLIENT_STATUS(current_status, new_status) \
do { \
(current_status) = \
@ -77,6 +79,7 @@ struct bfd_info {
time_t last_update;
uint8_t status;
enum bfd_sess_type type;
char profile[BFD_PROFILE_NAME_LEN];
};
extern struct bfd_info *bfd_info_create(void);
@ -120,6 +123,88 @@ extern void bfd_gbl_init(void);
extern void bfd_gbl_exit(void);
/*
* BFD new API.
*/
/**
* BFD session registration arguments.
*/
struct bfd_session_arg {
/**
* BFD command.
*
* Valid commands:
* - `ZEBRA_BFD_DEST_REGISTER`
* - `ZEBRA_BFD_DEST_DEREGISTER`
*/
int32_t command;
/**
* BFD family type.
*
* Supported types:
* - `AF_INET`
* - `AF_INET6`.
*/
uint32_t family;
/** Source address. */
struct in6_addr src;
/** Source address. */
struct in6_addr dst;
/** Multi hop indicator. */
uint8_t mhop;
/** Expected TTL. */
uint8_t ttl;
/** C bit (Control Plane Independent bit) indicator. */
uint8_t cbit;
/** Interface name size. */
uint8_t ifnamelen;
/** Interface name. */
char ifname[64];
/** Daemon or session VRF. */
vrf_id_t vrf_id;
/** Profile name length. */
uint8_t profilelen;
/** Profile name. */
char profile[BFD_PROFILE_NAME_LEN];
/*
* Deprecation fields: these fields should be removed once `ptm-bfd`
* no longer uses this interface.
*/
/** Minimum required receive interval (in microseconds). */
uint32_t min_rx;
/** Minimum desired transmission interval (in microseconds). */
uint32_t min_tx;
/** Detection multiplier. */
uint32_t detection_multiplier;
/** BFD client information output. */
struct bfd_info *bfd_info;
/** Write registration indicator. */
uint8_t set_flag;
};
/**
* Send a message to BFD daemon through the zebra client.
*
* \param zc the zebra client context.
* \param arg the BFD session command arguments.
*
* \returns `-1` on failure otherwise `0`.
*
* \see bfd_session_arg.
*/
extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,38 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r1-eth1",
"multihop": false,
"peer": "172.16.100.2",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
},
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r1-eth0",
"multihop": false,
"peer": "172.16.0.1",
"receive-interval": 800,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 800,
"remote-transmit-interval": 800,
"status": "up",
"transmit-interval": 800,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,14 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
profile slowtx
receive-interval 800
transmit-interval 800
!
peer 172.16.0.1 interface r1-eth0
profile slowtx
no shutdown
!
!

View File

@ -0,0 +1,8 @@
interface r1-eth1
ip ospf area 0
ip ospf bfd
!
router ospf
ospf router-id 10.254.254.1
redistribute connected
!

View File

@ -0,0 +1,9 @@
interface lo
ip address 10.254.254.1/32
!
interface r1-eth0
ip address 172.16.0.2/24
!
interface r1-eth1
ip address 172.16.100.1/24
!

View File

@ -0,0 +1,39 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r2-eth0",
"multihop": false,
"peer": "172.16.0.2",
"receive-interval": 800,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 800,
"remote-transmit-interval": 800,
"status": "up",
"transmit-interval": 800,
"uptime": "*",
"vrf": "default"
},
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r2-eth1",
"multihop": false,
"peer": "172.16.1.1",
"receive-interval": 250,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-echo-interval": 50,
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 250,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,18 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
profile slowtx
receive-interval 800
transmit-interval 800
!
profile fasttx
receive-interval 250
transmit-interval 250
!
peer 172.16.0.2 interface r2-eth0
profile slowtx
no shutdown
!
!

View File

@ -0,0 +1,19 @@
debug bgp neighbor-events
!
router bgp 100
bgp router-id 10.254.254.2
no bgp ebgp-requires-policy
neighbor 172.16.1.1 remote-as 100
neighbor 172.16.1.1 bfd profile fasttx
neighbor 2001:db8:2::2 remote-as 200
neighbor 2001:db8:2::2 ebgp-multihop 2
neighbor 2001:db8:2::2 bfd profile slowtx
address-family ipv4 unicast
redistribute connected
exit-address-family
address-family ipv6 unicast
redistribute connected
neighbor 172.16.1.1 activate
neighbor 2001:db8:2::2 activate
exit-address-family
!

View File

@ -0,0 +1,10 @@
interface lo
ip address 10.254.254.2/32
!
interface r2-eth0
ip address 172.16.0.1/24
!
interface r2-eth1
ip address 172.16.1.2/24
ipv6 address 2001:db8:1::2/64
!

View File

@ -0,0 +1,39 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r3-eth0",
"multihop": false,
"peer": "172.16.1.2",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 250,
"remote-transmit-interval": 250,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
},
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r3-eth1",
"local": "*",
"multihop": false,
"peer": "*",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,11 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
! profile is commented out on purpose.
!profile fasttx
! receive-interval 250
! transmit-interval 250
!!
!

View File

@ -0,0 +1,13 @@
router bgp 100
bgp router-id 10.254.254.3
neighbor 172.16.1.2 remote-as 100
neighbor 172.16.1.2 bfd profile fasttx
address-family ipv4 unicast
redistribute connected
exit-address-family
address-family ipv6 unicast
redistribute connected
neighbor 172.16.1.2 activate
exit-address-family
!
!

View File

@ -0,0 +1,15 @@
hostname r3
!
debug isis adj-packets
debug isis events
debug isis update-packets
!
interface r3-eth1
ipv6 router isis lan
isis circuit-type level-1
isis bfd
!
router isis lan
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
redistribute ipv6 connected level-1
!

View File

@ -0,0 +1,12 @@
ipv6 forwarding
!
interface lo
ip address 10.254.254.3/32
!
interface r3-eth0
ip address 172.16.1.1/24
ipv6 address 2001:db8:1::1/64
!
interface r3-eth1
ipv6 address 2001:db8:2::1/64
!

View File

@ -0,0 +1,41 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r4-eth0",
"local": "*",
"multihop": false,
"peer": "*",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
},
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r4-eth1",
"local": "*",
"multihop": false,
"peer": "*",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-echo-interval": 50,
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,6 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
!

View File

@ -0,0 +1,17 @@
debug bgp neighbor-events
!
router bgp 200
bgp router-id 10.254.254.4
no bgp ebgp-requires-policy
neighbor 2001:db8:1::2 remote-as 100
neighbor 2001:db8:1::2 ebgp-multihop 2
neighbor 2001:db8:1::2 bfd profile fasttx
address-family ipv4 unicast
redistribute connected
exit-address-family
address-family ipv6 unicast
redistribute connected
neighbor 2001:db8:1::2 activate
exit-address-family
!
!

View File

@ -0,0 +1,15 @@
hostname r4
!
debug isis adj-packets
debug isis events
debug isis update-packets
!
interface r4-eth0
ipv6 router isis lan
isis circuit-type level-1
isis bfd
!
router isis lan
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
redistribute ipv6 connected level-1
!

View File

@ -0,0 +1,8 @@
interface r4-eth1
ipv6 ospf6 bfd
!
router ospf6
ospf6 router-id 10.254.254.4
redistribute connected
interface r4-eth1 area 0.0.0.0
!

View File

@ -0,0 +1,12 @@
ipv6 forwarding
!
interface lo
ip address 10.254.254.4/32
!
interface r4-eth0
ipv6 address 2001:db8:2::2/64
!
interface r4-eth1
ip address 172.16.3.1/24
ipv6 address 2001:db8:3::1/64
!

View File

@ -0,0 +1,21 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r5-eth0",
"local": "*",
"multihop": false,
"peer": "*",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,11 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
! profile is commented out on purpose.
!profile fasttx
! receive-interval 250
! transmit-interval 250
!!
!

View File

@ -0,0 +1,8 @@
interface r5-eth0
ipv6 ospf6 bfd
!
router ospf6
ospf6 router-id 10.254.254.5
redistribute connected
interface r5-eth0 area 0.0.0.0
!

View File

@ -0,0 +1,6 @@
interface lo
ip address 10.254.254.5/32
!
interface r5-eth0
ipv6 address 2001:db8:3::2/64
!

View File

@ -0,0 +1,20 @@
[
{
"detect-multiplier": 3,
"diagnostic": "ok",
"id": "*",
"interface": "r6-eth0",
"multihop": false,
"peer": "172.16.100.1",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"vrf": "default"
}
]

View File

@ -0,0 +1,11 @@
debug bfd peer
debug bfd network
debug bfd zebra
!
bfd
! profile is commented out on purpose.
!profile fasttx
! receive-interval 250
! transmit-interval 250
!!
!

View File

@ -0,0 +1,8 @@
interface r6-eth0
ip ospf area 0
ip ospf bfd
!
router ospf
ospf router-id 10.254.254.6
redistribute connected
!

View File

@ -0,0 +1,6 @@
interface lo
ip address 10.254.254.6/32
!
interface r6-eth0
ip address 172.16.100.2/24
!

View File

@ -0,0 +1,97 @@
## 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-profiles-topo1";
# Routers
r1 [
shape=doubleoctagon,
label="r1",
fillcolor="#f08080",
style=filled,
];
r2 [
shape=doubleoctagon
label="r2",
fillcolor="#f08080",
style=filled,
];
r3 [
shape=doubleoctagon
label="r3",
fillcolor="#f08080",
style=filled,
];
r4 [
shape=doubleoctagon
label="r4",
fillcolor="#f08080",
style=filled,
];
r5 [
shape=doubleoctagon
label="r5",
fillcolor="#f08080",
style=filled,
];
# Switches
sw1 [
shape=oval,
label="sw1\n172.16.0.0/24",
fillcolor="#d0e0d0",
style=filled,
];
sw2 [
shape=oval,
label="sw2\n172.16.1.0/24\n2001:db8:1::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw3 [
shape=oval,
label="sw3\n2001:db8:2::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw4 [
shape=oval,
label="sw4\n2001:db8:3::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw5 [
shape=oval,
label="sw5\n172.16.100.0/24",
fillcolor="#d0e0d0",
style=filled,
];
# Connections
r1 -- sw1 [label="eth0"];
r2 -- sw1 [label="eth0"];
r2 -- sw2 [label="eth1"];
r3 -- sw2 [label="eth0"];
r3 -- sw3 [label="eth1"];
r4 -- sw3 [label="eth0"];
r4 -- sw4 [label="eth1"];
r5 -- sw4 [label="eth0"];
r1 -- sw5 [label="eth1"];
r6 -- sw5 [label="eth0"];
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -0,0 +1,198 @@
#!/usr/bin/env python
#
# test_bfd_profiles_topo1.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2020 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# 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_profiles_topo1.py: Test the FRR BFD profile protocol integration.
"""
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 BFDProfTopo(Topo):
"Test topology builder"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
# Create 6 routers
for routern in range(1, 7):
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"])
switch = tgen.add_switch("s3")
switch.add_link(tgen.gears["r3"])
switch.add_link(tgen.gears["r4"])
switch = tgen.add_switch("s4")
switch.add_link(tgen.gears["r4"])
switch.add_link(tgen.gears["r5"])
switch = tgen.add_switch("s5")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r6"])
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDProfTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for rname, router in router_list.iteritems():
daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_BFD, daemon_file)
daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_BGP, daemon_file)
daemon_file = "{}/{}/isisd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_ISIS, daemon_file)
daemon_file = "{}/{}/ospfd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_OSPF, daemon_file)
daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_OSPF6, daemon_file)
daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
# Initialize all routers.
tgen.start_router()
def teardown_module(_mod):
"Teardown the pytest environment"
tgen = get_topogen()
tgen.stop_topology()
def test_wait_protocols_convergence():
"Wait for all protocols to converge"
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("waiting for protocols to converge")
def expect_loopback_route(router, iptype, route, proto):
"Wait until route is present on RIB for protocol."
logger.info('waiting route {} in {}'.format(route, router))
test_func = partial(
topotest.router_json_cmp,
tgen.gears[router],
'show {} route json'.format(iptype),
{ route: [{ 'protocol': proto }] }
)
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
assertmsg = '"{}" OSPF convergence failure'.format(router)
assert result is None, assertmsg
# Wait for R1 <-> R6 convergence.
expect_loopback_route('r1', 'ip', '10.254.254.6/32', 'ospf')
# Wait for R6 <-> R1 convergence.
expect_loopback_route('r6', 'ip', '10.254.254.1/32', 'ospf')
# Wait for R2 <-> R3 convergence.
expect_loopback_route('r2', 'ip', '10.254.254.3/32', 'bgp')
# Wait for R3 <-> R2 convergence.
expect_loopback_route('r3', 'ip', '10.254.254.2/32', 'bgp')
# Wait for R3 <-> R4 convergence.
expect_loopback_route('r3', 'ipv6', '2001:db8:3::/64', 'isis')
# Wait for R4 <-> R3 convergence.
expect_loopback_route('r4', 'ipv6', '2001:db8:1::/64', 'isis')
# Wait for R4 <-> R5 convergence.
expect_loopback_route('r4', 'ipv6', '2001:db8:3::/64', 'ospf6')
# Wait for R5 <-> R4 convergence.
expect_loopback_route('r5', 'ipv6', '2001:db8:2::/64', 'ospf6')
def test_bfd_profile_values():
"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 and checking profile values")
for router in tgen.routers().values():
json_file = "{}/{}/bfd-peers-initial.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=12, 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))