summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pimd/pim_cmd.c54
-rw-r--r--pimd/pim_iface.c3
-rw-r--r--pimd/pim_iface.h3
-rw-r--r--pimd/pim_igmp.c24
-rw-r--r--pimd/pim_igmpv3.c19
-rw-r--r--pimd/pim_join.c18
-rw-r--r--pimd/pim_util.c19
-rw-r--r--pimd/pim_util.h3
-rw-r--r--pimd/pim_vty.c9
9 files changed, 137 insertions, 15 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 396b949e4..1ebe9c9ab 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -6462,6 +6462,58 @@ DEFUN (interface_no_ip_pim_sm,
return CMD_SUCCESS;
}
+/* boundaries */
+DEFUN(interface_ip_pim_boundary_oil,
+ interface_ip_pim_boundary_oil_cmd,
+ "ip multicast boundary oil WORD",
+ IP_STR
+ "Generic multicast configuration options\n"
+ "Define multicast boundary\n"
+ "Filter OIL by group using prefix list\n"
+ "Prefix list to filter OIL with")
+{
+ VTY_DECLVAR_CONTEXT(interface, iif);
+ struct pim_interface *pim_ifp;
+ int idx = 0;
+
+ argv_find(argv, argc, "WORD", &idx);
+
+ PIM_GET_PIM_INTERFACE(pim_ifp, iif);
+
+ if (pim_ifp->boundary_oil_plist)
+ XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+
+ pim_ifp->boundary_oil_plist =
+ XSTRDUP(MTYPE_PIM_INTERFACE, argv[idx]->arg);
+
+ /* Interface will be pruned from OIL on next Join */
+ return CMD_SUCCESS;
+}
+
+DEFUN(interface_no_ip_pim_boundary_oil,
+ interface_no_ip_pim_boundary_oil_cmd,
+ "no ip multicast boundary oil [WORD]",
+ NO_STR
+ IP_STR
+ "Generic multicast configuration options\n"
+ "Define multicast boundary\n"
+ "Filter OIL by group using prefix list\n"
+ "Prefix list to filter OIL with")
+{
+ VTY_DECLVAR_CONTEXT(interface, iif);
+ struct pim_interface *pim_ifp;
+ int idx;
+
+ argv_find(argv, argc, "WORD", &idx);
+
+ PIM_GET_PIM_INTERFACE(pim_ifp, iif);
+
+ if (pim_ifp->boundary_oil_plist)
+ XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (interface_ip_mroute,
interface_ip_mroute_cmd,
"ip mroute INTERFACE A.B.C.D",
@@ -8564,6 +8616,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_hello_cmd);
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);
// Static mroutes NEB
install_element(INTERFACE_NODE, &interface_ip_mroute_cmd);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index d98e5f1f6..b8cbed7f9 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -246,6 +246,9 @@ void pim_if_delete(struct interface *ifp)
list_delete(pim_ifp->upstream_switch_list);
list_delete(pim_ifp->sec_addr_list);
+ if (pim_ifp->boundary_oil_plist)
+ XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+
while ((ch = RB_ROOT(pim_ifchannel_rb,
&pim_ifp->ifchannel_rb)) != NULL)
pim_ifchannel_delete(ch);
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 2f27a1401..09bd2b06e 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -122,6 +122,9 @@ struct pim_interface {
uint32_t pim_dr_priority; /* config */
int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */
+ /* boundary prefix-list */
+ char *boundary_oil_plist;
+
int64_t pim_ifstat_start; /* start timestamp for stats */
uint32_t pim_ifstat_hello_sent;
uint32_t pim_ifstat_hello_sendfail;
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 3a870374c..f6c8db7ac 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -299,22 +299,19 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version,
return -1;
}
- /* RFC 3376 defines some guidelines on operating in backwards
- * compatibility
- * with older versions of IGMP but there are some gaps in the logic:
+ /*
+ * RFC 3376 defines some guidelines on operating in backwards
+ * compatibility with older versions of IGMP but there are some gaps in
+ * the logic:
*
* - once we drop from say version 3 to version 2 we will never go back
- * to
- * version 3 even if the node that TXed an IGMP v2 query upgrades to
- * v3
+ * to version 3 even if the node that TXed an IGMP v2 query upgrades
+ * to v3
*
* - The node with the lowest IP is the querier so we will only know to
- * drop
- * from v3 to v2 if the node that is the querier is also the one that
- * is
- * running igmp v2. If a non-querier only supports igmp v2 we will
- * have
- * no way of knowing.
+ * drop from v3 to v2 if the node that is the querier is also the one
+ * that is running igmp v2. If a non-querier only supports igmp v2
+ * we will have no way of knowing.
*
* For now we will simplify things and inform the user that they need to
* configure all PIM routers to use the same version of IGMP.
@@ -403,6 +400,9 @@ static int igmp_v1_recv_report(struct igmp_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))
+ return -1;
+
/* non-existant group is created as INCLUDE {empty} */
group = igmp_add_group_by_addr(igmp, group_addr);
if (!group) {
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index 1fc7517e0..ecde546c0 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -671,6 +671,9 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources,
sources);
+ if (pim_is_group_filtered(ifp->info, &group_addr))
+ return;
+
/* non-existant group is created as INCLUDE {empty} */
group = igmp_add_group_by_addr(igmp, group_addr);
if (!group) {
@@ -1869,6 +1872,9 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
struct interface *ifp = igmp->interface;
int i;
int local_ncb = 0;
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = igmp->interface->info;
if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
zlog_warn(
@@ -1920,6 +1926,7 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
int j;
struct prefix lncb;
struct prefix g;
+ bool filtered = false;
if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE)
> report_pastend) {
@@ -1983,6 +1990,16 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
g.family = AF_INET;
g.u.prefix4 = rec_group;
g.prefixlen = 32;
+
+ /* determine filtering status for group */
+ filtered = pim_is_group_filtered(ifp->info, &rec_group);
+
+ if (PIM_DEBUG_IGMP_PACKETS && filtered)
+ zlog_debug(
+ "Filtering IGMPv3 group record %s from %s on %s per prefix-list %s",
+ inet_ntoa(rec_group), from_str, ifp->name,
+ pim_ifp->boundary_oil_plist);
+
/*
* If we receive a igmp report with the group in 224.0.0.0/24
* then we should ignore it
@@ -1990,7 +2007,7 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
if (prefix_match(&lncb, &g))
local_ncb = 1;
- if (!local_ncb)
+ if (!local_ncb && !filtered)
switch (rec_type) {
case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
igmpv3_report_isin(igmp, from, rec_group,
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 4f5e53401..ae5032be7 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -38,6 +38,7 @@
#include "pim_rpf.h"
#include "pim_rp.h"
#include "pim_jp_agg.h"
+#include "pim_util.h"
static void on_trace(const char *label, struct interface *ifp,
struct in_addr src)
@@ -153,6 +154,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
int tlv_buf_size)
{
struct prefix msg_upstream_addr;
+ struct pim_interface *pim_ifp;
uint8_t msg_num_groups;
uint16_t msg_holdtime;
int addr_offset;
@@ -163,6 +165,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
buf = tlv_buf;
pastend = tlv_buf + tlv_buf_size;
+ pim_ifp = ifp->info;
/*
Parse ucast addr
@@ -231,6 +234,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;
memset(&sg, 0, sizeof(struct prefix_sg));
addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
@@ -273,6 +277,9 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
src_str, ifp->name);
}
+ /* boundary check */
+ filtered = pim_is_group_filtered(pim_ifp, &sg.grp);
+
/* Scan joined sources */
for (source = 0; source < msg_num_joined_sources; ++source) {
addr_offset = pim_parse_addr_source(
@@ -283,6 +290,10 @@ 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)
+ continue;
+
recv_join(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4, &sg,
msg_source_flags);
@@ -304,6 +315,11 @@ 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.u.prefix4, &sg,
msg_source_flags);
@@ -335,7 +351,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
}
}
}
- if (starg_ch)
+ if (starg_ch && !filtered)
pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
starg_ch = NULL;
} /* scan groups */
diff --git a/pimd/pim_util.c b/pimd/pim_util.c
index 820117a03..15bde256d 100644
--- a/pimd/pim_util.c
+++ b/pimd/pim_util.c
@@ -21,6 +21,7 @@
#include "log.h"
#include "prefix.h"
+#include "plist.h"
#include "pim_util.h"
@@ -114,7 +115,7 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr)
group.family = AF_INET;
group.u.prefix4 = group_addr;
- group.prefixlen = 32;
+ group.prefixlen = IPV4_MAX_PREFIXLEN;
return prefix_match(&group_224, &group);
}
@@ -137,3 +138,19 @@ int pim_is_group_224_4(struct in_addr group_addr)
return prefix_match(&group_all, &group);
}
+
+bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp)
+{
+ struct prefix grp_pfx;
+ struct prefix_list *pl;
+
+ if (!pim_ifp->boundary_oil_plist)
+ return false;
+
+ grp_pfx.family = AF_INET;
+ grp_pfx.prefixlen = 32;
+ grp_pfx.u.prefix4 = *grp;
+
+ pl = prefix_list_lookup(AFI_IP, pim_ifp->boundary_oil_plist);
+ return pl ? prefix_list_apply(pl, &grp_pfx) == PREFIX_DENY : false;
+}
diff --git a/pimd/pim_util.h b/pimd/pim_util.h
index 1b319cfe4..c66dd7b66 100644
--- a/pimd/pim_util.h
+++ b/pimd/pim_util.h
@@ -25,6 +25,8 @@
#include <zebra.h>
#include "checksum.h"
+#include "pimd.h"
+#include "pim_iface.h"
uint8_t igmp_msg_encode16to8(uint16_t value);
uint16_t igmp_msg_decode8to16(uint8_t code);
@@ -33,4 +35,5 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size);
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);
+bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp);
#endif /* PIM_UTIL_H */
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 3da092541..c1adbcc91 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -285,6 +285,7 @@ int pim_interface_config_write(struct vty *vty)
vty_out(vty, " %d",
pim_ifp->pim_default_holdtime);
vty_out(vty, "\n");
+ ++writes;
}
/* update source */
@@ -358,6 +359,14 @@ int pim_interface_config_write(struct vty *vty)
}
}
+ /* boundary */
+ if (pim_ifp->boundary_oil_plist) {
+ vty_out(vty,
+ " ip pim boundary oil %s\n",
+ pim_ifp->boundary_oil_plist);
+ ++writes;
+ }
+
writes +=
pim_static_write_mroute(pim, vty, ifp);
pim_bfd_write_config(vty, ifp);