summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/bfd.rst5
-rw-r--r--lib/bfd.c4
-rw-r--r--pimd/pim_bfd.c294
-rw-r--r--pimd/pim_bfd.h35
-rw-r--r--pimd/pim_cmd.c68
-rw-r--r--pimd/pim_iface.h9
-rw-r--r--pimd/pim_nb.c7
-rw-r--r--pimd/pim_nb.h2
-rw-r--r--pimd/pim_nb_config.c86
-rw-r--r--pimd/pim_neighbor.c8
-rw-r--r--pimd/pim_neighbor.h2
-rw-r--r--tests/topotests/pim-basic-topo2/__init__.py0
-rw-r--r--tests/topotests/pim-basic-topo2/r1/bfdd.conf6
-rw-r--r--tests/topotests/pim-basic-topo2/r1/pimd.conf4
-rw-r--r--tests/topotests/pim-basic-topo2/r1/zebra.conf3
-rw-r--r--tests/topotests/pim-basic-topo2/r2/bfdd.conf2
-rw-r--r--tests/topotests/pim-basic-topo2/r2/pimd.conf12
-rw-r--r--tests/topotests/pim-basic-topo2/r2/zebra.conf9
-rw-r--r--tests/topotests/pim-basic-topo2/r3/bfdd.conf2
-rw-r--r--tests/topotests/pim-basic-topo2/r3/pimd.conf4
-rw-r--r--tests/topotests/pim-basic-topo2/r3/zebra.conf3
-rw-r--r--tests/topotests/pim-basic-topo2/r4/bfdd.conf2
-rw-r--r--tests/topotests/pim-basic-topo2/r4/pimd.conf4
-rw-r--r--tests/topotests/pim-basic-topo2/r4/zebra.conf3
-rw-r--r--tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot73
-rw-r--r--tests/topotests/pim-basic-topo2/test_pim_basic_topo2.pngbin0 -> 33496 bytes
-rw-r--r--tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py238
-rw-r--r--yang/frr-pim.yang6
28 files changed, 554 insertions, 337 deletions
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 6f797f7cc1..f73c91e026 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -340,12 +340,15 @@ PIM BFD Configuration
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
a new neighbor is found a BFD peer is created to monitor the link
status for fast convergence.
+ Optionally uses the BFD profile ``BFDPROF`` in the created sessions under
+ that interface.
+
.. _bfd-configuration:
diff --git a/lib/bfd.c b/lib/bfd.c
index bf3eaa32db..b821094cdd 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -1080,7 +1080,7 @@ static int zclient_bfd_session_reply(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;
struct interface *ifp;
int remote_cbit = false;
@@ -1137,7 +1137,7 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
now = monotime(NULL);
/* Notify all matching sessions about update. */
- TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
+ TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) {
/* Skip not installed entries. */
if (!bsp->installed)
continue;
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 5e1b9a69e1..bc518391a5 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -42,36 +42,40 @@
void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
- struct bfd_info *bfd_info = NULL;
- if (!pim_ifp)
- return;
-
- bfd_info = pim_ifp->bfd_info;
- if (!bfd_info)
+ if (!pim_ifp || !pim_ifp->bfd_config.enabled)
return;
#if HAVE_BFDD == 0
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
- vty_out(vty, " ip pim bfd %d %d %d\n", bfd_info->detect_mult,
- bfd_info->required_min_rx, bfd_info->desired_min_tx);
+ if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
+ || pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX
+ || 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
#endif /* ! HAVE_BFDD */
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);
}
-/*
- * pim_bfd_show_info - Show BFD info structure
- */
-void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
- bool use_json, int param_only)
+static void pim_neighbor_bfd_cb(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss, void *arg)
{
- if (param_only)
- bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json,
- json_obj);
- else
- bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json,
- json_obj);
+ struct pim_neighbor *nbr = arg;
+
+ if (PIM_DEBUG_PIM_TRACE) {
+ zlog_debug("%s: status %s old_status %s", __func__,
+ bfd_get_status_str(bss->state),
+ 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,
struct pim_neighbor *neigh)
{
- struct bfd_info *nbr_bfd_info = NULL;
-
/* Check if Pim Interface BFD is enabled */
- if (!pim_ifp || !pim_ifp->bfd_info)
- return;
-
- if (!neigh->bfd_info)
- neigh->bfd_info = bfd_info_create();
-
- if (!neigh->bfd_info)
- return;
-
- nbr_bfd_info = neigh->bfd_info;
- nbr_bfd_info->detect_mult = pim_ifp->bfd_info->detect_mult;
- nbr_bfd_info->desired_min_tx = pim_ifp->bfd_info->desired_min_tx;
- nbr_bfd_info->required_min_rx = pim_ifp->bfd_info->required_min_rx;
-}
-
-/*
- * 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)
+ if (!pim_ifp || !pim_ifp->bfd_config.enabled)
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);
+ if (neigh->bfd_session == NULL)
+ neigh->bfd_session = bfd_sess_new(pim_neighbor_bfd_cb, neigh);
- bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->source_addr, NULL,
- nbr->interface->name, 0, 0, cbit,
- command, 0, VRF_DEFAULT);
+ bfd_sess_set_timers(
+ neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier,
+ pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
+ bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr);
+ bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name);
+ bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile);
+ bfd_sess_install(neigh->bfd_session);
}
/*
@@ -142,7 +106,7 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command)
* zebra for starting/stopping the monitoring of
* 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 listnode *node = NULL;
@@ -150,197 +114,17 @@ int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
pim_ifp = ifp->info;
if (!pim_ifp)
- return -1;
- if (!pim_ifp->bfd_info)
- return -1;
+ return;
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);
else
- pim_bfd_info_free((struct bfd_info **)&neigh->bfd_info);
-
- 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;
+ bfd_sess_free(&neigh->bfd_session);
}
-
- 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)
{
- struct zclient *zclient = NULL;
-
- 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;
+ bfd_protocol_integration_init(pim_zebra_zclient_get(), router->master);
}
diff --git a/pimd/pim_bfd.h b/pimd/pim_bfd.h
index 962b727f88..3bfbb7486e 100644
--- a/pimd/pim_bfd.h
+++ b/pimd/pim_bfd.h
@@ -25,16 +25,35 @@
#include "if.h"
+/**
+ * Initializes PIM BFD integration code.
+ */
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_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,
- uint32_t min_tx, uint8_t detect_mult, int defaults);
-int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command);
-void pim_bfd_trigger_event(struct pim_interface *pim_ifp,
- struct pim_neighbor *nbr, uint8_t nbr_up);
+
+/**
+ * Enables or disables all peers BFD sessions.
+ *
+ * \param ifp interface pointer.
+ * \param enable session state to set.
+ */
+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,
struct pim_neighbor *neigh);
-void pim_bfd_info_free(struct bfd_info **bfd_info);
+
#endif /* _PIM_BFD_H */
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 4bbe7d35f0..c01cfec88e 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -1955,8 +1955,8 @@ static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
vty_out(vty,
" Hello Option - T-bit : %s\n",
option_t_bit ? "yes" : "no");
- pim_bfd_show_info(vty, neigh->bfd_info,
- json_ifp, uj, 0);
+ bfd_sess_show(vty, json_ifp,
+ neigh->bfd_session);
vty_out(vty, "\n");
}
}
@@ -9676,19 +9676,16 @@ DEFUN (interface_no_pim_use_source,
"frr-routing:ipv4");
}
-DEFUN (ip_pim_bfd,
+DEFPY (ip_pim_bfd,
ip_pim_bfd_cmd,
- "ip pim bfd",
+ "ip pim bfd [profile BFDPROF$prof]",
IP_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;
- char bfd_xpath[XPATH_MAXLEN + 20];
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-igmp:igmp/igmp-enable",
@@ -9702,31 +9699,25 @@ DEFUN (ip_pim_bfd,
"true");
}
- snprintf(default_rx_interval, sizeof(default_rx_interval), "%d",
- BFD_DEF_MIN_RX);
- snprintf(default_tx_interval, sizeof(default_tx_interval), "%d",
- BFD_DEF_MIN_TX);
- snprintf(default_detect_mult, sizeof(default_detect_mult), "%d",
- BFD_DEF_DETECT_MULT);
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
+ if (prof)
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof);
- snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd",
- VTY_CURR_XPATH);
- bfd_info = nb_running_get_entry(NULL, bfd_xpath, false);
-
- if (!bfd_info ||
- !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) {
- nb_cli_enqueue_change(vty, "./bfd/min-rx-interval",
- NB_OP_MODIFY, default_rx_interval);
- nb_cli_enqueue_change(vty, "./bfd/min-tx-interval",
- NB_OP_MODIFY, default_tx_interval);
- nb_cli_enqueue_change(vty, "./bfd/detect_mult",
- NB_OP_MODIFY,
- default_detect_mult);
+ return nb_cli_apply_changes(vty, "./frr-pim:pim");
+}
- return nb_cli_apply_changes(vty, "./frr-pim:pim");
- }
+DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd,
+ "no ip pim bfd profile [BFDPROF]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Disable BFD profile\n"
+ "BFD Profile name\n")
+{
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL);
- return NB_OK;
+ return nb_cli_apply_changes(vty, "./frr-pim:pim");
}
DEFUN (no_ip_pim_bfd,
@@ -9847,19 +9838,8 @@ DEFUN_HIDDEN(
int idx_number = 3;
int idx_number_2 = 4;
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;
- 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,
"%s/frr-igmp:igmp/igmp-enable",
VTY_CURR_XPATH);
@@ -9872,6 +9852,7 @@ DEFUN_HIDDEN(
"true");
}
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
argv[idx_number_2]->arg);
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_element(INTERFACE_NODE, &ip_pim_bfd_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);
#if HAVE_BFDD == 0
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 664ab31949..92784103fe 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -158,9 +158,16 @@ struct pim_interface {
uint32_t pim_ifstat_bsm_cfg_miss;
uint32_t pim_ifstat_ucast_bsm_cfg_miss;
uint32_t pim_ifstat_bsm_invalid_sz;
- struct bfd_info *bfd_info;
bool bsm_enable; /* bsm processing enable */
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;
};
/*
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index 8ca0e0780b..37c539883d 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -259,6 +259,13 @@ const struct frr_yang_module_info frr_pim_info = {
}
},
{
+ .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",
.cbs = {
.modify = lib_interface_pim_bsm_modify,
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index 78eb680103..440384e45c 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -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(
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_unicast_bsm_modify(struct nb_cb_modify_args *args);
int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args);
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index f64adc6254..8e6f2ec42b 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -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)
{
+ 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;
+ pim_ifp->bfd_config.enabled = true;
break;
}
@@ -1912,13 +1920,10 @@ int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args)
case NB_EV_PREPARE:
break;
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;
- if (pim_ifp->bfd_info) {
- pim_bfd_reg_dereg_all_nbr(ifp,
- ZEBRA_BFD_DEST_DEREGISTER);
- bfd_info_free(&(pim_ifp->bfd_info));
- }
+ pim_ifp->bfd_config.enabled = false;
+ pim_bfd_reg_dereg_all_nbr(ifp);
break;
}
@@ -1932,11 +1937,8 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
{
struct interface *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;
if (!pim_ifp) {
@@ -1944,17 +1946,14 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
return;
}
- min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
- min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
- detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult");
-
- if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX)
- && (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);
+ pim_ifp->bfd_config.detection_multiplier =
+ 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");
- nb_running_set_entry(args->dnode, pim_ifp->bfd_info);
+ pim_bfd_reg_dereg_all_nbr(ifp);
}
/*
@@ -2006,6 +2005,53 @@ int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args)
}
/*
+ * 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
*/
int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args)
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index 167aa3c604..19dc469091 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -377,7 +377,7 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr,
}
// Register PIM Neighbor with BFD
- pim_bfd_trigger_event(pim_ifp, neigh, 1);
+ pim_bfd_info_nbr_create(pim_ifp, neigh);
return neigh;
}
@@ -419,8 +419,7 @@ void pim_neighbor_free(struct pim_neighbor *neigh)
list_delete(&neigh->upstream_jp_agg);
THREAD_OFF(neigh->jp_timer);
- if (neigh->bfd_info)
- pim_bfd_info_free(&neigh->bfd_info);
+ bfd_sess_free(&neigh->bfd_session);
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);
}
- // De-Register PIM Neighbor with BFD
- pim_bfd_trigger_event(pim_ifp, neigh, 0);
-
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh);
diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h
index a4f2e10c88..b461098a60 100644
--- a/pimd/pim_neighbor.h
+++ b/pimd/pim_neighbor.h
@@ -43,7 +43,7 @@ struct pim_neighbor {
struct thread *jp_timer;
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);
diff --git a/tests/topotests/pim-basic-topo2/__init__.py b/tests/topotests/pim-basic-topo2/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/__init__.py
diff --git a/tests/topotests/pim-basic-topo2/r1/bfdd.conf b/tests/topotests/pim-basic-topo2/r1/bfdd.conf
new file mode 100644
index 0000000000..76c6f82190
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r1/bfdd.conf
@@ -0,0 +1,6 @@
+bfd
+ profile fast-tx
+ receive-interval 250
+ transmit-interval 250
+ !
+!
diff --git a/tests/topotests/pim-basic-topo2/r1/pimd.conf b/tests/topotests/pim-basic-topo2/r1/pimd.conf
new file mode 100644
index 0000000000..b895d7d573
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r1/pimd.conf
@@ -0,0 +1,4 @@
+interface r1-eth0
+ ip pim
+ ip pim bfd profile fast-tx
+!
diff --git a/tests/topotests/pim-basic-topo2/r1/zebra.conf b/tests/topotests/pim-basic-topo2/r1/zebra.conf
new file mode 100644
index 0000000000..6bf02a3ee8
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r1/zebra.conf
@@ -0,0 +1,3 @@
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/pim-basic-topo2/r2/bfdd.conf b/tests/topotests/pim-basic-topo2/r2/bfdd.conf
new file mode 100644
index 0000000000..ca61e467dc
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r2/bfdd.conf
@@ -0,0 +1,2 @@
+bfd
+!
diff --git a/tests/topotests/pim-basic-topo2/r2/pimd.conf b/tests/topotests/pim-basic-topo2/r2/pimd.conf
new file mode 100644
index 0000000000..0b32ded19a
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r2/pimd.conf
@@ -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
+!
diff --git a/tests/topotests/pim-basic-topo2/r2/zebra.conf b/tests/topotests/pim-basic-topo2/r2/zebra.conf
new file mode 100644
index 0000000000..3ceb5f0fc2
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r2/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/pim-basic-topo2/r3/bfdd.conf b/tests/topotests/pim-basic-topo2/r3/bfdd.conf
new file mode 100644
index 0000000000..ca61e467dc
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r3/bfdd.conf
@@ -0,0 +1,2 @@
+bfd
+!
diff --git a/tests/topotests/pim-basic-topo2/r3/pimd.conf b/tests/topotests/pim-basic-topo2/r3/pimd.conf
new file mode 100644
index 0000000000..691a28ea27
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r3/pimd.conf
@@ -0,0 +1,4 @@
+interface r3-eth0
+ ip pim
+ ip pim bfd
+!
diff --git a/tests/topotests/pim-basic-topo2/r3/zebra.conf b/tests/topotests/pim-basic-topo2/r3/zebra.conf
new file mode 100644
index 0000000000..3df218ee16
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r3/zebra.conf
@@ -0,0 +1,3 @@
+interface r3-eth0
+ ip address 192.168.2.3/24
+!
diff --git a/tests/topotests/pim-basic-topo2/r4/bfdd.conf b/tests/topotests/pim-basic-topo2/r4/bfdd.conf
new file mode 100644
index 0000000000..ca61e467dc
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r4/bfdd.conf
@@ -0,0 +1,2 @@
+bfd
+!
diff --git a/tests/topotests/pim-basic-topo2/r4/pimd.conf b/tests/topotests/pim-basic-topo2/r4/pimd.conf
new file mode 100644
index 0000000000..2277b3e1f1
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r4/pimd.conf
@@ -0,0 +1,4 @@
+interface r4-eth0
+ ip pim
+ ip pim bfd
+!
diff --git a/tests/topotests/pim-basic-topo2/r4/zebra.conf b/tests/topotests/pim-basic-topo2/r4/zebra.conf
new file mode 100644
index 0000000000..6ac5c78fc3
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/r4/zebra.conf
@@ -0,0 +1,3 @@
+interface r4-eth0
+ ip address 192.168.3.4/24
+!
diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot
new file mode 100644
index 0000000000..22fce27e22
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot
@@ -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"];
+}
diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png
new file mode 100644
index 0000000000..39139a35b1
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png
Binary files differ
diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py
new file mode 100644
index 0000000000..883125cfc7
--- /dev/null
+++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py
@@ -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))
diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang
index 2070649ec2..52d8641613 100644
--- a/yang/frr-pim.yang
+++ b/yang/frr-pim.yang
@@ -331,6 +331,12 @@ module frr-pim {
description
"Detect Multiplier";
}
+
+ leaf profile {
+ type string;
+ description
+ "Use a preconfigure BFD profile.";
+ }
}
leaf bsm {