summaryrefslogtreecommitdiffstats
path: root/pimd
diff options
context:
space:
mode:
authorCorey Siltala <csiltala@atcorp.com>2024-11-25 17:36:54 +0100
committerCorey Siltala <csiltala@atcorp.com>2024-12-06 21:44:17 +0100
commit4de4017d64ccaaa5a0f768873bc36aad4a8912a6 (patch)
tree7bb032b90c4c08f3f65f188f60220e267f0a89a4 /pimd
parentpimd: Move ACL handling to pim_util.c (diff)
downloadfrr-4de4017d64ccaaa5a0f768873bc36aad4a8912a6.tar.xz
frr-4de4017d64ccaaa5a0f768873bc36aad4a8912a6.zip
pimd,yang: Extend multicast boundary functionality
Add new interface command ip multicast boundary ACCESSLIST4_NAME. This allows filtering on both source and group using the extended access-list syntax vs. group-only as with the existing "ip multicast boundary oil" command, which uses prefix-lists. If both are configured, the prefix- list is evaluated first. The default behavior for both prefix-lists and access-lists remains "deny", so the prefix-list must have a terminating "permit" statement in order to also evaluate against the access-list. The following example denies groups in range 229.1.1.0/24 and groups in range 232.1.1.0/24 with source 10.0.20.2: ! ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 ip prefix-list pim-oil-plist seq 20 permit any ! access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 access-list pim-acl seq 20 permit ip any any ! interface r1-eth0 ip address 10.0.20.1/24 ip igmp ip pim ip multicast boundary oil pim-oil-plist ip multicast boundary pim-acl ! Signed-off-by: Corey Siltala <csiltala@atcorp.com>
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_cmd.c16
-rw-r--r--pimd/pim_iface.c9
-rw-r--r--pimd/pim_iface.h4
-rw-r--r--pimd/pim_igmp.c2
-rw-r--r--pimd/pim_igmpv2.c3
-rw-r--r--pimd/pim_igmpv3.c23
-rw-r--r--pimd/pim_join.c14
-rw-r--r--pimd/pim_mroute.c8
-rw-r--r--pimd/pim_nb.c7
-rw-r--r--pimd/pim_nb.h2
-rw-r--r--pimd/pim_nb_config.c65
-rw-r--r--pimd/pim_util.c43
-rw-r--r--pimd/pim_util.h2
-rw-r--r--pimd/pim_vty.c7
14 files changed, 173 insertions, 32 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index f4c25ea81..bac964575 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 19460aa44..f92a42dd8 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 95bac084d..18e88ffbd 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 1ba9bc45a..12f424248 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 944dffdc3..720a4944f 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 2c5ad4d44..d0ba79378 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 2feafabb4..7796e8b95 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 9d290c3c6..96eb5f48f 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 4a5ad8794..2b39f2dcb 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 a9693c65d..f27b86680 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 171614208..2533f8c4d 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 49ae6949a..b6f3be52f 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 cffa93ed2..dda93110b 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 ed91d2339..ec8709332 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;