From 3d54a103d0f08bf189f62800e98b06144e44e698 Mon Sep 17 00:00:00 2001 From: Lukas Sismis Date: Mon, 19 Jun 2023 17:23:36 +0200 Subject: [PATCH] dpdk: improve DPDK thread handling Ticket: #6106 --- src/runmode-dpdk.c | 64 +++++++++++++++++++++++++++++++++++++++++---- src/source-dpdk.c | 1 + src/util-affinity.c | 56 +++++++++++++++++++++++++++++++++++++++ src/util-affinity.h | 5 ++++ 4 files changed, 121 insertions(+), 5 deletions(-) diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c index 687d88871a..da0ff052ed 100644 --- a/src/runmode-dpdk.c +++ b/src/runmode-dpdk.c @@ -48,6 +48,7 @@ #include "util-time.h" #include "util-conf.h" #include "suricata.h" +#include "util-affinity.h" #ifdef HAVE_DPDK @@ -355,8 +356,40 @@ static void ConfigSetIface(DPDKIfaceConfig *iconf, const char *entry_str) static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str) { SCEnter(); - const char *active_runmode = RunmodeGetActive(); + static int32_t remaining_auto_cpus = -1; + static uint32_t total_cpus = 0; + if (!threading_set_cpu_affinity) { + SCLogError("DPDK runmode requires configured thread affinity"); + SCReturnInt(-EINVAL); + } + ThreadsAffinityType *wtaf = GetAffinityTypeFromName("worker-cpu-set"); + if (wtaf == NULL) { + SCLogError("Specify worker-cpu-set list in the threading section"); + SCReturnInt(-EINVAL); + } + ThreadsAffinityType *mtaf = GetAffinityTypeFromName("management-cpu-set"); + if (mtaf == NULL) { + SCLogError("Specify management-cpu-set list in the threading section"); + SCReturnInt(-EINVAL); + } + uint32_t sched_cpus = UtilAffinityGetAffinedCPUNum(wtaf); + if (sched_cpus == UtilCpuGetNumProcessorsOnline()) { + SCLogWarning( + "\"all\" specified in worker CPU cores affinity, excluding management threads"); + UtilAffinityCpusExclude(wtaf, mtaf); + sched_cpus = UtilAffinityGetAffinedCPUNum(wtaf); + } + + if (sched_cpus == 0) { + SCLogError("No worker CPU cores with configured affinity were configured"); + SCReturnInt(-EINVAL); + } else if (UtilAffinityCpusOverlap(wtaf, mtaf) != 0) { + SCLogWarning("Worker threads should not overlap with management threads in the CPU core " + "affinity configuration"); + } + + const char *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("single", active_runmode)) { iconf->threads = 1; SCReturnInt(0); @@ -368,8 +401,23 @@ static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str) } if (strcmp(entry_str, "auto") == 0) { - iconf->threads = (int)UtilCpuGetNumProcessorsOnline(); - SCLogPerf("%u cores, so using %u threads", iconf->threads, iconf->threads); + iconf->threads = (uint16_t)sched_cpus / LiveGetDeviceCount(); + if (iconf->threads == 0) { + SCLogError("Not enough worker CPU cores with affinity were configured"); + SCReturnInt(-ERANGE); + } + + if (remaining_auto_cpus > 0) { + iconf->threads++; + remaining_auto_cpus--; + } else if (remaining_auto_cpus == -1) { + remaining_auto_cpus = (int32_t)sched_cpus % LiveGetDeviceCount(); + if (remaining_auto_cpus > 0) { + iconf->threads++; + remaining_auto_cpus--; + } + } + SCLogPerf("%s: auto-assigned %u threads", iconf->iface, iconf->threads); SCReturnInt(0); } @@ -379,8 +427,14 @@ static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str) SCReturnInt(-EINVAL); } - if (iconf->threads < 0) { - SCLogError("Interface %s has a negative number of threads", iconf->iface); + if (iconf->threads <= 0) { + SCLogError("%s: positive number of threads required", iconf->iface); + SCReturnInt(-ERANGE); + } + + total_cpus += iconf->threads; + if (total_cpus > sched_cpus) { + SCLogError("Interfaces requested more cores than configured in the threading section"); SCReturnInt(-ERANGE); } diff --git a/src/source-dpdk.c b/src/source-dpdk.c index cc9dcd6f6e..51b60fd409 100644 --- a/src/source-dpdk.c +++ b/src/source-dpdk.c @@ -85,6 +85,7 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data) #else /* We have DPDK support */ +#include "util-affinity.h" #include "util-dpdk.h" #include "util-dpdk-i40e.h" #include "util-dpdk-bonding.h" diff --git a/src/util-affinity.c b/src/util-affinity.c index c84de75f00..06256db5b8 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -306,3 +306,59 @@ uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf) #endif /* OS_WIN32 and __OpenBSD__ */ return ncpu; } + +uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf) +{ + uint16_t ncpu = 0; +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + SCMutexLock(&taf->taf_mutex); + for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) + if (CPU_ISSET(i, &taf->cpu_set)) + ncpu++; + SCMutexUnlock(&taf->taf_mutex); +#endif + return ncpu; +} + +#ifdef HAVE_DPDK +/** + * Find if CPU sets overlap + * \return 1 if CPUs overlap, 0 otherwise + */ +uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2) +{ + ThreadsAffinityType tmptaf; + CPU_ZERO(&tmptaf); + SCMutexInit(&tmptaf.taf_mutex, NULL); + + cpu_set_t tmpcset; + + SCMutexLock(&taf1->taf_mutex); + SCMutexLock(&taf2->taf_mutex); + CPU_AND(&tmpcset, &taf1->cpu_set, &taf2->cpu_set); + SCMutexUnlock(&taf2->taf_mutex); + SCMutexUnlock(&taf1->taf_mutex); + + for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) + if (CPU_ISSET(i, &tmpcset)) + return 1; + return 0; +} + +/** + * Function makes sure that CPUs of different types don't overlap by excluding + * one affinity type from the other + * \param mod_taf - CPU set to be modified + * \param static_taf - static CPU set to be used only for evaluation + */ +void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf) +{ + cpu_set_t tmpset; + SCMutexLock(&mod_taf->taf_mutex); + SCMutexLock(&static_taf->taf_mutex); + CPU_XOR(&tmpset, &mod_taf->cpu_set, &static_taf->cpu_set); + SCMutexUnlock(&static_taf->taf_mutex); + mod_taf->cpu_set = tmpset; + SCMutexUnlock(&mod_taf->taf_mutex); +} +#endif /* HAVE_DPDK */ diff --git a/src/util-affinity.h b/src/util-affinity.h index 91a6f97261..ef3c556498 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -87,6 +87,11 @@ void AffinitySetupLoadFromConfig(void); ThreadsAffinityType * GetAffinityTypeFromName(const char *name); uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf); +uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf); +#ifdef HAVE_DPDK +uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2); +void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf); +#endif /* HAVE_DPDK */ void BuildCpusetWithCallback(const char *name, ConfNode *node, void (*Callback)(int i, void * data),