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