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 }