diff options
| author | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2024-09-11 11:05:07 -0300 | 
|---|---|---|
| committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2025-02-10 15:40:07 -0300 | 
| commit | a98f2b86c46dc7d0e830f4465efd34492556bdb0 (patch) | |
| tree | aaf3bf4dd4d644ab9a9991c560f9716bbdea128d | |
| parent | f07d379b74e06f0602f3779e78038dc708aa7345 (diff) | |
pim6d: implement MLD source/group limits
Let user configure a source/group limit for MLD protocol.
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
| -rw-r--r-- | pimd/pim6_cmd.c | 40 | ||||
| -rw-r--r-- | pimd/pim6_mld.c | 80 | ||||
| -rw-r--r-- | pimd/pim6_mld.h | 2 | ||||
| -rw-r--r-- | pimd/pim_iface.c | 2 | ||||
| -rw-r--r-- | pimd/pim_igmp.c | 3 | ||||
| -rw-r--r-- | pimd/pim_vty.c | 4 | 
6 files changed, 124 insertions, 7 deletions
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 12493b7dbb..63444539ee 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -1612,6 +1612,43 @@ DEFPY (interface_no_ipv6_mld_version,  				    "frr-routing:ipv6");  } +DEFPY_YANG(interface_ipv6_mld_limits, +           interface_ipv6_mld_limits_cmd, +           "[no] ipv6 mld <max-sources$do_src (0-4294967295)$val" +	     "|max-groups$do_grp (0-4294967295)$val>", +           NO_STR +           IPV6_STR +           IFACE_MLD_STR +           "Limit number of MLDv2 sources to track\n" +           "Permitted number of sources\n" +           "Limit number of MLD 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_ipv6_mld_limits, +           no_interface_ipv6_mld_limits_cmd, +           "no ipv6 mld <max-sources$do_src|max-groups$do_grp>", +           NO_STR +           IPV6_STR +           IFACE_MLD_STR +           "Limit number of MLDv2 sources to track\n" +           "Limit number of MLD group memberships to track\n") +  DEFPY (interface_ipv6_mld_query_interval,         interface_ipv6_mld_query_interval_cmd,         "ipv6 mld query-interval (1-65535)$q_interval", @@ -2865,6 +2902,9 @@ void pim_cmd_init(void)  	install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd);  	install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd);  	install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); +	install_element(INTERFACE_NODE, &interface_ipv6_mld_limits_cmd); +	install_element(INTERFACE_NODE, &no_interface_ipv6_mld_limits_cmd); +  	/* Install BSM command */  	install_element(INTERFACE_NODE, &ipv6_pim_bsm_cmd);  	install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index acfb0c3af3..d7e0314d3b 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -190,11 +190,26 @@ static struct gm_sg *gm_sg_find(struct gm_if *gm_ifp, pim_addr grp,  	return gm_sgs_find(gm_ifp->sgs, &ref);  } +static bool gm_sg_has_group(struct gm_sgs_head *sgs, const pim_addr group) +{ +	struct gm_sg *sg; + +	frr_each (gm_sgs, sgs, sg) +		if (pim_addr_cmp(sg->sgaddr.grp, group) == 0) +			return true; + +	return false; +} +  static struct gm_sg *gm_sg_make(struct gm_if *gm_ifp, pim_addr grp,  				pim_addr src)  {  	struct gm_sg *ret, *prev; +	/* Count all unique group members. */ +	if (!gm_sg_has_group(gm_ifp->sgs, grp)) +		gm_ifp->groups_count++; +  	ret = XCALLOC(MTYPE_GM_SG, sizeof(*ret));  	ret->sgaddr.grp = grp;  	ret->sgaddr.src = src; @@ -212,6 +227,47 @@ static struct gm_sg *gm_sg_make(struct gm_if *gm_ifp, pim_addr grp,  	return ret;  } +static size_t gm_sg_source_count(struct gm_sgs_head *sgs, const pim_addr group) +{ +	struct gm_sg *sg; +	size_t source_count; + +	source_count = 0; +	frr_each (gm_sgs, sgs, sg) +		if (pim_addr_cmp(sg->sgaddr.grp, group) == 0) +			source_count++; + +	return source_count; +} + +static bool gm_sg_limit_reached(struct gm_if *gm_if, const pim_addr source, const pim_addr group) +{ +	const struct pim_interface *pim_interface = gm_if->ifp->info; + +	if (!gm_sg_has_group(gm_if->sgs, group)) { +		if (gm_if->groups_count >= pim_interface->gm_group_limit) { +			if (PIM_DEBUG_GM_TRACE) +				zlog_debug("interface %s has reached group limit (%u), refusing to add group %pPA", +					   gm_if->ifp->name, pim_interface->gm_group_limit, &group); + +			return true; +		} + +		return false; +	} + +	if (gm_sg_source_count(gm_if->sgs, group) >= pim_interface->gm_source_limit) { +		if (PIM_DEBUG_GM_TRACE) { +			zlog_debug("interface %s has reached source limit (%u), refusing to add source %pPA (group %pPA)", +				   gm_if->ifp->name, pim_interface->gm_source_limit, &source, +				   &group); +		} +		return true; +	} + +	return false; +} +  /*   * interface -> packets, sorted by expiry (because add_tail insert order)   */ @@ -471,6 +527,11 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired)  			zlog_debug(log_sg(sg, "dropping"));  		gm_sgs_del(gm_ifp->sgs, sg); + +		/* Decrement unique group members counter. */ +		if (!gm_sg_has_group(gm_ifp->sgs, sg->sgaddr.grp)) +			gm_ifp->groups_count--; +  		gm_sg_free(sg);  	}  } @@ -634,8 +695,12 @@ static void gm_handle_v2_pass1(struct gm_packet_state *pkt,  	case MLD_RECTYPE_CHANGE_TO_EXCLUDE:  		/* this always replaces or creates state */  		is_excl = true; -		if (!grp) +		if (!grp) { +			if (gm_sg_limit_reached(pkt->iface, PIMADDR_ANY, rechdr->grp)) +				return; +  			grp = gm_sg_make(pkt->iface, rechdr->grp, PIMADDR_ANY); +		}  		item = gm_packet_sg_setup(pkt, grp, is_excl, false);  		item->n_exclude = n_src; @@ -700,9 +765,13 @@ static void gm_handle_v2_pass1(struct gm_packet_state *pkt,  		struct gm_sg *sg;  		sg = gm_sg_find(pkt->iface, rechdr->grp, rechdr->srcs[j]); -		if (!sg) +		if (!sg) { +			if (gm_sg_limit_reached(pkt->iface, rechdr->srcs[j], rechdr->grp)) +				return; +  			sg = gm_sg_make(pkt->iface, rechdr->grp,  					rechdr->srcs[j]); +		}  		gm_packet_sg_setup(pkt, sg, is_excl, true);  	} @@ -952,6 +1021,10 @@ static void gm_handle_v1_report(struct gm_if *gm_ifp,  	hdr = (struct mld_v1_pkt *)data; +	if (!gm_sg_has_group(gm_ifp->sgs, hdr->grp) && +	    gm_sg_limit_reached(gm_ifp, PIMADDR_ANY, hdr->grp)) +		return; +  	max_entries = 1;  	pkt = XCALLOC(MTYPE_GM_STATE,  		      offsetof(struct gm_packet_state, items[max_entries])); @@ -1255,6 +1328,9 @@ static void gm_handle_q_groupsrc(struct gm_if *gm_ifp,  	for (i = 0; i < n_src; i++) {  		sg = gm_sg_find(gm_ifp, grp, srcs[i]); +		if (sg == NULL) +			continue; +  		GM_UPDATE_SG_STATE(sg);  		gm_sg_timer_start(gm_ifp, sg, timers->expire_wait);  	} diff --git a/pimd/pim6_mld.h b/pimd/pim6_mld.h index 183ab2fc50..c5a9708961 100644 --- a/pimd/pim6_mld.h +++ b/pimd/pim6_mld.h @@ -350,6 +350,8 @@ struct gm_if {  	struct gm_subscribers_head subscribers[1];  	struct gm_packet_expires_head expires[1]; +	size_t groups_count; +  	struct timeval started;  	struct gm_if_stats stats;  }; diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 9316cebc0a..8ec51ddc39 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -128,6 +128,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,  	pim_ifp->gm_specific_query_max_response_time_dsec =  		GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;  	pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE; +	pim_ifp->gm_group_limit = UINT32_MAX; +	pim_ifp->gm_source_limit = UINT32_MAX;  	/* BSM config on interface: true by default */  	pim_ifp->bsm_enable = true; diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index fa915719dd..b1b4566499 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -1126,9 +1126,6 @@ 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; diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 9456a40ffa..64750a22f6 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -457,14 +457,14 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,  		++writes;  	} -	/* IF ip igmp max-sources */ +	/* IF igmp/mld 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 igmp/mld 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);  | 
