pimd: Northbound implementation for pim commands.

interface_ip_pim_ssm
interface_ip_pim_sm
interface_ip_pim
interface_no_ip_pim_ssm
interface_no_ip_pim_sm
interface_no_ip_pim

Yang Model:

augment /frr-interface:lib/frr-interface:interface:
    +--rw pim!
       +--rw pim-enable?       boolean <false>

Signed-off-by: Sarita Patra <saritap@vmware.com>
This commit is contained in:
Sarita Patra 2020-10-23 05:06:06 -07:00
parent b0475d5a52
commit 50d194f8c8
2 changed files with 261 additions and 71 deletions

View File

@ -8092,36 +8092,19 @@ DEFUN_HIDDEN (interface_ip_pim_ssm,
PIM_STR PIM_STR
IFACE_PIM_STR) IFACE_PIM_STR)
{ {
VTY_DECLVAR_CONTEXT(interface, ifp); int ret;
if (!pim_cmd_interface_add(vty, ifp)) { nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
vty_out(vty, "Could not enable PIM SM on interface %s\n",
ifp->name); ret = nb_cli_apply_changes(vty, "./frr-pim:pim");
return CMD_WARNING_CONFIG_FAILED;
} if (ret != NB_OK)
return ret;
vty_out(vty, vty_out(vty,
"WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n"); "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n");
return CMD_SUCCESS;
}
static int interface_ip_pim_helper(struct vty *vty) return NB_OK;
{
struct pim_interface *pim_ifp;
VTY_DECLVAR_CONTEXT(interface, ifp);
if (!pim_cmd_interface_add(vty, ifp)) {
vty_out(vty, "Could not enable PIM SM on interface %s\n",
ifp->name);
return CMD_WARNING_CONFIG_FAILED;
}
pim_ifp = ifp->info;
pim_if_create_pimreg(pim_ifp->pim);
return CMD_SUCCESS;
} }
DEFUN_HIDDEN (interface_ip_pim_sm, DEFUN_HIDDEN (interface_ip_pim_sm,
@ -8131,7 +8114,9 @@ DEFUN_HIDDEN (interface_ip_pim_sm,
PIM_STR PIM_STR
IFACE_PIM_SM_STR) IFACE_PIM_SM_STR)
{ {
return interface_ip_pim_helper(vty); nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, "./frr-pim:pim");
} }
DEFUN (interface_ip_pim, DEFUN (interface_ip_pim,
@ -8140,43 +8125,9 @@ DEFUN (interface_ip_pim,
IP_STR IP_STR
PIM_STR) PIM_STR)
{ {
return interface_ip_pim_helper(vty); nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
}
static int pim_cmd_interface_delete(struct interface *ifp) return nb_cli_apply_changes(vty, "./frr-pim:pim");
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
return 1;
PIM_IF_DONT_PIM(pim_ifp->options);
pim_if_membership_clear(ifp);
/*
pim_sock_delete() removes all neighbors from
pim_ifp->pim_neighbor_list.
*/
pim_sock_delete(ifp, "pim unconfigured on interface");
if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
pim_if_addr_del_all(ifp);
pim_if_delete(ifp);
}
return 1;
}
static int interface_no_ip_pim_helper(struct vty *vty)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
if (!pim_cmd_interface_delete(ifp)) {
vty_out(vty, "Unable to delete interface information\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
} }
DEFUN_HIDDEN (interface_no_ip_pim_ssm, DEFUN_HIDDEN (interface_no_ip_pim_ssm,
@ -8187,7 +8138,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm,
PIM_STR PIM_STR
IFACE_PIM_STR) IFACE_PIM_STR)
{ {
return interface_no_ip_pim_helper(vty); const struct lyd_node *igmp_enable_dnode;
char igmp_if_xpath[XPATH_MAXLEN];
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/igmp-enable", igmp_if_xpath);
if (!igmp_enable_dnode) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else {
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
"false");
}
return nb_cli_apply_changes(vty, "./frr-pim:pim");
} }
DEFUN_HIDDEN (interface_no_ip_pim_sm, DEFUN_HIDDEN (interface_no_ip_pim_sm,
@ -8198,7 +8170,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm,
PIM_STR PIM_STR
IFACE_PIM_SM_STR) IFACE_PIM_SM_STR)
{ {
return interface_no_ip_pim_helper(vty); const struct lyd_node *igmp_enable_dnode;
char igmp_if_xpath[XPATH_MAXLEN];
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/igmp-enable", igmp_if_xpath);
if (!igmp_enable_dnode) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else {
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
"false");
}
return nb_cli_apply_changes(vty, "./frr-pim:pim");
} }
DEFUN (interface_no_ip_pim, DEFUN (interface_no_ip_pim,
@ -8208,7 +8201,28 @@ DEFUN (interface_no_ip_pim,
IP_STR IP_STR
PIM_STR) PIM_STR)
{ {
return interface_no_ip_pim_helper(vty); const struct lyd_node *igmp_enable_dnode;
char igmp_if_xpath[XPATH_MAXLEN];
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/igmp-enable", igmp_if_xpath);
if (!igmp_enable_dnode) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else {
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
NULL);
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
} else
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
"false");
}
return nb_cli_apply_changes(vty, "./frr-pim:pim");
} }
/* boundaries */ /* boundaries */

