From 6e1c4d28052629abaa87f4c56c3bba2788d0d40a Mon Sep 17 00:00:00 2001 From: Alkama Hasan Date: Fri, 19 Sep 2025 10:54:01 +0530 Subject: [PATCH 1/2] Marvell VSP: Add configurable MAC learning for OVS data plane Add isMacLearning parameter to control bridge switching behavior. When true, configures highest priority NORMAL flow for MAC-based learning. When false, allows traffic routing through network functions. Signed-off-by: Alkama Hasan --- .../marvell/debug-dp/debugdp.go | 2 +- .../vendor-specific-plugins/marvell/main.go | 7 +++++-- .../marvell/ovs-dp/ovsdp.go | 20 ++++++++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/internal/daemon/vendor-specific-plugins/marvell/debug-dp/debugdp.go b/internal/daemon/vendor-specific-plugins/marvell/debug-dp/debugdp.go index 03ce2c56b..6050c429c 100644 --- a/internal/daemon/vendor-specific-plugins/marvell/debug-dp/debugdp.go +++ b/internal/daemon/vendor-specific-plugins/marvell/debug-dp/debugdp.go @@ -26,7 +26,7 @@ func (debugDP *DebugDP) DeletePortFromDataPlane(bridgeName string, portName stri } -func (debugDP *DebugDP) InitDataPlane(bridgeName string) error { +func (debugDP *DebugDP) InitDataPlane(bridgeName string, isMacLearning bool) error { debugDP.log.Info("Init Data plane", "bridgeName", bridgeName) return nil } diff --git a/internal/daemon/vendor-specific-plugins/marvell/main.go b/internal/daemon/vendor-specific-plugins/marvell/main.go index e5728bca1..1b74a591e 100644 --- a/internal/daemon/vendor-specific-plugins/marvell/main.go +++ b/internal/daemon/vendor-specific-plugins/marvell/main.go @@ -48,13 +48,14 @@ const ( DpuRpmDeviceID string = "a063" NfName string = "mrvl-nf1" isNf bool = false + isMacLearning bool = true ) // multiple dataplane can be added using mrvldp interface functions type mrvldp interface { AddPortToDataPlane(bridgeName string, portName string, vfPCIAddres string, isDPDK bool) error DeletePortFromDataPlane(bridgeName string, portName string) error - InitDataPlane(bridgeName string) error + InitDataPlane(bridgeName string, isMacLearning bool) error ReadAllPortFromDataPlane(bridgeName string) (string, error) DeleteDataplane(bridgeName string) error AddFlowRuleToDataPlane(bridgeName string, inPort string, outPort string, dstMac string) error @@ -270,7 +271,7 @@ func (vsp *mrvlVspServer) doInit(dpuMode bool) (*pb.IpPort, error) { } // Initialize Marvell Data Path vsp.bridgeName = "br-mrv0" // TODO: example name discuss on it - if err := vsp.mrvlDP.InitDataPlane(vsp.bridgeName); err != nil { + if err := vsp.mrvlDP.InitDataPlane(vsp.bridgeName, isMacLearning); err != nil { klog.Errorf("Error occurred in initializing Data Path: %v", err) vsp.Stop() return nil, err @@ -297,6 +298,8 @@ func (vsp *mrvlVspServer) doInit(dpuMode bool) (*pb.IpPort, error) { // It will return the IpPort and error func (vsp *mrvlVspServer) Init(ctx context.Context, in *pb.InitRequest) (*pb.IpPort, error) { klog.Infof("Received Init() request: DpuMode: %v", in.DpuMode) + // To set the isMacLearning variable from the InitRequest + // vsp.isMacLearning = in.IsMacLearning result, err := vsp.doInit(in.DpuMode) klog.Infof("Received Init() request done: DpuMode: %v, IpPort: %v, err: %v", in.DpuMode, result, err) return result, err diff --git a/internal/daemon/vendor-specific-plugins/marvell/ovs-dp/ovsdp.go b/internal/daemon/vendor-specific-plugins/marvell/ovs-dp/ovsdp.go index 8b444b757..54d27e4c3 100644 --- a/internal/daemon/vendor-specific-plugins/marvell/ovs-dp/ovsdp.go +++ b/internal/daemon/vendor-specific-plugins/marvell/ovs-dp/ovsdp.go @@ -74,7 +74,7 @@ func createBridge(bridgeName string) error { } // InitDataPlane initializes the data path in this case it creates an ovs bridge -func (ovsdp *OvsDP) InitDataPlane(bridgeName string) error { +func (ovsdp *OvsDP) InitDataPlane(bridgeName string, isMacLearning bool) error { ovsdp.log.Info("Initializing OVS-DPDK Data Plane") ovsdp.bridgeName = bridgeName // "br0" For Testing Purpose @@ -84,6 +84,24 @@ func (ovsdp *OvsDP) InitDataPlane(bridgeName string) error { } ovsdp.log.Info("OVS-DPDK Bridge Created Successfully", "BridgeName", bridgeName) + + // Modify the default NORMAL flow to have highest priority + if isMacLearning { + ovsdp.log.Info("Modifying NORMAL flow to highest priority") + // First delete the existing NORMAL flow + cmd := exec.Command("chroot", "/host", "ovs-ofctl", "del-flows", bridgeName) + if err := cmd.Run(); err != nil { + ovsdp.log.Error(err, "Error occurred in deleting default NORMAL flow") + return err + } + // Add high priority NORMAL flow + cmd = exec.Command("chroot", "/host", "ovs-ofctl", "add-flow", bridgeName, "priority=65535,actions=NORMAL") + if err := cmd.Run(); err != nil { + ovsdp.log.Error(err, "Error occurred in adding high priority NORMAL flow") + return err + } + ovsdp.log.Info("NORMAL flow priority updated successfully", "Priority", 65535) + } // Get the name of interface from device id with device id as "a063" // a063 is the device id of RPM interface portName, err := mrvlutils.GetNameByDeviceID(deviceId) From afe4a3b014cef36f67e09167d77a513c30d106d6 Mon Sep 17 00:00:00 2001 From: Alkama Hasan Date: Tue, 23 Sep 2025 13:31:14 +0530 Subject: [PATCH 2/2] e2e-test: Removed skipNetworkFunctionTesting Option from e2e-test to test Marvell VSP Default DP With NF. Signed-off-by: Alkama Hasan --- e2e_test/e2e_test.go | 52 ++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index e477f055b..417431aee 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -314,23 +314,22 @@ var _ = g.Describe("E2E integration testing", g.Ordered, func() { g.Context("When Dpu Operator components are deployed and configured", g.Ordered, func() { var ( - testPodName = "test-pod-1" - testPod2Name = "test-pod-2" - secondaryNetDev = "net1" - pod1 *corev1.Pod - pod2 *corev1.Pod - nfPod *corev1.Pod - pod1_ip string - pod2_ip string - workloadSubnet string - nfIngressIp string - nfEgressIp string - externalClientIp string - externalClientDev string - externalSubnet string - skipNetworkFunctionTesting = false - sfc *configv1.ServiceFunctionChain - imageRef string + testPodName = "test-pod-1" + testPod2Name = "test-pod-2" + secondaryNetDev = "net1" + pod1 *corev1.Pod + pod2 *corev1.Pod + nfPod *corev1.Pod + pod1_ip string + pod2_ip string + workloadSubnet string + nfIngressIp string + nfEgressIp string + externalClientIp string + externalClientDev string + externalSubnet string + sfc *configv1.ServiceFunctionChain + imageRef string ) g.BeforeAll(func() { @@ -369,13 +368,6 @@ var _ = g.Describe("E2E integration testing", g.Ordered, func() { nfIngressIp, err = getEnv("NF_INGRESS_IP") Expect(err).NotTo(HaveOccurred()) - // Currently Marvell does have support for layer 3 network function connectivity, and it is possible future DPU vendors / solutions - // may take a similar approach. By default we will run the full test-suite but the user can opt out of the network function connectivity - // tests if running on hardware where this does not make sense. - if skipNF, exists := os.LookupEnv("SKIP_NF_TESTING"); exists && skipNF != "" { - skipNetworkFunctionTesting = true - } - externalSubnet = testutils.GetSubnet(externalClientIp) nfSubnet := testutils.GetSubnet(nfIngressIp) Expect(externalSubnet).To(Equal(nfSubnet), @@ -431,17 +423,11 @@ var _ = g.Describe("E2E integration testing", g.Ordered, func() { fmt.Println("Nf pod successfully created") }) g.It("Should support pod -> pod with Network-Function deployed", func() { - if skipNetworkFunctionTesting { - g.Skip("Skipping Network Function Testing") - } fmt.Println("Testing pod-to-pod connectivity w/ Network Function Deployed") pingTest(hostClientSet, hostRestConfig, pod1, pod2_ip, pod1.Name, pod2.Name) pingTest(hostClientSet, hostRestConfig, pod2, pod1_ip, pod2.Name, pod1.Name) }) g.It("Should support pod -> Network-Function", func() { - if skipNetworkFunctionTesting { - g.Skip("Skipping Network Function Testing") - } // We are assuming that net2 will always be ingress and net1 will always be egress, need to verify this assumption is reasonable // In this context, egress refers to traffic between the network function and the host and ingress refers to traffic between an @@ -465,9 +451,6 @@ var _ = g.Describe("E2E integration testing", g.Ordered, func() { pingTest(dpuClientSet, dpuRestConfig, nfPod, pod2_ip, nfPod.Name, pod2.Name) }) g.It("Should support Network-function -> external", func() { - if skipNetworkFunctionTesting { - g.Skip("Skipping Network Function Testing") - } fmt.Printf("Assigning NF ingress port IP %s\n", nfIngressIp) _, err := testutils.ExecInPod(dpuClientSet, dpuRestConfig, nfPod, fmt.Sprintf("ip addr add %s dev net2", nfIngressIp+"/24")) @@ -481,9 +464,6 @@ var _ = g.Describe("E2E integration testing", g.Ordered, func() { pingTest(dpuClientSet, dpuRestConfig, nfPod, externalClientIp, nfPod.Name, "external") }) g.It("Should support pod -> external", func() { - if skipNetworkFunctionTesting { - g.Skip("Skipping Network Function Testing") - } fmt.Printf("Setting route to %s in workload pods\n", externalSubnet) _, err := testutils.ExecInPod(hostClientSet, hostRestConfig, pod1, fmt.Sprintf("ip route add %s dev net1", externalSubnet))