#include "util-time.h"
#include "util-conf.h"
#include "suricata.h"
+#include "util-affinity.h"
#ifdef HAVE_DPDK
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);
}
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);
}
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);
}
#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 */
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),