Skip to content

Commit

Permalink
pimd,yang: Extend multicast boundary functionality
Browse files Browse the repository at this point in the history
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.

Move the extended access-list handling from pim_msdp_packet.c to
pim_util.c to allow use elsewhere in the daemon.

Signed-off-by: Corey Siltala <[email protected]>
  • Loading branch information
Corey Siltala committed Nov 21, 2024
1 parent a3e04a8 commit d84961b
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 83 deletions.
16 changes: 16 additions & 0 deletions pimd/pim_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]",
Expand Down Expand Up @@ -8999,6 +9014,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
Expand Down
7 changes: 7 additions & 0 deletions pimd/pim_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -1258,6 +1259,12 @@ 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)) {
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);
Expand Down
4 changes: 3 additions & 1 deletion pimd/pim_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
char *boundary_acl;

/* Turn on Active-Active for this interface */
bool activeactive;
Expand Down
2 changes: 1 addition & 1 deletion pimd/pim_igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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} */
Expand Down
3 changes: 3 additions & 0 deletions pimd/pim_igmpv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 12 additions & 12 deletions pimd/pim_igmpv3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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} */
Expand Down Expand Up @@ -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 : "(not found)"));
}
return false;
}
Expand All @@ -1823,7 +1826,6 @@ static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str,
* If we receive a igmp report with the group in 224.0.0.0/24
* then we should ignore it
*/

grp_addr.s_addr = ntohl(grp.s_addr);

if (pim_is_group_224_0_0_0_24(grp_addr)) {
Expand Down Expand Up @@ -1943,11 +1945,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 */
Expand Down
14 changes: 5 additions & 9 deletions pimd/pim_join.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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,
Expand All @@ -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);
/*
Expand Down Expand Up @@ -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 */
Expand Down
8 changes: 6 additions & 2 deletions pimd/pim_mroute.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down Expand 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__);
Expand Down
51 changes: 2 additions & 49 deletions pimd/pim_msdp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,53 +367,6 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
}

static bool msdp_cisco_match(const struct filter *filter,
const struct in_addr *source,
const struct in_addr *group)
{
const struct filter_cisco *cfilter = &filter->u.cfilter;
uint32_t source_addr;
uint32_t group_addr;

group_addr = group->s_addr & ~cfilter->mask_mask.s_addr;

if (cfilter->extended) {
source_addr = source->s_addr & ~cfilter->addr_mask.s_addr;
if (group_addr == cfilter->mask.s_addr &&
source_addr == cfilter->addr.s_addr)
return true;
} else if (group_addr == cfilter->addr.s_addr)
return true;

return false;
}

static enum filter_type msdp_access_list_apply(struct access_list *access,
const struct in_addr *source,
const struct in_addr *group)
{
struct filter *filter;
struct prefix group_prefix;

if (access == NULL)
return FILTER_DENY;

for (filter = access->head; filter; filter = filter->next) {
if (filter->cisco) {
if (msdp_cisco_match(filter, source, group))
return filter->type;
} else {
group_prefix.family = AF_INET;
group_prefix.prefixlen = IPV4_MAX_BITLEN;
group_prefix.u.prefix4.s_addr = group->s_addr;
if (access_list_apply(access, &group_prefix))
return filter->type;
}
}

return FILTER_DENY;
}

bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp,
const struct pim_msdp_sa *sa)
{
Expand All @@ -425,7 +378,7 @@ bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp,

/* Find access list and test it. */
acl = access_list_lookup(AFI_IP, mp->acl_out);
if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY)
if (pim_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY)
return true;

return false;
Expand Down Expand Up @@ -641,7 +594,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
/* Filter incoming SA with configured access list. */
if (mp->acl_in) {
acl = access_list_lookup(AFI_IP, mp->acl_in);
if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) {
if (pim_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) {
if (pim_msdp_log_sa_events(mp->pim))
zlog_info("MSDP peer %pI4 filter SA in (%pI4, %pI4)", &mp->peer,
&sg.src, &sg.grp);
Expand Down
7 changes: 7 additions & 0 deletions pimd/pim_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,13 @@ const struct frr_yang_module_info frr_pim_info = {
.destroy = lib_interface_pim_address_family_multicast_boundary_oil_destroy,
}
},
{
.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 = {
Expand Down
2 changes: 2 additions & 0 deletions pimd/pim_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,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(
Expand Down
67 changes: 67 additions & 0 deletions pimd/pim_nb_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2425,6 +2425,73 @@ int lib_interface_pim_address_family_multicast_boundary_oil_destroy(
return NB_OK;
}

/*
* 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 char *acl_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)) {
snprintf(args->errmsg, args->errmsg_len,
"%% PIM not enabled on this interface");
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;
acl_name = yang_dnode_get_string(args->dnode, NULL);

if (pim_ifp->boundary_acl)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_acl);

pim_ifp->boundary_acl = XSTRDUP(MTYPE_PIM_INTERFACE, acl_name);

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;
if (pim_ifp->boundary_acl)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_acl);
break;
}

return NB_OK;
}

/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute
*/
Expand Down
Loading

0 comments on commit d84961b

Please sign in to comment.