summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pimd/pim_cmd.c630
-rw-r--r--pimd/pim_nb_config.c414
2 files changed, 559 insertions, 485 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 38123cc8f6..9065d30f14 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -64,6 +64,9 @@
#include "pim_mlag.h"
#include "bfd.h"
#include "pim_bsm.h"
+#include "lib/northbound_cli.h"
+#include "pim_errors.h"
+#include "pim_nb.h"
#ifndef VTYSH_EXTRACT_PL
#include "pimd/pim_cmd_clippy.c"
@@ -101,7 +104,7 @@ static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
return vrf;
}
-static void pim_if_membership_clear(struct interface *ifp)
+void pim_if_membership_clear(struct interface *ifp)
{
struct pim_interface *pim_ifp;
@@ -125,7 +128,7 @@ static void pim_if_membership_clear(struct interface *ifp)
whenever PIM is enabled on the interface in order to collect missed
local membership information.
*/
-static void pim_if_membership_refresh(struct interface *ifp)
+void pim_if_membership_refresh(struct interface *ifp)
{
struct pim_interface *pim_ifp;
struct listnode *sock_node;
@@ -7517,51 +7520,15 @@ DEFUN (no_ip_pim_ecmp_rebalance,
return CMD_SUCCESS;
}
-static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp)
-{
- struct pim_interface *pim_ifp;
- struct pim_instance *pim;
- uint8_t need_startup = 0;
-
- pim_ifp = ifp->info;
-
- if (!pim_ifp) {
- pim = pim_get_pim_instance(ifp->vrf_id);
- /* Limit mcast interfaces to number of vifs available */
- if (pim->mcast_if_count == MAXVIFS) {
- vty_out(vty,
- "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s\n",
- MAXVIFS, ifp->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
- (void)pim_if_new(ifp, true, false, false, false);
- need_startup = 1;
- } else {
- if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
- PIM_IF_DO_IGMP(pim_ifp->options);
- need_startup = 1;
- }
- }
-
- /* 'ip igmp' executed multiple times, with need_startup
- avoid multiple if add all and membership refresh */
- if (need_startup) {
- pim_if_addr_add_all(ifp);
- pim_if_membership_refresh(ifp);
- }
-
- return CMD_SUCCESS;
-}
-
DEFUN (interface_ip_igmp,
interface_ip_igmp_cmd,
"ip igmp",
IP_STR
IFACE_IGMP_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, "true");
- return pim_cmd_igmp_start(vty, ifp);
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp,
@@ -7571,23 +7538,28 @@ DEFUN (interface_no_ip_igmp,
IP_STR
IFACE_IGMP_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
-
- if (!pim_ifp)
- return CMD_SUCCESS;
+ const struct lyd_node *pim_enable_dnode;
+ char pim_if_xpath[XPATH_MAXLEN];
- PIM_IF_DONT_IGMP(pim_ifp->options);
+ snprintf(pim_if_xpath, sizeof(pim_if_xpath),
+ "%s/frr-pim:pim", VTY_CURR_XPATH);
- pim_if_membership_clear(ifp);
-
- pim_if_addr_del_all_igmp(ifp);
-
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- pim_if_delete(ifp);
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/pim-enable", pim_if_xpath);
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, ".")) {
+ nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY,
+ NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ } else
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "false");
}
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_ip_igmp_join,
@@ -7599,46 +7571,28 @@ DEFUN (interface_ip_igmp_join,
"Multicast group address\n"
"Source address\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- int idx_ipv4 = 3;
- int idx_ipv4_2 = 4;
- const char *group_str;
+ int idx_group = 3;
+ int idx_source = 4;
const char *source_str;
- struct in_addr group_addr;
- struct in_addr source_addr;
- int result;
+ char xpath[XPATH_MAXLEN];
- /* Group address */
- group_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, group_str, &group_addr);
- if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str,
- errno, safe_strerror(errno));
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (argc == 5) {
+ source_str = argv[idx_source]->arg;
- /* Source address */
- if (argc == (idx_ipv4_2 + 1)) {
- source_str = argv[idx_ipv4_2]->arg;
- result = inet_pton(AF_INET, source_str, &source_addr);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s\n",
- source_str, errno, safe_strerror(errno));
+ if (strcmp(source_str, "0.0.0.0") == 0) {
+ vty_out(vty, "Bad source address %s\n",
+ argv[idx_source]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
- /* Reject 0.0.0.0. Reserved for any source. */
- if (source_addr.s_addr == INADDR_ANY) {
- vty_out(vty, "Bad source address %s\n", source_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else {
- source_addr.s_addr = INADDR_ANY;
- }
+ } else
+ source_str = "0.0.0.0";
- CMD_FERR_RETURN(pim_if_igmp_join_add(ifp, group_addr, source_addr),
- "Failure joining IGMP group: $ERR");
+ snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
+ "frr-routing:ipv4", argv[idx_group]->arg, source_str);
- return CMD_SUCCESS;
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (interface_no_ip_igmp_join,
@@ -7651,190 +7605,30 @@ DEFUN (interface_no_ip_igmp_join,
"Multicast group address\n"
"Source address\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- const char *group_str;
+ int idx_group = 4;
+ int idx_source = 5;
const char *source_str;
- struct in_addr group_addr;
- struct in_addr source_addr;
- int result;
+ char xpath[XPATH_MAXLEN];
- /* Group address */
- group_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, group_str, &group_addr);
- if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str,
- errno, safe_strerror(errno));
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (argc == 6) {
+ source_str = argv[idx_source]->arg;
- /* Source address */
- if (argc == (idx_ipv4_2 + 1)) {
- source_str = argv[idx_ipv4_2]->arg;
- result = inet_pton(AF_INET, source_str, &source_addr);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s\n",
- source_str, errno, safe_strerror(errno));
+ if (strcmp(source_str, "0.0.0.0") == 0) {
+ vty_out(vty, "Bad source address %s\n",
+ argv[idx_source]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
- /* Reject 0.0.0.0. Reserved for any source. */
- if (source_addr.s_addr == INADDR_ANY) {
- vty_out(vty, "Bad source address %s\n", source_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else {
- source_str = "*";
- source_addr.s_addr = INADDR_ANY;
- }
-
- result = pim_if_igmp_join_del(ifp, group_addr, source_addr);
- if (result) {
- vty_out(vty,
- "%% Failure leaving IGMP group %s source %s on interface %s: %d\n",
- group_str, source_str, ifp->name, result);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
-/*
- CLI reconfiguration affects the interface level (struct pim_interface).
- This function propagates the reconfiguration to every active socket
- for that interface.
- */
-static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
-{
- struct interface *ifp;
- struct pim_interface *pim_ifp;
-
- zassert(igmp);
-
- /* other querier present? */
-
- if (igmp->t_other_querier_timer)
- return;
-
- /* this is the querier */
-
- zassert(igmp->interface);
- zassert(igmp->interface->info);
-
- ifp = igmp->interface;
- pim_ifp = ifp->info;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
- sizeof(ifaddr_str));
- zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
- __func__, ifaddr_str, ifp->name,
- pim_ifp->igmp_default_query_interval);
- }
-
- /*
- igmp_startup_mode_on() will reset QQI:
-
- igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
- */
- igmp_startup_mode_on(igmp);
-}
-
-static void igmp_sock_query_reschedule(struct igmp_sock *igmp)
-{
- if (igmp->mtrace_only)
- return;
-
- if (igmp->t_igmp_query_timer) {
- /* other querier present */
- zassert(igmp->t_igmp_query_timer);
- zassert(!igmp->t_other_querier_timer);
-
- pim_igmp_general_query_off(igmp);
- pim_igmp_general_query_on(igmp);
-
- zassert(igmp->t_igmp_query_timer);
- zassert(!igmp->t_other_querier_timer);
- } else {
- /* this is the querier */
-
- zassert(!igmp->t_igmp_query_timer);
- zassert(igmp->t_other_querier_timer);
-
- pim_igmp_other_querier_timer_off(igmp);
- pim_igmp_other_querier_timer_on(igmp);
-
- zassert(!igmp->t_igmp_query_timer);
- zassert(igmp->t_other_querier_timer);
- }
-}
-
-static void change_query_interval(struct pim_interface *pim_ifp,
- int query_interval)
-{
- struct listnode *sock_node;
- struct igmp_sock *igmp;
-
- pim_ifp->igmp_default_query_interval = query_interval;
-
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- igmp_sock_query_interval_reconfig(igmp);
- igmp_sock_query_reschedule(igmp);
- }
-}
-
-static void change_query_max_response_time(struct pim_interface *pim_ifp,
- int query_max_response_time_dsec)
-{
- struct listnode *sock_node;
- struct igmp_sock *igmp;
-
- pim_ifp->igmp_query_max_response_time_dsec =
- query_max_response_time_dsec;
-
- /*
- Below we modify socket/group/source timers in order to quickly
- reflect the change. Otherwise, those timers would eventually catch
- up.
- */
-
- /* scan all sockets */
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- struct listnode *grp_node;
- struct igmp_group *grp;
-
- /* reschedule socket general query */
- igmp_sock_query_reschedule(igmp);
-
- /* scan socket groups */
- for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
- grp)) {
- struct listnode *src_node;
- struct igmp_source *src;
+ } else
+ source_str = "0.0.0.0";
- /* reset group timers for groups in EXCLUDE mode */
- if (grp->group_filtermode_isexcl) {
- igmp_group_reset_gmi(grp);
- }
+ snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
+ "frr-routing:ipv4", argv[idx_group]->arg, source_str);
- /* scan group sources */
- for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
- src_node, src)) {
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- /* reset source timers for sources with running
- * timers */
- if (src->t_source_timer) {
- igmp_source_reset_gmi(igmp, grp, src);
- }
- }
- }
- }
+ return nb_cli_apply_changes(vty, NULL);
}
-#define IGMP_QUERY_INTERVAL_MIN (1)
-#define IGMP_QUERY_INTERVAL_MAX (1800)
-
DEFUN (interface_ip_igmp_query_interval,
interface_ip_igmp_query_interval_cmd,
"ip igmp query-interval (1-1800)",
@@ -7843,50 +7637,24 @@ DEFUN (interface_ip_igmp_query_interval,
IFACE_IGMP_QUERY_INTERVAL_STR
"Query interval in seconds\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int query_interval;
- int query_interval_dsec;
- int ret;
-
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
- }
-
- query_interval = atoi(argv[3]->arg);
- query_interval_dsec = 10 * query_interval;
-
- /*
- It seems we don't need to check bounds since command.c does it
- already, but we verify them anyway for extra safety.
- */
- if (query_interval < IGMP_QUERY_INTERVAL_MIN) {
- vty_out(vty,
- "General query interval %d lower than minimum %d\n",
- query_interval, IGMP_QUERY_INTERVAL_MIN);
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (query_interval > IGMP_QUERY_INTERVAL_MAX) {
- vty_out(vty,
- "General query interval %d higher than maximum %d\n",
- query_interval, IGMP_QUERY_INTERVAL_MAX);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ const struct lyd_node *pim_enable_dnode;
- if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) {
- vty_out(vty,
- "Can't set general query interval %d dsec <= query max response time %d dsec.\n",
- query_interval_dsec,
- pim_ifp->igmp_query_max_response_time_dsec);
- return CMD_WARNING_CONFIG_FAILED;
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-pim:pim/pim-enable",
+ VTY_CURR_XPATH);
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "true");
}
- change_query_interval(pim_ifp, query_interval);
+ nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
+ argv[3]->arg);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp_query_interval,
@@ -7897,27 +7665,15 @@ DEFUN (interface_no_ip_igmp_query_interval,
IFACE_IGMP_STR
IFACE_IGMP_QUERY_INTERVAL_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int default_query_interval_dsec;
-
- if (!pim_ifp)
- return CMD_SUCCESS;
-
- default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10;
+ char default_query_interval[5];
- if (default_query_interval_dsec
- <= pim_ifp->igmp_query_max_response_time_dsec) {
- vty_out(vty,
- "Can't set default general query interval %d dsec <= query max response time %d dsec.\n",
- default_query_interval_dsec,
- pim_ifp->igmp_query_max_response_time_dsec);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ snprintf(default_query_interval, sizeof(default_query_interval), "%d",
+ IGMP_GENERAL_QUERY_INTERVAL);
- change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL);
+ nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
+ default_query_interval);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_ip_igmp_version,
@@ -7928,36 +7684,11 @@ DEFUN (interface_ip_igmp_version,
"IGMP version\n"
"IGMP version number\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int igmp_version, old_version = 0;
- int ret;
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, argv[3]->arg);
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
- }
-
- igmp_version = atoi(argv[3]->arg);
- old_version = pim_ifp->igmp_version;
- pim_ifp->igmp_version = igmp_version;
-
- // Check if IGMP is Enabled otherwise, enable on interface
- if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
- PIM_IF_DO_IGMP(pim_ifp->options);
- pim_if_addr_add_all(ifp);
- pim_if_membership_refresh(ifp);
- old_version = igmp_version;
- // avoid refreshing membership again.
- }
- /* Current and new version is different refresh existing
- membership. Going from 3 -> 2 or 2 -> 3. */
- if (old_version != igmp_version)
- pim_if_membership_refresh(ifp);
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp_version,
@@ -7969,20 +7700,11 @@ DEFUN (interface_no_ip_igmp_version,
"IGMP version\n"
"IGMP version number\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
-
- if (!pim_ifp)
- return CMD_SUCCESS;
+ nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL);
- pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
-
DEFUN (interface_ip_igmp_query_max_response_time,
interface_ip_igmp_query_max_response_time_cmd,
"ip igmp query-max-response-time (10-250)",
@@ -7991,32 +7713,25 @@ DEFUN (interface_ip_igmp_query_max_response_time,
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
"Query response value in deci-seconds\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int query_max_response_time;
- int ret;
-
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
- }
+ const struct lyd_node *pim_enable_dnode;
- query_max_response_time = atoi(argv[3]->arg);
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-pim:pim/pim-enable",
+ VTY_CURR_XPATH);
- if (query_max_response_time
- >= pim_ifp->igmp_default_query_interval * 10) {
- vty_out(vty,
- "Can't set query max response time %d sec >= general query interval %d sec\n",
- query_max_response_time,
- pim_ifp->igmp_default_query_interval);
- return CMD_WARNING_CONFIG_FAILED;
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "true");
}
- change_query_max_response_time(pim_ifp, query_max_response_time);
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+ argv[3]->arg);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp_query_max_response_time,
@@ -8028,21 +7743,17 @@ DEFUN (interface_no_ip_igmp_query_max_response_time,
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
"Time for response in deci-seconds\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
-
- if (!pim_ifp)
- return CMD_SUCCESS;
+ char default_query_max_response_time[4];
- change_query_max_response_time(pim_ifp,
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
+ snprintf(default_query_max_response_time,
+ sizeof(default_query_max_response_time),
+ "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
- return CMD_SUCCESS;
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+ default_query_max_response_time);
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
-
DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
interface_ip_igmp_query_max_response_time_dsec_cmd,
"ip igmp query-max-response-time-dsec (10-250)",
@@ -8051,34 +7762,24 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
"Query response value in deciseconds\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int query_max_response_time_dsec;
- int default_query_interval_dsec;
- int ret;
-
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
- }
-
- query_max_response_time_dsec = atoi(argv[4]->arg);
+ const struct lyd_node *pim_enable_dnode;
- default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval;
-
- if (query_max_response_time_dsec >= default_query_interval_dsec) {
- vty_out(vty,
- "Can't set query max response time %d dsec >= general query interval %d dsec\n",
- query_max_response_time_dsec,
- default_query_interval_dsec);
- return CMD_WARNING_CONFIG_FAILED;
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-pim:pim/pim-enable",
+ VTY_CURR_XPATH);
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "true");
}
- change_query_max_response_time(pim_ifp, query_max_response_time_dsec);
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+ argv[3]->arg);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
@@ -8089,21 +7790,18 @@ DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
IFACE_IGMP_STR
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
+ char default_query_max_response_time[4];
- if (!pim_ifp)
- return CMD_SUCCESS;
+ snprintf(default_query_max_response_time,
+ sizeof(default_query_max_response_time),
+ "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
- change_query_max_response_time(pim_ifp,
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+ default_query_max_response_time);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
-#define IGMP_LAST_MEMBER_QUERY_COUNT_MIN (1)
-#define IGMP_LAST_MEMBER_QUERY_COUNT_MAX (7)
-
DEFUN (interface_ip_igmp_last_member_query_count,
interface_ip_igmp_last_member_query_count_cmd,
"ip igmp last-member-query-count (1-7)",
@@ -8112,23 +7810,24 @@ DEFUN (interface_ip_igmp_last_member_query_count,
IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
"Last member query count\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int last_member_query_count;
- int ret;
+ const struct lyd_node *pim_enable_dnode;
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-pim:pim/pim-enable",
+ VTY_CURR_XPATH);
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "true");
}
- last_member_query_count = atoi(argv[3]->arg);
-
- pim_ifp->igmp_last_member_query_count = last_member_query_count;
+ nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
+ argv[3]->arg);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp_last_member_query_count,
@@ -8139,21 +7838,17 @@ DEFUN (interface_no_ip_igmp_last_member_query_count,
IFACE_IGMP_STR
IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
+ char default_robustness[2];
- if (!pim_ifp)
- return CMD_SUCCESS;
+ snprintf(default_robustness, sizeof(default_robustness), "%d",
+ IGMP_DEFAULT_ROBUSTNESS_VARIABLE);
- pim_ifp->igmp_last_member_query_count =
- IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
+ nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
+ default_robustness);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
-#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MIN (1)
-#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MAX (255)
-
DEFUN (interface_ip_igmp_last_member_query_interval,
interface_ip_igmp_last_member_query_interval_cmd,
"ip igmp last-member-query-interval (1-255)",
@@ -8162,23 +7857,24 @@ DEFUN (interface_ip_igmp_last_member_query_interval,
IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
"Last member query interval in deciseconds\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
- int last_member_query_interval;
- int ret;
+ const struct lyd_node *pim_enable_dnode;
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
+ pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-pim:pim/pim-enable",
+ VTY_CURR_XPATH);
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./igmp-enable",
+ NB_OP_MODIFY, "true");
}
- last_member_query_interval = atoi(argv[3]->arg);
- pim_ifp->igmp_specific_query_max_response_time_dsec
- = last_member_query_interval;
+ nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
+ argv[3]->arg);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_no_ip_igmp_last_member_query_interval,
@@ -8189,16 +7885,16 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval,
IFACE_IGMP_STR
IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct pim_interface *pim_ifp = ifp->info;
+ char default_last_member_query_count[4];
- if (!pim_ifp)
- return CMD_SUCCESS;
+ snprintf(default_last_member_query_count,
+ sizeof(default_last_member_query_count),
+ "%d", IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC);
- pim_ifp->igmp_specific_query_max_response_time_dsec =
- IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+ nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
+ default_last_member_query_count);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
}
DEFUN (interface_ip_pim_drprio,
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index f7496b3a5d..366b00f4b6 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -20,6 +20,192 @@
#include "pimd.h"
#include "pim_nb.h"
#include "lib/northbound_cli.h"
+#include "pim_igmpv3.h"
+
+void pim_if_membership_clear(struct interface *ifp);
+void pim_if_membership_refresh(struct interface *ifp);
+
+static bool is_pim_interface(const struct lyd_node *dnode)
+{
+ char if_xpath[XPATH_MAXLEN];
+ const struct lyd_node *pim_enable_dnode;
+ const struct lyd_node *igmp_enable_dnode;
+
+ yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath));
+ pim_enable_dnode = yang_dnode_get(dnode, "%s/frr-pim:pim/pim-enable",
+ if_xpath);
+ igmp_enable_dnode = yang_dnode_get(dnode, "%s/frr-igmp:igmp/igmp-enable",
+ if_xpath);
+
+ if (((pim_enable_dnode) &&
+ (yang_dnode_get_bool(pim_enable_dnode, "."))) ||
+ ((igmp_enable_dnode) &&
+ (yang_dnode_get_bool(igmp_enable_dnode, "."))))
+ return true;
+
+ return false;
+}
+
+static int pim_cmd_igmp_start(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ uint8_t need_startup = 0;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp) {
+ (void)pim_if_new(ifp, true, false, false, false);
+ need_startup = 1;
+ } else {
+ if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
+ PIM_IF_DO_IGMP(pim_ifp->options);
+ need_startup = 1;
+ }
+ }
+
+ /* 'ip igmp' executed multiple times, with need_startup
+ * avoid multiple if add all and membership refresh
+ */
+ if (need_startup) {
+ pim_if_addr_add_all(ifp);
+ pim_if_membership_refresh(ifp);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * CLI reconfiguration affects the interface level (struct pim_interface).
+ * This function propagates the reconfiguration to every active socket
+ * for that interface.
+ */
+static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
+ zassert(igmp);
+
+ /* other querier present? */
+
+ if (igmp->t_other_querier_timer)
+ return;
+
+ /* this is the querier */
+
+ zassert(igmp->interface);
+ zassert(igmp->interface->info);
+
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char ifaddr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
+ sizeof(ifaddr_str));
+ zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
+ __func__, ifaddr_str, ifp->name,
+ pim_ifp->igmp_default_query_interval);
+ }
+
+ /*
+ * igmp_startup_mode_on() will reset QQI:
+
+ * igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
+ */
+ igmp_startup_mode_on(igmp);
+}
+
+static void igmp_sock_query_reschedule(struct igmp_sock *igmp)
+{
+ if (igmp->mtrace_only)
+ return;
+
+ if (igmp->t_igmp_query_timer) {
+ /* other querier present */
+ zassert(igmp->t_igmp_query_timer);
+ zassert(!igmp->t_other_querier_timer);
+
+ pim_igmp_general_query_off(igmp);
+ pim_igmp_general_query_on(igmp);
+
+ zassert(igmp->t_igmp_query_timer);
+ zassert(!igmp->t_other_querier_timer);
+ } else {
+ /* this is the querier */
+
+ zassert(!igmp->t_igmp_query_timer);
+ zassert(igmp->t_other_querier_timer);
+
+ pim_igmp_other_querier_timer_off(igmp);
+ pim_igmp_other_querier_timer_on(igmp);
+
+ zassert(!igmp->t_igmp_query_timer);
+ zassert(igmp->t_other_querier_timer);
+ }
+}
+
+static void change_query_interval(struct pim_interface *pim_ifp,
+ int query_interval)
+{
+ struct listnode *sock_node;
+ struct igmp_sock *igmp;
+
+ pim_ifp->igmp_default_query_interval = query_interval;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+ igmp_sock_query_interval_reconfig(igmp);
+ igmp_sock_query_reschedule(igmp);
+ }
+}
+
+static void change_query_max_response_time(struct pim_interface *pim_ifp,
+ int query_max_response_time_dsec)
+{
+ struct listnode *sock_node;
+ struct igmp_sock *igmp;
+
+ pim_ifp->igmp_query_max_response_time_dsec =
+ query_max_response_time_dsec;
+
+ /*
+ * Below we modify socket/group/source timers in order to quickly
+ * reflect the change. Otherwise, those timers would args->eventually
+ * catch up.
+ */
+
+ /* scan all sockets */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+ struct listnode *grp_node;
+ struct igmp_group *grp;
+
+ /* reschedule socket general query */
+ igmp_sock_query_reschedule(igmp);
+
+ /* scan socket groups */
+ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
+ grp)) {
+ struct listnode *src_node;
+ struct igmp_source *src;
+
+ /* reset group timers for groups in EXCLUDE mode */
+ if (grp->group_filtermode_isexcl)
+ igmp_group_reset_gmi(grp);
+
+ /* scan group sources */
+ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+ src_node, src)) {
+
+ /* reset source timers for sources with running
+ * timers
+ */
+ if (src->t_source_timer)
+ igmp_source_reset_gmi(igmp, grp, src);
+ }
+ }
+ }
+}
int routing_control_plane_protocols_name_validate(
struct nb_cb_create_args *args)
@@ -1174,7 +1360,6 @@ int lib_interface_igmp_create(struct nb_cb_create_args *args)
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
- /* TODO: implement me. */
break;
}
@@ -1183,13 +1368,29 @@ int lib_interface_igmp_create(struct nb_cb_create_args *args)
int lib_interface_igmp_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:
- case NB_EV_APPLY:
- /* TODO: implement me. */
break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return NB_OK;
+
+ PIM_IF_DONT_IGMP(pim_ifp->options);
+
+ pim_if_membership_clear(ifp);
+
+ pim_if_addr_del_all_igmp(ifp);
+
+ if (!PIM_IF_TEST_PIM(pim_ifp->options))
+ pim_if_delete(ifp);
}
return NB_OK;
@@ -1200,13 +1401,52 @@ int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args)
*/
int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ bool igmp_enable;
+ struct pim_interface *pim_ifp;
+ int mcast_if_count;
+ const char *ifp_name;
+ const struct lyd_node *if_dnode;
+
switch (args->event) {
case NB_EV_VALIDATE:
+ if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+ ifp_name = yang_dnode_get_string(if_dnode, ".");
+ 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. Could not enable IGMP on interface %s",
+ MAXVIFS, ifp_name);
+ return NB_ERR_VALIDATION;
+ }
+ break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
- case NB_EV_APPLY:
- /* TODO: implement me. */
break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ igmp_enable = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (igmp_enable)
+ return pim_cmd_igmp_start(ifp);
+
+ else {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return NB_ERR_INCONSISTENCY;
+
+ PIM_IF_DONT_IGMP(pim_ifp->options);
+
+ pim_if_membership_clear(ifp);
+
+ pim_if_addr_del_all_igmp(ifp);
+
+ if (!PIM_IF_TEST_PIM(pim_ifp->options))
+ pim_if_delete(ifp);
+ }
}
return NB_OK;
@@ -1217,12 +1457,34 @@ int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args)
*/
int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int igmp_version, old_version = 0;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return NB_ERR_INCONSISTENCY;
+
+ igmp_version = yang_dnode_get_uint8(args->dnode, NULL);
+ old_version = pim_ifp->igmp_version;
+ pim_ifp->igmp_version = igmp_version;
+
+ old_version = igmp_version;
+
+ /* Current and new version is different refresh existing
+ * membership. Going from 3 -> 2 or 2 -> 3.
+ */
+ if (old_version != igmp_version)
+ pim_if_membership_refresh(ifp);
+
break;
}
@@ -1231,12 +1493,18 @@ int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args)
int lib_interface_igmp_version_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:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
break;
}
@@ -1248,13 +1516,30 @@ int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args)
*/
int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int query_interval;
+ int query_interval_dsec;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- case NB_EV_APPLY:
- /* TODO: implement me. */
break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ query_interval = yang_dnode_get_uint16(args->dnode, NULL);
+ query_interval_dsec = 10 * query_interval;
+ if (query_interval_dsec <=
+ pim_ifp->igmp_query_max_response_time_dsec) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Can't set general query interval %d dsec <= query max response time %d dsec.",
+ query_interval_dsec,
+ pim_ifp->igmp_query_max_response_time_dsec);
+ return NB_ERR_INCONSISTENCY;
+ }
+ change_query_interval(pim_ifp, query_interval);
}
return NB_OK;
@@ -1265,13 +1550,35 @@ int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args)
*/
int lib_interface_igmp_query_max_response_time_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int query_max_response_time_dsec;
+ int default_query_interval_dsec;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- case NB_EV_APPLY:
- /* TODO: implement me. */
break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ query_max_response_time_dsec =
+ yang_dnode_get_uint8(args->dnode, NULL);
+ default_query_interval_dsec =
+ 10 * pim_ifp->igmp_default_query_interval;
+
+ if (query_max_response_time_dsec
+ >= default_query_interval_dsec) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Can't set query max response time %d sec >= general query interval %d sec",
+ query_max_response_time_dsec,
+ pim_ifp->igmp_default_query_interval);
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ change_query_max_response_time(pim_ifp,
+ query_max_response_time_dsec);
}
return NB_OK;
@@ -1282,12 +1589,23 @@ int lib_interface_igmp_query_max_response_time_modify(struct nb_cb_modify_args *
*/
int lib_interface_igmp_last_member_query_interval_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int last_member_query_interval;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ last_member_query_interval = yang_dnode_get_uint8(args->dnode,
+ NULL);
+ pim_ifp->igmp_specific_query_max_response_time_dsec =
+ last_member_query_interval;
+
break;
}
@@ -1299,12 +1617,22 @@ int lib_interface_igmp_last_member_query_interval_modify(struct nb_cb_modify_arg
*/
int lib_interface_igmp_robustness_variable_modify(struct nb_cb_modify_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int last_member_query_count;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ last_member_query_count = yang_dnode_get_uint8(args->dnode,
+ NULL);
+ pim_ifp->igmp_last_member_query_count = last_member_query_count;
+
break;
}
@@ -1321,7 +1649,6 @@ int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args)
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
- /* TODO: implement me. */
break;
}
@@ -1335,7 +1662,6 @@ int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args)
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
- /* TODO: implement me. */
break;
}
@@ -1347,13 +1673,39 @@ int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args)
*/
int lib_interface_igmp_address_family_static_group_create(struct nb_cb_create_args *args)
{
+ struct interface *ifp;
+ struct ipaddr source_addr;
+ struct ipaddr group_addr;
+ int result;
+ const char *ifp_name;
+ const struct lyd_node *if_dnode;
+
switch (args->event) {
case NB_EV_VALIDATE:
+ if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+ if (!is_pim_interface(if_dnode)) {
+ ifp_name = yang_dnode_get_string(if_dnode, ".");
+ snprintf(args->errmsg, args->errmsg_len,
+ "multicast not enabled on interface %s",
+ ifp_name);
+ return NB_ERR_VALIDATION;
+ }
+ break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
- case NB_EV_APPLY:
- /* TODO: implement me. */
break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
+ yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+
+ result = pim_if_igmp_join_add(ifp, group_addr.ip._v4_addr,
+ source_addr.ip._v4_addr);
+ if (result) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Failure joining IGMP group");
+ return NB_ERR_INCONSISTENCY;
+ }
}
return NB_OK;
@@ -1361,12 +1713,38 @@ int lib_interface_igmp_address_family_static_group_create(struct nb_cb_create_ar
int lib_interface_igmp_address_family_static_group_destroy(struct nb_cb_destroy_args *args)
{
+ struct interface *ifp;
+ struct ipaddr source_addr;
+ struct ipaddr group_addr;
+ int result;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
+ yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+
+ result = pim_if_igmp_join_del(ifp, group_addr.ip._v4_addr,
+ source_addr.ip._v4_addr);
+
+ if (result) {
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+
+ ipaddr2str(&source_addr, src_str, sizeof(src_str));
+ ipaddr2str(&group_addr, grp_str, sizeof(grp_str));
+
+ snprintf(args->errmsg, args->errmsg_len,
+ "%% Failure leaving IGMP group %s %s on interface %s: %d",
+ src_str, grp_str, ifp->name, result);
+
+ return NB_ERR_INCONSISTENCY;
+ }
+
break;
}