mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-05 11:26:14 +00:00
Merge pull request #8462 from opensourcerouting/pim-bfd-refactor
pimd: rework BFD integration and add profile support
This commit is contained in:
commit
d06501f3c6
@ -340,12 +340,15 @@ PIM BFD Configuration
|
|||||||
|
|
||||||
The following commands are available inside the interface configuration node.
|
The following commands are available inside the interface configuration node.
|
||||||
|
|
||||||
.. clicmd:: ip pim bfd
|
.. clicmd:: ip pim bfd [profile BFDPROF]
|
||||||
|
|
||||||
Listen for BFD events on peers created on the interface. Every time
|
Listen for BFD events on peers created on the interface. Every time
|
||||||
a new neighbor is found a BFD peer is created to monitor the link
|
a new neighbor is found a BFD peer is created to monitor the link
|
||||||
status for fast convergence.
|
status for fast convergence.
|
||||||
|
|
||||||
|
Optionally uses the BFD profile ``BFDPROF`` in the created sessions under
|
||||||
|
that interface.
|
||||||
|
|
||||||
|
|
||||||
.. _bfd-configuration:
|
.. _bfd-configuration:
|
||||||
|
|
||||||
|
@ -1080,7 +1080,7 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
|
|||||||
|
|
||||||
static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
|
static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
|
||||||
{
|
{
|
||||||
struct bfd_session_params *bsp;
|
struct bfd_session_params *bsp, *bspn;
|
||||||
size_t sessions_updated = 0;
|
size_t sessions_updated = 0;
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
int remote_cbit = false;
|
int remote_cbit = false;
|
||||||
@ -1137,7 +1137,7 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
|
|||||||
now = monotime(NULL);
|
now = monotime(NULL);
|
||||||
|
|
||||||
/* Notify all matching sessions about update. */
|
/* Notify all matching sessions about update. */
|
||||||
TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
|
TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) {
|
||||||
/* Skip not installed entries. */
|
/* Skip not installed entries. */
|
||||||
if (!bsp->installed)
|
if (!bsp->installed)
|
||||||
continue;
|
continue;
|
||||||
|
294
pimd/pim_bfd.c
294
pimd/pim_bfd.c
@ -42,36 +42,40 @@
|
|||||||
void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
|
void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
|
||||||
{
|
{
|
||||||
struct pim_interface *pim_ifp = ifp->info;
|
struct pim_interface *pim_ifp = ifp->info;
|
||||||
struct bfd_info *bfd_info = NULL;
|
|
||||||
|
|
||||||
if (!pim_ifp)
|
if (!pim_ifp || !pim_ifp->bfd_config.enabled)
|
||||||
return;
|
|
||||||
|
|
||||||
bfd_info = pim_ifp->bfd_info;
|
|
||||||
if (!bfd_info)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if HAVE_BFDD == 0
|
#if HAVE_BFDD == 0
|
||||||
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
|
if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
|
||||||
vty_out(vty, " ip pim bfd %d %d %d\n", bfd_info->detect_mult,
|
|| pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX
|
||||||
bfd_info->required_min_rx, bfd_info->desired_min_tx);
|
|| pim_ifp->bfd_config.min_tx != BFD_DEF_MIN_TX)
|
||||||
|
vty_out(vty, " ip pim bfd %d %d %d\n",
|
||||||
|
pim_ifp->bfd_config.detection_multiplier,
|
||||||
|
pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
|
||||||
else
|
else
|
||||||
#endif /* ! HAVE_BFDD */
|
#endif /* ! HAVE_BFDD */
|
||||||
vty_out(vty, " ip pim bfd\n");
|
vty_out(vty, " ip pim bfd\n");
|
||||||
|
|
||||||
|
if (pim_ifp->bfd_config.profile)
|
||||||
|
vty_out(vty, " ip pim bfd profile %s\n",
|
||||||
|
pim_ifp->bfd_config.profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void pim_neighbor_bfd_cb(struct bfd_session_params *bsp,
|
||||||
* pim_bfd_show_info - Show BFD info structure
|
const struct bfd_session_status *bss, void *arg)
|
||||||
*/
|
|
||||||
void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
|
|
||||||
bool use_json, int param_only)
|
|
||||||
{
|
{
|
||||||
if (param_only)
|
struct pim_neighbor *nbr = arg;
|
||||||
bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json,
|
|
||||||
json_obj);
|
if (PIM_DEBUG_PIM_TRACE) {
|
||||||
else
|
zlog_debug("%s: status %s old_status %s", __func__,
|
||||||
bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json,
|
bfd_get_status_str(bss->state),
|
||||||
json_obj);
|
bfd_get_status_str(bss->previous_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bss->state == BFD_STATUS_DOWN
|
||||||
|
&& bss->previous_state == BFD_STATUS_UP)
|
||||||
|
pim_neighbor_delete(nbr->interface, nbr, "BFD Session Expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -80,60 +84,20 @@ void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
|
|||||||
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
|
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
|
||||||
struct pim_neighbor *neigh)
|
struct pim_neighbor *neigh)
|
||||||
{
|
{
|
||||||
struct bfd_info *nbr_bfd_info = NULL;
|
|
||||||
|
|
||||||
/* Check if Pim Interface BFD is enabled */
|
/* Check if Pim Interface BFD is enabled */
|
||||||
if (!pim_ifp || !pim_ifp->bfd_info)
|
if (!pim_ifp || !pim_ifp->bfd_config.enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!neigh->bfd_info)
|
if (neigh->bfd_session == NULL)
|
||||||
neigh->bfd_info = bfd_info_create();
|
neigh->bfd_session = bfd_sess_new(pim_neighbor_bfd_cb, neigh);
|
||||||
|
|
||||||
if (!neigh->bfd_info)
|
bfd_sess_set_timers(
|
||||||
return;
|
neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier,
|
||||||
|
pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
|
||||||
nbr_bfd_info = neigh->bfd_info;
|
bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr);
|
||||||
nbr_bfd_info->detect_mult = pim_ifp->bfd_info->detect_mult;
|
bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name);
|
||||||
nbr_bfd_info->desired_min_tx = pim_ifp->bfd_info->desired_min_tx;
|
bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile);
|
||||||
nbr_bfd_info->required_min_rx = pim_ifp->bfd_info->required_min_rx;
|
bfd_sess_install(neigh->bfd_session);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pim_bfd_info_free - Free BFD info structure
|
|
||||||
*/
|
|
||||||
void pim_bfd_info_free(struct bfd_info **bfd_info)
|
|
||||||
{
|
|
||||||
bfd_info_free(bfd_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
if (!nbr)
|
|
||||||
return;
|
|
||||||
pim_ifp = nbr->interface->info;
|
|
||||||
bfd_info = pim_ifp->bfd_info;
|
|
||||||
if (!bfd_info)
|
|
||||||
return;
|
|
||||||
if (PIM_DEBUG_PIM_TRACE) {
|
|
||||||
char str[INET_ADDRSTRLEN];
|
|
||||||
pim_inet4_dump("<bfd_nbr?>", nbr->source_addr, str,
|
|
||||||
sizeof(str));
|
|
||||||
zlog_debug("%s Nbr %s %s with BFD", __func__, 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, cbit,
|
|
||||||
command, 0, VRF_DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -142,7 +106,7 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command)
|
|||||||
* zebra for starting/stopping the monitoring of
|
* zebra for starting/stopping the monitoring of
|
||||||
* the neighbor rechahability.
|
* the neighbor rechahability.
|
||||||
*/
|
*/
|
||||||
int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
|
void pim_bfd_reg_dereg_all_nbr(struct interface *ifp)
|
||||||
{
|
{
|
||||||
struct pim_interface *pim_ifp = NULL;
|
struct pim_interface *pim_ifp = NULL;
|
||||||
struct listnode *node = NULL;
|
struct listnode *node = NULL;
|
||||||
@ -150,197 +114,17 @@ int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
|
|||||||
|
|
||||||
pim_ifp = ifp->info;
|
pim_ifp = ifp->info;
|
||||||
if (!pim_ifp)
|
if (!pim_ifp)
|
||||||
return -1;
|
return;
|
||||||
if (!pim_ifp->bfd_info)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
|
||||||
if (command != ZEBRA_BFD_DEST_DEREGISTER)
|
if (pim_ifp->bfd_config.enabled)
|
||||||
pim_bfd_info_nbr_create(pim_ifp, neigh);
|
pim_bfd_info_nbr_create(pim_ifp, neigh);
|
||||||
else
|
else
|
||||||
pim_bfd_info_free((struct bfd_info **)&neigh->bfd_info);
|
bfd_sess_free(&neigh->bfd_session);
|
||||||
|
|
||||||
pim_bfd_reg_dereg_nbr(neigh, command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pim_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
|
|
||||||
* neighbor state is changed to/from 2way.
|
|
||||||
*/
|
|
||||||
void pim_bfd_trigger_event(struct pim_interface *pim_ifp,
|
|
||||||
struct pim_neighbor *nbr, uint8_t nbr_up)
|
|
||||||
{
|
|
||||||
if (nbr_up) {
|
|
||||||
pim_bfd_info_nbr_create(pim_ifp, nbr);
|
|
||||||
pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER);
|
|
||||||
} else {
|
|
||||||
pim_bfd_info_free(&nbr->bfd_info);
|
|
||||||
pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pim_bfd_if_param_set - Set the configured BFD paramter values for
|
|
||||||
* interface.
|
|
||||||
*/
|
|
||||||
void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
|
|
||||||
uint32_t min_tx, uint8_t detect_mult, int defaults)
|
|
||||||
{
|
|
||||||
struct pim_interface *pim_ifp = ifp->info;
|
|
||||||
int command = 0;
|
|
||||||
|
|
||||||
if (!pim_ifp)
|
|
||||||
return;
|
|
||||||
bfd_set_param(&(pim_ifp->bfd_info), min_rx, min_tx, detect_mult, NULL,
|
|
||||||
defaults, &command);
|
|
||||||
|
|
||||||
if (pim_ifp->bfd_info) {
|
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
|
||||||
zlog_debug("%s: interface %s has bfd_info", __func__,
|
|
||||||
ifp->name);
|
|
||||||
}
|
|
||||||
if (command)
|
|
||||||
pim_bfd_reg_dereg_all_nbr(ifp, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pim_bfd_interface_dest_update - Find the neighbor for which the BFD status
|
|
||||||
* has changed and bring down the neighbor
|
|
||||||
* connectivity if the BFD status changed to
|
|
||||||
* down.
|
|
||||||
*/
|
|
||||||
static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
|
|
||||||
{
|
|
||||||
struct interface *ifp = NULL;
|
|
||||||
struct pim_interface *pim_ifp = NULL;
|
|
||||||
struct prefix p, src_p;
|
|
||||||
int status;
|
|
||||||
char msg[100];
|
|
||||||
int old_status;
|
|
||||||
struct bfd_info *bfd_info = NULL;
|
|
||||||
struct timeval tv;
|
|
||||||
struct listnode *neigh_node = NULL;
|
|
||||||
struct listnode *neigh_nextnode = NULL;
|
|
||||||
struct pim_neighbor *neigh = NULL;
|
|
||||||
|
|
||||||
ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL,
|
|
||||||
vrf_id);
|
|
||||||
|
|
||||||
if ((ifp == NULL) || (p.family != AF_INET))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pim_ifp = ifp->info;
|
|
||||||
if (!pim_ifp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!pim_ifp->bfd_info) {
|
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
|
||||||
zlog_debug("%s: pim interface %s BFD is disabled ",
|
|
||||||
__func__, ifp->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
|
||||||
zlog_debug("%s: interface %s bfd destination %pFX %s", __func__,
|
|
||||||
ifp->name, &p, bfd_get_status_str(status));
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
|
|
||||||
neigh_nextnode, neigh)) {
|
|
||||||
/* Check neigh address matches with BFD address */
|
|
||||||
if (neigh->source_addr.s_addr != p.u.prefix4.s_addr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bfd_info = (struct bfd_info *)neigh->bfd_info;
|
|
||||||
if (bfd_info->status == status) {
|
|
||||||
if (PIM_DEBUG_PIM_TRACE) {
|
|
||||||
char str[INET_ADDRSTRLEN];
|
|
||||||
pim_inet4_dump("<nht_nbr?>", neigh->source_addr,
|
|
||||||
str, sizeof(str));
|
|
||||||
zlog_debug("%s: bfd status is same for nbr %s",
|
|
||||||
__func__, str);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
old_status = bfd_info->status;
|
|
||||||
BFD_SET_CLIENT_STATUS(bfd_info->status, status);
|
|
||||||
monotime(&tv);
|
|
||||||
bfd_info->last_update = tv.tv_sec;
|
|
||||||
|
|
||||||
if (PIM_DEBUG_PIM_TRACE) {
|
|
||||||
zlog_debug("%s: status %s old_status %s", __func__,
|
|
||||||
bfd_get_status_str(status),
|
|
||||||
bfd_get_status_str(old_status));
|
|
||||||
}
|
|
||||||
if ((status == BFD_STATUS_DOWN)
|
|
||||||
&& (old_status == BFD_STATUS_UP)) {
|
|
||||||
snprintf(msg, sizeof(msg), "BFD Session Expired");
|
|
||||||
pim_neighbor_delete(ifp, neigh, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pim_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
|
|
||||||
* to zebra
|
|
||||||
*/
|
|
||||||
static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
|
|
||||||
{
|
|
||||||
struct interface *ifp = NULL;
|
|
||||||
struct pim_interface *pim_ifp = NULL;
|
|
||||||
struct pim_neighbor *neigh = NULL;
|
|
||||||
struct listnode *neigh_node;
|
|
||||||
struct listnode *neigh_nextnode;
|
|
||||||
struct vrf *vrf = NULL;
|
|
||||||
|
|
||||||
/* Send the client registration */
|
|
||||||
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
|
|
||||||
|
|
||||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
||||||
FOR_ALL_INTERFACES (vrf, ifp) {
|
|
||||||
pim_ifp = ifp->info;
|
|
||||||
|
|
||||||
if (!pim_ifp)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pim_ifp->pim_sock_fd < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list,
|
|
||||||
neigh_node, neigh_nextnode,
|
|
||||||
neigh)) {
|
|
||||||
if (!neigh->bfd_info)
|
|
||||||
continue;
|
|
||||||
if (PIM_DEBUG_PIM_TRACE) {
|
|
||||||
char str[INET_ADDRSTRLEN];
|
|
||||||
|
|
||||||
pim_inet4_dump("<bfd_nbr?>",
|
|
||||||
neigh->source_addr, str,
|
|
||||||
sizeof(str));
|
|
||||||
zlog_debug(
|
|
||||||
"%s: Replaying Pim Neigh %s to BFD vrf_id %u",
|
|
||||||
__func__, str, vrf->vrf_id);
|
|
||||||
}
|
|
||||||
pim_bfd_reg_dereg_nbr(neigh,
|
|
||||||
ZEBRA_BFD_DEST_UPDATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_bfd_init(void)
|
void pim_bfd_init(void)
|
||||||
{
|
{
|
||||||
struct zclient *zclient = NULL;
|
bfd_protocol_integration_init(pim_zebra_zclient_get(), router->master);
|
||||||
|
|
||||||
zclient = pim_zebra_zclient_get();
|
|
||||||
|
|
||||||
bfd_gbl_init();
|
|
||||||
|
|
||||||
zclient->interface_bfd_dest_update = pim_bfd_interface_dest_update;
|
|
||||||
zclient->bfd_dest_replay = pim_bfd_nbr_replay;
|
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,35 @@
|
|||||||
|
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes PIM BFD integration code.
|
||||||
|
*/
|
||||||
void pim_bfd_init(void);
|
void pim_bfd_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write configuration to `show running-config`.
|
||||||
|
*
|
||||||
|
* \param vty the vty output pointer.
|
||||||
|
* \param ifp the interface pointer that has the configuration.
|
||||||
|
*/
|
||||||
void pim_bfd_write_config(struct vty *vty, struct interface *ifp);
|
void pim_bfd_write_config(struct vty *vty, struct interface *ifp);
|
||||||
void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
|
|
||||||
bool use_json, int param_only);
|
/**
|
||||||
void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
|
* Enables or disables all peers BFD sessions.
|
||||||
uint32_t min_tx, uint8_t detect_mult, int defaults);
|
*
|
||||||
int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command);
|
* \param ifp interface pointer.
|
||||||
void pim_bfd_trigger_event(struct pim_interface *pim_ifp,
|
* \param enable session state to set.
|
||||||
struct pim_neighbor *nbr, uint8_t nbr_up);
|
*/
|
||||||
|
void pim_bfd_reg_dereg_all_nbr(struct interface *ifp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and configure peer BFD session if it does not exist. It will use
|
||||||
|
* the interface configured parameters as the peer configuration.
|
||||||
|
*
|
||||||
|
* \param pim_ifp the interface configuration pointer.
|
||||||
|
* \param neigh the neighbor configuration pointer.
|
||||||
|
*/
|
||||||
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
|
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
|
||||||
struct pim_neighbor *neigh);
|
struct pim_neighbor *neigh);
|
||||||
void pim_bfd_info_free(struct bfd_info **bfd_info);
|
|
||||||
#endif /* _PIM_BFD_H */
|
#endif /* _PIM_BFD_H */
|
||||||
|
@ -1955,8 +1955,8 @@ static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" Hello Option - T-bit : %s\n",
|
" Hello Option - T-bit : %s\n",
|
||||||
option_t_bit ? "yes" : "no");
|
option_t_bit ? "yes" : "no");
|
||||||
pim_bfd_show_info(vty, neigh->bfd_info,
|
bfd_sess_show(vty, json_ifp,
|
||||||
json_ifp, uj, 0);
|
neigh->bfd_session);
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9676,19 +9676,16 @@ DEFUN (interface_no_pim_use_source,
|
|||||||
"frr-routing:ipv4");
|
"frr-routing:ipv4");
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (ip_pim_bfd,
|
DEFPY (ip_pim_bfd,
|
||||||
ip_pim_bfd_cmd,
|
ip_pim_bfd_cmd,
|
||||||
"ip pim bfd",
|
"ip pim bfd [profile BFDPROF$prof]",
|
||||||
IP_STR
|
IP_STR
|
||||||
PIM_STR
|
PIM_STR
|
||||||
"Enables BFD support\n")
|
"Enables BFD support\n"
|
||||||
|
"Use BFD profile\n"
|
||||||
|
"Use BFD profile name\n")
|
||||||
{
|
{
|
||||||
struct bfd_info *bfd_info = NULL;
|
|
||||||
char default_rx_interval[5];
|
|
||||||
char default_tx_interval[5];
|
|
||||||
char default_detect_mult[3];
|
|
||||||
const struct lyd_node *igmp_enable_dnode;
|
const struct lyd_node *igmp_enable_dnode;
|
||||||
char bfd_xpath[XPATH_MAXLEN + 20];
|
|
||||||
|
|
||||||
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
||||||
"%s/frr-igmp:igmp/igmp-enable",
|
"%s/frr-igmp:igmp/igmp-enable",
|
||||||
@ -9702,31 +9699,25 @@ DEFUN (ip_pim_bfd,
|
|||||||
"true");
|
"true");
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(default_rx_interval, sizeof(default_rx_interval), "%d",
|
nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
|
||||||
BFD_DEF_MIN_RX);
|
if (prof)
|
||||||
snprintf(default_tx_interval, sizeof(default_tx_interval), "%d",
|
nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof);
|
||||||
BFD_DEF_MIN_TX);
|
|
||||||
snprintf(default_detect_mult, sizeof(default_detect_mult), "%d",
|
|
||||||
BFD_DEF_DETECT_MULT);
|
|
||||||
|
|
||||||
snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd",
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
||||||
VTY_CURR_XPATH);
|
}
|
||||||
bfd_info = nb_running_get_entry(NULL, bfd_xpath, false);
|
|
||||||
|
|
||||||
if (!bfd_info ||
|
DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd,
|
||||||
!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) {
|
"no ip pim bfd profile [BFDPROF]",
|
||||||
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval",
|
NO_STR
|
||||||
NB_OP_MODIFY, default_rx_interval);
|
IP_STR
|
||||||
nb_cli_enqueue_change(vty, "./bfd/min-tx-interval",
|
PIM_STR
|
||||||
NB_OP_MODIFY, default_tx_interval);
|
"Enables BFD support\n"
|
||||||
nb_cli_enqueue_change(vty, "./bfd/detect_mult",
|
"Disable BFD profile\n"
|
||||||
NB_OP_MODIFY,
|
"BFD Profile name\n")
|
||||||
default_detect_mult);
|
{
|
||||||
|
nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL);
|
||||||
|
|
||||||
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
||||||
}
|
|
||||||
|
|
||||||
return NB_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (no_ip_pim_bfd,
|
DEFUN (no_ip_pim_bfd,
|
||||||
@ -9847,19 +9838,8 @@ DEFUN_HIDDEN(
|
|||||||
int idx_number = 3;
|
int idx_number = 3;
|
||||||
int idx_number_2 = 4;
|
int idx_number_2 = 4;
|
||||||
int idx_number_3 = 5;
|
int idx_number_3 = 5;
|
||||||
uint32_t rx_val;
|
|
||||||
uint32_t tx_val;
|
|
||||||
uint8_t dm_val;
|
|
||||||
int ret;
|
|
||||||
const struct lyd_node *igmp_enable_dnode;
|
const struct lyd_node *igmp_enable_dnode;
|
||||||
|
|
||||||
if ((ret = bfd_validate_param(vty, argv[idx_number]->arg,
|
|
||||||
argv[idx_number_2]->arg,
|
|
||||||
argv[idx_number_3]->arg, &dm_val, &rx_val,
|
|
||||||
&tx_val))
|
|
||||||
!= CMD_SUCCESS)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
||||||
"%s/frr-igmp:igmp/igmp-enable",
|
"%s/frr-igmp:igmp/igmp-enable",
|
||||||
VTY_CURR_XPATH);
|
VTY_CURR_XPATH);
|
||||||
@ -9872,6 +9852,7 @@ DEFUN_HIDDEN(
|
|||||||
"true");
|
"true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
|
||||||
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
|
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
|
||||||
argv[idx_number_2]->arg);
|
argv[idx_number_2]->arg);
|
||||||
nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
|
nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
|
||||||
@ -11731,6 +11712,7 @@ void pim_cmd_init(void)
|
|||||||
/* Install BFD command */
|
/* Install BFD command */
|
||||||
install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
|
install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
|
||||||
install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
|
install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
|
||||||
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd);
|
||||||
install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
|
||||||
#if HAVE_BFDD == 0
|
#if HAVE_BFDD == 0
|
||||||
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
|
||||||
|
@ -158,9 +158,16 @@ struct pim_interface {
|
|||||||
uint32_t pim_ifstat_bsm_cfg_miss;
|
uint32_t pim_ifstat_bsm_cfg_miss;
|
||||||
uint32_t pim_ifstat_ucast_bsm_cfg_miss;
|
uint32_t pim_ifstat_ucast_bsm_cfg_miss;
|
||||||
uint32_t pim_ifstat_bsm_invalid_sz;
|
uint32_t pim_ifstat_bsm_invalid_sz;
|
||||||
struct bfd_info *bfd_info;
|
|
||||||
bool bsm_enable; /* bsm processing enable */
|
bool bsm_enable; /* bsm processing enable */
|
||||||
bool ucast_bsm_accept; /* ucast bsm processing */
|
bool ucast_bsm_accept; /* ucast bsm processing */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool enabled;
|
||||||
|
uint32_t min_rx;
|
||||||
|
uint32_t min_tx;
|
||||||
|
uint8_t detection_multiplier;
|
||||||
|
char *profile;
|
||||||
|
} bfd_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -258,6 +258,13 @@ const struct frr_yang_module_info frr_pim_info = {
|
|||||||
.modify = lib_interface_pim_bfd_detect_mult_modify,
|
.modify = lib_interface_pim_bfd_detect_mult_modify,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/profile",
|
||||||
|
.cbs = {
|
||||||
|
.modify = lib_interface_pim_bfd_profile_modify,
|
||||||
|
.destroy = lib_interface_pim_bfd_profile_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm",
|
.xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm",
|
||||||
.cbs = {
|
.cbs = {
|
||||||
|
@ -121,6 +121,8 @@ int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args)
|
|||||||
int lib_interface_pim_bfd_min_tx_interval_modify(
|
int lib_interface_pim_bfd_min_tx_interval_modify(
|
||||||
struct nb_cb_modify_args *args);
|
struct nb_cb_modify_args *args);
|
||||||
int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args);
|
int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args);
|
||||||
|
int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args);
|
||||||
|
int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args);
|
||||||
int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args);
|
int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args);
|
||||||
int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args);
|
int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args);
|
||||||
int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args);
|
int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args);
|
||||||
|
@ -1882,11 +1882,19 @@ int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args)
|
|||||||
*/
|
*/
|
||||||
int lib_interface_pim_bfd_create(struct nb_cb_create_args *args)
|
int lib_interface_pim_bfd_create(struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
|
struct interface *ifp;
|
||||||
|
struct pim_interface *pim_ifp;
|
||||||
|
|
||||||
switch (args->event) {
|
switch (args->event) {
|
||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
case NB_EV_PREPARE:
|
case NB_EV_PREPARE:
|
||||||
case NB_EV_ABORT:
|
case NB_EV_ABORT:
|
||||||
|
/* NOTHING */
|
||||||
|
break;
|
||||||
case NB_EV_APPLY:
|
case NB_EV_APPLY:
|
||||||
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
pim_ifp = ifp->info;
|
||||||
|
pim_ifp->bfd_config.enabled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1912,13 +1920,10 @@ int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args)
|
|||||||
case NB_EV_PREPARE:
|
case NB_EV_PREPARE:
|
||||||
break;
|
break;
|
||||||
case NB_EV_APPLY:
|
case NB_EV_APPLY:
|
||||||
ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
pim_ifp = ifp->info;
|
pim_ifp = ifp->info;
|
||||||
if (pim_ifp->bfd_info) {
|
pim_ifp->bfd_config.enabled = false;
|
||||||
pim_bfd_reg_dereg_all_nbr(ifp,
|
pim_bfd_reg_dereg_all_nbr(ifp);
|
||||||
ZEBRA_BFD_DEST_DEREGISTER);
|
|
||||||
bfd_info_free(&(pim_ifp->bfd_info));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1932,11 +1937,8 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
|
|||||||
{
|
{
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
struct pim_interface *pim_ifp;
|
struct pim_interface *pim_ifp;
|
||||||
uint32_t min_rx;
|
|
||||||
uint32_t min_tx;
|
|
||||||
uint8_t detect_mult;
|
|
||||||
|
|
||||||
ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
pim_ifp = ifp->info;
|
pim_ifp = ifp->info;
|
||||||
|
|
||||||
if (!pim_ifp) {
|
if (!pim_ifp) {
|
||||||
@ -1944,17 +1946,14 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
|
pim_ifp->bfd_config.detection_multiplier =
|
||||||
min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
|
yang_dnode_get_uint8(args->dnode, "./detect_mult");
|
||||||
detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult");
|
pim_ifp->bfd_config.min_rx =
|
||||||
|
yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
|
||||||
|
pim_ifp->bfd_config.min_tx =
|
||||||
|
yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
|
||||||
|
|
||||||
if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX)
|
pim_bfd_reg_dereg_all_nbr(ifp);
|
||||||
&& (detect_mult == BFD_DEF_DETECT_MULT))
|
|
||||||
pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1);
|
|
||||||
else
|
|
||||||
pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0);
|
|
||||||
|
|
||||||
nb_running_set_entry(args->dnode, pim_ifp->bfd_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2005,6 +2004,53 @@ int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args)
|
|||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/profile
|
||||||
|
*/
|
||||||
|
int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
struct interface *ifp;
|
||||||
|
struct pim_interface *pim_ifp;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
/* NOTHING */
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
pim_ifp = ifp->info;
|
||||||
|
XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
|
||||||
|
pim_ifp->bfd_config.profile = XSTRDUP(
|
||||||
|
MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args)
|
||||||
|
{
|
||||||
|
struct interface *ifp;
|
||||||
|
struct pim_interface *pim_ifp;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
/* NOTHING */
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
pim_ifp = ifp->info;
|
||||||
|
XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XPath: /frr-interface:lib/interface/frr-pim:pim/bsm
|
* XPath: /frr-interface:lib/interface/frr-pim:pim/bsm
|
||||||
*/
|
*/
|
||||||
|
@ -377,7 +377,7 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register PIM Neighbor with BFD
|
// Register PIM Neighbor with BFD
|
||||||
pim_bfd_trigger_event(pim_ifp, neigh, 1);
|
pim_bfd_info_nbr_create(pim_ifp, neigh);
|
||||||
|
|
||||||
return neigh;
|
return neigh;
|
||||||
}
|
}
|
||||||
@ -419,8 +419,7 @@ void pim_neighbor_free(struct pim_neighbor *neigh)
|
|||||||
list_delete(&neigh->upstream_jp_agg);
|
list_delete(&neigh->upstream_jp_agg);
|
||||||
THREAD_OFF(neigh->jp_timer);
|
THREAD_OFF(neigh->jp_timer);
|
||||||
|
|
||||||
if (neigh->bfd_info)
|
bfd_sess_free(&neigh->bfd_session);
|
||||||
pim_bfd_info_free(&neigh->bfd_info);
|
|
||||||
|
|
||||||
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
|
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
|
||||||
}
|
}
|
||||||
@ -669,9 +668,6 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
|
|||||||
__func__, src_str, ifp->name);
|
__func__, src_str, ifp->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-Register PIM Neighbor with BFD
|
|
||||||
pim_bfd_trigger_event(pim_ifp, neigh, 0);
|
|
||||||
|
|
||||||
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
|
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
|
||||||
|
|
||||||
pim_neighbor_free(neigh);
|
pim_neighbor_free(neigh);
|
||||||
|
@ -43,7 +43,7 @@ struct pim_neighbor {
|
|||||||
|
|
||||||
struct thread *jp_timer;
|
struct thread *jp_timer;
|
||||||
struct list *upstream_jp_agg;
|
struct list *upstream_jp_agg;
|
||||||
struct bfd_info *bfd_info;
|
struct bfd_session_params *bfd_session;
|
||||||
};
|
};
|
||||||
|
|
||||||
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
|
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
|
||||||
|
0
tests/topotests/pim-basic-topo2/__init__.py
Normal file
0
tests/topotests/pim-basic-topo2/__init__.py
Normal file
6
tests/topotests/pim-basic-topo2/r1/bfdd.conf
Normal file
6
tests/topotests/pim-basic-topo2/r1/bfdd.conf
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
bfd
|
||||||
|
profile fast-tx
|
||||||
|
receive-interval 250
|
||||||
|
transmit-interval 250
|
||||||
|
!
|
||||||
|
!
|
4
tests/topotests/pim-basic-topo2/r1/pimd.conf
Normal file
4
tests/topotests/pim-basic-topo2/r1/pimd.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface r1-eth0
|
||||||
|
ip pim
|
||||||
|
ip pim bfd profile fast-tx
|
||||||
|
!
|
3
tests/topotests/pim-basic-topo2/r1/zebra.conf
Normal file
3
tests/topotests/pim-basic-topo2/r1/zebra.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface r1-eth0
|
||||||
|
ip address 192.168.1.1/24
|
||||||
|
!
|
2
tests/topotests/pim-basic-topo2/r2/bfdd.conf
Normal file
2
tests/topotests/pim-basic-topo2/r2/bfdd.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bfd
|
||||||
|
!
|
12
tests/topotests/pim-basic-topo2/r2/pimd.conf
Normal file
12
tests/topotests/pim-basic-topo2/r2/pimd.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
interface r2-eth0
|
||||||
|
ip pim
|
||||||
|
ip pim bfd
|
||||||
|
!
|
||||||
|
interface r2-eth1
|
||||||
|
ip pim
|
||||||
|
ip pim bfd
|
||||||
|
!
|
||||||
|
interface r2-eth2
|
||||||
|
ip pim
|
||||||
|
ip pim bfd
|
||||||
|
!
|
9
tests/topotests/pim-basic-topo2/r2/zebra.conf
Normal file
9
tests/topotests/pim-basic-topo2/r2/zebra.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
interface r2-eth0
|
||||||
|
ip address 192.168.1.2/24
|
||||||
|
!
|
||||||
|
interface r2-eth1
|
||||||
|
ip address 192.168.2.1/24
|
||||||
|
!
|
||||||
|
interface r2-eth2
|
||||||
|
ip address 192.168.3.1/24
|
||||||
|
!
|
2
tests/topotests/pim-basic-topo2/r3/bfdd.conf
Normal file
2
tests/topotests/pim-basic-topo2/r3/bfdd.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bfd
|
||||||
|
!
|
4
tests/topotests/pim-basic-topo2/r3/pimd.conf
Normal file
4
tests/topotests/pim-basic-topo2/r3/pimd.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface r3-eth0
|
||||||
|
ip pim
|
||||||
|
ip pim bfd
|
||||||
|
!
|
3
tests/topotests/pim-basic-topo2/r3/zebra.conf
Normal file
3
tests/topotests/pim-basic-topo2/r3/zebra.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface r3-eth0
|
||||||
|
ip address 192.168.2.3/24
|
||||||
|
!
|
2
tests/topotests/pim-basic-topo2/r4/bfdd.conf
Normal file
2
tests/topotests/pim-basic-topo2/r4/bfdd.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bfd
|
||||||
|
!
|
4
tests/topotests/pim-basic-topo2/r4/pimd.conf
Normal file
4
tests/topotests/pim-basic-topo2/r4/pimd.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface r4-eth0
|
||||||
|
ip pim
|
||||||
|
ip pim bfd
|
||||||
|
!
|
3
tests/topotests/pim-basic-topo2/r4/zebra.conf
Normal file
3
tests/topotests/pim-basic-topo2/r4/zebra.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface r4-eth0
|
||||||
|
ip address 192.168.3.4/24
|
||||||
|
!
|
73
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot
Normal file
73
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
## 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-topo3";
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
];
|
||||||
|
|
||||||
|
# Switches
|
||||||
|
sw1 [
|
||||||
|
shape=oval,
|
||||||
|
label="sw1\n192.168.1.0/24",
|
||||||
|
fillcolor="#d0e0d0",
|
||||||
|
style=filled,
|
||||||
|
];
|
||||||
|
sw2 [
|
||||||
|
shape=oval,
|
||||||
|
label="sw2\n192.168.2.0/24",
|
||||||
|
fillcolor="#d0e0d0",
|
||||||
|
style=filled,
|
||||||
|
];
|
||||||
|
sw2 [
|
||||||
|
shape=oval,
|
||||||
|
label="sw2\n192.168.3.0/24",
|
||||||
|
fillcolor="#d0e0d0",
|
||||||
|
style=filled,
|
||||||
|
];
|
||||||
|
|
||||||
|
# Connections
|
||||||
|
r1 -- sw1 [label="eth0\n.1"];
|
||||||
|
r2 -- sw1 [label="eth0\n.2"];
|
||||||
|
|
||||||
|
r2 -- sw2 [label="eth1\n.1"];
|
||||||
|
r3 -- sw2 [label="eth0\n.3"];
|
||||||
|
|
||||||
|
r2 -- sw3 [label="eth1\n.1"];
|
||||||
|
r4 -- sw3 [label="eth2\n.4"];
|
||||||
|
}
|
BIN
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png
Normal file
BIN
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
238
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py
Normal file
238
tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#
|
||||||
|
# test_pim_basic_topo2.py
|
||||||
|
# Part of NetDEF Topology Tests
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 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_pim_basic_topo2.py: Test the FRR PIM protocol convergence.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.bfdd, pytest.mark.pimd]
|
||||||
|
|
||||||
|
|
||||||
|
class PimBasicTopo2(Topo):
|
||||||
|
"Test topology builder"
|
||||||
|
|
||||||
|
def build(self, *_args, **_opts):
|
||||||
|
"Build function"
|
||||||
|
tgen = get_topogen(self)
|
||||||
|
|
||||||
|
# Create 4 routers
|
||||||
|
for routern in range(1, 5):
|
||||||
|
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["r2"])
|
||||||
|
switch.add_link(tgen.gears["r4"])
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
"Sets up the pytest environment"
|
||||||
|
tgen = Topogen(PimBasicTopo2, mod.__name__)
|
||||||
|
tgen.start_topology()
|
||||||
|
|
||||||
|
router_list = tgen.routers()
|
||||||
|
for rname, router in router_list.items():
|
||||||
|
daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
|
||||||
|
if os.path.isfile(daemon_file):
|
||||||
|
router.load_config(TopoRouter.RD_BFD, daemon_file)
|
||||||
|
|
||||||
|
daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
|
||||||
|
if os.path.isfile(daemon_file):
|
||||||
|
router.load_config(TopoRouter.RD_PIM, 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 expect_neighbor(router, interface, peer):
|
||||||
|
"Wait until peer is present on interface."
|
||||||
|
logger.info("waiting peer {} in {}".format(peer, interface))
|
||||||
|
tgen = get_topogen()
|
||||||
|
test_func = partial(
|
||||||
|
topotest.router_json_cmp,
|
||||||
|
tgen.gears[router],
|
||||||
|
"show ip pim neighbor json",
|
||||||
|
{interface: {peer: {}}}
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
|
||||||
|
assertmsg = '"{}" PIM convergence failure'.format(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
|
||||||
|
def test_wait_pim_convergence():
|
||||||
|
"Wait for PIM to converge"
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
logger.info("waiting for PIM to converge")
|
||||||
|
|
||||||
|
expect_neighbor('r1', 'r1-eth0', '192.168.1.2')
|
||||||
|
expect_neighbor('r2', 'r2-eth0', '192.168.1.1')
|
||||||
|
|
||||||
|
expect_neighbor('r2', 'r2-eth1', '192.168.2.3')
|
||||||
|
expect_neighbor('r2', 'r2-eth2', '192.168.3.4')
|
||||||
|
|
||||||
|
expect_neighbor('r3', 'r3-eth0', '192.168.2.1')
|
||||||
|
expect_neighbor('r4', 'r4-eth0', '192.168.3.1')
|
||||||
|
|
||||||
|
|
||||||
|
def test_bfd_peers():
|
||||||
|
"Wait for BFD peers to show up."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
logger.info("waiting for BFD to converge")
|
||||||
|
|
||||||
|
def expect_bfd_peer(router, peer):
|
||||||
|
"Wait until peer is present on interface."
|
||||||
|
logger.info("waiting BFD peer {} in {}".format(peer, router))
|
||||||
|
test_func = partial(
|
||||||
|
topotest.router_json_cmp,
|
||||||
|
tgen.gears[router],
|
||||||
|
"show bfd peers json",
|
||||||
|
[{"peer": peer, "status": "up"}]
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||||
|
assertmsg = '"{}" BFD convergence failure'.format(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
expect_bfd_peer("r1", "192.168.1.2")
|
||||||
|
expect_bfd_peer("r2", "192.168.1.1")
|
||||||
|
expect_bfd_peer("r2", "192.168.2.3")
|
||||||
|
expect_bfd_peer("r2", "192.168.3.4")
|
||||||
|
expect_bfd_peer("r3", "192.168.2.1")
|
||||||
|
expect_bfd_peer("r4", "192.168.3.1")
|
||||||
|
|
||||||
|
|
||||||
|
def test_pim_reconvergence():
|
||||||
|
"Disconnect a peer and expect it to disconnect."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
logger.info("waiting for disconnect convergence")
|
||||||
|
tgen.gears["r4"].link_enable("r4-eth0", enabled=False)
|
||||||
|
|
||||||
|
def expect_neighbor_down(router, interface, peer):
|
||||||
|
"Wait until peer is present on interface."
|
||||||
|
logger.info("waiting peer {} in {} to disappear".format(peer, interface))
|
||||||
|
test_func = partial(
|
||||||
|
topotest.router_json_cmp,
|
||||||
|
tgen.gears[router],
|
||||||
|
"show ip pim neighbor json",
|
||||||
|
{interface: {peer: None}}
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
|
||||||
|
assertmsg = '"{}" PIM convergence failure'.format(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
expect_neighbor_down("r2", "r2-eth2", "192.168.3.4")
|
||||||
|
|
||||||
|
logger.info("waiting for reconvergence")
|
||||||
|
tgen.gears["r4"].link_enable("r4-eth0", enabled=True)
|
||||||
|
expect_neighbor("r2", "r2-eth2", "192.168.3.4")
|
||||||
|
|
||||||
|
|
||||||
|
def test_pim_bfd_profile():
|
||||||
|
"Test that the BFD profile is properly applied in BFD."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
def expect_bfd_peer_settings(router, settings):
|
||||||
|
"Expect the following BFD configuration"
|
||||||
|
logger.info("Verifying BFD peer {} in {}".format(settings["peer"], router))
|
||||||
|
test_func = partial(
|
||||||
|
topotest.router_json_cmp,
|
||||||
|
tgen.gears[router],
|
||||||
|
"show bfd peers json",
|
||||||
|
[settings]
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
|
||||||
|
assertmsg = '"{}" BFD convergence failure'.format(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
expect_bfd_peer_settings("r1", {
|
||||||
|
"peer": "192.168.1.2",
|
||||||
|
"receive-interval": 250,
|
||||||
|
"transmit-interval": 250,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect_bfd_peer_settings("r2", {
|
||||||
|
"peer": "192.168.1.1",
|
||||||
|
"remote-receive-interval": 250,
|
||||||
|
"remote-transmit-interval": 250,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
@ -331,6 +331,12 @@ module frr-pim {
|
|||||||
description
|
description
|
||||||
"Detect Multiplier";
|
"Detect Multiplier";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leaf profile {
|
||||||
|
type string;
|
||||||
|
description
|
||||||
|
"Use a preconfigure BFD profile.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf bsm {
|
leaf bsm {
|
||||||
|
Loading…
Reference in New Issue
Block a user