View File

@ -21,9 +21,136 @@
#include "pim_nb.h" #include "pim_nb.h"
#include "lib/northbound_cli.h" #include "lib/northbound_cli.h"
#include "pim_igmpv3.h" #include "pim_igmpv3.h"
#include "pim_pim.h"
void pim_if_membership_clear(struct interface *ifp); static void pim_if_membership_clear(struct interface *ifp)
void pim_if_membership_refresh(struct interface *ifp); {
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
zassert(pim_ifp);
if (PIM_IF_TEST_PIM(pim_ifp->options)
&& PIM_IF_TEST_IGMP(pim_ifp->options)) {
return;
}
pim_ifchannel_membership_clear(ifp);
}
/*
* When PIM is disabled on interface, IGMPv3 local membership
* information is not injected into PIM interface state.
* The function pim_if_membership_refresh() fetches all IGMPv3 local
* membership information into PIM. It is intented to be called
* whenever PIM is enabled on the interface in order to collect missed
* local membership information.
*/
static void pim_if_membership_refresh(struct interface *ifp)
{
struct pim_interface *pim_ifp;
struct listnode *sock_node;
struct igmp_sock *igmp;
pim_ifp = ifp->info;
zassert(pim_ifp);
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
if (!PIM_IF_TEST_IGMP(pim_ifp->options))
return;
/*
* First clear off membership from all PIM (S,G) entries on the
* interface
*/
pim_ifchannel_membership_clear(ifp);
/*
* Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on
* the interface
*/
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
struct listnode *grpnode;
struct igmp_group *grp;
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode,
grp)) {
struct listnode *srcnode;
struct igmp_source *src;
/* scan group sources */
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
srcnode, src)) {
if (IGMP_SOURCE_TEST_FORWARDING(
src->source_flags)) {
struct prefix_sg sg;
memset(&sg, 0,
sizeof(struct prefix_sg));
sg.src = src->source_addr;
sg.grp = grp->group_addr;
pim_ifchannel_local_membership_add(
ifp, &sg, false /*is_vxlan*/);
}
} /* scan group sources */
} /* scan igmp groups */
} /* scan igmp sockets */
/*
* Finally delete every PIM (S,G) entry lacking all state info
*/
pim_ifchannel_delete_on_noinfo(ifp);
}
static int pim_cmd_interface_add(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
pim_ifp = pim_if_new(ifp, false, true, false, false);
else
PIM_IF_DO_PIM(pim_ifp->options);
pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
return 1;
}
static int pim_cmd_interface_delete(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
return 1;
PIM_IF_DONT_PIM(pim_ifp->options);
pim_if_membership_clear(ifp);
/*
* pim_sock_delete() removes all neighbors from
* pim_ifp->pim_neighbor_list.
*/
pim_sock_delete(ifp, "pim unconfigured on interface");
if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
pim_if_addr_del_all(ifp);
pim_if_delete(ifp);
}
return 1;
}
static bool is_pim_interface(const struct lyd_node *dnode) static bool is_pim_interface(const struct lyd_node *dnode)
{ {
@ -866,7 +993,6 @@ int lib_interface_pim_create(struct nb_cb_create_args *args)
case NB_EV_PREPARE: case NB_EV_PREPARE:
case NB_EV_ABORT: case NB_EV_ABORT:
case NB_EV_APPLY: case NB_EV_APPLY:
/* TODO: implement me. */
break; break;
} }
@ -875,13 +1001,26 @@ int lib_interface_pim_create(struct nb_cb_create_args *args)
int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) int lib_interface_pim_destroy(struct nb_cb_destroy_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:
case NB_EV_APPLY:
/* TODO: implement me. */
break; break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_OK;
if (!pim_cmd_interface_delete(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Unable to delete interface information %s",
ifp->name);
return NB_ERR_INCONSISTENCY;
}
} }
return NB_OK; return NB_OK;
@ -892,12 +1031,49 @@ int lib_interface_pim_destroy(struct nb_cb_destroy_args *args)
*/ */
int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args) int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args)
{ {
struct interface *ifp;
struct pim_interface *pim_ifp;
int mcast_if_count;
const struct lyd_node *if_dnode;
switch (args->event) { switch (args->event) {
case NB_EV_VALIDATE: case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
mcast_if_count =
yang_get_list_elements_count(if_dnode);
/* Limiting mcast interfaces to number of VIFs */
if (mcast_if_count == MAXVIFS) {
snprintf(args->errmsg, args->errmsg_len,
"Max multicast interfaces(%d) reached.",
MAXVIFS);
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE: case NB_EV_PREPARE:
case NB_EV_ABORT: case NB_EV_ABORT:
break;
case NB_EV_APPLY: case NB_EV_APPLY:
/* TODO: implement me. */ ifp = nb_running_get_entry(args->dnode, NULL, true);
if (yang_dnode_get_bool(args->dnode, NULL)) {
if (!pim_cmd_interface_add(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Could not enable PIM SM on interface %s",
ifp->name);
return NB_ERR_INCONSISTENCY;
}
} else {
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_ERR_INCONSISTENCY;
if (!pim_cmd_interface_delete(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Unable to delete interface information");
return NB_ERR_INCONSISTENCY;
}
}
break; break;
} }