]> git.puffer.fish Git - mirror/frr.git/commitdiff
pimd: add support for boundaries 1247/head
authorQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 1 Sep 2017 18:33:00 +0000 (14:33 -0400)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 26 Sep 2017 17:00:52 +0000 (13:00 -0400)
Adds the ability to filter PIM Joins & IGMP reports on an interface.
Enabling a multicast boundary on an interface for a particular group
will prevent the interface from appearing in the group's OIL.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_igmp.c
pimd/pim_igmpv3.c
pimd/pim_join.c
pimd/pim_util.c
pimd/pim_util.h
pimd/pim_vty.c

index 396b949e4f905237fb7211bcca411ecba525e0fc..1ebe9c9aba6964de5160e2ded0b09ecc5d1999a3 100644 (file)
@@ -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);
index d98e5f1f66614d339e17bf7f4787e4dc8d6bb5eb..b8cbed7f93a5dff491471f2a220c61b57248ac93 100644 (file)
@@ -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);
index 2f27a1401077097dec3f55791b3a8218a3728f84..09bd2b06e455c9b4ac375e66c07ffe00c28390c0 100644 (file)
@@ -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;
index 3a870374c044c6e7a4924d6397de106e30d30510..f6c8db7acbad84d6cc4be47f9c11df740168fb0e 100644 (file)
@@ -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) {
index 1fc7517e0564fe7e613482e8a10bfc5bc1b9b5a7..ecde546c06a431ae75a0228cb8e1b72e39905cc8 100644 (file)
@@ -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,
index 4f5e534010481500018d4f3bace81dca3a448580..ae5032be73f7d41088a7e19f54babc2f8351d8ef 100644 (file)
@@ -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 */
index 820117a03a46ace6962bc47c452dd26d1de6bb7c..15bde256daf77ee3888507ad6442c7aa44e6c46d 100644 (file)
@@ -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;
+}
index 1b319cfe4ccb4b496ae297e035fdcc0b6c8ebc71..c66dd7b660c40b0015bb7562f4e312477cad8ac7 100644 (file)
@@ -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 */
index 3da092541dd838f40799507e9050ea005752d060..c1adbcc915b3d3a174c2bf4ca1598acaa2c2939c 100644 (file)
@@ -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);