]> git.proxmox.com Git - mirror_frr.git/commitdiff
pimd : Handling of Exclude mode IGMPv3 report messages for SSM aware group.
authorAbhishek N R <abnr@vmware.com>
Tue, 9 Nov 2021 07:00:41 +0000 (23:00 -0800)
committerAbhishek N R <abnr@vmware.com>
Thu, 20 Jan 2022 15:52:06 +0000 (07:52 -0800)
Problem Statement:
==================

(rcv1)-----A----B---C
 v3 enabled with src 90.0.0.1
       |
(rcv2)--
 v3 enable with src none

rcv1 sends the packet in INCLUDE mode, rcv2 sends the IGMP report
in exclude mode. As per the state machine the group structure was
getting added and deleted. As group gets deleted the mroute for 90.0.0.1
and recreated back.
This effects the end to end trafiic.

Root Cause Analysis:
====================
As per state machine
INCLUDE (A) IS_EX (B) EXCLUDE (A*B,B-A) (B-A)=0
Delete (A-B)
Group Timer=GMI

EXCLUDE (X,Y) TO_EX (A) EXCLUDE (A-Y,Y*A) (A-X-Y)=Group Timer
Delete (X-A)
Delete (Y-A)
Send Q(G,A-Y)
Group Timer=GMI

The above equations were getiing calulated for IP address
90.0.0.1 and 0.0.0.0
This results in group creation deletion.

Fix:
====
As per RFC 4604.
drop the exclude mode, IGMP reports, if destnation group is
SSM based.
EXCLUDE
mode does not apply to SSM addresses, and an SSM-aware router will
ignore MODE_IS_EXCLUDE and CHANGE_TO_EXCLUDE_MODE requests in the SSM
range.

Signed-off-by: Abhishek N R <abnr@vmware.com>
Signed-off-by: Vishal Dhingra <rac.vishaldhingra@gmail.com>
pimd/pim_igmpv3.c

index 492af5f2d28d303a41fd1ee750757086287ffda8..51f1cf3d57f57fb7e74c33aee8e90ba59676bf80 100644 (file)
@@ -32,6 +32,7 @@
 #include "pim_time.h"
 #include "pim_zebra.h"
 #include "pim_oil.h"
+#include "pim_ssm.h"
 
 static void group_retransmit_timer_on(struct gm_group *group);
 static long igmp_group_timer_remain_msec(struct gm_group *group);
@@ -1826,6 +1827,64 @@ void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str,
        } /* s_flag is clear: timer updates */
 }
 
+static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str,
+                                struct in_addr grp, int rec_type)
+{
+       struct pim_interface *pim_ifp;
+       struct in_addr grp_addr;
+
+       pim_ifp = ifp->info;
+
+       /* determine filtering status for group */
+       if (pim_is_group_filtered(pim_ifp, &grp)) {
+               if (PIM_DEBUG_IGMP_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);
+               }
+               return false;
+       }
+
+       /*
+        * 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)) {
+               if (PIM_DEBUG_IGMP_PACKETS) {
+                       zlog_debug(
+                               "Ignoring IGMPv3 group record %pI4 from %s on %s group range falls in 224.0.0.0/24",
+                               &grp.s_addr, from_str, ifp->name);
+               }
+               return false;
+       }
+
+       /*
+        * RFC 4604
+        * section 2.2.1
+        * EXCLUDE mode does not apply to SSM addresses, and an SSM-aware router
+        * will ignore MODE_IS_EXCLUDE and CHANGE_TO_EXCLUDE_MODE requests in
+        * the SSM range.
+        */
+       if (pim_is_grp_ssm(pim_ifp->pim, grp)) {
+               switch (rec_type) {
+               case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
+               case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
+                       if (PIM_DEBUG_IGMP_PACKETS) {
+                               zlog_debug(
+                                       "Ignoring IGMPv3 group record %pI4 from %s on %s exclude mode in SSM range",
+                                       &grp.s_addr, from_str, ifp->name);
+                       }
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
                        const char *from_str, char *igmp_msg, int igmp_msg_len)
 {
@@ -1834,14 +1893,10 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
        uint8_t *report_pastend = (uint8_t *)igmp_msg + igmp_msg_len;
        struct interface *ifp = igmp->interface;
        int i;
-       int local_ncb = 0;
-       struct pim_interface *pim_ifp;
 
        if (igmp->mtrace_only)
                return 0;
 
-       pim_ifp = igmp->interface->info;
-
        if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
                zlog_warn(
                        "Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
@@ -1886,9 +1941,6 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
                int rec_auxdatalen;
                int rec_num_sources;
                int j;
-               struct prefix lncb;
-               struct prefix g;
-               bool filtered = false;
 
                if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE)
                    > report_pastend) {
@@ -1946,31 +1998,7 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
                } /* for (sources) */
 
 
-               lncb.family = AF_INET;
-               lncb.u.prefix4.s_addr = 0x000000E0;
-               lncb.prefixlen = 24;
-
-               g.family = AF_INET;
-               g.u.prefix4 = rec_group;
-               g.prefixlen = IPV4_MAX_BITLEN;
-
-               /* 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 %pI4 from %s on %s per prefix-list %s",
-                               &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
-                */
-               if (prefix_match(&lncb, &g))
-                       local_ncb = 1;
-
-               if (!local_ncb && !filtered)
+               if (igmp_pkt_grp_addr_ok(ifp, from_str, rec_group, rec_type))
                        switch (rec_type) {
                        case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
                                igmpv3_report_isin(igmp, from, rec_group,
@@ -2010,7 +2038,6 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
 
                group_record +=
                        8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
-               local_ncb = 0;
 
        } /* for (group records) */