Blob Blame History Raw
From 635df521886b802dd7d4dce0da45fda8759e9d1f Mon Sep 17 00:00:00 2001
From: Dumitru Ceara <dceara@redhat.com>
Date: Thu, 27 Feb 2020 10:15:59 +0100
Subject: [PATCH] ovn-northd: Fix IP local multicast flooding.

Skip IGMP entries learned for local multicast groups when generating
logical flows. We still allow ovn-controller to learn them as
it might be useful information for administrators to see that hosts
register for the groups even though they are not expected to send JOIN
messages for this range.

Note: The upstream OVN master patch doesn't apply cleanly because OVN
2.12 doesn't support MLD. The conflict is however easy to solve and
involves removing the IPv6 specific code.

Fixes: ddc64665b678 ("OVN: Add ovn-northd IGMP support")
Reported-by: Lucas Alvares Gomes <lmartins@redhat.com>
Reported-at: https://bugzilla.redhat.com/1803008
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
Acked-by: Mark Michelson <mmichels@redhat.com>
(cherry picked from OVN commit 755ffada2a66416173d5f1e09672909d40f87fd1)

Conflicts:
	ovn/northd/ovn-northd.c
	tests/ovn.at
Signed-off-by: Ben Pfaff <blp@ovn.org>

(cherry picked from upstream commit 616e3c592af8dcf77a40af67042c4c417f4d550a)

Conflicts:
	ovn/northd/ovn-northd.c

Change-Id: Iedfaa16b10521cbaa3a0e0b373476aa7ac5903fd
---
 ovn/northd/ovn-northd.c |  9 +++++++++
 tests/ovn.at            | 48 +++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 7cb3773..1d21f8c 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -6309,6 +6309,15 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         struct mcast_switch_info *mcast_sw_info =
             &igmp_group->datapath->mcast_info.sw;
 
+        /* RFC 4541, section 2.1.2, item 2: Skip groups in the 224.0.0.X
+         * range.
+         */
+        ovs_be32 group_address =
+            in6_addr_get_mapped_ipv4(&igmp_group->address);
+        if (ip_is_local_multicast(group_address)) {
+            continue;
+        }
+
         if (mcast_sw_info->active_flows >= mcast_sw_info->table_size) {
             continue;
         }
diff --git a/tests/ovn.at b/tests/ovn.at
index d74a8b0..d6e9b65 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -15293,7 +15293,7 @@ ovn-nbctl set Logical_Switch sw1       \
     other_config:mcast_snoop="true"
 
 # No IGMP query should be generated by sw1 (mcast_querier="false").
-truncate -s 0 expected
+> expected
 OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected])
 OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected])
 OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
@@ -15313,14 +15313,14 @@ send_igmp_v3_report hv2-vif1 hv2 000000000002 $(ip_to_hex 10 0 0 2) f9f9 \
 
 # Check that the IGMP Group is learned on both hv.
 OVS_WAIT_UNTIL([
-    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l`
+    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" -c`
     test "${total_entries}" = "2"
 ])
 
 # Send traffic and make sure it gets forwarded only on the two ports that
 # joined.
-truncate -s 0 expected
-truncate -s 0 expected_empty
+> expected
+> expected_empty
 send_ip_multicast_pkt hv1-vif2 hv1 \
     000000000001 01005e000144 \
     $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
@@ -15345,15 +15345,15 @@ send_igmp_v3_report hv1-vif1 hv1 \
 
 # Check IGMP_Group table on both HV.
 OVS_WAIT_UNTIL([
-    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l`
+    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" -c`
     test "${total_entries}" = "1"
 ])
 
 # Send traffic and make sure it gets forwarded only on the port that joined.
 as hv1 reset_pcap_file hv1-vif1 hv1/vif1
 as hv2 reset_pcap_file hv2-vif1 hv2/vif1
-truncate -s 0 expected
-truncate -s 0 expected_empty
+> expected
+> expected_empty
 send_ip_multicast_pkt hv1-vif2 hv1 \
     000000000001 01005e000144 \
     $(ip_to_hex 10 0 0 42) $(ip_to_hex 239 0 1 68) 1e 20 ca70 11 \
@@ -15373,10 +15373,40 @@ OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected_empty])
 # Flush IGMP groups.
 ovn-sbctl ip-multicast-flush sw1
 OVS_WAIT_UNTIL([
-    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" | wc -l`
+    total_entries=`ovn-sbctl find IGMP_Group | grep "239.0.1.68" -c`
     test "${total_entries}" = "0"
 ])
 
+# Check that traffic for 224.0.0.X is flooded even if some hosts register for
+# it.
+# Inject IGMP Join for 224.0.0.42 on sw1-p11.
+send_igmp_v3_report hv1-vif1 hv1 \
+    000000000001 $(ip_to_hex 10 0 0 1) f9f8 \
+    $(ip_to_hex 224 0 0 42) 04 f9d3 \
+    /dev/null
+
+# Check that the IGMP Group is learned.
+OVS_WAIT_UNTIL([
+    total_entries=`ovn-sbctl find IGMP_Group | grep "224.0.0.42" -c`
+    test "${total_entries}" = "1"
+])
+
+# Send traffic and make sure it gets flooded to all ports.
+as hv1 reset_pcap_file hv1-vif1 hv1/vif1
+as hv1 reset_pcap_file hv1-vif2 hv1/vif2
+as hv2 reset_pcap_file hv2-vif1 hv2/vif1
+as hv2 reset_pcap_file hv2-vif2 hv2/vif2
+> expected
+send_ip_multicast_pkt hv1-vif2 hv1 \
+    000000000001 01005e000144 \
+    $(ip_to_hex 10 0 0 42) $(ip_to_hex 224 0 0 42) 1e f989 11 \
+    e518e518000a4b540000 \
+    expected
+
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected])
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [expected])
+
 # Enable IGMP snooping and querier on sw2 and set query interval to minimum.
 ovn-nbctl set Logical_Switch sw2 \
     other_config:mcast_snoop="true" \
@@ -15386,7 +15416,7 @@ ovn-nbctl set Logical_Switch sw2 \
     other_config:mcast_ip4_src="20.0.0.254"
 
 # Wait for 1 query interval (1 sec) and check that two queries are generated.
-truncate -s 0 expected
+> expected
 store_igmp_v3_query 0000000002fe $(ip_to_hex 20 0 0 254) 84dd expected
 store_igmp_v3_query 0000000002fe $(ip_to_hex 20 0 0 254) 84dd expected
 
-- 
1.8.3.1