mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 15:10:38 +00:00
Merge pull request #6437 from opensourcerouting/bfd-profiles-bgp
bfdd,bgpd: profiles integration support
This commit is contained in:
commit
7799deeed6
12
bfdd/bfd.c
12
bfdd/bfd.c
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -63,6 +63,8 @@ static void sigusr1_handler(void)
|
||||
|
||||
static void sigterm_handler(void)
|
||||
{
|
||||
bglobal.bg_shutdown = true;
|
||||
|
||||
/* Signalize shutdown. */
|
||||
frr_early_fini();
|
||||
|
||||
|
@ -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. */
|
||||
|
205
bgpd/bgp_bfd.c
205
bgpd/bgp_bfd.c
@ -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 */
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
193
lib/bfd.c
@ -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;
|
||||
}
|
||||
|
85
lib/bfd.h
85
lib/bfd.h
@ -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
|
||||
|
0
tests/topotests/bfd-profiles-topo1/__init__.py
Normal file
0
tests/topotests/bfd-profiles-topo1/__init__.py
Normal file
38
tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
Normal file
38
tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
14
tests/topotests/bfd-profiles-topo1/r1/bfdd.conf
Normal file
14
tests/topotests/bfd-profiles-topo1/r1/bfdd.conf
Normal 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
|
||||
!
|
||||
!
|
8
tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
Normal file
8
tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
Normal 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
|
||||
!
|
9
tests/topotests/bfd-profiles-topo1/r1/zebra.conf
Normal file
9
tests/topotests/bfd-profiles-topo1/r1/zebra.conf
Normal 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
|
||||
!
|
39
tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json
Normal file
39
tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
18
tests/topotests/bfd-profiles-topo1/r2/bfdd.conf
Normal file
18
tests/topotests/bfd-profiles-topo1/r2/bfdd.conf
Normal 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
|
||||
!
|
||||
!
|
19
tests/topotests/bfd-profiles-topo1/r2/bgpd.conf
Normal file
19
tests/topotests/bfd-profiles-topo1/r2/bgpd.conf
Normal 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
|
||||
!
|
10
tests/topotests/bfd-profiles-topo1/r2/zebra.conf
Normal file
10
tests/topotests/bfd-profiles-topo1/r2/zebra.conf
Normal 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
|
||||
!
|
39
tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json
Normal file
39
tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
11
tests/topotests/bfd-profiles-topo1/r3/bfdd.conf
Normal file
11
tests/topotests/bfd-profiles-topo1/r3/bfdd.conf
Normal 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
|
||||
!!
|
||||
!
|
13
tests/topotests/bfd-profiles-topo1/r3/bgpd.conf
Normal file
13
tests/topotests/bfd-profiles-topo1/r3/bgpd.conf
Normal 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
|
||||
!
|
||||
!
|
15
tests/topotests/bfd-profiles-topo1/r3/isisd.conf
Normal file
15
tests/topotests/bfd-profiles-topo1/r3/isisd.conf
Normal 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
|
||||
!
|
12
tests/topotests/bfd-profiles-topo1/r3/zebra.conf
Normal file
12
tests/topotests/bfd-profiles-topo1/r3/zebra.conf
Normal 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
|
||||
!
|
41
tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json
Normal file
41
tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
6
tests/topotests/bfd-profiles-topo1/r4/bfdd.conf
Normal file
6
tests/topotests/bfd-profiles-topo1/r4/bfdd.conf
Normal file
@ -0,0 +1,6 @@
|
||||
debug bfd peer
|
||||
debug bfd network
|
||||
debug bfd zebra
|
||||
!
|
||||
bfd
|
||||
!
|
17
tests/topotests/bfd-profiles-topo1/r4/bgpd.conf
Normal file
17
tests/topotests/bfd-profiles-topo1/r4/bgpd.conf
Normal 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
|
||||
!
|
||||
!
|
15
tests/topotests/bfd-profiles-topo1/r4/isisd.conf
Normal file
15
tests/topotests/bfd-profiles-topo1/r4/isisd.conf
Normal 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
|
||||
!
|
8
tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf
Normal file
8
tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf
Normal 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
|
||||
!
|
12
tests/topotests/bfd-profiles-topo1/r4/zebra.conf
Normal file
12
tests/topotests/bfd-profiles-topo1/r4/zebra.conf
Normal 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
|
||||
!
|
21
tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json
Normal file
21
tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
11
tests/topotests/bfd-profiles-topo1/r5/bfdd.conf
Normal file
11
tests/topotests/bfd-profiles-topo1/r5/bfdd.conf
Normal 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
|
||||
!!
|
||||
!
|
8
tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf
Normal file
8
tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf
Normal 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
|
||||
!
|
6
tests/topotests/bfd-profiles-topo1/r5/zebra.conf
Normal file
6
tests/topotests/bfd-profiles-topo1/r5/zebra.conf
Normal file
@ -0,0 +1,6 @@
|
||||
interface lo
|
||||
ip address 10.254.254.5/32
|
||||
!
|
||||
interface r5-eth0
|
||||
ipv6 address 2001:db8:3::2/64
|
||||
!
|
20
tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
Normal file
20
tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
Normal 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"
|
||||
}
|
||||
]
|
11
tests/topotests/bfd-profiles-topo1/r6/bfdd.conf
Normal file
11
tests/topotests/bfd-profiles-topo1/r6/bfdd.conf
Normal 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
|
||||
!!
|
||||
!
|
8
tests/topotests/bfd-profiles-topo1/r6/ospfd.conf
Normal file
8
tests/topotests/bfd-profiles-topo1/r6/ospfd.conf
Normal 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
|
||||
!
|
6
tests/topotests/bfd-profiles-topo1/r6/zebra.conf
Normal file
6
tests/topotests/bfd-profiles-topo1/r6/zebra.conf
Normal file
@ -0,0 +1,6 @@
|
||||
interface lo
|
||||
ip address 10.254.254.6/32
|
||||
!
|
||||
interface r6-eth0
|
||||
ip address 172.16.100.2/24
|
||||
!
|
@ -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"];
|
||||
}
|
BIN
tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.png
Normal file
BIN
tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
198
tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
Normal file
198
tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
Normal 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))
|
Loading…
Reference in New Issue
Block a user