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