From b7aa252f3e25a750fbc5b703e4b1f51c47f205fd Mon Sep 17 00:00:00 2001 From: Talor Itzhak Date: Thu, 20 Aug 2026 15:51:04 +0300 Subject: [PATCH] e2e: make OVS dynamic pinning tests compatible with ovsDpdk CPUs When ovsDpdk CPUs are configured on the performance profile, the OVS affinity and cgroup tests need to account for DPDK PMD threads that run on dedicated ovsDpdk CPUs with their own exclusive cgroup partition. Signed-off-by: Talor Itzhak --- .../7_performance_kubelet_node/cgroups.go | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/test/e2e/performanceprofile/functests/7_performance_kubelet_node/cgroups.go b/test/e2e/performanceprofile/functests/7_performance_kubelet_node/cgroups.go index 029acc1ce..e83d2b31b 100644 --- a/test/e2e/performanceprofile/functests/7_performance_kubelet_node/cgroups.go +++ b/test/e2e/performanceprofile/functests/7_performance_kubelet_node/cgroups.go @@ -46,6 +46,7 @@ const ( cpuSetShared = "shared" cpuSetOfflined = "offlined" cpuSetGUPod = "guPod" + cpuSetOvsDpdk = "ovsDpdk" ) var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(label.OVSPinning)), func() { @@ -56,6 +57,7 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab var ( reservedCPUSet cpuset.CPUSet isolatedCPUSet cpuset.CPUSet + ovsDpdkCPUSet cpuset.CPUSet workerRTNode *corev1.Node workerRTNodes []corev1.Node profile, initialProfile *performancev2.PerformanceProfile @@ -103,8 +105,12 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab profileCPUSets := parseProfileCPUSets(profile) reservedCPUSet = profileCPUSets[cpuSetReserved] isolatedCPUSet = profileCPUSets[cpuSetIsolated] + ovsDpdkCPUSet = profileCPUSets[cpuSetOvsDpdk] testlog.Infof("Reserved CPUSet: %s", reservedCPUSet) testlog.Infof("Isolated CPUSet: %s", isolatedCPUSet) + if ovsDpdkCPUSet.Size() > 0 { + testlog.Infof("OvsDpdk CPUSet: %s", ovsDpdkCPUSet) + } }) Describe("[rfe_id: 64006][Dynamic OVS Pinning]", Ordered, Label(string(label.Tier0)), func() { @@ -277,7 +283,11 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab Expect(err).ToNot(HaveOccurred()) onlineCPUSet, err := nodes.GetOnlineCPUsSet(context.TODO(), workerRTNode) Expect(err).ToNot(HaveOccurred()) - Expect(ovsCPUSet).To(Equal(onlineCPUSet)) + expectedCPUSet := onlineCPUSet + if ovsDpdkCPUSet.Size() > 0 { + expectedCPUSet = onlineCPUSet.Difference(ovsDpdkCPUSet) + } + Expect(ovsCPUSet).To(Equal(expectedCPUSet)) if isCgroupV2 { Skip("CPU load balance can be checked only functionally on cgroupv2") @@ -493,6 +503,10 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab parts := strings.Split(line, ":") threadsCpuset, err := cpuset.Parse(strings.TrimSpace(parts[1])) Expect(err).ToNot(HaveOccurred()) + if isOvsDpdkPMDThread(threadsCpuset, ovsDpdkCPUSet) { + testlog.Infof("skipping ovs-vswitchd DPDK PMD thread with affinity %s", threadsCpuset) + continue + } Expect(threadsCpuset.Equals(baselineCpus)).To(BeTrue(), "actual cpuset %s not equals to expected cpuset %s", threadsCpuset, baselineCpus) } @@ -536,6 +550,10 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab parts := strings.Split(line, ":") threadsCpuset, err := cpuset.Parse(strings.TrimSpace(parts[1])) Expect(err).ToNot(HaveOccurred()) + if isOvsDpdkPMDThread(threadsCpuset, ovsDpdkCPUSet) { + testlog.Infof("skipping ovs-vswitchd DPDK PMD thread with affinity %s", threadsCpuset) + continue + } testlog.Infof("ovs-vswitchd thread affinity: %s, pod %s affinity: %s", threadsCpuset, podList.Items[i].Name, podcpus) Expect(podcpus.IsSubsetOf(threadsCpuset)).To(BeFalse()) } @@ -557,6 +575,10 @@ var _ = Describe("[performance] Cgroups and affinity", Ordered, Label(string(lab parts := strings.Split(line, ":") threadsCpuset, err := cpuset.Parse(strings.TrimSpace(parts[1])) Expect(err).ToNot(HaveOccurred()) + if isOvsDpdkPMDThread(threadsCpuset, ovsDpdkCPUSet) { + testlog.Infof("skipping ovs-vswitchd DPDK PMD thread with affinity %s", threadsCpuset) + continue + } testlog.Infof("ovs-vswitchd thread affinity: %s, pod %s affinity: %s", threadsCpuset, podList.Items[i].Name, podcpus) Expect(podcpus.IsSubsetOf(threadsCpuset)).To(BeFalse()) } @@ -928,6 +950,13 @@ func ovsSwitchdThreadAffinity(ctx context.Context, workerRTNode *corev1.Node) ([ return threadAffinity, nil } +// isOvsDpdkPMDThread returns true when the thread's CPU affinity falls entirely +// within the ovsDpdk CPU set, indicating it is a DPDK PMD thread managed by +// the ovsdpdk.slice cgroup rather than a regular OVS service thread. +func isOvsDpdkPMDThread(threadCPUs, ovsDpdkCPUs cpuset.CPUSet) bool { + return ovsDpdkCPUs.Size() > 0 && threadCPUs.IsSubsetOf(ovsDpdkCPUs) +} + // expectedOvsAffinity computes the expected OVN/OVS CPU affinity set. // Formula: (reserved + isolated) - GU_Pinned // reserved+isolated is the profile-derived baseline for OVS. Subtracting @@ -1006,6 +1035,7 @@ func parseProfileCPUSets(profile *performancev2.PerformanceProfile) map[string]c cpuSetIsolated: cpuset.New(), cpuSetShared: cpuset.New(), cpuSetOfflined: cpuset.New(), + cpuSetOvsDpdk: cpuset.New(), } parseCPUSet := func(name string, raw *performancev2.CPUSet) { @@ -1021,6 +1051,7 @@ func parseProfileCPUSets(profile *performancev2.PerformanceProfile) map[string]c parseCPUSet(cpuSetIsolated, profile.Spec.CPU.Isolated) parseCPUSet(cpuSetShared, profile.Spec.CPU.Shared) parseCPUSet(cpuSetOfflined, profile.Spec.CPU.Offlined) + parseCPUSet(cpuSetOvsDpdk, profile.Spec.CPU.OvsDpdk) return cpuSets }