suricata
runmode-dpdk.c
Go to the documentation of this file.
1 /* Copyright (C) 2021-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \ingroup dpdk
20  *
21  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Lukas Sismis <lukas.sismis@gmail.com>
28  *
29  * DPDK runmode
30  *
31  */
32 
33 #include "suricata-common.h"
34 #include "runmodes.h"
35 #include "runmode-dpdk.h"
36 #include "decode.h"
37 #include "source-dpdk.h"
38 #include "util-runmodes.h"
39 #include "util-byte.h"
40 #include "util-cpu.h"
41 #include "util-debug.h"
42 #include "util-device.h"
43 #include "util-dpdk.h"
44 #include "util-dpdk-bonding.h"
45 #include "util-dpdk-common.h"
46 #include "util-dpdk-i40e.h"
47 #include "util-dpdk-ice.h"
48 #include "util-dpdk-ixgbe.h"
49 #include "util-dpdk-rss.h"
50 #include "util-time.h"
51 #include "util-conf.h"
52 #include "suricata.h"
53 #include "util-affinity.h"
54 
55 #ifdef HAVE_DPDK
56 
57 // Calculates the closest multiple of y from x
58 #define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y))
59 
60 /* Maximum DPDK EAL parameters count. */
61 #define EAL_ARGS 48
62 
63 struct Arguments {
64  uint16_t capacity;
65  char **argv;
66  uint16_t argc;
67 };
68 
69 static char *AllocArgument(size_t arg_len);
70 static char *AllocAndSetArgument(const char *arg);
71 static char *AllocAndSetOption(const char *arg);
72 
73 static void ArgumentsInit(struct Arguments *args, unsigned capacity);
74 static void ArgumentsCleanup(struct Arguments *args);
75 static void ArgumentsAdd(struct Arguments *args, char *value);
76 static void ArgumentsAddOptionAndArgument(struct Arguments *args, const char *opt, const char *arg);
77 static void InitEal(void);
78 
79 static void ConfigSetIface(DPDKIfaceConfig *iconf, const char *entry_str);
80 static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str);
81 static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues);
82 static int ConfigSetTxQueues(
83  DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues, bool iface_sends_pkts);
84 static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str);
85 static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str);
86 static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc);
87 static int ConfigSetTxDescriptors(
88  DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc, bool iface_sends_pkts);
89 static int ConfigSetMtu(DPDKIfaceConfig *iconf, intmax_t entry_int);
90 static bool ConfigSetPromiscuousMode(DPDKIfaceConfig *iconf, int entry_bool);
91 static bool ConfigSetMulticast(DPDKIfaceConfig *iconf, int entry_bool);
92 static int ConfigSetChecksumChecks(DPDKIfaceConfig *iconf, int entry_bool);
93 static int ConfigSetChecksumOffload(DPDKIfaceConfig *iconf, int entry_bool);
94 static int ConfigSetCopyIface(DPDKIfaceConfig *iconf, const char *entry_str);
95 static int ConfigSetCopyMode(DPDKIfaceConfig *iconf, const char *entry_str);
96 static int ConfigSetCopyIfaceSettings(DPDKIfaceConfig *iconf, const char *iface, const char *mode);
97 static void ConfigInit(DPDKIfaceConfig **iconf);
98 static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface);
99 static DPDKIfaceConfig *ConfigParse(const char *iface);
100 
101 static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
102  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf);
103 static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info,
104  const struct rte_eth_conf *port_conf);
105 static int DeviceValidateOutIfaceConfig(DPDKIfaceConfig *iconf);
106 static int DeviceConfigureIPS(DPDKIfaceConfig *iconf);
107 static int DeviceConfigure(DPDKIfaceConfig *iconf);
108 static void *ParseDpdkConfigAndConfigureDevice(const char *iface);
109 static void DPDKDerefConfig(void *conf);
110 
111 #define DPDK_CONFIG_DEFAULT_THREADS "auto"
112 #define DPDK_CONFIG_DEFAULT_INTERRUPT_MODE false
113 #define DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE "auto"
114 #define DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE "auto"
115 #define DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS "auto"
116 #define DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS "auto"
117 #define DPDK_CONFIG_DEFAULT_RSS_HASH_FUNCTIONS RTE_ETH_RSS_IP
118 #define DPDK_CONFIG_DEFAULT_MTU 1500
119 #define DPDK_CONFIG_DEFAULT_PROMISCUOUS_MODE 1
120 #define DPDK_CONFIG_DEFAULT_MULTICAST_MODE 1
121 #define DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION 1
122 #define DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION_OFFLOAD 1
123 #define DPDK_CONFIG_DEFAULT_VLAN_STRIP 0
124 #define DPDK_CONFIG_DEFAULT_LINKUP_TIMEOUT 0
125 #define DPDK_CONFIG_DEFAULT_COPY_MODE "none"
126 #define DPDK_CONFIG_DEFAULT_COPY_INTERFACE "none"
127 
128 DPDKIfaceConfigAttributes dpdk_yaml = {
129  .threads = "threads",
130  .irq_mode = "interrupt-mode",
131  .promisc = "promisc",
132  .multicast = "multicast",
133  .checksum_checks = "checksum-checks",
134  .checksum_checks_offload = "checksum-checks-offload",
135  .mtu = "mtu",
136  .vlan_strip_offload = "vlan-strip-offload",
137  .rss_hf = "rss-hash-functions",
138  .linkup_timeout = "linkup-timeout",
139  .mempool_size = "mempool-size",
140  .mempool_cache_size = "mempool-cache-size",
141  .rx_descriptors = "rx-descriptors",
142  .tx_descriptors = "tx-descriptors",
143  .copy_mode = "copy-mode",
144  .copy_iface = "copy-iface",
145 };
146 
147 /**
148  * \brief Input is a number of which we want to find the greatest divisor up to max_num (inclusive).
149  * The divisor is returned.
150  */
151 static int GreatestDivisorUpTo(uint32_t num, uint32_t max_num)
152 {
153  for (int i = max_num; i >= 2; i--) {
154  if (num % i == 0) {
155  return i;
156  }
157  }
158  return 1;
159 }
160 
161 /**
162  * \brief Input is a number of which we want to find the greatest power of 2 up to num. The power of
163  * 2 is returned or 0 if no valid power of 2 is found.
164  */
165 static uint64_t GreatestPowOf2UpTo(uint64_t num)
166 {
167  if (num == 0) {
168  return 0; // No power of 2 exists for 0
169  }
170 
171  // Bit manipulation to isolate the highest set bit
172  num |= (num >> 1);
173  num |= (num >> 2);
174  num |= (num >> 4);
175  num |= (num >> 8);
176  num |= (num >> 16);
177  num |= (num >> 32);
178  num = num - (num >> 1);
179 
180  return num;
181 }
182 
183 static char *AllocArgument(size_t arg_len)
184 {
185  SCEnter();
186  char *ptr;
187 
188  arg_len += 1; // null character
189  ptr = (char *)SCCalloc(arg_len, sizeof(char));
190  if (ptr == NULL)
191  FatalError("Could not allocate memory for an argument");
192 
193  SCReturnPtr(ptr, "char *");
194 }
195 
196 /**
197  * Allocates space for length of the given string and then copies contents
198  * @param arg String to set to the newly allocated space
199  * @return memory address if no error otherwise NULL (with errno set)
200  */
201 static char *AllocAndSetArgument(const char *arg)
202 {
203  SCEnter();
204  if (arg == NULL)
205  FatalError("Passed argument is NULL in DPDK config initialization");
206 
207  char *ptr;
208  size_t arg_len = strlen(arg);
209 
210  ptr = AllocArgument(arg_len);
211  strlcpy(ptr, arg, arg_len + 1);
212  SCReturnPtr(ptr, "char *");
213 }
214 
215 static char *AllocAndSetOption(const char *arg)
216 {
217  SCEnter();
218  if (arg == NULL)
219  FatalError("Passed option is NULL in DPDK config initialization");
220 
221  char *ptr = NULL;
222  size_t arg_len = strlen(arg);
223  uint8_t is_long_arg = arg_len > 1;
224  const char *dash_prefix = is_long_arg ? "--" : "-";
225  size_t full_len = arg_len + strlen(dash_prefix);
226 
227  ptr = AllocArgument(full_len);
228  strlcpy(ptr, dash_prefix, strlen(dash_prefix) + 1);
229  strlcat(ptr, arg, full_len + 1);
230  SCReturnPtr(ptr, "char *");
231 }
232 
233 static void ArgumentsInit(struct Arguments *args, unsigned capacity)
234 {
235  SCEnter();
236  args->argv = SCCalloc(capacity, sizeof(*args->argv)); // alloc array of pointers
237  if (args->argv == NULL)
238  FatalError("Could not allocate memory for Arguments structure");
239 
240  args->capacity = capacity;
241  args->argc = 0;
242  SCReturn;
243 }
244 
245 static void ArgumentsCleanup(struct Arguments *args)
246 {
247  SCEnter();
248  for (int i = 0; i < args->argc; i++) {
249  if (args->argv[i] != NULL) {
250  SCFree(args->argv[i]);
251  args->argv[i] = NULL;
252  }
253  }
254 
255  SCFree(args->argv);
256  args->argv = NULL;
257  args->argc = 0;
258  args->capacity = 0;
259 }
260 
261 static void ArgumentsAdd(struct Arguments *args, char *value)
262 {
263  SCEnter();
264  if (args->argc + 1 > args->capacity)
265  FatalError("No capacity for more arguments (Max: %" PRIu32 ")", EAL_ARGS);
266 
267  args->argv[args->argc++] = value;
268  SCReturn;
269 }
270 
271 static void ArgumentsAddOptionAndArgument(struct Arguments *args, const char *opt, const char *arg)
272 {
273  SCEnter();
274  char *option;
275  char *argument;
276 
277  option = AllocAndSetOption(opt);
278  ArgumentsAdd(args, option);
279 
280  // Empty argument could mean option only (e.g. --no-huge)
281  if (arg == NULL || arg[0] == '\0')
282  SCReturn;
283 
284  argument = AllocAndSetArgument(arg);
285  ArgumentsAdd(args, argument);
286  SCReturn;
287 }
288 
289 static void InitEal(void)
290 {
291  SCEnter();
292  int retval;
293  SCConfNode *param;
294  const SCConfNode *eal_params = SCConfGetNode("dpdk.eal-params");
295  struct Arguments args;
296  char **eal_argv;
297 
298  if (eal_params == NULL) {
299  FatalError("DPDK EAL parameters not found in the config");
300  }
301 
302  ArgumentsInit(&args, EAL_ARGS);
303  ArgumentsAdd(&args, AllocAndSetArgument("suricata"));
304 
305  TAILQ_FOREACH (param, &eal_params->head, next) {
306  if (SCConfNodeIsSequence(param)) {
307  const char *key = param->name;
308  SCConfNode *val;
309  TAILQ_FOREACH (val, &param->head, next) {
310  ArgumentsAddOptionAndArgument(&args, key, (const char *)val->val);
311  }
312  continue;
313  }
314  ArgumentsAddOptionAndArgument(&args, param->name, param->val);
315  }
316 
317  // creating a shallow copy for cleanup because rte_eal_init changes array contents
318  eal_argv = SCCalloc(args.argc, sizeof(*args.argv));
319  if (eal_argv == NULL) {
320  FatalError("Failed to allocate memory for the array of DPDK EAL arguments");
321  }
322  memcpy(eal_argv, args.argv, args.argc * sizeof(*args.argv));
323 
324  rte_log_set_global_level(RTE_LOG_WARNING);
325  retval = rte_eal_init(args.argc, eal_argv);
326 
327  ArgumentsCleanup(&args);
328  SCFree(eal_argv);
329 
330  if (retval < 0) { // retval bound to the result of rte_eal_init
331  FatalError("DPDK EAL initialization error: %s", rte_strerror(-retval));
332  }
333 }
334 
335 static void DPDKDerefConfig(void *conf)
336 {
337  SCEnter();
338  DPDKIfaceConfig *iconf = (DPDKIfaceConfig *)conf;
339 
340  if (SC_ATOMIC_SUB(iconf->ref, 1) == 1) {
341  DPDKDeviceResourcesDeinit(&iconf->pkt_mempools);
342  SCFree(iconf);
343  }
344  SCReturn;
345 }
346 
347 static void ConfigInit(DPDKIfaceConfig **iconf)
348 {
349  SCEnter();
350  DPDKIfaceConfig *ptr = NULL;
351  ptr = SCCalloc(1, sizeof(DPDKIfaceConfig));
352  if (ptr == NULL)
353  FatalError("Could not allocate memory for DPDKIfaceConfig");
354 
355  ptr->out_port_id = -1; // make sure no port is set
356  SC_ATOMIC_INIT(ptr->ref);
357  (void)SC_ATOMIC_ADD(ptr->ref, 1);
358  ptr->DerefFunc = DPDKDerefConfig;
359  ptr->flags = 0;
360 
361  *iconf = ptr;
362  SCReturn;
363 }
364 
365 static void ConfigSetIface(DPDKIfaceConfig *iconf, const char *entry_str)
366 {
367  SCEnter();
368  int retval;
369 
370  if (entry_str == NULL || entry_str[0] == '\0')
371  FatalError("Interface name in DPDK config is NULL or empty");
372 
373  retval = rte_eth_dev_get_port_by_name(entry_str, &iconf->port_id);
374  if (retval < 0)
375  FatalError("%s: interface not found: %s", entry_str, rte_strerror(-retval));
376 
377  strlcpy(iconf->iface, entry_str, sizeof(iconf->iface));
378  SCReturn;
379 }
380 
381 static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str)
382 {
383  SCEnter();
384  static int32_t remaining_auto_cpus = -1;
386  SCLogError("DPDK runmode requires configured thread affinity");
387  SCReturnInt(-EINVAL);
388  }
389 
390  ThreadsAffinityType *wtaf = GetAffinityTypeFromName("worker-cpu-set");
391  if (wtaf == NULL) {
392  SCLogError("Specify worker-cpu-set list in the threading section");
393  SCReturnInt(-EINVAL);
394  }
395  ThreadsAffinityType *mtaf = GetAffinityTypeFromName("management-cpu-set");
396  if (mtaf == NULL) {
397  SCLogError("Specify management-cpu-set list in the threading section");
398  SCReturnInt(-EINVAL);
399  }
400  uint32_t sched_cpus = UtilAffinityGetAffinedCPUNum(wtaf);
401  if (sched_cpus == UtilCpuGetNumProcessorsOnline()) {
402  SCLogWarning(
403  "\"all\" specified in worker CPU cores affinity, excluding management threads");
404  UtilAffinityCpusExclude(wtaf, mtaf);
405  sched_cpus = UtilAffinityGetAffinedCPUNum(wtaf);
406  }
407 
408  if (sched_cpus == 0) {
409  SCLogError("No worker CPU cores with configured affinity were configured");
410  SCReturnInt(-EINVAL);
411  } else if (UtilAffinityCpusOverlap(wtaf, mtaf) != 0) {
412  SCLogWarning("Worker threads should not overlap with management threads in the CPU core "
413  "affinity configuration");
414  }
415 
416  const char *active_runmode = RunmodeGetActive();
417  if (active_runmode && !strcmp("single", active_runmode)) {
418  iconf->threads = 1;
419  SCReturnInt(0);
420  }
421 
422  if (entry_str == NULL) {
423  SCLogError("Number of threads for interface \"%s\" not specified", iconf->iface);
424  SCReturnInt(-EINVAL);
425  }
426 
427  if (strcmp(entry_str, "auto") == 0) {
428  iconf->threads = (uint16_t)sched_cpus / LiveGetDeviceCount();
429  if (iconf->threads == 0) {
430  SCLogError("Not enough worker CPU cores with affinity were configured");
431  SCReturnInt(-ERANGE);
432  }
433 
434  if (remaining_auto_cpus > 0) {
435  iconf->threads++;
436  remaining_auto_cpus--;
437  } else if (remaining_auto_cpus == -1) {
438  remaining_auto_cpus = (int32_t)sched_cpus % LiveGetDeviceCount();
439  if (remaining_auto_cpus > 0) {
440  iconf->threads++;
441  remaining_auto_cpus--;
442  }
443  }
444  SCLogConfig("%s: auto-assigned %u threads", iconf->iface, iconf->threads);
445  SCReturnInt(0);
446  }
447 
448  if (StringParseInt32(&iconf->threads, 10, 0, entry_str) < 0) {
449  SCLogError("Threads entry for interface %s contain non-numerical characters - \"%s\"",
450  iconf->iface, entry_str);
451  SCReturnInt(-EINVAL);
452  }
453 
454  if (iconf->threads <= 0) {
455  SCLogError("%s: positive number of threads required", iconf->iface);
456  SCReturnInt(-ERANGE);
457  }
458 
459  SCReturnInt(0);
460 }
461 
462 static bool ConfigSetInterruptMode(DPDKIfaceConfig *iconf, bool enable)
463 {
464  SCEnter();
465  if (enable)
466  iconf->flags |= DPDK_IRQ_MODE;
467 
468  SCReturnBool(true);
469 }
470 
471 static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues)
472 {
473  SCEnter();
474  if (nb_queues == 0) {
475  SCLogInfo("%s: positive number of RX queues is required", iconf->iface);
476  SCReturnInt(-ERANGE);
477  }
478 
479  if (nb_queues > max_queues) {
480  SCLogInfo("%s: number of RX queues cannot exceed %" PRIu16, iconf->iface, max_queues);
481  SCReturnInt(-ERANGE);
482  }
483 
484  iconf->nb_rx_queues = nb_queues;
485  SCReturnInt(0);
486 }
487 
488 static bool ConfigIfaceSendsPkts(const char *mode)
489 {
490  SCEnter();
491  if (strcmp(mode, "ips") == 0 || strcmp(mode, "tap") == 0) {
492  SCReturnBool(true);
493  }
494  SCReturnBool(false);
495 }
496 
497 static int ConfigSetTxQueues(
498  DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues, bool iface_sends_pkts)
499 {
500  SCEnter();
501  if (nb_queues == 0 && iface_sends_pkts) {
502  SCLogInfo("%s: positive number of TX queues is required", iconf->iface);
503  SCReturnInt(-ERANGE);
504  }
505 
506  if (nb_queues > max_queues) {
507  SCLogInfo("%s: number of TX queues cannot exceed %" PRIu16, iconf->iface, max_queues);
508  SCReturnInt(-ERANGE);
509  }
510 
511  iconf->nb_tx_queues = nb_queues;
512  SCReturnInt(0);
513 }
514 
515 static uint32_t MempoolSizeCalculate(
516  uint32_t rx_queues, uint32_t rx_desc, uint32_t tx_queues, uint32_t tx_desc)
517 {
518  uint32_t sz = rx_queues * rx_desc + tx_queues * tx_desc;
519  if (!tx_queues || !tx_desc)
520  sz *= 2; // double to have enough space for RX descriptors
521 
522  return sz;
523 }
524 
525 static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str)
526 {
527  SCEnter();
528  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
529  // calculate the mempool size based on the number of:
530  // - RX / TX queues
531  // - RX / TX descriptors
532  bool err = false;
533  if (iconf->nb_rx_queues == 0) {
534  // in IDS mode, we don't need TX queues
535  SCLogError("%s: cannot autocalculate mempool size without RX queues", iconf->iface);
536  err = true;
537  }
538 
539  if (iconf->nb_rx_desc == 0) {
540  SCLogError(
541  "%s: cannot autocalculate mempool size without RX descriptors", iconf->iface);
542  err = true;
543  }
544 
545  if (err) {
546  SCReturnInt(-EINVAL);
547  }
548 
549  iconf->mempool_size = MempoolSizeCalculate(
550  iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues, iconf->nb_tx_desc);
551  SCReturnInt(0);
552  }
553 
554  if (StringParseUint32(&iconf->mempool_size, 10, 0, entry_str) < 0) {
555  SCLogError("%s: mempool size entry contain non-numerical characters - \"%s\"", iconf->iface,
556  entry_str);
557  SCReturnInt(-EINVAL);
558  }
559 
560  if (MempoolSizeCalculate(
561  iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues, iconf->nb_tx_desc) >
562  iconf->mempool_size + 1) { // +1 to mask mempool size advice given in Suricata 7.0.x -
563  // mp_size should be n = (2^q - 1)
564  SCLogError("%s: mempool size is likely too small for the number of descriptors and queues, "
565  "set to \"auto\" or adjust to the value of \"%" PRIu32 "\"",
566  iconf->iface,
567  MempoolSizeCalculate(iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues,
568  iconf->nb_tx_desc));
569  SCReturnInt(-ERANGE);
570  }
571 
572  if (iconf->mempool_size == 0) {
573  SCLogError("%s: mempool size requires a positive integer", iconf->iface);
574  SCReturnInt(-ERANGE);
575  }
576 
577  SCReturnInt(0);
578 }
579 
580 static uint32_t MempoolCacheSizeCalculate(uint32_t mp_sz)
581 {
582  // It is advised to have mempool cache size lower or equal to:
583  // RTE_MEMPOOL_CACHE_MAX_SIZE (by default 512) and "mempool-size / 1.5"
584  // and at the same time "mempool-size modulo cache_size == 0".
585  uint32_t max_cache_size = MIN(RTE_MEMPOOL_CACHE_MAX_SIZE, mp_sz / 1.5);
586  return GreatestDivisorUpTo(mp_sz, max_cache_size);
587 }
588 
589 static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str)
590 {
591  SCEnter();
592  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
593  // calculate the mempool size based on the mempool size (it needs to be already filled in)
594  if (iconf->mempool_size == 0) {
595  SCLogError("%s: cannot calculate mempool cache size of a mempool with size %d",
596  iconf->iface, iconf->mempool_size);
597  SCReturnInt(-EINVAL);
598  }
599 
600  iconf->mempool_cache_size = MempoolCacheSizeCalculate(iconf->mempool_size);
601  SCReturnInt(0);
602  }
603 
604  if (StringParseUint32(&iconf->mempool_cache_size, 10, 0, entry_str) < 0) {
605  SCLogError("%s: mempool cache size entry contain non-numerical characters - \"%s\"",
606  iconf->iface, entry_str);
607  SCReturnInt(-EINVAL);
608  }
609 
610  if (iconf->mempool_cache_size <= 0 || iconf->mempool_cache_size > RTE_MEMPOOL_CACHE_MAX_SIZE) {
611  SCLogError("%s: mempool cache size requires a positive number smaller than %" PRIu32,
612  iconf->iface, RTE_MEMPOOL_CACHE_MAX_SIZE);
613  SCReturnInt(-ERANGE);
614  }
615 
616  SCReturnInt(0);
617 }
618 
619 static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc)
620 {
621  SCEnter();
622  if (entry_str == NULL || entry_str[0] == '\0') {
623  SCLogInfo("%s: number of RX descriptors not found, going with: %s", iconf->iface,
624  DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS);
625  entry_str = DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS;
626  }
627 
628  if (strcmp(entry_str, "auto") == 0) {
629  iconf->nb_rx_desc = GreatestPowOf2UpTo(max_desc);
630  SCReturnInt(0);
631  }
632 
633  if (StringParseUint16(&iconf->nb_rx_desc, 10, 0, entry_str) < 0) {
634  SCLogError("%s: RX descriptors entry contains non-numerical characters - \"%s\"",
635  iconf->iface, entry_str);
636  SCReturnInt(-EINVAL);
637  }
638 
639  if (iconf->nb_rx_desc == 0) {
640  SCLogError("%s: positive number of RX descriptors is required", iconf->iface);
641  SCReturnInt(-ERANGE);
642  } else if (iconf->nb_rx_desc > max_desc) {
643  SCLogError("%s: number of RX descriptors cannot exceed %" PRIu16, iconf->iface, max_desc);
644  SCReturnInt(-ERANGE);
645  }
646 
647  SCReturnInt(0);
648 }
649 
650 static int ConfigSetTxDescriptors(
651  DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc, bool iface_sends_pkts)
652 {
653  SCEnter();
654  if (entry_str == NULL || entry_str[0] == '\0') {
655  SCLogInfo("%s: number of TX descriptors not found, going with: %s", iconf->iface,
656  DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS);
657  entry_str = DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS;
658  }
659 
660  if (strcmp(entry_str, "auto") == 0) {
661  if (iface_sends_pkts) {
662  iconf->nb_tx_desc = GreatestPowOf2UpTo(max_desc);
663  } else {
664  iconf->nb_tx_desc = 0;
665  }
666  SCReturnInt(0);
667  }
668 
669  if (StringParseUint16(&iconf->nb_tx_desc, 10, 0, entry_str) < 0) {
670  SCLogError("%s: TX descriptors entry contains non-numerical characters - \"%s\"",
671  iconf->iface, entry_str);
672  SCReturnInt(-EINVAL);
673  }
674 
675  if (iconf->nb_tx_desc == 0 && iface_sends_pkts) {
676  SCLogError("%s: positive number of TX descriptors is required", iconf->iface);
677  SCReturnInt(-ERANGE);
678  } else if (iconf->nb_tx_desc > max_desc) {
679  SCLogError("%s: number of TX descriptors cannot exceed %" PRIu16, iconf->iface, max_desc);
680  SCReturnInt(-ERANGE);
681  }
682 
683  SCReturnInt(0);
684 }
685 
686 static int ConfigSetRSSHashFunctions(DPDKIfaceConfig *iconf, const char *entry_str)
687 {
688  SCEnter();
689  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
690  iconf->rss_hf = DPDK_CONFIG_DEFAULT_RSS_HASH_FUNCTIONS;
691  SCReturnInt(0);
692  }
693 
694  if (StringParseUint64(&iconf->rss_hf, 0, 0, entry_str) < 0) {
695  SCLogError("%s: RSS hash functions entry contain non-numerical characters - \"%s\"",
696  iconf->iface, entry_str);
697  SCReturnInt(-EINVAL);
698  }
699 
700  SCReturnInt(0);
701 }
702 
703 static int ConfigSetMtu(DPDKIfaceConfig *iconf, intmax_t entry_int)
704 {
705  SCEnter();
706  if (entry_int < RTE_ETHER_MIN_MTU || entry_int > RTE_ETHER_MAX_JUMBO_FRAME_LEN) {
707  SCLogError("%s: MTU size can only be between %" PRIu32 " and %" PRIu32, iconf->iface,
708  RTE_ETHER_MIN_MTU, RTE_ETHER_MAX_JUMBO_FRAME_LEN);
709  SCReturnInt(-ERANGE);
710  }
711 
712  iconf->mtu = entry_int;
713  SCReturnInt(0);
714 }
715 
716 static int ConfigSetLinkupTimeout(DPDKIfaceConfig *iconf, intmax_t entry_int)
717 {
718  SCEnter();
719  if (entry_int < 0) {
720  SCLogError("%s: Link-up waiting timeout needs to be a positive number or 0 to disable",
721  iconf->iface);
722  SCReturnInt(-ERANGE);
723  }
724 
725  iconf->linkup_timeout = entry_int;
726  SCReturnInt(0);
727 }
728 
729 static bool ConfigSetPromiscuousMode(DPDKIfaceConfig *iconf, int entry_bool)
730 {
731  SCEnter();
732  if (entry_bool)
733  iconf->flags |= DPDK_PROMISC;
734 
735  SCReturnBool(true);
736 }
737 
738 static bool ConfigSetMulticast(DPDKIfaceConfig *iconf, int entry_bool)
739 {
740  SCEnter();
741  if (entry_bool)
742  iconf->flags |= DPDK_MULTICAST; // enable
743 
744  SCReturnBool(true);
745 }
746 
747 static int ConfigSetChecksumChecks(DPDKIfaceConfig *iconf, int entry_bool)
748 {
749  SCEnter();
750  if (entry_bool)
751  iconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
752 
753  SCReturnInt(0);
754 }
755 
756 static int ConfigSetChecksumOffload(DPDKIfaceConfig *iconf, int entry_bool)
757 {
758  SCEnter();
759  if (entry_bool)
760  iconf->flags |= DPDK_RX_CHECKSUM_OFFLOAD;
761 
762  SCReturnInt(0);
763 }
764 
765 static void ConfigSetVlanStrip(DPDKIfaceConfig *iconf, int entry_bool)
766 {
767  SCEnter();
768  iconf->vlan_strip_enabled = entry_bool;
769  SCReturn;
770 }
771 
772 static int ConfigSetCopyIface(DPDKIfaceConfig *iconf, const char *entry_str)
773 {
774  SCEnter();
775  int retval;
776 
777  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "none") == 0) {
778  iconf->out_iface = NULL;
779  SCReturnInt(0);
780  }
781 
782  retval = rte_eth_dev_get_port_by_name(entry_str, &iconf->out_port_id);
783  if (retval < 0) {
784  SCLogError("%s: copy interface (%s) not found: %s", iconf->iface, entry_str,
785  rte_strerror(-retval));
786  SCReturnInt(retval);
787  }
788 
789  iconf->out_iface = entry_str;
790  SCReturnInt(0);
791 }
792 
793 static int ConfigSetCopyMode(DPDKIfaceConfig *iconf, const char *entry_str)
794 {
795  SCEnter();
796  if (entry_str == NULL) {
797  SCLogWarning("%s: no copy mode specified, changing to %s ", iconf->iface,
798  DPDK_CONFIG_DEFAULT_COPY_MODE);
799  entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
800  }
801 
802  if (strcmp(entry_str, "none") != 0 && strcmp(entry_str, "tap") != 0 &&
803  strcmp(entry_str, "ips") != 0) {
804  SCLogWarning("%s: copy mode \"%s\" is not one of the possible values (none|tap|ips). "
805  "Changing to %s",
806  entry_str, iconf->iface, DPDK_CONFIG_DEFAULT_COPY_MODE);
807  entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
808  }
809 
810  if (strcmp(entry_str, "none") == 0) {
811  iconf->copy_mode = DPDK_COPY_MODE_NONE;
812  } else if (strcmp(entry_str, "tap") == 0) {
813  iconf->copy_mode = DPDK_COPY_MODE_TAP;
814  } else if (strcmp(entry_str, "ips") == 0) {
815  iconf->copy_mode = DPDK_COPY_MODE_IPS;
816  }
817 
818  SCReturnInt(0);
819 }
820 
821 static int ConfigSetCopyIfaceSettings(DPDKIfaceConfig *iconf, const char *iface, const char *mode)
822 {
823  SCEnter();
824  int retval;
825 
826  retval = ConfigSetCopyIface(iconf, iface);
827  if (retval < 0)
828  SCReturnInt(retval);
829 
830  retval = ConfigSetCopyMode(iconf, mode);
831  if (retval < 0)
832  SCReturnInt(retval);
833 
834  if (iconf->copy_mode == DPDK_COPY_MODE_NONE) {
835  if (iconf->out_iface != NULL)
836  iconf->out_iface = NULL;
837  SCReturnInt(0);
838  }
839 
840  if (iconf->out_iface == NULL || strlen(iconf->out_iface) <= 0) {
841  SCLogError("%s: copy mode enabled but interface not set", iconf->iface);
842  SCReturnInt(-EINVAL);
843  }
844 
845  SCReturnInt(0);
846 }
847 
848 static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface)
849 {
850  SCEnter();
851  int retval;
852  SCConfNode *if_root;
853  SCConfNode *if_default;
854  const char *entry_str = NULL;
855  intmax_t entry_int = 0;
856  int entry_bool = 0;
857  const char *copy_iface_str = NULL;
858  const char *copy_mode_str = NULL;
859 
860  ConfigSetIface(iconf, iface);
861  struct rte_eth_dev_info dev_info = { 0 };
862  retval = rte_eth_dev_info_get(iconf->port_id, &dev_info);
863  if (retval < 0) {
864  SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-retval));
865  SCReturnInt(retval);
866  }
867 
868  retval = SCConfSetRootAndDefaultNodes("dpdk.interfaces", iconf->iface, &if_root, &if_default);
869  if (retval < 0) {
870  FatalError("failed to find DPDK configuration for the interface %s", iconf->iface);
871  }
872 
873  retval = SCConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.threads, &entry_str) != 1
874  ? ConfigSetThreads(iconf, DPDK_CONFIG_DEFAULT_THREADS)
875  : ConfigSetThreads(iconf, entry_str);
876  if (retval < 0)
877  SCReturnInt(retval);
878 
879  bool irq_enable;
881  if_root, if_default, dpdk_yaml.irq_mode, &entry_bool);
882  if (retval != 1) {
883  irq_enable = DPDK_CONFIG_DEFAULT_INTERRUPT_MODE;
884  } else {
885  irq_enable = entry_bool ? true : false;
886  }
887  retval = ConfigSetInterruptMode(iconf, irq_enable);
888  if (retval != true)
889  SCReturnInt(-EINVAL);
890 
892  if_root, if_default, dpdk_yaml.copy_mode, &copy_mode_str);
893  if (retval != 1) {
894  copy_mode_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
895  }
896 
898  if_root, if_default, dpdk_yaml.rx_descriptors, &entry_str) != 1
899  ? ConfigSetRxDescriptors(iconf, DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS,
900  dev_info.rx_desc_lim.nb_max)
901  : ConfigSetRxDescriptors(iconf, entry_str, dev_info.rx_desc_lim.nb_max);
902  if (retval < 0)
903  SCReturnInt(retval);
904 
905  bool iface_sends_pkts = ConfigIfaceSendsPkts(copy_mode_str);
907  if_root, if_default, dpdk_yaml.tx_descriptors, &entry_str) != 1
908  ? ConfigSetTxDescriptors(iconf, DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS,
909  dev_info.tx_desc_lim.nb_max, iface_sends_pkts)
910  : ConfigSetTxDescriptors(
911  iconf, entry_str, dev_info.tx_desc_lim.nb_max, iface_sends_pkts);
912  if (retval < 0)
913  SCReturnInt(retval);
914 
915  // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
916  retval = ConfigSetRxQueues(iconf, (uint16_t)iconf->threads, dev_info.max_rx_queues);
917  if (retval < 0) {
918  SCLogError("%s: too many threads configured - reduce thread count to: %" PRIu16,
919  iconf->iface, dev_info.max_rx_queues);
920  SCReturnInt(retval);
921  }
922 
923  // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
924  uint16_t tx_queues = iconf->nb_tx_desc > 0 ? (uint16_t)iconf->threads : 0;
925  retval = ConfigSetTxQueues(iconf, tx_queues, dev_info.max_tx_queues, iface_sends_pkts);
926  if (retval < 0) {
927  SCLogError("%s: too many threads configured - reduce thread count to: %" PRIu16,
928  iconf->iface, dev_info.max_tx_queues);
929  SCReturnInt(retval);
930  }
931 
933  if_root, if_default, dpdk_yaml.mempool_size, &entry_str) != 1
934  ? ConfigSetMempoolSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE)
935  : ConfigSetMempoolSize(iconf, entry_str);
936  if (retval < 0)
937  SCReturnInt(retval);
938 
940  if_root, if_default, dpdk_yaml.mempool_cache_size, &entry_str) != 1
941  ? ConfigSetMempoolCacheSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE)
942  : ConfigSetMempoolCacheSize(iconf, entry_str);
943  if (retval < 0)
944  SCReturnInt(retval);
945 
946  retval = SCConfGetChildValueIntWithDefault(if_root, if_default, dpdk_yaml.mtu, &entry_int) != 1
947  ? ConfigSetMtu(iconf, DPDK_CONFIG_DEFAULT_MTU)
948  : ConfigSetMtu(iconf, entry_int);
949  if (retval < 0)
950  SCReturnInt(retval);
951 
952  retval = SCConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.rss_hf, &entry_str) != 1
953  ? ConfigSetRSSHashFunctions(iconf, NULL)
954  : ConfigSetRSSHashFunctions(iconf, entry_str);
955  if (retval < 0)
956  SCReturnInt(retval);
957 
959  if_root, if_default, dpdk_yaml.promisc, &entry_bool) != 1
960  ? ConfigSetPromiscuousMode(iconf, DPDK_CONFIG_DEFAULT_PROMISCUOUS_MODE)
961  : ConfigSetPromiscuousMode(iconf, entry_bool);
962  if (retval != true)
963  SCReturnInt(-EINVAL);
964 
966  if_root, if_default, dpdk_yaml.multicast, &entry_bool) != 1
967  ? ConfigSetMulticast(iconf, DPDK_CONFIG_DEFAULT_MULTICAST_MODE)
968  : ConfigSetMulticast(iconf, entry_bool);
969  if (retval != true)
970  SCReturnInt(-EINVAL);
971 
973  if_root, if_default, dpdk_yaml.checksum_checks, &entry_bool) != 1
974  ? ConfigSetChecksumChecks(iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION)
975  : ConfigSetChecksumChecks(iconf, entry_bool);
976  if (retval < 0)
977  SCReturnInt(retval);
978 
980  if_root, if_default, dpdk_yaml.checksum_checks_offload, &entry_bool) != 1
981  ? ConfigSetChecksumOffload(
982  iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION_OFFLOAD)
983  : ConfigSetChecksumOffload(iconf, entry_bool);
984  if (retval < 0)
985  SCReturnInt(retval);
986 
988  if_root, if_default, dpdk_yaml.vlan_strip_offload, &entry_bool);
989  if (retval != 1) {
990  ConfigSetVlanStrip(iconf, DPDK_CONFIG_DEFAULT_VLAN_STRIP);
991  } else {
992  ConfigSetVlanStrip(iconf, entry_bool);
993  }
994 
996  if_root, if_default, dpdk_yaml.linkup_timeout, &entry_int) != 1
997  ? ConfigSetLinkupTimeout(iconf, DPDK_CONFIG_DEFAULT_LINKUP_TIMEOUT)
998  : ConfigSetLinkupTimeout(iconf, entry_int);
999  if (retval < 0)
1000  SCReturnInt(retval);
1001 
1003  if_root, if_default, dpdk_yaml.copy_iface, &copy_iface_str);
1004  if (retval != 1) {
1005  copy_iface_str = DPDK_CONFIG_DEFAULT_COPY_INTERFACE;
1006  }
1007 
1008  retval = ConfigSetCopyIfaceSettings(iconf, copy_iface_str, copy_mode_str);
1009  if (retval < 0)
1010  SCReturnInt(retval);
1011 
1012  SCReturnInt(0);
1013 }
1014 
1015 static int32_t ConfigValidateThreads(uint16_t iface_threads)
1016 {
1017  static uint32_t total_cpus = 0;
1018  total_cpus += iface_threads;
1019  ThreadsAffinityType *wtaf = GetAffinityTypeFromName("worker-cpu-set");
1020  if (wtaf == NULL) {
1021  SCLogError("Specify worker-cpu-set list in the threading section");
1022  return -1;
1023  }
1024  if (total_cpus > UtilAffinityGetAffinedCPUNum(wtaf)) {
1025  SCLogError("Interfaces requested more cores than configured in the threading section "
1026  "(requested %d configured %d",
1027  total_cpus, UtilAffinityGetAffinedCPUNum(wtaf));
1028  return -1;
1029  }
1030 
1031  return 0;
1032 }
1033 
1034 static DPDKIfaceConfig *ConfigParse(const char *iface)
1035 {
1036  SCEnter();
1037  int retval;
1038  DPDKIfaceConfig *iconf = NULL;
1039  if (iface == NULL)
1040  FatalError("DPDK interface is NULL");
1041 
1042  ConfigInit(&iconf);
1043  retval = ConfigLoad(iconf, iface);
1044  if (retval < 0 || ConfigValidateThreads(iconf->threads) != 0) {
1045  iconf->DerefFunc(iconf);
1046  SCReturnPtr(NULL, "void *");
1047  }
1048 
1049  SCReturnPtr(iconf, "DPDKIfaceConfig *");
1050 }
1051 
1052 static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const char *driver_name)
1053 {
1054  if (strcmp(driver_name, "net_i40e") == 0)
1055  i40eDeviceSetRSSConf(rss_conf);
1056  if (strcmp(driver_name, "net_ice") == 0)
1057  iceDeviceSetRSSConf(rss_conf);
1058  if (strcmp(driver_name, "net_ixgbe") == 0)
1059  ixgbeDeviceSetRSSHashFunction(&rss_conf->rss_hf);
1060  if (strcmp(driver_name, "net_e1000_igb") == 0)
1061  rss_conf->rss_hf = (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_IPV6_EX);
1062 }
1063 
1064 // Returns -1 if no bit is set
1065 static int GetFirstSetBitPosition(uint64_t bits)
1066 {
1067  for (uint64_t i = 0; i < 64; i++) {
1068  if (bits & BIT_U64(i))
1069  return i;
1070  }
1071  return -1;
1072 }
1073 
1074 static void DumpRSSFlags(const uint64_t requested, const uint64_t actual)
1075 {
1076  SCLogConfig("REQUESTED (groups):");
1077 
1078  SCLogConfig(
1079  "RTE_ETH_RSS_IP %sset", ((requested & RTE_ETH_RSS_IP) == RTE_ETH_RSS_IP) ? "" : "NOT ");
1080  SCLogConfig("RTE_ETH_RSS_TCP %sset",
1081  ((requested & RTE_ETH_RSS_TCP) == RTE_ETH_RSS_TCP) ? "" : "NOT ");
1082  SCLogConfig("RTE_ETH_RSS_UDP %sset",
1083  ((requested & RTE_ETH_RSS_UDP) == RTE_ETH_RSS_UDP) ? "" : "NOT ");
1084  SCLogConfig("RTE_ETH_RSS_SCTP %sset",
1085  ((requested & RTE_ETH_RSS_SCTP) == RTE_ETH_RSS_SCTP) ? "" : "NOT ");
1086  SCLogConfig("RTE_ETH_RSS_TUNNEL %sset",
1087  ((requested & RTE_ETH_RSS_TUNNEL) == RTE_ETH_RSS_TUNNEL) ? "" : "NOT ");
1088 
1089  SCLogConfig("REQUESTED (individual):");
1090  SCLogConfig("RTE_ETH_RSS_IPV4 (Bit position: %d) %sset",
1091  GetFirstSetBitPosition(RTE_ETH_RSS_IPV4), (requested & RTE_ETH_RSS_IPV4) ? "" : "NOT ");
1092  SCLogConfig("RTE_ETH_RSS_FRAG_IPV4 (Bit position: %d) %sset",
1093  GetFirstSetBitPosition(RTE_ETH_RSS_FRAG_IPV4),
1094  (requested & RTE_ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
1095  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_TCP (Bit position: %d) %sset",
1096  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_TCP),
1097  (requested & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
1098  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_UDP (Bit position: %d) %sset",
1099  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_UDP),
1100  (requested & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
1101  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_SCTP (Bit position: %d) %sset",
1102  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_SCTP),
1103  (requested & RTE_ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
1104  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_OTHER (Bit position: %d) %sset",
1105  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_OTHER),
1106  (requested & RTE_ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
1107  SCLogConfig("RTE_ETH_RSS_IPV6 (Bit position: %d) %sset",
1108  GetFirstSetBitPosition(RTE_ETH_RSS_IPV6), (requested & RTE_ETH_RSS_IPV6) ? "" : "NOT ");
1109  SCLogConfig("RTE_ETH_RSS_FRAG_IPV6 (Bit position: %d) %sset",
1110  GetFirstSetBitPosition(RTE_ETH_RSS_FRAG_IPV6),
1111  (requested & RTE_ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
1112  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_TCP (Bit position: %d) %sset",
1113  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_TCP),
1114  (requested & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
1115  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_UDP (Bit position: %d) %sset",
1116  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_UDP),
1117  (requested & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
1118  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_SCTP (Bit position: %d) %sset",
1119  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_SCTP),
1120  (requested & RTE_ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
1121  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_OTHER (Bit position: %d) %sset",
1122  GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_OTHER),
1123  (requested & RTE_ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
1124 
1125  SCLogConfig("RTE_ETH_RSS_L2_PAYLOAD (Bit position: %d) %sset",
1126  GetFirstSetBitPosition(RTE_ETH_RSS_L2_PAYLOAD),
1127  (requested & RTE_ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
1128  SCLogConfig("RTE_ETH_RSS_IPV6_EX (Bit position: %d) %sset",
1129  GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_EX),
1130  (requested & RTE_ETH_RSS_IPV6_EX) ? "" : "NOT ");
1131  SCLogConfig("RTE_ETH_RSS_IPV6_TCP_EX (Bit position: %d) %sset",
1132  GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_TCP_EX),
1133  (requested & RTE_ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
1134  SCLogConfig("RTE_ETH_RSS_IPV6_UDP_EX (Bit position: %d) %sset",
1135  GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_UDP_EX),
1136  (requested & RTE_ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
1137 
1138  SCLogConfig("RTE_ETH_RSS_PORT (Bit position: %d) %sset",
1139  GetFirstSetBitPosition(RTE_ETH_RSS_PORT), (requested & RTE_ETH_RSS_PORT) ? "" : "NOT ");
1140  SCLogConfig("RTE_ETH_RSS_VXLAN (Bit position: %d) %sset",
1141  GetFirstSetBitPosition(RTE_ETH_RSS_VXLAN),
1142  (requested & RTE_ETH_RSS_VXLAN) ? "" : "NOT ");
1143  SCLogConfig("RTE_ETH_RSS_NVGRE (Bit position: %d) %sset",
1144  GetFirstSetBitPosition(RTE_ETH_RSS_NVGRE),
1145  (requested & RTE_ETH_RSS_NVGRE) ? "" : "NOT ");
1146  SCLogConfig("RTE_ETH_RSS_GTPU (Bit position: %d) %sset",
1147  GetFirstSetBitPosition(RTE_ETH_RSS_GTPU), (requested & RTE_ETH_RSS_GTPU) ? "" : "NOT ");
1148 
1149  SCLogConfig("RTE_ETH_RSS_L3_SRC_ONLY (Bit position: %d) %sset",
1150  GetFirstSetBitPosition(RTE_ETH_RSS_L3_SRC_ONLY),
1151  (requested & RTE_ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
1152  SCLogConfig("RTE_ETH_RSS_L3_DST_ONLY (Bit position: %d) %sset",
1153  GetFirstSetBitPosition(RTE_ETH_RSS_L3_DST_ONLY),
1154  (requested & RTE_ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
1155  SCLogConfig("RTE_ETH_RSS_L4_SRC_ONLY (Bit position: %d) %sset",
1156  GetFirstSetBitPosition(RTE_ETH_RSS_L4_SRC_ONLY),
1157  (requested & RTE_ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
1158  SCLogConfig("RTE_ETH_RSS_L4_DST_ONLY (Bit position: %d) %sset",
1159  GetFirstSetBitPosition(RTE_ETH_RSS_L4_DST_ONLY),
1160  (requested & RTE_ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
1161  SCLogConfig("ACTUAL (group):");
1162  SCLogConfig(
1163  "RTE_ETH_RSS_IP %sset", ((actual & RTE_ETH_RSS_IP) == RTE_ETH_RSS_IP) ? "" : "NOT ");
1164  SCLogConfig(
1165  "RTE_ETH_RSS_TCP %sset", ((actual & RTE_ETH_RSS_TCP) == RTE_ETH_RSS_TCP) ? "" : "NOT ");
1166  SCLogConfig(
1167  "RTE_ETH_RSS_UDP %sset", ((actual & RTE_ETH_RSS_UDP) == RTE_ETH_RSS_UDP) ? "" : "NOT ");
1168  SCLogConfig("RTE_ETH_RSS_SCTP %sset",
1169  ((actual & RTE_ETH_RSS_SCTP) == RTE_ETH_RSS_SCTP) ? "" : "NOT ");
1170  SCLogConfig("RTE_ETH_RSS_TUNNEL %sset",
1171  ((actual & RTE_ETH_RSS_TUNNEL) == RTE_ETH_RSS_TUNNEL) ? "" : "NOT ");
1172 
1173  SCLogConfig("ACTUAL (individual flags):");
1174  SCLogConfig("RTE_ETH_RSS_IPV4 %sset", (actual & RTE_ETH_RSS_IPV4) ? "" : "NOT ");
1175  SCLogConfig("RTE_ETH_RSS_FRAG_IPV4 %sset", (actual & RTE_ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
1176  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_TCP %sset",
1177  (actual & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
1178  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_UDP %sset",
1179  (actual & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
1180  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_SCTP %sset",
1181  (actual & RTE_ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
1182  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_OTHER %sset",
1183  (actual & RTE_ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
1184  SCLogConfig("RTE_ETH_RSS_IPV6 %sset", (actual & RTE_ETH_RSS_IPV6) ? "" : "NOT ");
1185  SCLogConfig("RTE_ETH_RSS_FRAG_IPV6 %sset", (actual & RTE_ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
1186  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_TCP %sset",
1187  (actual & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
1188  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_UDP %sset",
1189  (actual & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
1190  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_SCTP %sset",
1191  (actual & RTE_ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
1192  SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_OTHER %sset",
1193  (actual & RTE_ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
1194 
1195  SCLogConfig("RTE_ETH_RSS_L2_PAYLOAD %sset", (actual & RTE_ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
1196  SCLogConfig("RTE_ETH_RSS_IPV6_EX %sset", (actual & RTE_ETH_RSS_IPV6_EX) ? "" : "NOT ");
1197  SCLogConfig("RTE_ETH_RSS_IPV6_TCP_EX %sset", (actual & RTE_ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
1198  SCLogConfig("RTE_ETH_RSS_IPV6_UDP_EX %sset", (actual & RTE_ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
1199 
1200  SCLogConfig("RTE_ETH_RSS_PORT %sset", (actual & RTE_ETH_RSS_PORT) ? "" : "NOT ");
1201  SCLogConfig("RTE_ETH_RSS_VXLAN %sset", (actual & RTE_ETH_RSS_VXLAN) ? "" : "NOT ");
1202  SCLogConfig("RTE_ETH_RSS_NVGRE %sset", (actual & RTE_ETH_RSS_NVGRE) ? "" : "NOT ");
1203  SCLogConfig("RTE_ETH_RSS_GTPU %sset", (actual & RTE_ETH_RSS_GTPU) ? "" : "NOT ");
1204 
1205  SCLogConfig("RTE_ETH_RSS_L3_SRC_ONLY %sset", (actual & RTE_ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
1206  SCLogConfig("RTE_ETH_RSS_L3_DST_ONLY %sset", (actual & RTE_ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
1207  SCLogConfig("RTE_ETH_RSS_L4_SRC_ONLY %sset", (actual & RTE_ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
1208  SCLogConfig("RTE_ETH_RSS_L4_DST_ONLY %sset", (actual & RTE_ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
1209 }
1210 
1211 static void DumpRXOffloadCapabilities(const uint64_t rx_offld_capa)
1212 {
1213  SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_STRIP - %savailable",
1214  rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_STRIP ? "" : "NOT ");
1215  SCLogConfig("RTE_ETH_RX_OFFLOAD_IPV4_CKSUM - %savailable",
1216  rx_offld_capa & RTE_ETH_RX_OFFLOAD_IPV4_CKSUM ? "" : "NOT ");
1217  SCLogConfig("RTE_ETH_RX_OFFLOAD_UDP_CKSUM - %savailable",
1218  rx_offld_capa & RTE_ETH_RX_OFFLOAD_UDP_CKSUM ? "" : "NOT ");
1219  SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_CKSUM - %savailable",
1220  rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_CKSUM ? "" : "NOT ");
1221  SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_LRO - %savailable",
1222  rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_LRO ? "" : "NOT ");
1223  SCLogConfig("RTE_ETH_RX_OFFLOAD_QINQ_STRIP - %savailable",
1224  rx_offld_capa & RTE_ETH_RX_OFFLOAD_QINQ_STRIP ? "" : "NOT ");
1225  SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM - %savailable",
1226  rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM ? "" : "NOT ");
1227  SCLogConfig("RTE_ETH_RX_OFFLOAD_MACSEC_STRIP - %savailable",
1228  rx_offld_capa & RTE_ETH_RX_OFFLOAD_MACSEC_STRIP ? "" : "NOT ");
1229 #if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0)
1230  SCLogConfig("RTE_ETH_RX_OFFLOAD_HEADER_SPLIT - %savailable",
1231  rx_offld_capa & RTE_ETH_RX_OFFLOAD_HEADER_SPLIT ? "" : "NOT ");
1232 #endif
1233  SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_FILTER - %savailable",
1234  rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_FILTER ? "" : "NOT ");
1235  SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_EXTEND - %savailable",
1236  rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND ? "" : "NOT ");
1237  SCLogConfig("RTE_ETH_RX_OFFLOAD_SCATTER - %savailable",
1238  rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCATTER ? "" : "NOT ");
1239  SCLogConfig("RTE_ETH_RX_OFFLOAD_TIMESTAMP - %savailable",
1240  rx_offld_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP ? "" : "NOT ");
1241  SCLogConfig("RTE_ETH_RX_OFFLOAD_SECURITY - %savailable",
1242  rx_offld_capa & RTE_ETH_RX_OFFLOAD_SECURITY ? "" : "NOT ");
1243  SCLogConfig("RTE_ETH_RX_OFFLOAD_KEEP_CRC - %savailable",
1244  rx_offld_capa & RTE_ETH_RX_OFFLOAD_KEEP_CRC ? "" : "NOT ");
1245  SCLogConfig("RTE_ETH_RX_OFFLOAD_SCTP_CKSUM - %savailable",
1246  rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCTP_CKSUM ? "" : "NOT ");
1247  SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM - %savailable",
1248  rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM ? "" : "NOT ");
1249  SCLogConfig("RTE_ETH_RX_OFFLOAD_RSS_HASH - %savailable",
1250  rx_offld_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH ? "" : "NOT ");
1251 #if RTE_VERSION >= RTE_VERSION_NUM(20, 11, 0, 0)
1252  SCLogConfig("RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT - %savailable",
1253  rx_offld_capa & RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT ? "" : "NOT ");
1254 #endif
1255 }
1256 
1257 static int DeviceValidateMTU(const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
1258 {
1259  SCEnter();
1260  if (iconf->mtu > dev_info->max_mtu || iconf->mtu < dev_info->min_mtu) {
1261  SCLogError("%s: MTU out of bounds. "
1262  "Min MTU: %" PRIu16 " Max MTU: %" PRIu16,
1263  iconf->iface, dev_info->min_mtu, dev_info->max_mtu);
1264  SCReturnInt(-ERANGE);
1265  }
1266 
1267 #if RTE_VERSION < RTE_VERSION_NUM(21, 11, 0, 0)
1268  // check if jumbo frames are set and are available
1269  if (iconf->mtu > RTE_ETHER_MAX_LEN &&
1270  !(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME)) {
1271  SCLogError("%s: jumbo frames not supported, set MTU to 1500", iconf->iface);
1272  SCReturnInt(-EINVAL);
1273  }
1274 #endif
1275 
1276  SCReturnInt(0);
1277 }
1278 
1279 static void DeviceSetMTU(struct rte_eth_conf *port_conf, uint16_t mtu)
1280 {
1281 #if RTE_VERSION >= RTE_VERSION_NUM(21, 11, 0, 0)
1282  port_conf->rxmode.mtu = mtu;
1283 #else
1284  port_conf->rxmode.max_rx_pkt_len = mtu;
1285  if (mtu > RTE_ETHER_MAX_LEN) {
1286  port_conf->rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
1287  }
1288 #endif
1289 }
1290 
1291 /**
1292  * \param port_id - queried port
1293  * \param socket_id - socket ID of the queried port
1294  * \return non-negative number on success, negative on failure (errno)
1295  */
1296 static int32_t DeviceSetSocketID(uint16_t port_id, int32_t *socket_id)
1297 {
1298  rte_errno = 0;
1299  int retval = rte_eth_dev_socket_id(port_id);
1300  *socket_id = retval;
1301 
1302 #if RTE_VERSION >= RTE_VERSION_NUM(22, 11, 0, 0) // DPDK API changed since 22.11
1303  retval = -rte_errno;
1304 #else
1305  if (retval == SOCKET_ID_ANY)
1306  retval = 0; // DPDK couldn't determine socket ID of a port
1307 #endif
1308 
1309  return retval;
1310 }
1311 
1312 static void PortConfSetInterruptMode(const DPDKIfaceConfig *iconf, struct rte_eth_conf *port_conf)
1313 {
1314  SCLogConfig("%s: interrupt mode is %s", iconf->iface,
1315  iconf->flags & DPDK_IRQ_MODE ? "enabled" : "disabled");
1316  if (iconf->flags & DPDK_IRQ_MODE)
1317  port_conf->intr_conf.rxq = 1;
1318 }
1319 
1320 static void PortConfSetRSSConf(const DPDKIfaceConfig *iconf,
1321  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1322 {
1323  if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH) {
1324  if (iconf->nb_rx_queues > 1) {
1325  SCLogConfig("%s: RSS enabled for %d queues", iconf->iface, iconf->nb_rx_queues);
1326  port_conf->rx_adv_conf.rss_conf = (struct rte_eth_rss_conf){
1327  .rss_key = RSS_HKEY,
1328  .rss_key_len = RSS_HKEY_LEN,
1329  .rss_hf = iconf->rss_hf,
1330  };
1331 
1332  const char *dev_driver = dev_info->driver_name;
1333  if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
1334  dev_driver = BondingDeviceDriverGet(iconf->port_id);
1335  }
1336 
1337  DeviceSetPMDSpecificRSS(&port_conf->rx_adv_conf.rss_conf, dev_driver);
1338 
1339  uint64_t rss_hf_tmp =
1340  port_conf->rx_adv_conf.rss_conf.rss_hf & dev_info->flow_type_rss_offloads;
1341  if (port_conf->rx_adv_conf.rss_conf.rss_hf != rss_hf_tmp) {
1342  DumpRSSFlags(port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
1343 
1344  SCLogWarning("%s: modified RSS hash function based on hardware support: "
1345  "requested:%#" PRIx64 ", configured:%#" PRIx64,
1346  iconf->iface, port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
1347  port_conf->rx_adv_conf.rss_conf.rss_hf = rss_hf_tmp;
1348  }
1349  port_conf->rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
1350  } else {
1351  SCLogConfig("%s: RSS not enabled", iconf->iface);
1352  port_conf->rx_adv_conf.rss_conf.rss_key = NULL;
1353  port_conf->rx_adv_conf.rss_conf.rss_hf = 0;
1354  }
1355  } else {
1356  SCLogConfig("%s: RSS not supported", iconf->iface);
1357  }
1358 }
1359 
1360 static void PortConfSetChsumOffload(const DPDKIfaceConfig *iconf,
1361  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1362 {
1363  if (iconf->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
1364  SCLogConfig("%s: checksum validation disabled", iconf->iface);
1365  } else if ((dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_CHECKSUM) ==
1366  RTE_ETH_RX_OFFLOAD_CHECKSUM) { // multibit comparison to make sure all bits are set
1367  if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
1368  iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD) {
1369  SCLogConfig("%s: IP, TCP and UDP checksum validation offloaded", iconf->iface);
1370  port_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
1371  } else if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
1372  !(iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD)) {
1373  SCLogConfig("%s: checksum validation enabled (but can be offloaded)", iconf->iface);
1374  }
1375  }
1376 }
1377 
1378 static void PortConfSetVlanOffload(const DPDKIfaceConfig *iconf,
1379  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1380 {
1381  if (iconf->vlan_strip_enabled) {
1382  if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_VLAN_STRIP) {
1383  port_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_STRIP;
1384  SCLogConfig("%s: hardware VLAN stripping enabled", iconf->iface);
1385  } else {
1386  SCLogWarning("%s: hardware VLAN stripping enabled but not supported, disabling",
1387  iconf->iface);
1388  }
1389  }
1390 }
1391 
1392 static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
1393  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1394 {
1395  DumpRXOffloadCapabilities(dev_info->rx_offload_capa);
1396  *port_conf = (struct rte_eth_conf){
1397  .rxmode = {
1398  .mq_mode = RTE_ETH_MQ_RX_NONE,
1399  .offloads = 0, // turn every offload off to prevent any packet modification
1400  },
1401  .txmode = {
1402  .mq_mode = RTE_ETH_MQ_TX_NONE,
1403  .offloads = 0,
1404  },
1405  };
1406 
1407  PortConfSetInterruptMode(iconf, port_conf);
1408 
1409  // configure RX offloads
1410  PortConfSetRSSConf(iconf, dev_info, port_conf);
1411  PortConfSetChsumOffload(iconf, dev_info, port_conf);
1412  DeviceSetMTU(port_conf, iconf->mtu);
1413  PortConfSetVlanOffload(iconf, dev_info, port_conf);
1414 
1415  if (dev_info->tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) {
1416  port_conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1417  }
1418 }
1419 
1420 static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info,
1421  const struct rte_eth_conf *port_conf)
1422 {
1423  SCEnter();
1424  int retval;
1425  struct rte_eth_rxconf rxq_conf;
1426  struct rte_eth_txconf txq_conf;
1427 
1428  retval = DPDKDeviceResourcesInit(&(iconf->pkt_mempools), iconf->nb_rx_queues);
1429  if (retval < 0) {
1430  goto cleanup;
1431  }
1432 
1433  // +4 for VLAN header
1434  uint16_t mtu_size = iconf->mtu + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN + 4;
1435  uint16_t mbuf_size = ROUNDUP(mtu_size, 1024) + RTE_PKTMBUF_HEADROOM;
1436  // ceil the div so e.g. mp_size of 262144 and 262143 both lead to 65535 on 4 rx queues
1437  uint32_t q_mp_sz = (iconf->mempool_size + iconf->nb_rx_queues - 1) / iconf->nb_rx_queues - 1;
1438  uint32_t q_mp_cache_sz = MempoolCacheSizeCalculate(q_mp_sz);
1439  SCLogInfo("%s: creating %u packet mempools of size %u, cache size %u, mbuf size %u",
1440  iconf->iface, iconf->nb_rx_queues, q_mp_sz, q_mp_cache_sz, mbuf_size);
1441  for (int i = 0; i < iconf->nb_rx_queues; i++) {
1442  char mempool_name[64];
1443  snprintf(mempool_name, sizeof(mempool_name), "mp_%d_%.20s", i, iconf->iface);
1444  iconf->pkt_mempools->pkt_mp[i] = rte_pktmbuf_pool_create(
1445  mempool_name, q_mp_sz, q_mp_cache_sz, 0, mbuf_size, (int)iconf->socket_id);
1446  if (iconf->pkt_mempools->pkt_mp[i] == NULL) {
1447  retval = -rte_errno;
1448  SCLogError("%s: rte_pktmbuf_pool_create failed with code %d (mempool: %s) - %s",
1449  iconf->iface, rte_errno, mempool_name, rte_strerror(rte_errno));
1450  goto cleanup;
1451  }
1452  }
1453 
1454  for (uint16_t queue_id = 0; queue_id < iconf->nb_rx_queues; queue_id++) {
1455  rxq_conf = dev_info->default_rxconf;
1456  rxq_conf.offloads = port_conf->rxmode.offloads;
1457  rxq_conf.rx_thresh.hthresh = 0;
1458  rxq_conf.rx_thresh.pthresh = 0;
1459  rxq_conf.rx_thresh.wthresh = 0;
1460  rxq_conf.rx_free_thresh = 0;
1461  rxq_conf.rx_drop_en = 0;
1462  SCLogConfig("%s: setting up RX queue %d: rx_desc: %u offloads: 0x%" PRIx64
1463  " hthresh: %" PRIu8 " pthresh: %" PRIu8 " wthresh: %" PRIu8
1464  " free_thresh: %" PRIu16 " drop_en: %" PRIu8,
1465  iconf->iface, queue_id, iconf->nb_rx_desc, rxq_conf.offloads,
1466  rxq_conf.rx_thresh.hthresh, rxq_conf.rx_thresh.pthresh, rxq_conf.rx_thresh.wthresh,
1467  rxq_conf.rx_free_thresh, rxq_conf.rx_drop_en);
1468 
1469  retval = rte_eth_rx_queue_setup(iconf->port_id, queue_id, iconf->nb_rx_desc,
1470  iconf->socket_id, &rxq_conf, iconf->pkt_mempools->pkt_mp[queue_id]);
1471  if (retval < 0) {
1472  SCLogError("%s: failed to setup RX queue %u: %s", iconf->iface, queue_id,
1473  rte_strerror(-retval));
1474  goto cleanup;
1475  }
1476  }
1477 
1478  for (uint16_t queue_id = 0; queue_id < iconf->nb_tx_queues; queue_id++) {
1479  txq_conf = dev_info->default_txconf;
1480  txq_conf.offloads = port_conf->txmode.offloads;
1481  SCLogConfig("%s: setting up TX queue %d: tx_desc: %" PRIu16 " tx: offloads: 0x%" PRIx64
1482  " hthresh: %" PRIu8 " pthresh: %" PRIu8 " wthresh: %" PRIu8
1483  " tx_free_thresh: %" PRIu16 " tx_rs_thresh: %" PRIu16
1484  " txq_deferred_start: %" PRIu8,
1485  iconf->iface, queue_id, iconf->nb_tx_desc, txq_conf.offloads,
1486  txq_conf.tx_thresh.hthresh, txq_conf.tx_thresh.pthresh, txq_conf.tx_thresh.wthresh,
1487  txq_conf.tx_free_thresh, txq_conf.tx_rs_thresh, txq_conf.tx_deferred_start);
1488  retval = rte_eth_tx_queue_setup(
1489  iconf->port_id, queue_id, iconf->nb_tx_desc, iconf->socket_id, &txq_conf);
1490  if (retval < 0) {
1491  SCLogError("%s: failed to setup TX queue %u: %s", iconf->iface, queue_id,
1492  rte_strerror(-retval));
1493  retval = -1; // the error code explained, informing about failure
1494  goto cleanup;
1495  }
1496  }
1497 
1498  SCReturnInt(0);
1499 
1500 cleanup:
1501  DPDKDeviceResourcesDeinit(&iconf->pkt_mempools);
1502  SCReturnInt(retval);
1503 }
1504 
1505 static int DeviceValidateOutIfaceConfig(DPDKIfaceConfig *iconf)
1506 {
1507  SCEnter();
1508  int retval;
1509  DPDKIfaceConfig *out_iconf = NULL;
1510  ConfigInit(&out_iconf);
1511  if (out_iconf == NULL) {
1512  FatalError("Copy interface of the interface \"%s\" is NULL", iconf->iface);
1513  }
1514 
1515  retval = ConfigLoad(out_iconf, iconf->out_iface);
1516  if (retval < 0) {
1517  SCLogError("%s: fail to load config of interface", iconf->out_iface);
1518  out_iconf->DerefFunc(out_iconf);
1519  SCReturnInt(-EINVAL);
1520  }
1521 
1522  if (iconf->nb_rx_queues != out_iconf->nb_tx_queues) {
1523  // the other direction is validated when the copy interface is configured
1524  SCLogError("%s: configured %d RX queues but copy interface %s has %d TX queues"
1525  " - number of queues must be equal",
1526  iconf->iface, iconf->nb_rx_queues, out_iconf->iface, out_iconf->nb_tx_queues);
1527  out_iconf->DerefFunc(out_iconf);
1528  SCReturnInt(-EINVAL);
1529  } else if (iconf->mtu != out_iconf->mtu) {
1530  SCLogError("%s: configured MTU of %d but copy interface %s has MTU set to %d"
1531  " - MTU must be equal",
1532  iconf->iface, iconf->mtu, out_iconf->iface, out_iconf->mtu);
1533  out_iconf->DerefFunc(out_iconf);
1534  SCReturnInt(-EINVAL);
1535  } else if (iconf->copy_mode != out_iconf->copy_mode) {
1536  SCLogError("%s: copy modes of interfaces %s and %s are not equal", iconf->iface,
1537  iconf->iface, out_iconf->iface);
1538  out_iconf->DerefFunc(out_iconf);
1539  SCReturnInt(-EINVAL);
1540  } else if (strcmp(iconf->iface, out_iconf->out_iface) != 0) {
1541  // check if the other iface has the current iface set as a copy iface
1542  SCLogError("%s: copy interface of %s is not set to %s", iconf->iface, out_iconf->iface,
1543  iconf->iface);
1544  out_iconf->DerefFunc(out_iconf);
1545  SCReturnInt(-EINVAL);
1546  }
1547 
1548  out_iconf->DerefFunc(out_iconf);
1549  SCReturnInt(0);
1550 }
1551 
1552 static int DeviceConfigureIPS(DPDKIfaceConfig *iconf)
1553 {
1554  SCEnter();
1555  if (iconf->out_iface != NULL) {
1556  if (!rte_eth_dev_is_valid_port(iconf->out_port_id)) {
1557  SCLogError("%s: retrieved copy interface port ID \"%d\" is invalid or the device is "
1558  "not attached ",
1559  iconf->iface, iconf->out_port_id);
1560  SCReturnInt(-ENODEV);
1561  }
1562  int32_t out_port_socket_id;
1563  int retval = DeviceSetSocketID(iconf->out_port_id, &out_port_socket_id);
1564  if (retval < 0) {
1565  SCLogError("%s: invalid socket id: %s", iconf->out_iface, rte_strerror(-retval));
1566  SCReturnInt(retval);
1567  }
1568 
1569  if (iconf->socket_id != out_port_socket_id) {
1570  SCLogWarning(
1571  "%s: out iface %s is not on the same NUMA node (%s - NUMA %d, %s - NUMA %d)",
1572  iconf->iface, iconf->out_iface, iconf->iface, iconf->socket_id,
1573  iconf->out_iface, out_port_socket_id);
1574  }
1575 
1576  retval = DeviceValidateOutIfaceConfig(iconf);
1577  if (retval != 0) {
1578  // Error will be written out by the validation function
1579  SCReturnInt(retval);
1580  }
1581 
1582  if (iconf->copy_mode == DPDK_COPY_MODE_IPS)
1583  SCLogInfo("%s: DPDK IPS mode activated: %s->%s", iconf->iface, iconf->iface,
1584  iconf->out_iface);
1585  else if (iconf->copy_mode == DPDK_COPY_MODE_TAP)
1586  SCLogInfo("%s: DPDK TAP mode activated: %s->%s", iconf->iface, iconf->iface,
1587  iconf->out_iface);
1588  }
1589  SCReturnInt(0);
1590 }
1591 
1592 /**
1593  * Function verifies changes in e.g. device info after configuration has
1594  * happened. Sometimes (e.g. DPDK Bond PMD with Intel NICs i40e/ixgbe) change
1595  * device info only after the device configuration.
1596  * @param iconf
1597  * @param dev_info
1598  * @return 0 on success, -EAGAIN when reconfiguration is needed, <0 on failure
1599  */
1600 static int32_t DeviceVerifyPostConfigure(
1601  const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
1602 {
1603  SCEnter();
1604  struct rte_eth_dev_info post_conf_dev_info = { 0 };
1605  int32_t ret = rte_eth_dev_info_get(iconf->port_id, &post_conf_dev_info);
1606  if (ret < 0) {
1607  SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-ret));
1608  SCReturnInt(ret);
1609  }
1610 
1611  if (dev_info->flow_type_rss_offloads != post_conf_dev_info.flow_type_rss_offloads ||
1612  dev_info->rx_offload_capa != post_conf_dev_info.rx_offload_capa ||
1613  dev_info->tx_offload_capa != post_conf_dev_info.tx_offload_capa ||
1614  dev_info->max_rx_queues != post_conf_dev_info.max_rx_queues ||
1615  dev_info->max_tx_queues != post_conf_dev_info.max_tx_queues ||
1616  dev_info->max_mtu != post_conf_dev_info.max_mtu) {
1617  SCLogWarning("%s: device information severely changed after configuration, reconfiguring",
1618  iconf->iface);
1619  return -EAGAIN;
1620  }
1621 
1622  if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
1623  ret = BondingAllDevicesSameDriver(iconf->port_id);
1624  if (ret < 0) {
1625  SCLogError("%s: bond port uses port with different DPDK drivers", iconf->iface);
1626  SCReturnInt(ret);
1627  }
1628  }
1629 
1630  return 0;
1631 }
1632 
1633 static int DeviceConfigure(DPDKIfaceConfig *iconf)
1634 {
1635  SCEnter();
1636  if (!rte_eth_dev_is_valid_port(iconf->port_id)) {
1637  SCLogError("%s: retrieved port ID \"%d\" is invalid or the device is not attached ",
1638  iconf->iface, iconf->port_id);
1639  SCReturnInt(-ENODEV);
1640  }
1641 
1642  int32_t retval = DeviceSetSocketID(iconf->port_id, &iconf->socket_id);
1643  if (retval < 0) {
1644  SCLogError("%s: invalid socket id: %s", iconf->iface, rte_strerror(-retval));
1645  SCReturnInt(retval);
1646  }
1647 
1648  struct rte_eth_dev_info dev_info = { 0 };
1649  retval = rte_eth_dev_info_get(iconf->port_id, &dev_info);
1650  if (retval < 0) {
1651  SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-retval));
1652  SCReturnInt(retval);
1653  }
1654 
1655  if (iconf->nb_rx_queues > dev_info.max_rx_queues) {
1656  SCLogError("%s: configured RX queues %u is higher than device maximum (%" PRIu16 ")",
1657  iconf->iface, iconf->nb_rx_queues, dev_info.max_rx_queues);
1658  SCReturnInt(-ERANGE);
1659  }
1660 
1661  if (iconf->nb_tx_queues > dev_info.max_tx_queues) {
1662  SCLogError("%s: configured TX queues %u is higher than device maximum (%" PRIu16 ")",
1663  iconf->iface, iconf->nb_tx_queues, dev_info.max_tx_queues);
1664  SCReturnInt(-ERANGE);
1665  }
1666 
1667  retval = DeviceValidateMTU(iconf, &dev_info);
1668  if (retval < 0)
1669  return retval;
1670 
1671  struct rte_eth_conf port_conf = { 0 };
1672  DeviceInitPortConf(iconf, &dev_info, &port_conf);
1673  if (port_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) {
1674  // Suricata does not need recalc checksums now
1675  iconf->checksum_mode = CHECKSUM_VALIDATION_OFFLOAD;
1676  }
1677 
1678  retval = rte_eth_dev_configure(
1679  iconf->port_id, iconf->nb_rx_queues, iconf->nb_tx_queues, &port_conf);
1680  if (retval < 0) {
1681  SCLogError("%s: failed to configure the device: %s", iconf->iface, rte_strerror(-retval));
1682  SCReturnInt(retval);
1683  }
1684 
1685  retval = DeviceVerifyPostConfigure(iconf, &dev_info);
1686  if (retval < 0)
1687  return retval;
1688 
1689  uint16_t tmp_nb_rx_desc = iconf->nb_rx_desc;
1690  uint16_t tmp_nb_tx_desc = iconf->nb_tx_desc;
1691  retval = rte_eth_dev_adjust_nb_rx_tx_desc(
1692  iconf->port_id, &iconf->nb_rx_desc, &iconf->nb_tx_desc);
1693  if (retval != 0) {
1694  SCLogError("%s: failed to adjust device queue descriptors: %s", iconf->iface,
1695  rte_strerror(-retval));
1696  SCReturnInt(retval);
1697  } else if (tmp_nb_rx_desc != iconf->nb_rx_desc || tmp_nb_tx_desc != iconf->nb_tx_desc) {
1698  SCLogWarning("%s: device queue descriptors adjusted (RX: from %u to %u, TX: from %u to %u)",
1699  iconf->iface, tmp_nb_rx_desc, iconf->nb_rx_desc, tmp_nb_tx_desc, iconf->nb_tx_desc);
1700  }
1701 
1702  retval = iconf->flags & DPDK_MULTICAST ? rte_eth_allmulticast_enable(iconf->port_id)
1703  : rte_eth_allmulticast_disable(iconf->port_id);
1704  if (retval == -ENOTSUP) {
1705  retval = rte_eth_allmulticast_get(iconf->port_id);
1706  // when multicast is enabled but set to disable or vice versa
1707  if ((retval == 1 && !(iconf->flags & DPDK_MULTICAST)) ||
1708  (retval == 0 && (iconf->flags & DPDK_MULTICAST))) {
1709  SCLogWarning("%s: cannot configure allmulticast, the port is %sin allmulticast mode",
1710  iconf->iface, retval == 1 ? "" : "not ");
1711  } else if (retval < 0) {
1712  SCLogError("%s: failed to get multicast mode: %s", iconf->iface, rte_strerror(-retval));
1713  SCReturnInt(retval);
1714  }
1715  } else if (retval < 0) {
1716  SCLogError("%s: error when changing multicast setting: %s", iconf->iface,
1717  rte_strerror(-retval));
1718  SCReturnInt(retval);
1719  }
1720 
1721  retval = iconf->flags & DPDK_PROMISC ? rte_eth_promiscuous_enable(iconf->port_id)
1722  : rte_eth_promiscuous_disable(iconf->port_id);
1723  if (retval == -ENOTSUP) {
1724  retval = rte_eth_promiscuous_get(iconf->port_id);
1725  if ((retval == 1 && !(iconf->flags & DPDK_PROMISC)) ||
1726  (retval == 0 && (iconf->flags & DPDK_PROMISC))) {
1727  SCLogError("%s: cannot configure promiscuous mode, the port is in %spromiscuous mode",
1728  iconf->iface, retval == 1 ? "" : "non-");
1730  } else if (retval < 0) {
1731  SCLogError(
1732  "%s: failed to get promiscuous mode: %s", iconf->iface, rte_strerror(-retval));
1733  SCReturnInt(retval);
1734  }
1735  } else if (retval < 0) {
1736  SCLogError("%s: error when changing promiscuous setting: %s", iconf->iface,
1737  rte_strerror(-retval));
1739  }
1740 
1741  // set maximum transmission unit
1742  SCLogConfig("%s: setting MTU to %d", iconf->iface, iconf->mtu);
1743  retval = rte_eth_dev_set_mtu(iconf->port_id, iconf->mtu);
1744  if (retval == -ENOTSUP) {
1745  // if it is not possible to set the MTU, retrieve it
1746  retval = rte_eth_dev_get_mtu(iconf->port_id, &iconf->mtu);
1747  if (retval < 0) {
1748  SCLogError("%s: failed to retrieve MTU: %s", iconf->iface, rte_strerror(-retval));
1749  SCReturnInt(retval);
1750  }
1751  SCLogWarning(
1752  "%s: changing MTU is not supported, current MTU: %u", iconf->iface, iconf->mtu);
1753  } else if (retval < 0) {
1754  SCLogError(
1755  "%s: failed to set MTU to %u: %s", iconf->iface, iconf->mtu, rte_strerror(-retval));
1756  SCReturnInt(retval);
1757  }
1758 
1759  retval = DeviceConfigureQueues(iconf, &dev_info, &port_conf);
1760  if (retval < 0) {
1761  SCReturnInt(retval);
1762  }
1763 
1764  retval = DeviceConfigureIPS(iconf);
1765  if (retval < 0) {
1766  SCReturnInt(retval);
1767  }
1768 
1769  SCReturnInt(0);
1770 }
1771 
1772 static void *ParseDpdkConfigAndConfigureDevice(const char *iface)
1773 {
1774  int retval;
1775  DPDKIfaceConfig *iconf = ConfigParse(iface);
1776  if (iconf == NULL) {
1777  FatalError("DPDK configuration could not be parsed");
1778  }
1779 
1780  retval = DeviceConfigure(iconf);
1781  if (retval == -EAGAIN) {
1782  // for e.g. bonding PMD it needs to be reconfigured
1783  retval = DeviceConfigure(iconf);
1784  }
1785 
1786  if (retval < 0) { // handles both configure attempts
1787  iconf->DerefFunc(iconf);
1788  if (rte_eal_cleanup() != 0)
1789  FatalError("EAL cleanup failed: %s", rte_strerror(-retval));
1790 
1791  if (retval == -ENOMEM) {
1792  FatalError("%s: memory allocation failed - consider"
1793  "%s freeing up some memory.",
1794  iface,
1795  rte_eal_has_hugepages() != 0 ? " increasing the number of hugepages or" : "");
1796  } else {
1797  FatalError("%s: failed to configure", iface);
1798  }
1799  }
1800 
1801  SC_ATOMIC_RESET(iconf->ref);
1802  (void)SC_ATOMIC_ADD(iconf->ref, iconf->threads);
1803  // This counter is increased by worker threads that individually pick queue IDs.
1804  SC_ATOMIC_RESET(iconf->queue_id);
1805  SC_ATOMIC_RESET(iconf->inconsistent_numa_cnt);
1806  iconf->workers_sync = SCCalloc(1, sizeof(*iconf->workers_sync));
1807  if (iconf->workers_sync == NULL) {
1808  FatalError("Failed to allocate memory for workers_sync");
1809  }
1810  SC_ATOMIC_RESET(iconf->workers_sync->worker_checked_in);
1811  iconf->workers_sync->worker_cnt = iconf->threads;
1812 
1813  // initialize LiveDev DPDK values
1814  LiveDevice *ldev_instance = LiveGetDevice(iface);
1815  if (ldev_instance == NULL) {
1816  FatalError("Device %s is not registered as a live device", iface);
1817  }
1818  for (int32_t i = 0; i < iconf->threads; i++) {
1819  ldev_instance->dpdk_vars = iconf->pkt_mempools;
1820  iconf->pkt_mempools = NULL;
1821  }
1822  return iconf;
1823 }
1824 
1825 /**
1826  * \brief extract information from config file
1827  *
1828  * The returned structure will be freed by the thread init function.
1829  * This is thus necessary to or copy the structure before giving it
1830  * to thread or to reparse the file for each thread (and thus have
1831  * new structure.
1832  *
1833  * After configuration is loaded, DPDK also configures the device according to the settings.
1834  *
1835  * \return a DPDKIfaceConfig corresponding to the interface name
1836  */
1837 
1838 static int DPDKConfigGetThreadsCount(void *conf)
1839 {
1840  if (conf == NULL)
1841  FatalError("Configuration file is NULL");
1842 
1843  DPDKIfaceConfig *dpdk_conf = (DPDKIfaceConfig *)conf;
1844  return dpdk_conf->threads;
1845 }
1846 
1847 #endif /* HAVE_DPDK */
1848 
1849 static int DPDKRunModeIsIPS(void)
1850 {
1851  /* Find initial node */
1852  const char dpdk_node_query[] = "dpdk.interfaces";
1853  SCConfNode *dpdk_node = SCConfGetNode(dpdk_node_query);
1854  if (dpdk_node == NULL) {
1855  FatalError("Unable to get %s configuration node", dpdk_node_query);
1856  }
1857 
1858  const char default_iface[] = "default";
1859  SCConfNode *if_default = SCConfNodeLookupKeyValue(dpdk_node, "interface", default_iface);
1860  int nlive = LiveGetDeviceCount();
1861  bool has_ips = false;
1862  bool has_ids = false;
1863  for (int ldev = 0; ldev < nlive; ldev++) {
1864  const char *live_dev = LiveGetDeviceName(ldev);
1865  if (live_dev == NULL)
1866  FatalError("Unable to get device id %d from LiveDevice list", ldev);
1867 
1868  SCConfNode *if_root = ConfFindDeviceConfig(dpdk_node, live_dev);
1869  if (if_root == NULL) {
1870  if (if_default == NULL)
1871  FatalError("Unable to get %s or %s interface", live_dev, default_iface);
1872 
1873  if_root = if_default;
1874  }
1875 
1876  const char *copymodestr = NULL;
1877  const char *copyifacestr = NULL;
1878  if (SCConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
1879  SCConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
1880  if (strcmp(copymodestr, "ips") == 0) {
1881  has_ips = true;
1882  } else {
1883  has_ids = true;
1884  }
1885  } else {
1886  has_ids = true;
1887  }
1888 
1889  if (has_ids && has_ips) {
1890  FatalError("Copy-mode of interface %s mixes with the previously set copy-modes "
1891  "(only IDS/TAP and IPS copy-mode combinations are allowed in DPDK",
1892  live_dev);
1893  }
1894  }
1895 
1896  return has_ips;
1897 }
1898 
1899 static int DPDKRunModeEnableIPS(void)
1900 {
1901  int r = DPDKRunModeIsIPS();
1902  if (r == 1) {
1903  SCLogInfo("Setting IPS mode");
1904  EngineModeSetIPS();
1905  }
1906  return r;
1907 }
1908 
1909 const char *RunModeDpdkGetDefaultMode(void)
1910 {
1911  return "workers";
1912 }
1913 
1915 {
1917  "Workers DPDK mode, each thread does all"
1918  " tasks from acquisition to logging",
1919  RunModeIdsDpdkWorkers, DPDKRunModeEnableIPS);
1920 }
1921 
1922 /**
1923  * \brief Workers version of the DPDK processing.
1924  *
1925  * Start N threads with each thread doing all the work.
1926  *
1927  */
1929 {
1930  SCEnter();
1931 #ifdef HAVE_DPDK
1932  int ret;
1933 
1934  TimeModeSetLive();
1935 
1936  InitEal();
1937  ret = RunModeSetLiveCaptureWorkers(ParseDpdkConfigAndConfigureDevice, DPDKConfigGetThreadsCount,
1938  "ReceiveDPDK", "DecodeDPDK", thread_name_workers, NULL);
1939  if (ret != 0) {
1940  FatalError("Unable to start runmode");
1941  }
1942 
1943  SCLogDebug("RunModeIdsDpdkWorkers initialised");
1944 
1945 #endif /* HAVE_DPDK */
1946  SCReturnInt(0);
1947 }
1948 
1949 /**
1950  * @}
1951  */
thread_name_workers
const char * thread_name_workers
Definition: runmodes.c:68
DPDKIfaceConfigAttributes_::checksum_checks_offload
const char * checksum_checks_offload
Definition: runmode-dpdk.h:32
util-byte.h
DPDKIfaceConfigAttributes_::mempool_size
const char * mempool_size
Definition: runmode-dpdk.h:37
threading_set_cpu_affinity
bool threading_set_cpu_affinity
Definition: runmodes.c:62
CHECKSUM_VALIDATION_OFFLOAD
@ CHECKSUM_VALIDATION_OFFLOAD
Definition: decode.h:48
RunModeSetLiveCaptureWorkers
int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
Definition: util-runmodes.c:321
DPDKIfaceConfigAttributes_::promisc
const char * promisc
Definition: runmode-dpdk.h:29
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
DPDKIfaceConfigAttributes_::mempool_cache_size
const char * mempool_cache_size
Definition: runmode-dpdk.h:38
DPDK_COPY_MODE_IPS
@ DPDK_COPY_MODE_IPS
Definition: source-dpdk.h:34
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
UtilAffinityGetAffinedCPUNum
uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf)
Definition: util-affinity.c:306
LiveDevice_
Definition: util-device.h:41
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
DPDKIfaceConfigAttributes_::copy_iface
const char * copy_iface
Definition: runmode-dpdk.h:42
StringParseUint16
int StringParseUint16(uint16_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:337
RunModeIdsDpdkWorkers
int RunModeIdsDpdkWorkers(void)
Workers version of the DPDK processing.
Definition: runmode-dpdk.c:1928
util-runmodes.h
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
MIN
#define MIN(x, y)
Definition: suricata-common.h:400
CHECKSUM_VALIDATION_DISABLE
@ CHECKSUM_VALIDATION_DISABLE
Definition: decode.h:43
RunmodeGetActive
char * RunmodeGetActive(void)
Definition: runmodes.c:199
StringParseInt32
int StringParseInt32(int32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:622
util-dpdk-rss.h
DPDKIfaceConfig_
Definition: source-dpdk.h:53
util-dpdk-ice.h
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
SCConfNodeIsSequence
int SCConfNodeIsSequence(const SCConfNode *node)
Check if a node is a sequence or node.
Definition: conf.c:925
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
SCReturnBool
#define SCReturnBool(x)
Definition: util-debug.h:289
CHECKSUM_VALIDATION_ENABLE
@ CHECKSUM_VALIDATION_ENABLE
Definition: decode.h:44
DPDKIfaceConfigAttributes_::linkup_timeout
const char * linkup_timeout
Definition: runmode-dpdk.h:36
RunModeDpdkGetDefaultMode
const char * RunModeDpdkGetDefaultMode(void)
Definition: runmode-dpdk.c:1909
decode.h
util-device.h
util-debug.h
SCConfGetChildValueIntWithDefault
int SCConfGetChildValueIntWithDefault(const SCConfNode *base, const SCConfNode *dflt, const char *name, intmax_t *val)
Definition: conf.c:476
DPDKIfaceConfigAttributes_::rx_descriptors
const char * rx_descriptors
Definition: runmode-dpdk.h:39
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
util-cpu.h
DPDKIfaceConfigAttributes_::checksum_checks
const char * checksum_checks
Definition: runmode-dpdk.h:31
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:248
DPDK_RX_CHECKSUM_OFFLOAD
#define DPDK_RX_CHECKSUM_OFFLOAD
Definition: source-dpdk.h:44
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
util-affinity.h
EngineModeSetIPS
void EngineModeSetIPS(void)
Definition: suricata.c:246
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
util-time.h
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
DPDKIfaceConfigAttributes_
Definition: runmode-dpdk.h:26
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:341
SCReturn
#define SCReturn
Definition: util-debug.h:273
DPDKIfaceConfigAttributes_::irq_mode
const char * irq_mode
Definition: runmode-dpdk.h:28
RunModeRegisterNewRunMode
void RunModeRegisterNewRunMode(enum SCRunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void), int(*RunModeIsIPSEnabled)(void))
Registers a new runmode.
Definition: runmodes.c:476
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:287
DPDKIfaceConfigAttributes_::vlan_strip_offload
const char * vlan_strip_offload
Definition: runmode-dpdk.h:34
BIT_U64
#define BIT_U64(n)
Definition: suricata-common.h:410
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
DPDKIfaceConfigAttributes_::threads
const char * threads
Definition: runmode-dpdk.h:27
TimeModeSetLive
void TimeModeSetLive(void)
Definition: util-time.c:99
DPDKIfaceConfigAttributes_::tx_descriptors
const char * tx_descriptors
Definition: runmode-dpdk.h:40
DPDK_IRQ_MODE
#define DPDK_IRQ_MODE
Definition: source-dpdk.h:42
util-dpdk.h
util-conf.h
SCConfNodeLookupKeyValue
SCConfNode * SCConfNodeLookupKeyValue(const SCConfNode *base, const char *key, const char *value)
Lookup for a key value under a specific node.
Definition: conf.c:841
SCConfGetChildValue
int SCConfGetChildValue(const SCConfNode *base, const char *name, const char **vptr)
Definition: conf.c:363
StringParseUint64
int StringParseUint64(uint64_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:308
source-dpdk.h
suricata-common.h
LiveGetDeviceName
const char * LiveGetDeviceName(int number)
Get a pointer to the device name at idx.
Definition: util-device.c:184
DPDK_PROMISC
#define DPDK_PROMISC
Definition: source-dpdk.h:40
FatalError
#define FatalError(...)
Definition: util-debug.h:502
SC_ATOMIC_RESET
#define SC_ATOMIC_RESET(name)
wrapper for reinitializing an atomic variable.
Definition: util-atomic.h:323
ThreadsAffinityType_
Definition: util-affinity.h:65
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:181
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
RUNMODE_DPDK
@ RUNMODE_DPDK
Definition: runmodes.h:39
util-dpdk-bonding.h
DPDKIfaceConfigAttributes_::multicast
const char * multicast
Definition: runmode-dpdk.h:30
RunModeDpdkRegister
void RunModeDpdkRegister(void)
Definition: runmode-dpdk.c:1914
util-dpdk-ixgbe.h
SCConfSetRootAndDefaultNodes
int SCConfSetRootAndDefaultNodes(const char *ifaces_node_name, const char *iface, SCConfNode **if_root, SCConfNode **if_default)
Finds and sets root and default node of the interface.
Definition: conf.c:962
util-dpdk-i40e.h
suricata.h
runmode-dpdk.h
SCConfNode_::name
char * name
Definition: conf.h:33
DPDKIfaceConfigAttributes_::rss_hf
const char * rss_hf
Definition: runmode-dpdk.h:35
ConfFindDeviceConfig
SCConfNode * ConfFindDeviceConfig(SCConfNode *node, const char *iface)
Find the configuration node for a specific device.
Definition: util-conf.c:121
GetAffinityTypeFromName
ThreadsAffinityType * GetAffinityTypeFromName(const char *name)
find affinity by its name
Definition: util-affinity.c:68
LiveGetDeviceCount
int LiveGetDeviceCount(void)
Get the number of registered devices.
Definition: util-device.c:164
SCConfGetChildValueWithDefault
int SCConfGetChildValueWithDefault(const SCConfNode *base, const SCConfNode *dflt, const char *name, const char **vptr)
Definition: conf.c:393
DPDKIfaceConfigAttributes_::mtu
const char * mtu
Definition: runmode-dpdk.h:33
DPDKIfaceConfigAttributes_::copy_mode
const char * copy_mode
Definition: runmode-dpdk.h:41
UtilCpuGetNumProcessorsOnline
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
Definition: util-cpu.c:108
SCConfGetChildValueBoolWithDefault
int SCConfGetChildValueBoolWithDefault(const SCConfNode *base, const SCConfNode *dflt, const char *name, int *val)
Definition: conf.c:528
util-dpdk-common.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCConfNode_
Definition: conf.h:32
SCConfNode_::val
char * val
Definition: conf.h:34
DPDK_COPY_MODE_TAP
@ DPDK_COPY_MODE_TAP
Definition: source-dpdk.h:34
DPDK_COPY_MODE_NONE
@ DPDK_COPY_MODE_NONE
Definition: source-dpdk.h:34
DPDK_MULTICAST
#define DPDK_MULTICAST
Definition: source-dpdk.h:41