mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-14 12:52:37 +00:00
pimd: Northbound implementation for igmp commands.
interface_ip_igmp interface_no_ip_igmp interface_ip_igmp_join interface_no_ip_igmp_join interface_ip_igmp_query_interval interface_no_ip_igmp_query_interval interface_ip_igmp_version interface_no_ip_igmp_version interface_ip_igmp_query_max_response_time interface_no_ip_igmp_query_max_response_time interface_ip_igmp_query_max_response_time_dsec interface_no_ip_igmp_query_max_response_time_dsec interface_ip_igmp_last_member_query_count interface_no_ip_igmp_last_member_query_count interface_ip_igmp_last_member_query_interval interface_no_ip_igmp_last_member_query_interval IGMP yang tree: module: frr-igmp augment /frr-interface:lib/frr-interface:interface: +--rw igmp! +--rw igmp-enable? boolean <false> +--rw version? uint8 +--rw query-interval? uint16 <125> +--rw query-max-response-time? uint8 <100> +--rw last-member-query-interval? uint8 <10> +--rw robustness-variable? uint8 <2> +--rw address-family* [address-family] +--rw address-family identityref +--rw static-group* [group-addr source-addr] +--rw group-addr ietf-routing-types:ip-multicast-group-address +--rw source-addr ietf-inet-types:ip-address Signed-off-by: Sarita Patra <saritap@vmware.com>
This commit is contained in:
parent
299c66b3b6
commit
b0475d5a52
634
pimd/pim_cmd.c
634
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;
|
||||
const struct lyd_node *pim_enable_dnode;
|
||||
char pim_if_xpath[XPATH_MAXLEN];
|
||||
|
||||
if (!pim_ifp)
|
||||
return CMD_SUCCESS;
|
||||
snprintf(pim_if_xpath, sizeof(pim_if_xpath),
|
||||
"%s/frr-pim:pim", VTY_CURR_XPATH);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
} else
|
||||
source_str = "0.0.0.0";
|
||||
|
||||
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;
|
||||
}
|
||||
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_DESTROY, NULL);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
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");
|
||||
}
|
||||
|
||||
query_interval = atoi(argv[3]->arg);
|
||||
query_interval_dsec = 10 * query_interval;
|
||||
nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
change_query_interval(pim_ifp, query_interval);
|
||||
|
||||
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;
|
||||
char default_query_interval[5];
|
||||
|
||||
if (!pim_ifp)
|
||||
return CMD_SUCCESS;
|
||||
snprintf(default_query_interval, sizeof(default_query_interval), "%d",
|
||||
IGMP_GENERAL_QUERY_INTERVAL);
|
||||
|
||||
default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10;
|
||||
nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
|
||||
default_query_interval);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
change_query_interval(pim_ifp, IGMP_GENERAL_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;
|
||||
nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL);
|
||||
|
||||
if (!pim_ifp)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
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;
|
||||
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");
|
||||
}
|
||||
|
||||
query_max_response_time = atoi(argv[3]->arg);
|
||||
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
change_query_max_response_time(pim_ifp, query_max_response_time);
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
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");
|
||||
}
|
||||
|
||||
query_max_response_time_dsec = atoi(argv[4]->arg);
|
||||
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
change_query_max_response_time(pim_ifp, query_max_response_time_dsec);
|
||||
|
||||
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);
|
||||
nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
|
||||
pim_ifp->igmp_last_member_query_count = last_member_query_count;
|
||||
|
||||
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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user