diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2021-08-24 18:21:59 +0200 | 
|---|---|---|
| committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2025-02-10 15:40:07 -0300 | 
| commit | f07d379b74e06f0602f3779e78038dc708aa7345 (patch) | |
| tree | 80b01573958993e1bda24b32184a3dcb085f303d /pimd | |
| parent | baf4c1a78fe4cafdbb2cdbed030a31ea04a18c4a (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.c | 39 | ||||
| -rw-r--r-- | pimd/pim_iface.h | 2 | ||||
| -rw-r--r-- | pimd/pim_igmp.c | 11 | ||||
| -rw-r--r-- | pimd/pim_igmpv3.c | 9 | ||||
| -rw-r--r-- | pimd/pim_nb.c | 12 | ||||
| -rw-r--r-- | pimd/pim_nb.h | 2 | ||||
| -rw-r--r-- | pimd/pim_nb_config.c | 66 | ||||
| -rw-r--r-- | pimd/pim_vty.c | 14 | 
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",  | 
