diff options
Diffstat (limited to 'pimd')
| -rw-r--r-- | pimd/pim_cmd.c | 16 | ||||
| -rw-r--r-- | pimd/pim_iface.c | 9 | ||||
| -rw-r--r-- | pimd/pim_iface.h | 4 | ||||
| -rw-r--r-- | pimd/pim_igmp.c | 2 | ||||
| -rw-r--r-- | pimd/pim_igmpv2.c | 3 | ||||
| -rw-r--r-- | pimd/pim_igmpv3.c | 23 | ||||
| -rw-r--r-- | pimd/pim_join.c | 14 | ||||
| -rw-r--r-- | pimd/pim_mroute.c | 8 | ||||
| -rw-r--r-- | pimd/pim_nb.c | 7 | ||||
| -rw-r--r-- | pimd/pim_nb.h | 2 | ||||
| -rw-r--r-- | pimd/pim_nb_config.c | 65 | ||||
| -rw-r--r-- | pimd/pim_util.c | 43 | ||||
| -rw-r--r-- | pimd/pim_util.h | 2 | ||||
| -rw-r--r-- | pimd/pim_vty.c | 7 | 
14 files changed, 173 insertions, 32 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f4c25ea81e..bac9645759 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -5871,6 +5871,21 @@ DEFUN(interface_no_ip_pim_boundary_oil,  	return pim_process_no_ip_pim_boundary_oil_cmd(vty);  } +DEFPY_YANG(interface_ip_pim_boundary_acl, +           interface_ip_pim_boundary_acl_cmd, +           "[no] ip multicast boundary ACCESSLIST4_NAME$name", +           NO_STR +           IP_STR +           "Generic multicast configuration options\n" +           "Define multicast boundary\n" +           "Access-list to filter OIL with by source and group\n") +{ +	nb_cli_enqueue_change(vty, "./multicast-boundary-acl", +			      (!!no ? NB_OP_DESTROY : NB_OP_MODIFY), name); + +	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL); +} +  DEFUN (interface_ip_mroute,         interface_ip_mroute_cmd,         "ip mroute INTERFACE A.B.C.D [A.B.C.D]", @@ -9018,6 +9033,7 @@ void pim_cmd_init(void)  	install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd);  	install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd);  	install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd); +	install_element(INTERFACE_NODE, &interface_ip_pim_boundary_acl_cmd);  	install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd);  	// Static mroutes NEB diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 19460aa445..f92a42dd8a 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -38,6 +38,7 @@  #include "pim_igmp_join.h"  #include "pim_vxlan.h"  #include "pim_tib.h" +#include "pim_util.h"  #include "pim6_mld.h" @@ -1258,6 +1259,14 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex,  {  	int join_fd; +	if (pim_is_group_filtered(pim_ifp, &group_addr, &source_addr)) { +		if (PIM_DEBUG_GM_EVENTS) { +			zlog_debug("%s: join failed for (S,G)=(%pPAs,%pPAs) due to multicast boundary filtering", +				   __func__, &source_addr, &group_addr); +		} +		return -1; +	} +  	pim_ifp->igmp_ifstat_joins_sent++;  	join_fd = pim_socket_raw(IPPROTO_GM); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 95bac084d2..18e88ffbd5 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -133,8 +133,10 @@ struct pim_interface {  	uint32_t pim_dr_priority;	  /* config */  	int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ -	/* boundary prefix-list */ +	/* boundary prefix-list (group) */  	char *boundary_oil_plist; +	/* boundary access-list (source and group) */ +	struct access_list *boundary_acl;  	/* Turn on Active-Active for this interface */  	bool activeactive; diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 1ba9bc45a2..12f424248f 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -666,7 +666,7 @@ static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from,  	memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); -	if (pim_is_group_filtered(ifp->info, &group_addr)) +	if (pim_is_group_filtered(ifp->info, &group_addr, NULL))  		return -1;  	/* non-existent group is created as INCLUDE {empty} */ diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index 944dffdc33..720a4944fe 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -134,6 +134,9 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from,  			   ifp->name, group_str);  	} +	if (pim_is_group_filtered(pim_ifp, &group_addr, NULL)) +		return -1; +  	/*  	 * RFC 4604  	 * section 2.2.1 diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 2c5ad4d44b..d0ba79378b 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -507,6 +507,8 @@ static void allow(struct gm_sock *igmp, struct in_addr from,  		struct in_addr *src_addr;  		src_addr = sources + i; +		if (pim_is_group_filtered(igmp->interface->info, &group_addr, src_addr)) +			continue;  		source = igmp_get_source_by_addr(group, *src_addr, NULL);  		if (!source) @@ -646,7 +648,7 @@ void igmpv3_report_isex(struct gm_sock *igmp, struct in_addr from,  	on_trace(__func__, ifp, from, group_addr, num_sources, sources); -	if (pim_is_group_filtered(ifp->info, &group_addr)) +	if (pim_is_group_filtered(ifp->info, &group_addr, NULL))  		return;  	/* non-existent group is created as INCLUDE {empty} */ @@ -1809,12 +1811,13 @@ static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str,  	pim_ifp = ifp->info;  	/* determine filtering status for group */ -	if (pim_is_group_filtered(pim_ifp, &grp)) { +	if (pim_is_group_filtered(pim_ifp, &grp, NULL)) {  		if (PIM_DEBUG_GM_PACKETS) { -			zlog_debug( -				"Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s", -				&grp.s_addr, from_str, ifp->name, -				pim_ifp->boundary_oil_plist); +			zlog_debug("Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s or access-list %s", +				   &grp.s_addr, from_str, ifp->name, +				   (pim_ifp->boundary_oil_plist ? pim_ifp->boundary_oil_plist +								: "(not found)"), +				   (pim_ifp->boundary_acl ? pim_ifp->boundary_acl->name : "(not found)"));  		}  		return false;  	} @@ -1943,11 +1946,9 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,  		       sizeof(struct in_addr));  		if (PIM_DEBUG_GM_PACKETS) { -			zlog_debug( -				"    Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", -				from_str, ifp->name, i, rec_type, -				rec_auxdatalen, rec_num_sources, -				&rec_group); +			zlog_debug("    Recv IGMP report v3 (type %d) from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", +				   rec_type, from_str, ifp->name, i, rec_type, rec_auxdatalen, +				   rec_num_sources, &rec_group);  		}  		/* Scan sources */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 2feafabb4d..7796e8b951 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -245,7 +245,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,  		uint16_t msg_num_pruned_sources;  		int source;  		struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; -		bool filtered = false; +		bool group_filtered = false;  		memset(&sg, 0, sizeof(sg));  		addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); @@ -275,7 +275,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,  				&src_addr, ifp->name);  		/* boundary check */ -		filtered = pim_is_group_filtered(pim_ifp, &sg.grp); +		group_filtered = pim_is_group_filtered(pim_ifp, &sg.grp, NULL);  		/* Scan joined sources */  		for (source = 0; source < msg_num_joined_sources; ++source) { @@ -287,8 +287,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,  			buf += addr_offset; -			/* if we are filtering this group, skip the join */ -			if (filtered) +			/* if we are filtering this group or (S,G), skip the join */ +			if (group_filtered || pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src))  				continue;  			recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr, @@ -312,10 +312,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,  			buf += addr_offset; -			/* if we are filtering this group, skip the prune */ -			if (filtered) -				continue; -  			recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr,  				   &sg, msg_source_flags);  			/* @@ -361,7 +357,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,  				}  			}  		} -		if (starg_ch && !filtered) +		if (starg_ch && !group_filtered)  			pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);  		starg_ch = NULL;  	} /* scan groups */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 9d290c3c6f..96eb5f48f5 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -35,6 +35,7 @@  #include "pim_sock.h"  #include "pim_vxlan.h"  #include "pim_msg.h" +#include "pim_util.h"  static void mroute_read_on(struct pim_instance *pim);  static int pim_upstream_mroute_update(struct channel_oil *c_oil, @@ -271,7 +272,9 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)  	    *oil_incoming_vif(up->channel_oil) >= MAXVIFS) {  		pim_upstream_mroute_iif_update(up->channel_oil, __func__);  	} -	pim_register_join(up); + +	if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) +		pim_register_join(up);  	/* if we have receiver, inherit from parent */  	pim_upstream_inherited_olist_decide(pim_ifp->pim, up); @@ -632,7 +635,8 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,  		pim_upstream_keep_alive_timer_start(  			up, pim_ifp->pim->keep_alive_time);  		up->channel_oil->cc.pktcnt++; -		pim_register_join(up); +		if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) +			pim_register_join(up);  		pim_upstream_inherited_olist(pim_ifp->pim, up);  		if (!up->channel_oil->installed)  			pim_upstream_mroute_add(up->channel_oil, __func__); diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 4a5ad87942..2b39f2dcb8 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -353,6 +353,13 @@ const struct frr_yang_module_info frr_pim_info = {  			}  		},  		{ +			.xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl", +			.cbs = { +				.modify = lib_interface_pim_address_family_multicast_boundary_acl_modify, +				.destroy = lib_interface_pim_address_family_multicast_boundary_acl_destroy, +			} +		}, +		{  			.xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute",  			.cbs = {  				.create = lib_interface_pim_address_family_mroute_create, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index a9693c65d8..f27b86680f 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -140,6 +140,8 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify(  	struct nb_cb_modify_args *args);  int lib_interface_pim_address_family_multicast_boundary_oil_destroy(  	struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args);  int lib_interface_pim_address_family_mroute_create(  	struct nb_cb_create_args *args);  int lib_interface_pim_address_family_mroute_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 171614208f..2533f8c4d4 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2453,6 +2453,71 @@ int lib_interface_pim_address_family_multicast_boundary_oil_destroy(  }  /* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl + */ +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args) +{ +	struct interface *ifp; +	struct pim_interface *pim_ifp; +	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)) { +			snprintf(args->errmsg, args->errmsg_len, +				 "%% Enable PIM and/or IGMP on this interface first"); +			return NB_ERR_VALIDATION; +		} +		if (!access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL))) { +			snprintf(args->errmsg, args->errmsg_len, +				 "%% Specified access-list not found"); +			return NB_ERR_VALIDATION; +		} +		break; +	case NB_EV_ABORT: +	case NB_EV_PREPARE: +		break; +	case NB_EV_APPLY: +		ifp = nb_running_get_entry(args->dnode, NULL, true); +		pim_ifp = ifp->info; +		pim_ifp->boundary_acl = +			access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL)); +		break; +	} + +	return NB_OK; +} + +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args) +{ +	struct interface *ifp; +	struct pim_interface *pim_ifp; +	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)) { +			snprintf(args->errmsg, args->errmsg_len, +				 "%% Enable PIM and/or IGMP on this interface first"); +			return NB_ERR_VALIDATION; +		} +		break; +	case NB_EV_ABORT: +	case NB_EV_PREPARE: +		break; +	case NB_EV_APPLY: +		ifp = nb_running_get_entry(args->dnode, NULL, true); +		pim_ifp = ifp->info; +		pim_ifp->boundary_acl = NULL; +		break; +	} + +	return NB_OK; +} + +/*   * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute   */  int lib_interface_pim_address_family_mroute_create( diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 49ae6949a2..b6f3be52fc 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -10,6 +10,8 @@  #include "prefix.h"  #include "plist.h" +#include "pimd.h" +#include "pim_instance.h"  #include "pim_util.h"  /* @@ -167,20 +169,47 @@ enum filter_type pim_access_list_apply(struct access_list *access, const struct  	return access_list_apply(access, &group_prefix);  } -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src)  { -	struct prefix grp_pfx; -	struct prefix_list *pl; +	bool is_filtered = false; +#if PIM_IPV == 4 +	struct prefix grp_pfx = {}; +	struct prefix_list *pl = NULL; +	pim_addr any_src = PIMADDR_ANY; -	if (!pim_ifp->boundary_oil_plist) +	if (!pim_ifp->boundary_oil_plist && !pim_ifp->boundary_acl)  		return false;  	pim_addr_to_prefix(&grp_pfx, *grp);  	pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); -	return pl ? prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == -			       PREFIX_DENY -		  : false; + +	/* Filter if either group or (S,G) are denied */ +	if (pl) { +		is_filtered = prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == PREFIX_DENY; +		if (is_filtered && PIM_DEBUG_EVENTS) { +			zlog_debug("Filtering group %pI4 per prefix-list %s", grp, +				   pim_ifp->boundary_oil_plist); +		} +	} +	if (!is_filtered && pim_ifp->boundary_acl) { +		/* If src not provided, set to "any" (*)? */ +		if (!src) +			src = &any_src; +		/* S,G filtering using extended access-list syntax */ +		is_filtered = pim_access_list_apply(pim_ifp->boundary_acl, src, grp) == FILTER_DENY; +		if (is_filtered && PIM_DEBUG_EVENTS) { +			if (pim_addr_is_any(*src)) { +				zlog_debug("Filtering (S,G)=(*, %pI4) per access-list %s", grp, +					   pim_ifp->boundary_acl->name); +			} else { +				zlog_debug("Filtering (S,G)=(%pI4, %pI4) per access-list %s", src, +					   grp, pim_ifp->boundary_acl->name); +			} +		} +	} +#endif +	return is_filtered;  } diff --git a/pimd/pim_util.h b/pimd/pim_util.h index cffa93ed29..dda93110b8 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -25,7 +25,7 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr);  int pim_is_group_224_4(struct in_addr group_addr);  enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source,  				       const struct in_addr *group); -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src);  int pim_get_all_mcast_group(struct prefix *prefix);  bool pim_addr_is_multicast(pim_addr addr);  #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index ed91d2339b..ec87093325 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -12,6 +12,7 @@  #include "vty.h"  #include "vrf.h"  #include "plist.h" +#include "filter.h"  #include "pimd.h"  #include "pim_vty.h" @@ -496,6 +497,12 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,  		++writes;  	} +	if (pim_ifp->boundary_acl) { +		vty_out(vty, " " PIM_AF_NAME " multicast boundary %s\n", +			pim_ifp->boundary_acl->name); +		++writes; +	} +  	if (pim_ifp->pim_passive_enable) {  		vty_out(vty, " " PIM_AF_NAME " pim passive\n");  		++writes;  | 
