diff options
author | Corey Siltala <csiltala@atcorp.com> | 2024-11-25 17:36:54 +0100 |
---|---|---|
committer | Corey Siltala <csiltala@atcorp.com> | 2024-12-06 21:44:17 +0100 |
commit | 4de4017d64ccaaa5a0f768873bc36aad4a8912a6 (patch) | |
tree | 7bb032b90c4c08f3f65f188f60220e267f0a89a4 /pimd | |
parent | pimd: Move ACL handling to pim_util.c (diff) | |
download | frr-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.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 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; |