mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 19:39:28 +00:00
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:
parent
b0475d5a52
commit
50d194f8c8
144
pimd/pim_cmd.c
144
pimd/pim_cmd.c
@ -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 */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user