summaryrefslogtreecommitdiff
path: root/pimd
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2021-08-24 18:21:59 +0200
committerRafael Zalamena <rzalamena@opensourcerouting.org>2025-02-10 15:40:07 -0300
commitf07d379b74e06f0602f3779e78038dc708aa7345 (patch)
tree80b01573958993e1bda24b32184a3dcb085f303d /pimd
parentbaf4c1a78fe4cafdbb2cdbed030a31ea04a18c4a (diff)
pimd: implement IGMP group/source count limit
For groups we can just look at the length of the list, for sources we need to count them on a per-interface level. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_cmd.c39
-rw-r--r--pimd/pim_iface.h2
-rw-r--r--pimd/pim_igmp.c11
-rw-r--r--pimd/pim_igmpv3.c9
-rw-r--r--pimd/pim_nb.c12
-rw-r--r--pimd/pim_nb.h2
-rw-r--r--pimd/pim_nb_config.c66
-rw-r--r--pimd/pim_vty.c14
8 files changed, 155 insertions, 0 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index a1ad261869..fa9c6f9537 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5656,6 +5656,43 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval,
return gm_process_no_last_member_query_interval_cmd(vty);
}
+DEFPY_YANG(interface_ip_igmp_limits,
+ interface_ip_igmp_limits_cmd,
+ "[no] ip igmp <max-sources$do_src (0-4294967295)$val"
+ "|max-groups$do_grp (0-4294967295)$val>",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Limit number of IGMPv3 sources to track\n"
+ "Permitted number of sources\n"
+ "Limit number of IGMP group memberships to track\n"
+ "Permitted number of groups\n")
+{
+ const char *xpath;
+
+ assert(do_src || do_grp);
+ if (do_src)
+ xpath = "./max-sources";
+ else
+ xpath = "./max-groups";
+
+ if (no)
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, val_str);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
+ALIAS_YANG(interface_ip_igmp_limits,
+ no_interface_ip_igmp_limits_cmd,
+ "no ip igmp <max-sources$do_src|max-groups$do_grp>",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Limit number of IGMPv3 sources to track\n"
+ "Limit number of IGMP group memberships to track\n")
+
DEFUN (interface_ip_pim_drprio,
interface_ip_pim_drprio_cmd,
"ip pim drpriority (0-4294967295)",
@@ -9101,6 +9138,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE,
&interface_no_ip_igmp_last_member_query_interval_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_limits_cmd);
+ install_element(INTERFACE_NODE, &no_interface_ip_igmp_limits_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 90a81a21d0..0a7993fd27 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -105,6 +105,8 @@ struct pim_interface {
struct gm_if *mld;
+ uint32_t gm_source_limit, gm_group_limit;
+
int pim_sock_fd; /* PIM socket file descriptor */
struct event *t_pim_sock_read; /* thread for reading PIM socket */
int64_t pim_sock_creation; /* timestamp of PIM socket creation */
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 12f424248f..fa915719dd 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -1126,6 +1126,9 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp)
{
char hash_name[64];
+ pim_ifp->gm_group_limit = UINT32_MAX;
+ pim_ifp->gm_source_limit = UINT32_MAX;
+
pim_ifp->gm_socket_list = list_new();
pim_ifp->gm_socket_list->del = (void (*)(void *))igmp_sock_free;
@@ -1416,6 +1419,14 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
__func__, &group_addr);
return NULL;
}
+
+ if (listcount(pim_ifp->gm_group_list) >= pim_ifp->gm_group_limit) {
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("interface %s has reached group limit (%u), refusing to add group %pI4",
+ igmp->interface->name, pim_ifp->gm_group_limit, &group_addr);
+ return NULL;
+ }
+
/*
Non-existant group is created as INCLUDE {empty}:
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index 7348d8130f..7cb168dc5d 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -423,6 +423,7 @@ struct gm_source *igmp_find_source_by_addr(struct gm_group *group,
struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
struct in_addr src_addr, bool *new)
{
+ const struct pim_interface *pim_interface = group->interface->info;
struct gm_source *src;
if (new)
@@ -432,6 +433,14 @@ struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
if (src)
return src;
+ if (listcount(group->group_source_list) >= pim_interface->gm_source_limit) {
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("interface %s has reached source limit (%u), refusing to add source %pI4 (group %pI4)",
+ group->interface->name, pim_interface->gm_source_limit,
+ &src_addr, &group->group_addr);
+ return NULL;
+ }
+
if (PIM_DEBUG_GM_TRACE) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index ea9ce3cecb..62c5d531d9 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -725,6 +725,18 @@ const struct frr_yang_module_info frr_gmp_info = {
.destroy = lib_interface_gmp_address_family_join_group_destroy,
}
},
+ {
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/max-sources",
+ .cbs = {
+ .modify = lib_interface_gm_max_sources_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups",
+ .cbs = {
+ .modify = lib_interface_gm_max_groups_modify,
+ }
+ },
{
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy",
.cbs = {
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index a15c6e6d9f..1656313fc2 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -287,6 +287,8 @@ int lib_interface_gmp_address_family_static_group_create(
struct nb_cb_create_args *args);
int lib_interface_gmp_address_family_static_group_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args);
+int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args);
/*
* Callback registered with routing_nb lib to validate only
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 5203f78b92..c926696610 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -4397,6 +4397,72 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
}
/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups
+ */
+int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ 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, "name");
+ 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:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->gm_group_limit = yang_dnode_get_uint32(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-sources
+ */
+int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ 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, "name");
+ 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:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->gm_source_limit = yang_dnode_get_uint32(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable
*/
int lib_interface_gmp_address_family_robustness_variable_modify(
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index a972a38c72..9456a40ffa 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -457,6 +457,20 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
++writes;
}
+ /* IF ip igmp max-sources */
+ if (pim_ifp->gm_source_limit != UINT32_MAX) {
+ vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-sources %u\n",
+ pim_ifp->gm_source_limit);
+ ++writes;
+ }
+
+ /* IF ip igmp max-groups */
+ if (pim_ifp->gm_group_limit != UINT32_MAX) {
+ vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-groups %u\n",
+ pim_ifp->gm_group_limit);
+ ++writes;
+ }
+
/* IF ip pim drpriority */
if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n",