From 6917edf13f6dbd5f0587ded97bc160f5c8e55516 Mon Sep 17 00:00:00 2001
From: Shuyang Xin <gavinx@vmware.com>
Date: Wed, 17 Jul 2024 10:21:20 +0800
Subject: [PATCH] Match dstIP in Classifier to address windows promiscuous mode
 issue
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When promiscuous mode is enabled, OVS incorrectly forwards packets destined for
non-local IP addresses from the uplink to the host interface. Due to IP forwarding
being enabled, these packets are re-sent to br-int according to the default route
and are eventually forwarded to the uplink. Since the source MAC of these packets
has been changed to the local host’s MAC, this can potentially cause errors on the switch.

This patch matches dstIP field in ClassifierTable to ensure proper packet handling
and preventing unintended forwarding.

Signed-off-by: Shuyang Xin <gavinx@vmware.com>
---
 pkg/agent/openflow/pipeline.go              | 4 ++--
 pkg/agent/openflow/pipeline_other.go        | 4 ++++
 pkg/agent/openflow/pipeline_windows.go      | 7 +++++++
 pkg/agent/openflow/pod_connectivity_test.go | 4 ++--
 4 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go
index b5f75df9327..68198232e57 100644
--- a/pkg/agent/openflow/pipeline.go
+++ b/pkg/agent/openflow/pipeline.go
@@ -2967,9 +2967,9 @@ func (f *featurePodConnectivity) hostBridgeLocalFlows() []binding.Flow {
 	cookieID := f.cookieAllocator.Request(f.category).Raw()
 	return []binding.Flow{
 		// This generates the flow to forward the packets from uplink port to bridge local port.
-		ClassifierTable.ofTable.BuildFlow(priorityNormal).
+		f.matchUplinkInPort(ClassifierTable.ofTable.BuildFlow(priorityNormal).
 			Cookie(cookieID).
-			MatchInPort(f.uplinkPort).
+			MatchInPort(f.uplinkPort)).
 			Action().Output(f.hostIfacePort).
 			Done(),
 		// This generates the flow to forward the packets from bridge local port to uplink port.
diff --git a/pkg/agent/openflow/pipeline_other.go b/pkg/agent/openflow/pipeline_other.go
index 60459fba878..7d849ecf2cd 100644
--- a/pkg/agent/openflow/pipeline_other.go
+++ b/pkg/agent/openflow/pipeline_other.go
@@ -25,6 +25,10 @@ import (
 	binding "antrea.io/antrea/pkg/ovs/openflow"
 )
 
+func (f *featurePodConnectivity) matchUplinkInPort(flowBuilder binding.FlowBuilder) binding.FlowBuilder {
+	return flowBuilder
+}
+
 // hostBridgeUplinkFlows generates the flows that forward traffic between the bridge local port and the uplink port to
 // support the host traffic.
 // TODO(gran): sync latest changes from pipeline_windows.go
diff --git a/pkg/agent/openflow/pipeline_windows.go b/pkg/agent/openflow/pipeline_windows.go
index 2557d3f6ffb..79b9118c72f 100644
--- a/pkg/agent/openflow/pipeline_windows.go
+++ b/pkg/agent/openflow/pipeline_windows.go
@@ -23,6 +23,13 @@ import (
 	binding "antrea.io/antrea/pkg/ovs/openflow"
 )
 
+// matchUplinkInPort matches dstIP field to prevent unintended forwarding when promiscuous mode is enabled on Windows.
+func (f *featurePodConnectivity) matchUplinkInPort(flowBuilder binding.FlowBuilder) binding.FlowBuilder {
+	return flowBuilder.
+		MatchProtocol(binding.ProtocolIP).
+		MatchDstIP(f.nodeConfig.NodeTransportIPv4Addr.IP)
+}
+
 // hostBridgeUplinkFlows generates the flows that forward traffic between the bridge local port and the uplink port to
 // support the host traffic with outside.
 func (f *featurePodConnectivity) hostBridgeUplinkFlows() []binding.Flow {
diff --git a/pkg/agent/openflow/pod_connectivity_test.go b/pkg/agent/openflow/pod_connectivity_test.go
index 327372ebb08..77e3aba9a73 100644
--- a/pkg/agent/openflow/pod_connectivity_test.go
+++ b/pkg/agent/openflow/pod_connectivity_test.go
@@ -90,7 +90,7 @@ func podConnectivityInitFlows(
 			flows = append(flows,
 				"cookie=0x1010000000000, table=ARPSpoofGuard, priority=200,in_port=32770 actions=output:4294967294",
 				"cookie=0x1010000000000, table=ARPSpoofGuard, priority=200,in_port=4294967294 actions=output:32770",
-				"cookie=0x1010000000000, table=Classifier, priority=200,in_port=32770 actions=output:4294967294",
+				"cookie=0x1010000000000, table=Classifier, priority=200,ip,in_port=32770,nw_dst=192.168.77.100 actions=output:4294967294",
 				"cookie=0x1010000000000, table=Classifier, priority=200,in_port=4294967294 actions=output:32770",
 				"cookie=0x1010000000000, table=IngressSecurityClassifier, priority=210,ct_state=-rpl+trk,ip,nw_src=10.10.0.1 actions=goto_table:ConntrackCommit",
 			)
@@ -161,7 +161,7 @@ func podConnectivityInitFlows(
 				"cookie=0x1010000000000, table=ARPSpoofGuard, priority=200,in_port=32770 actions=output:4294967294",
 				"cookie=0x1010000000000, table=ARPSpoofGuard, priority=200,in_port=4294967294 actions=output:32770",
 				"cookie=0x1010000000000, table=Classifier, priority=210,ip,in_port=32770,nw_dst=10.10.0.0/24 actions=set_field:0x4/0xf->reg0,set_field:0x200/0x200->reg0,goto_table:UnSNAT",
-				"cookie=0x1010000000000, table=Classifier, priority=200,in_port=32770 actions=output:4294967294",
+				"cookie=0x1010000000000, table=Classifier, priority=200,ip,in_port=32770,nw_dst=192.168.77.100 actions=output:4294967294",
 				"cookie=0x1010000000000, table=Classifier, priority=200,in_port=4294967294 actions=output:32770",
 				"cookie=0x1010000000000, table=SpoofGuard, priority=200,ip,in_port=32769 actions=goto_table:UnSNAT",
 				"cookie=0x1010000000000, table=ConntrackZone, priority=200,ip actions=ct(table=ConntrackState,zone=65520,nat)",