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 "source-dpdk.h"
37 #include "util-runmodes.h"
38 #include "util-byte.h"
39 #include "util-cpu.h"
40 #include "util-dpdk.h"
41 #include "util-dpdk-i40e.h"
42 #include "util-dpdk-ice.h"
43 #include "util-dpdk-ixgbe.h"
44 #include "util-time.h"
45 
46 #ifdef HAVE_DPDK
47 
48 #define RSS_HKEY_LEN 40
49 // General purpose RSS key for symmetric bidirectional flow distribution
50 uint8_t rss_hkey[] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
51  0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
52  0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A };
53 
54 // Calculates the closest multiple of y from x
55 #define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y))
56 
57 /* Maximum DPDK EAL parameters count. */
58 #define EAL_ARGS 48
59 
60 struct Arguments {
61  uint16_t capacity;
62  char **argv;
63  uint16_t argc;
64 };
65 
66 static char *AllocArgument(size_t arg_len);
67 static char *AllocAndSetArgument(const char *arg);
68 static char *AllocAndSetOption(const char *arg);
69 
70 static void ArgumentsInit(struct Arguments *args, unsigned capacity);
71 static void ArgumentsCleanup(struct Arguments *args);
72 static void ArgumentsAdd(struct Arguments *args, char *value);
73 static void ArgumentsAddOptionAndArgument(struct Arguments *args, const char *opt, const char *arg);
74 static void InitEal(void);
75 
76 static void ConfigSetIface(DPDKIfaceConfig *iconf, const char *entry_str);
77 static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str);
78 static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues);
79 static int ConfigSetTxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues);
80 static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, intmax_t entry_int);
81 static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str);
82 static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, intmax_t entry_int);
83 static int ConfigSetTxDescriptors(DPDKIfaceConfig *iconf, intmax_t entry_int);
84 static int ConfigSetMtu(DPDKIfaceConfig *iconf, intmax_t entry_int);
85 static bool ConfigSetPromiscuousMode(DPDKIfaceConfig *iconf, int entry_bool);
86 static bool ConfigSetMulticast(DPDKIfaceConfig *iconf, int entry_bool);
87 static int ConfigSetChecksumChecks(DPDKIfaceConfig *iconf, int entry_bool);
88 static int ConfigSetChecksumOffload(DPDKIfaceConfig *iconf, int entry_bool);
89 static int ConfigSetCopyIface(DPDKIfaceConfig *iconf, const char *entry_str);
90 static int ConfigSetCopyMode(DPDKIfaceConfig *iconf, const char *entry_str);
91 static int ConfigSetCopyIfaceSettings(DPDKIfaceConfig *iconf, const char *iface, const char *mode);
92 static void ConfigInit(DPDKIfaceConfig **iconf);
93 static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface);
94 static DPDKIfaceConfig *ConfigParse(const char *iface);
95 
96 static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
97  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf);
98 static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info,
99  const struct rte_eth_conf *port_conf);
100 static int DeviceValidateOutIfaceConfig(DPDKIfaceConfig *iconf);
101 static int DeviceConfigureIPS(DPDKIfaceConfig *iconf);
102 static int DeviceConfigure(DPDKIfaceConfig *iconf);
103 static void *ParseDpdkConfigAndConfigureDevice(const char *iface);
104 static void DPDKDerefConfig(void *conf);
105 
106 #define DPDK_CONFIG_DEFAULT_THREADS "auto"
107 #define DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE 65535
108 #define DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE "auto"
109 #define DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS 1024
110 #define DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS 1024
111 #define DPDK_CONFIG_DEFAULT_MTU 1500
112 #define DPDK_CONFIG_DEFAULT_PROMISCUOUS_MODE 1
113 #define DPDK_CONFIG_DEFAULT_MULTICAST_MODE 1
114 #define DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION 1
115 #define DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION_OFFLOAD 1
116 #define DPDK_CONFIG_DEFAULT_COPY_MODE "none"
117 #define DPDK_CONFIG_DEFAULT_COPY_INTERFACE "none"
118 
119 DPDKIfaceConfigAttributes dpdk_yaml = {
120  .threads = "threads",
121  .promisc = "promisc",
122  .multicast = "multicast",
123  .checksum_checks = "checksum-checks",
124  .checksum_checks_offload = "checksum-checks-offload",
125  .mtu = "mtu",
126  .mempool_size = "mempool-size",
127  .mempool_cache_size = "mempool-cache-size",
128  .rx_descriptors = "rx-descriptors",
129  .tx_descriptors = "tx-descriptors",
130  .copy_mode = "copy-mode",
131  .copy_iface = "copy-iface",
132 };
133 
134 static int GreatestDivisorUpTo(uint32_t num, uint32_t max_num)
135 {
136  for (int i = max_num; i >= 2; i--) {
137  if (num % i == 0) {
138  return i;
139  }
140  }
141  return 1;
142 }
143 
144 static char *AllocArgument(size_t arg_len)
145 {
146  SCEnter();
147  char *ptr;
148 
149  arg_len += 1; // null character
150  ptr = (char *)SCCalloc(arg_len, sizeof(char));
151  if (ptr == NULL)
152  FatalError(SC_ERR_MEM_ALLOC, "Could not allocate memory for an argument");
153 
154  SCReturnPtr(ptr, "char *");
155 }
156 
157 /**
158  * Allocates space for length of the given string and then copies contents
159  * @param arg String to set to the newly allocated space
160  * @return memory address if no error otherwise NULL (with errno set)
161  */
162 static char *AllocAndSetArgument(const char *arg)
163 {
164  SCEnter();
165  if (arg == NULL)
166  FatalError(SC_ERR_DPDK_CONF, "Passed argument is NULL in DPDK config initialization");
167 
168  char *ptr;
169  size_t arg_len = strlen(arg);
170 
171  ptr = AllocArgument(arg_len);
172  strlcpy(ptr, arg, arg_len + 1);
173  SCReturnPtr(ptr, "char *");
174 }
175 
176 static char *AllocAndSetOption(const char *arg)
177 {
178  SCEnter();
179  if (arg == NULL)
180  FatalError(SC_ERR_DPDK_CONF, "Passed option is NULL in DPDK config initialization");
181 
182  char *ptr = NULL;
183  size_t arg_len = strlen(arg);
184  uint8_t is_long_arg = arg_len > 1;
185  const char *dash_prefix = is_long_arg ? "--" : "-";
186  size_t full_len = arg_len + strlen(dash_prefix);
187 
188  ptr = AllocArgument(full_len);
189  strlcpy(ptr, dash_prefix, strlen(dash_prefix) + 1);
190  strlcat(ptr, arg, full_len + 1);
191  SCReturnPtr(ptr, "char *");
192 }
193 
194 static void ArgumentsInit(struct Arguments *args, unsigned capacity)
195 {
196  SCEnter();
197  args->argv = SCCalloc(capacity, sizeof(args->argv));
198  if (args->argv == NULL)
199  FatalError(SC_ERR_MEM_ALLOC, "Could not allocate memory for Arguments structure");
200 
201  args->capacity = capacity;
202  args->argc = 0;
203  SCReturn;
204 }
205 
206 static void ArgumentsCleanup(struct Arguments *args)
207 {
208  SCEnter();
209  for (int i = 0; i < args->argc; i++) {
210  if (args->argv[i] != NULL) {
211  SCFree(args->argv[i]);
212  args->argv[i] = NULL;
213  }
214  }
215 
216  SCFree(args->argv);
217  args->argv = NULL;
218  args->argc = 0;
219  args->capacity = 0;
220 }
221 
222 static void ArgumentsAdd(struct Arguments *args, char *value)
223 {
224  SCEnter();
225  if (args->argc + 1 > args->capacity)
226  FatalError(SC_ERR_DPDK_EAL_INIT, "No capacity for more arguments (Max: %" PRIu32 ")",
227  EAL_ARGS);
228 
229  args->argv[args->argc++] = value;
230  SCReturn;
231 }
232 
233 static void ArgumentsAddOptionAndArgument(struct Arguments *args, const char *opt, const char *arg)
234 {
235  SCEnter();
236  char *option;
237  char *argument;
238 
239  option = AllocAndSetOption(opt);
240  ArgumentsAdd(args, option);
241 
242  // Empty argument could mean option only (e.g. --no-huge)
243  if (arg == NULL || arg[0] == '\0')
244  SCReturn;
245 
246  argument = AllocAndSetArgument(arg);
247  ArgumentsAdd(args, argument);
248  SCReturn;
249 }
250 
251 static void InitEal()
252 {
253  SCEnter();
254  int retval;
255  ConfNode *param;
256  const ConfNode *eal_params = ConfGetNode("dpdk.eal-params");
257  struct Arguments args;
258  char **eal_argv;
259 
260  if (eal_params == NULL) {
261  FatalError(SC_ERR_DPDK_CONF, "DPDK EAL parameters not found in the config");
262  }
263 
264  ArgumentsInit(&args, EAL_ARGS);
265  ArgumentsAdd(&args, AllocAndSetArgument("suricata"));
266 
267  TAILQ_FOREACH (param, &eal_params->head, next) {
268  ArgumentsAddOptionAndArgument(&args, param->name, param->val);
269  }
270 
271  // creating a shallow copy for cleanup because rte_eal_init changes array contents
272  eal_argv = SCMalloc(args.argc * sizeof(args.argv));
273  if (eal_argv == NULL) {
274  FatalError(
275  SC_ERR_MEM_ALLOC, "Failed to allocate memory for the array of DPDK EAL arguments");
276  }
277  memcpy(eal_argv, args.argv, args.argc * sizeof(*args.argv));
278 
279  rte_log_set_global_level(RTE_LOG_WARNING);
280  retval = rte_eal_init(args.argc, eal_argv);
281 
282  ArgumentsCleanup(&args);
283  SCFree(eal_argv);
284 
285  if (retval < 0) { // retval binded to the result of rte_eal_init
286  FatalError(
287  SC_ERR_DPDK_EAL_INIT, "DPDK EAL initialization error: %s", rte_strerror(-retval));
288  }
289 }
290 
291 static void DPDKDerefConfig(void *conf)
292 {
293  SCEnter();
294  DPDKIfaceConfig *iconf = (DPDKIfaceConfig *)conf;
295 
296  if (SC_ATOMIC_SUB(iconf->ref, 1) == 1) {
297  if (iconf->pkt_mempool != NULL) {
298  rte_mempool_free(iconf->pkt_mempool);
299  }
300 
301  SCFree(iconf);
302  }
303  SCReturn;
304 }
305 
306 static void ConfigInit(DPDKIfaceConfig **iconf)
307 {
308  SCEnter();
309  DPDKIfaceConfig *ptr = NULL;
310  ptr = SCCalloc(1, sizeof(DPDKIfaceConfig));
311  if (ptr == NULL)
312  FatalError(SC_ERR_DPDK_CONF, "Could not allocate memory for DPDKIfaceConfig");
313 
314  ptr->pkt_mempool = NULL;
315  ptr->out_port_id = -1; // make sure no port is set
316  SC_ATOMIC_INIT(ptr->ref);
317  (void)SC_ATOMIC_ADD(ptr->ref, 1);
318  ptr->DerefFunc = DPDKDerefConfig;
319  ptr->flags = 0;
320 
321  *iconf = ptr;
322  SCReturn;
323 }
324 
325 static void ConfigSetIface(DPDKIfaceConfig *iconf, const char *entry_str)
326 {
327  SCEnter();
328  int retval;
329 
330  if (entry_str == NULL || entry_str[0] == '\0')
331  FatalError(SC_ERR_INVALID_VALUE, "Interface name in DPDK config is NULL or empty");
332 
333  retval = rte_eth_dev_get_port_by_name(entry_str, &iconf->port_id);
334  if (retval < 0)
335  FatalError(SC_ERR_DPDK_CONF, "Interface \"%s\": %s", entry_str, rte_strerror(-retval));
336 
337  strlcpy(iconf->iface, entry_str, sizeof(iconf->iface));
338  SCReturn;
339 }
340 
341 static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str)
342 {
343  SCEnter();
344  const char *active_runmode = RunmodeGetActive();
345 
346  if (active_runmode && !strcmp("single", active_runmode)) {
347  iconf->threads = 1;
348  SCReturnInt(0);
349  }
350 
351  if (entry_str == NULL) {
352  SCLogError(SC_ERR_INVALID_VALUE, "Number of threads for interface \"%s\" not specified",
353  iconf->iface);
354  SCReturnInt(-EINVAL);
355  }
356 
357  if (strcmp(entry_str, "auto") == 0) {
358  iconf->threads = (int)UtilCpuGetNumProcessorsOnline();
359  SCLogPerf("%u cores, so using %u threads", iconf->threads, iconf->threads);
360  SCReturnInt(0);
361  }
362 
363  if (StringParseInt32(&iconf->threads, 10, 0, entry_str) < 0) {
365  "Threads entry for interface %s contain non-numerical characters - \"%s\"",
366  iconf->iface, entry_str);
367  SCReturnInt(-EINVAL);
368  }
369 
370  if (iconf->threads < 0) {
371  SCLogError(SC_ERR_INVALID_VALUE, "Interface %s has a negative number of threads",
372  iconf->iface);
373  SCReturnInt(-ERANGE);
374  }
375 
376  SCReturnInt(0);
377 }
378 
379 static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues)
380 {
381  SCEnter();
382  iconf->nb_rx_queues = nb_queues;
383  if (iconf->nb_rx_queues < 1) {
385  "Interface %s requires to have positive number of RX queues", iconf->iface);
386  SCReturnInt(-ERANGE);
387  }
388 
389  SCReturnInt(0);
390 }
391 
392 static int ConfigSetTxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues)
393 {
394  SCEnter();
395  iconf->nb_tx_queues = nb_queues;
396  if (iconf->nb_tx_queues < 1) {
398  "Interface %s requires to have positive number of TX queues", iconf->iface);
399  SCReturnInt(-ERANGE);
400  }
401 
402  SCReturnInt(0);
403 }
404 
405 static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, intmax_t entry_int)
406 {
407  SCEnter();
408  if (entry_int <= 0) {
409  SCLogError(SC_ERR_INVALID_VALUE, "Interface %s requires to have positive memory pool size",
410  iconf->iface);
411  SCReturnInt(-ERANGE);
412  }
413 
414  iconf->mempool_size = entry_int;
415  SCReturnInt(0);
416 }
417 
418 static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str)
419 {
420  SCEnter();
421  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
422  // calculate the mempool size based on the mempool size (it needs to be already filled in)
423  // It is advised to have mempool cache size lower or equal to:
424  // RTE_MEMPOOL_CACHE_MAX_SIZE (by default 512) and "mempool-size / 1.5"
425  // and at the same time "mempool-size modulo cache_size == 0".
426  if (iconf->mempool_size == 0) {
428  "Cannot calculate mempool cache size of a mempool with size %d",
429  iconf->mempool_size);
430  SCReturnInt(-EINVAL);
431  }
432 
433  uint32_t max_cache_size = MAX(RTE_MEMPOOL_CACHE_MAX_SIZE, iconf->mempool_size / 1.5);
434  iconf->mempool_cache_size = GreatestDivisorUpTo(iconf->mempool_size, max_cache_size);
435  SCReturnInt(0);
436  }
437 
438  if (StringParseUint32(&iconf->mempool_cache_size, 10, 0, entry_str) < 0) {
440  "Mempool cache size entry for interface %s contain non-numerical "
441  "characters - \"%s\"",
442  iconf->iface, entry_str);
443  SCReturnInt(-EINVAL);
444  }
445 
446  if (iconf->mempool_cache_size <= 0 || iconf->mempool_cache_size > RTE_MEMPOOL_CACHE_MAX_SIZE) {
448  "Interface %s requires to have positive memory pool size and be less than %" PRIu32,
449  iconf->iface, RTE_MEMPOOL_CACHE_MAX_SIZE);
450  SCReturnInt(-ERANGE);
451  }
452 
453  SCReturnInt(0);
454 }
455 
456 static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, intmax_t entry_int)
457 {
458  SCEnter();
459  if (entry_int <= 0) {
461  "Interface %s requires to have positive number of RX descriptors", iconf->iface);
462  SCReturnInt(-ERANGE);
463  }
464 
465  iconf->nb_rx_desc = entry_int;
466  SCReturnInt(0);
467 }
468 
469 static int ConfigSetTxDescriptors(DPDKIfaceConfig *iconf, intmax_t entry_int)
470 {
471  SCEnter();
472  if (entry_int <= 0) {
474  "Interface %s requires to have positive number of TX descriptors", iconf->iface);
475  SCReturnInt(-ERANGE);
476  }
477 
478  iconf->nb_tx_desc = entry_int;
479  SCReturnInt(0);
480 }
481 
482 static int ConfigSetMtu(DPDKIfaceConfig *iconf, intmax_t entry_int)
483 {
484  SCEnter();
485  if (entry_int < RTE_ETHER_MIN_MTU || entry_int > RTE_ETHER_MAX_JUMBO_FRAME_LEN) {
487  "Interface %s requires to have size of MTU between %" PRIu32 " and %" PRIu32,
488  iconf->iface, RTE_ETHER_MIN_MTU, RTE_ETHER_MAX_JUMBO_FRAME_LEN);
489  SCReturnInt(-ERANGE);
490  }
491 
492  iconf->mtu = entry_int;
493  SCReturnInt(0);
494 }
495 
496 static bool ConfigSetPromiscuousMode(DPDKIfaceConfig *iconf, int entry_bool)
497 {
498  SCEnter();
499  if (entry_bool)
500  iconf->flags |= DPDK_PROMISC;
501 
502  SCReturnBool(true);
503 }
504 
505 static bool ConfigSetMulticast(DPDKIfaceConfig *iconf, int entry_bool)
506 {
507  SCEnter();
508  if (entry_bool)
509  iconf->flags |= DPDK_MULTICAST; // enable
510 
511  SCReturnBool(true);
512 }
513 
514 static int ConfigSetChecksumChecks(DPDKIfaceConfig *iconf, int entry_bool)
515 {
516  SCEnter();
517  if (entry_bool)
518  iconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
519 
520  SCReturnInt(0);
521 }
522 
523 static int ConfigSetChecksumOffload(DPDKIfaceConfig *iconf, int entry_bool)
524 {
525  SCEnter();
526  if (entry_bool)
527  iconf->flags |= DPDK_RX_CHECKSUM_OFFLOAD;
528 
529  SCReturnInt(0);
530 }
531 
532 static int ConfigSetCopyIface(DPDKIfaceConfig *iconf, const char *entry_str)
533 {
534  SCEnter();
535  int retval;
536 
537  if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "none") == 0) {
538  iconf->out_iface = NULL;
539  SCReturnInt(0);
540  }
541 
542  retval = rte_eth_dev_get_port_by_name(entry_str, &iconf->out_port_id);
543  if (retval < 0) {
545  "Name of the copy interface (%s) for the interface %s is not valid, changing to %s",
546  entry_str, iconf->iface, DPDK_CONFIG_DEFAULT_COPY_INTERFACE);
547  iconf->out_iface = DPDK_CONFIG_DEFAULT_COPY_INTERFACE;
548  }
549 
550  iconf->out_iface = entry_str;
551  SCReturnInt(0);
552 }
553 
554 static int ConfigSetCopyMode(DPDKIfaceConfig *iconf, const char *entry_str)
555 {
556  SCEnter();
557  if (entry_str == NULL) {
559  "Interface %s has no copy mode specified, changing to %s ", iconf->iface,
560  DPDK_CONFIG_DEFAULT_COPY_MODE);
561  entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
562  }
563 
564  if (strcmp(entry_str, "none") != 0 && strcmp(entry_str, "tap") != 0 &&
565  strcmp(entry_str, "ips") != 0) {
567  "Copy mode \"%s\" is not one of the possible values (none|tap|ips) for interface "
568  "%s. Changing to %s",
569  entry_str, iconf->iface, DPDK_CONFIG_DEFAULT_COPY_MODE);
570  entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
571  }
572 
573  if (strcmp(entry_str, "none") == 0) {
574  iconf->copy_mode = DPDK_COPY_MODE_NONE;
575  } else if (strcmp(entry_str, "tap") == 0) {
576  iconf->copy_mode = DPDK_COPY_MODE_TAP;
577  } else if (strcmp(entry_str, "ips") == 0) {
578  iconf->copy_mode = DPDK_COPY_MODE_IPS;
579  }
580 
581  SCReturnInt(0);
582 }
583 
584 static int ConfigSetCopyIfaceSettings(DPDKIfaceConfig *iconf, const char *iface, const char *mode)
585 {
586  SCEnter();
587  int retval;
588 
589  retval = ConfigSetCopyIface(iconf, iface);
590  if (retval < 0)
591  SCReturnInt(retval);
592 
593  retval = ConfigSetCopyMode(iconf, mode);
594  if (retval < 0)
595  SCReturnInt(retval);
596 
597  if (iconf->copy_mode == DPDK_COPY_MODE_NONE) {
598  if (iconf->out_iface != NULL)
599  iconf->out_iface = NULL;
600  SCReturnInt(0);
601  }
602 
603  if (iconf->out_iface == NULL || strlen(iconf->out_iface) <= 0) {
604  SCLogError(SC_ERR_DPDK_CONF, "Copy mode enabled but interface not set");
605  SCReturnInt(-EINVAL);
606  }
607 
608  if (iconf->copy_mode == DPDK_COPY_MODE_IPS)
609  SCLogInfo("DPDK IPS mode activated between %s and %s", iconf->iface, iconf->out_iface);
610  else if (iconf->copy_mode == DPDK_COPY_MODE_TAP)
611  SCLogInfo("DPDK IPS mode activated between %s and %s", iconf->iface, iconf->out_iface);
612 
613  SCReturnInt(0);
614 }
615 
616 static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface)
617 {
618  SCEnter();
619  int retval;
620  ConfNode *if_root;
621  ConfNode *if_default;
622  const char *entry_str = NULL;
623  intmax_t entry_int = 0;
624  int entry_bool = 0;
625  const char *copy_iface_str = NULL;
626  const char *copy_mode_str = NULL;
627 
628  ConfigSetIface(iconf, iface);
629 
630  retval = ConfSetRootAndDefaultNodes("dpdk.interfaces", iconf->iface, &if_root, &if_default);
631  if (retval < 0) {
632  FatalError(SC_ERR_DPDK_CONF, "failed to find DPDK configuration for the interface %s",
633  iconf->iface);
634  }
635 
636  retval = ConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.threads, &entry_str) != 1
637  ? ConfigSetThreads(iconf, DPDK_CONFIG_DEFAULT_THREADS)
638  : ConfigSetThreads(iconf, entry_str);
639  if (retval < 0)
640  SCReturnInt(retval);
641 
642  // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
643  retval = ConfigSetRxQueues(iconf, (uint16_t)iconf->threads);
644  if (retval < 0)
645  SCReturnInt(retval);
646 
647  // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
648  retval = ConfigSetTxQueues(iconf, (uint16_t)iconf->threads);
649  if (retval < 0)
650  SCReturnInt(retval);
651 
653  if_root, if_default, dpdk_yaml.mempool_size, &entry_int) != 1
654  ? ConfigSetMempoolSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE)
655  : ConfigSetMempoolSize(iconf, entry_int);
656  if (retval < 0)
657  SCReturnInt(retval);
658 
660  if_root, if_default, dpdk_yaml.mempool_cache_size, &entry_str) != 1
661  ? ConfigSetMempoolCacheSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE)
662  : ConfigSetMempoolCacheSize(iconf, entry_str);
663  if (retval < 0)
664  SCReturnInt(retval);
665 
667  if_root, if_default, dpdk_yaml.rx_descriptors, &entry_int) != 1
668  ? ConfigSetRxDescriptors(iconf, DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS)
669  : ConfigSetRxDescriptors(iconf, entry_int);
670  if (retval < 0)
671  SCReturnInt(retval);
672 
674  if_root, if_default, dpdk_yaml.tx_descriptors, &entry_int) != 1
675  ? ConfigSetTxDescriptors(iconf, DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS)
676  : ConfigSetTxDescriptors(iconf, entry_int);
677  if (retval < 0)
678  SCReturnInt(retval);
679 
680  retval = ConfGetChildValueIntWithDefault(if_root, if_default, dpdk_yaml.mtu, &entry_int) != 1
681  ? ConfigSetMtu(iconf, DPDK_CONFIG_DEFAULT_MTU)
682  : ConfigSetMtu(iconf, entry_int);
683  if (retval < 0)
684  SCReturnInt(retval);
685 
687  if_root, if_default, dpdk_yaml.promisc, &entry_bool) != 1
688  ? ConfigSetPromiscuousMode(iconf, DPDK_CONFIG_DEFAULT_PROMISCUOUS_MODE)
689  : ConfigSetPromiscuousMode(iconf, entry_bool);
690  if (retval != true)
691  SCReturnInt(-EINVAL);
692 
694  if_root, if_default, dpdk_yaml.multicast, &entry_bool) != 1
695  ? ConfigSetMulticast(iconf, DPDK_CONFIG_DEFAULT_MULTICAST_MODE)
696  : ConfigSetMulticast(iconf, entry_bool);
697  if (retval != true)
698  SCReturnInt(-EINVAL);
699 
701  if_root, if_default, dpdk_yaml.checksum_checks, &entry_bool) != 1
702  ? ConfigSetChecksumChecks(iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION)
703  : ConfigSetChecksumChecks(iconf, entry_bool);
704  if (retval < 0)
705  SCReturnInt(retval);
706 
708  if_root, if_default, dpdk_yaml.checksum_checks_offload, &entry_bool) != 1
709  ? ConfigSetChecksumOffload(
710  iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION_OFFLOAD)
711  : ConfigSetChecksumOffload(iconf, entry_bool);
712  if (retval < 0)
713  SCReturnInt(retval);
714 
715  retval =
716  ConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.copy_mode, &copy_mode_str) |
718  if_root, if_default, dpdk_yaml.copy_iface, &copy_iface_str);
719  // if one of copy interface settings fail to load then the default values are set
720  retval = retval != 1 ? ConfigSetCopyIfaceSettings(iconf, DPDK_CONFIG_DEFAULT_COPY_INTERFACE,
721  DPDK_CONFIG_DEFAULT_COPY_MODE)
722  : ConfigSetCopyIfaceSettings(iconf, copy_iface_str, copy_mode_str);
723  if (retval < 0)
724  SCReturnInt(retval);
725 
726  SCReturnInt(0);
727 }
728 
729 static DPDKIfaceConfig *ConfigParse(const char *iface)
730 {
731  SCEnter();
732  int retval;
733  DPDKIfaceConfig *iconf = NULL;
734  if (iface == NULL)
735  FatalError(SC_ERR_DPDK_CONF, "DPDK interface is NULL");
736 
737  ConfigInit(&iconf);
738  retval = ConfigLoad(iconf, iface);
739  if (retval < 0) {
740  iconf->DerefFunc(iconf);
741  SCReturnPtr(NULL, "void *");
742  }
743 
744  SCReturnPtr(iconf, "DPDKIfaceConfig *");
745 }
746 
747 static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const char *driver_name)
748 {
749  // RSS is configured in a specific way for a driver i40e and DPDK version <= 19.xx
750  if (strcmp(driver_name, "net_i40e") == 0)
751  i40eDeviceSetRSSHashFunction(&rss_conf->rss_hf);
752  if (strcmp(driver_name, "net_ice") == 0)
753  iceDeviceSetRSSHashFunction(&rss_conf->rss_hf);
754  if (strcmp(driver_name, "net_ixgbe") == 0)
755  ixgbeDeviceSetRSSHashFunction(&rss_conf->rss_hf);
756 }
757 
758 static void DumpRSSFlags(const uint64_t requested, const uint64_t actual)
759 {
760  SCLogConfig("REQUESTED (groups):");
761 
762  SCLogConfig("ETH_RSS_IP %sset", ((requested & ETH_RSS_IP) == ETH_RSS_IP) ? "" : "NOT ");
763  SCLogConfig("ETH_RSS_TCP %sset", ((requested & ETH_RSS_TCP) == ETH_RSS_TCP) ? "" : "NOT ");
764  SCLogConfig("ETH_RSS_UDP %sset", ((requested & ETH_RSS_UDP) == ETH_RSS_UDP) ? "" : "NOT ");
765  SCLogConfig("ETH_RSS_SCTP %sset", ((requested & ETH_RSS_SCTP) == ETH_RSS_SCTP) ? "" : "NOT ");
766  SCLogConfig(
767  "ETH_RSS_TUNNEL %sset", ((requested & ETH_RSS_TUNNEL) == ETH_RSS_TUNNEL) ? "" : "NOT ");
768 
769  SCLogConfig("REQUESTED (individual):");
770  SCLogConfig("ETH_RSS_IPV4 %sset", (requested & ETH_RSS_IPV4) ? "" : "NOT ");
771  SCLogConfig("ETH_RSS_FRAG_IPV4 %sset", (requested & ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
772  SCLogConfig(
773  "ETH_RSS_NONFRAG_IPV4_TCP %sset", (requested & ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
774  SCLogConfig(
775  "ETH_RSS_NONFRAG_IPV4_UDP %sset", (requested & ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
776  SCLogConfig("ETH_RSS_NONFRAG_IPV4_SCTP %sset",
777  (requested & ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
778  SCLogConfig("ETH_RSS_NONFRAG_IPV4_OTHER %sset",
779  (requested & ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
780  SCLogConfig("ETH_RSS_IPV6 %sset", (requested & ETH_RSS_IPV6) ? "" : "NOT ");
781  SCLogConfig("ETH_RSS_FRAG_IPV6 %sset", (requested & ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
782  SCLogConfig(
783  "ETH_RSS_NONFRAG_IPV6_TCP %sset", (requested & ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
784  SCLogConfig(
785  "ETH_RSS_NONFRAG_IPV6_UDP %sset", (requested & ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
786  SCLogConfig("ETH_RSS_NONFRAG_IPV6_SCTP %sset",
787  (requested & ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
788  SCLogConfig("ETH_RSS_NONFRAG_IPV6_OTHER %sset",
789  (requested & ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
790 
791  SCLogConfig("ETH_RSS_L2_PAYLOAD %sset", (requested & ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
792  SCLogConfig("ETH_RSS_IPV6_EX %sset", (requested & ETH_RSS_IPV6_EX) ? "" : "NOT ");
793  SCLogConfig("ETH_RSS_IPV6_TCP_EX %sset", (requested & ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
794  SCLogConfig("ETH_RSS_IPV6_UDP_EX %sset", (requested & ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
795 
796  SCLogConfig("ETH_RSS_PORT %sset", (requested & ETH_RSS_PORT) ? "" : "NOT ");
797  SCLogConfig("ETH_RSS_VXLAN %sset", (requested & ETH_RSS_VXLAN) ? "" : "NOT ");
798  SCLogConfig("ETH_RSS_NVGRE %sset", (requested & ETH_RSS_NVGRE) ? "" : "NOT ");
799  SCLogConfig("ETH_RSS_GTPU %sset", (requested & ETH_RSS_GTPU) ? "" : "NOT ");
800 
801  SCLogConfig("ETH_RSS_L3_SRC_ONLY %sset", (requested & ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
802  SCLogConfig("ETH_RSS_L3_DST_ONLY %sset", (requested & ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
803  SCLogConfig("ETH_RSS_L4_SRC_ONLY %sset", (requested & ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
804  SCLogConfig("ETH_RSS_L4_DST_ONLY %sset", (requested & ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
805 
806  SCLogConfig("ACTUAL (group):");
807  SCLogConfig("ETH_RSS_IP %sset", ((actual & ETH_RSS_IP) == ETH_RSS_IP) ? "" : "NOT ");
808  SCLogConfig("ETH_RSS_TCP %sset", ((actual & ETH_RSS_TCP) == ETH_RSS_TCP) ? "" : "NOT ");
809  SCLogConfig("ETH_RSS_UDP %sset", ((actual & ETH_RSS_UDP) == ETH_RSS_UDP) ? "" : "NOT ");
810  SCLogConfig("ETH_RSS_SCTP %sset", ((actual & ETH_RSS_SCTP) == ETH_RSS_SCTP) ? "" : "NOT ");
811  SCLogConfig(
812  "ETH_RSS_TUNNEL %sset", ((actual & ETH_RSS_TUNNEL) == ETH_RSS_TUNNEL) ? "" : "NOT ");
813 
814  SCLogConfig("ACTUAL (individual flags):");
815  SCLogConfig("ETH_RSS_IPV4 %sset", (actual & ETH_RSS_IPV4) ? "" : "NOT ");
816  SCLogConfig("ETH_RSS_FRAG_IPV4 %sset", (actual & ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
817  SCLogConfig(
818  "ETH_RSS_NONFRAG_IPV4_TCP %sset", (actual & ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
819  SCLogConfig(
820  "ETH_RSS_NONFRAG_IPV4_UDP %sset", (actual & ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
821  SCLogConfig(
822  "ETH_RSS_NONFRAG_IPV4_SCTP %sset", (actual & ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
823  SCLogConfig("ETH_RSS_NONFRAG_IPV4_OTHER %sset",
824  (actual & ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
825  SCLogConfig("ETH_RSS_IPV6 %sset", (actual & ETH_RSS_IPV6) ? "" : "NOT ");
826  SCLogConfig("ETH_RSS_FRAG_IPV6 %sset", (actual & ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
827  SCLogConfig(
828  "ETH_RSS_NONFRAG_IPV6_TCP %sset", (actual & ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
829  SCLogConfig(
830  "ETH_RSS_NONFRAG_IPV6_UDP %sset", (actual & ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
831  SCLogConfig(
832  "ETH_RSS_NONFRAG_IPV6_SCTP %sset", (actual & ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
833  SCLogConfig("ETH_RSS_NONFRAG_IPV6_OTHER %sset",
834  (actual & ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
835 
836  SCLogConfig("ETH_RSS_L2_PAYLOAD %sset", (actual & ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
837  SCLogConfig("ETH_RSS_IPV6_EX %sset", (actual & ETH_RSS_IPV6_EX) ? "" : "NOT ");
838  SCLogConfig("ETH_RSS_IPV6_TCP_EX %sset", (actual & ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
839  SCLogConfig("ETH_RSS_IPV6_UDP_EX %sset", (actual & ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
840 
841  SCLogConfig("ETH_RSS_PORT %sset", (actual & ETH_RSS_PORT) ? "" : "NOT ");
842  SCLogConfig("ETH_RSS_VXLAN %sset", (actual & ETH_RSS_VXLAN) ? "" : "NOT ");
843  SCLogConfig("ETH_RSS_NVGRE %sset", (actual & ETH_RSS_NVGRE) ? "" : "NOT ");
844  SCLogConfig("ETH_RSS_GTPU %sset", (actual & ETH_RSS_GTPU) ? "" : "NOT ");
845 
846  SCLogConfig("ETH_RSS_L3_SRC_ONLY %sset", (actual & ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
847  SCLogConfig("ETH_RSS_L3_DST_ONLY %sset", (actual & ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
848  SCLogConfig("ETH_RSS_L4_SRC_ONLY %sset", (actual & ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
849  SCLogConfig("ETH_RSS_L4_DST_ONLY %sset", (actual & ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
850 }
851 
852 static int DeviceValidateMTU(const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
853 {
854  if (iconf->mtu > dev_info->max_mtu || iconf->mtu < dev_info->min_mtu) {
856  "Loaded MTU of \"%s\" is out of bounds. "
857  "Min MTU: %" PRIu16 " Max MTU: %" PRIu16,
858  iconf->iface, dev_info->min_mtu, dev_info->max_mtu);
859  SCReturnInt(-ERANGE);
860  }
861 
862 #if RTE_VER_YEAR < 21 || RTE_VER_YEAR == 21 && RTE_VER_MONTH < 11
863  // check if jumbo frames are set and are available
864  if (iconf->mtu > RTE_ETHER_MAX_LEN &&
865  !(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME)) {
866  SCLogError(SC_ERR_DPDK_CONF, "Jumbo frames not supported, set MTU of \"%s\" to 1500B",
867  iconf->iface);
868  SCReturnInt(-EINVAL);
869  }
870 #endif
871 
872  SCReturnInt(0);
873 }
874 
875 static void DeviceSetMTU(struct rte_eth_conf *port_conf, uint16_t mtu)
876 {
877 #if RTE_VER_YEAR > 21 || RTE_VER_YEAR == 21 && RTE_VER_MONTH == 11
878  port_conf->rxmode.mtu = mtu;
879 #else
880  port_conf->rxmode.max_rx_pkt_len = mtu;
881  if (mtu > RTE_ETHER_MAX_LEN) {
882  port_conf->rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
883  }
884 #endif
885 }
886 
887 static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
888  const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
889 {
890  *port_conf = (struct rte_eth_conf){
891  .rxmode = {
892  .mq_mode = ETH_MQ_RX_NONE,
893  .offloads = 0, // turn every offload off to prevent any packet modification
894  },
895  .txmode = {
896  .mq_mode = ETH_MQ_TX_NONE,
897  .offloads = 0,
898  },
899  };
900 
901  // configure RX offloads
902  if (dev_info->rx_offload_capa & DEV_RX_OFFLOAD_RSS_HASH) {
903  if (iconf->nb_rx_queues > 1) {
904  SCLogConfig("RSS enabled on %s for %d queues", iconf->iface, iconf->nb_rx_queues);
905  port_conf->rx_adv_conf.rss_conf = (struct rte_eth_rss_conf){
906  .rss_key = rss_hkey,
907  .rss_key_len = RSS_HKEY_LEN,
908  .rss_hf = ETH_RSS_IP,
909  };
910 
911  DeviceSetPMDSpecificRSS(&port_conf->rx_adv_conf.rss_conf, dev_info->driver_name);
912 
913  uint64_t rss_hf_tmp =
914  port_conf->rx_adv_conf.rss_conf.rss_hf & dev_info->flow_type_rss_offloads;
915  if (port_conf->rx_adv_conf.rss_conf.rss_hf != rss_hf_tmp) {
916  DumpRSSFlags(port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
917 
919  "Interface %s modified RSS hash function based on hardware support, "
920  "requested:%#" PRIx64 " configured:%#" PRIx64,
921  iconf->iface, port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
922  port_conf->rx_adv_conf.rss_conf.rss_hf = rss_hf_tmp;
923  }
924  port_conf->rxmode.mq_mode = ETH_MQ_RX_RSS;
925  } else {
926  SCLogConfig("RSS not enabled on %s", iconf->iface);
927  port_conf->rx_adv_conf.rss_conf.rss_key = NULL;
928  port_conf->rx_adv_conf.rss_conf.rss_hf = 0;
929  }
930  } else {
931  SCLogConfig("RSS not supported on %s", iconf->iface);
932  }
933 
934  if (iconf->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
935  SCLogConfig("Checksum validation disabled on %s", iconf->iface);
936  } else if (dev_info->rx_offload_capa & DEV_RX_OFFLOAD_CHECKSUM) {
937  if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
938  iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD) {
939  SCLogConfig("IP, TCP and UDP checksum validation enabled and offloaded "
940  "on %s",
941  iconf->iface);
942  port_conf->rxmode.offloads |= DEV_RX_OFFLOAD_CHECKSUM;
943  } else if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
944  !(iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD)) {
945  SCLogConfig("Suricata checksum validation enabled (but can be offloaded on %s)",
946  iconf->iface);
947  }
948  }
949 
950  DeviceSetMTU(port_conf, iconf->mtu);
951 
952  if (dev_info->tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) {
953  port_conf->txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
954  }
955 }
956 
957 static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info,
958  const struct rte_eth_conf *port_conf)
959 {
960  SCEnter();
961  int retval;
962  uint16_t mtu_size;
963  uint16_t mbuf_size;
964  struct rte_eth_rxconf rxq_conf;
965  struct rte_eth_txconf txq_conf;
966 
967  char mempool_name[64];
968  snprintf(mempool_name, 64, "mempool_%.20s", iconf->iface);
969  // +4 for VLAN header
970  mtu_size = iconf->mtu + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN + 4;
971  mbuf_size = ROUNDUP(mtu_size, 1024) + RTE_PKTMBUF_HEADROOM;
972  SCLogInfo("Creating a packet mbuf pool %s of size %d, cache size %d, mbuf size %d",
973  mempool_name, iconf->mempool_size, iconf->mempool_cache_size, mbuf_size);
974 
975  iconf->pkt_mempool = rte_pktmbuf_pool_create(mempool_name, iconf->mempool_size,
976  iconf->mempool_cache_size, 0, mbuf_size, (int)iconf->socket_id);
977  if (iconf->pkt_mempool == NULL) {
978  retval = -rte_errno;
980  "Error (err=%d) during rte_pktmbuf_pool_create (mempool: %s) - %s", rte_errno,
981  mempool_name, rte_strerror(rte_errno));
982  SCReturnInt(retval);
983  }
984 
985  for (uint16_t queue_id = 0; queue_id < iconf->nb_rx_queues; queue_id++) {
986  rxq_conf = dev_info->default_rxconf;
987  rxq_conf.offloads = port_conf->rxmode.offloads;
988  rxq_conf.rx_thresh.hthresh = 0;
989  rxq_conf.rx_thresh.pthresh = 0;
990  rxq_conf.rx_thresh.wthresh = 0;
991  rxq_conf.rx_free_thresh = 0;
992  rxq_conf.rx_drop_en = 0;
993  SCLogPerf(
994  "Creating Q %d of P %d using desc RX: %d TX: %d RX htresh: %d RX pthresh %d wtresh "
995  "%d free_tresh %d drop_en %d Offloads %lu",
996  queue_id, iconf->port_id, iconf->nb_rx_desc, iconf->nb_tx_desc,
997  rxq_conf.rx_thresh.hthresh, rxq_conf.rx_thresh.pthresh, rxq_conf.rx_thresh.wthresh,
998  rxq_conf.rx_free_thresh, rxq_conf.rx_drop_en, rxq_conf.offloads);
999 
1000  retval = rte_eth_rx_queue_setup(iconf->port_id, queue_id, iconf->nb_rx_desc,
1001  iconf->socket_id, &rxq_conf, iconf->pkt_mempool);
1002  if (retval < 0) {
1003  rte_mempool_free(iconf->pkt_mempool);
1005  "Error (err=%d) during initialization of device queue %u of port %u", retval,
1006  queue_id, iconf->port_id);
1007  SCReturnInt(retval);
1008  }
1009  }
1010 
1011  for (uint16_t queue_id = 0; queue_id < iconf->nb_tx_queues; queue_id++) {
1012  txq_conf = dev_info->default_txconf;
1013  txq_conf.offloads = port_conf->txmode.offloads;
1014  SCLogPerf("Creating TX queue %d on port %d", queue_id, iconf->port_id);
1015  retval = rte_eth_tx_queue_setup(
1016  iconf->port_id, queue_id, iconf->nb_tx_desc, iconf->socket_id, &txq_conf);
1017  if (retval < 0) {
1018  rte_mempool_free(iconf->pkt_mempool);
1020  "Error (err=%d) during initialization of device queue %u of port %u", retval,
1021  queue_id, iconf->port_id);
1022  SCReturnInt(retval);
1023  }
1024  }
1025 
1026  SCReturnInt(0);
1027 }
1028 
1029 static int DeviceValidateOutIfaceConfig(DPDKIfaceConfig *iconf)
1030 {
1031  SCEnter();
1032  int retval;
1033  DPDKIfaceConfig *out_iconf = NULL;
1034  ConfigInit(&out_iconf);
1035  if (out_iconf == NULL) {
1036  FatalError(
1037  SC_ERR_DPDK_CONF, "Copy interface of the interface \"%s\" is NULL", iconf->iface);
1038  }
1039 
1040  retval = ConfigLoad(out_iconf, iconf->out_iface);
1041  if (retval < 0) {
1042  SCLogError(SC_ERR_DPDK_CONF, "Fail to load config of interface %s", iconf->out_iface);
1043  out_iconf->DerefFunc(out_iconf);
1044  SCReturnInt(-EINVAL);
1045  }
1046 
1047  if (iconf->nb_rx_queues != out_iconf->nb_tx_queues) {
1048  // the other direction is validated when the copy interface is configured
1050  "Interface %s has configured %d RX queues but copy interface %s has %d TX queues"
1051  " - number of queues must be equal",
1052  iconf->iface, iconf->nb_rx_queues, out_iconf->iface, out_iconf->nb_tx_queues);
1053  out_iconf->DerefFunc(out_iconf);
1054  SCReturnInt(-EINVAL);
1055  } else if (iconf->mtu != out_iconf->mtu) {
1057  "Interface %s has configured MTU of %dB but copy interface %s has MTU set to %dB"
1058  " - MTU must be equal",
1059  iconf->iface, iconf->mtu, out_iconf->iface, out_iconf->mtu);
1060  out_iconf->DerefFunc(out_iconf);
1061  SCReturnInt(-EINVAL);
1062  } else if (iconf->copy_mode != out_iconf->copy_mode) {
1063  SCLogError(SC_ERR_DPDK_CONF, "Copy modes of interfaces %s and %s are not equal",
1064  iconf->iface, out_iconf->iface);
1065  out_iconf->DerefFunc(out_iconf);
1066  SCReturnInt(-EINVAL);
1067  } else if (strcmp(iconf->iface, out_iconf->out_iface) != 0) {
1068  // check if the other iface has the current iface set as a copy iface
1069  SCLogError(SC_ERR_DPDK_CONF, "Copy interface of %s is not set to %s", out_iconf->iface,
1070  iconf->iface);
1071  out_iconf->DerefFunc(out_iconf);
1072  SCReturnInt(-EINVAL);
1073  }
1074 
1075  out_iconf->DerefFunc(out_iconf);
1076  SCReturnInt(0);
1077 }
1078 
1079 static int DeviceConfigureIPS(DPDKIfaceConfig *iconf)
1080 {
1081  SCEnter();
1082  int retval;
1083 
1084  if (iconf->out_iface != NULL) {
1085  retval = rte_eth_dev_get_port_by_name(iconf->out_iface, &iconf->out_port_id);
1086  if (retval != 0) {
1087  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) during obtaining port id of %s", retval,
1088  iconf->out_iface);
1089  SCReturnInt(retval);
1090  }
1091 
1092  if (rte_eth_dev_socket_id(iconf->port_id) != rte_eth_dev_socket_id(iconf->out_port_id)) {
1093  SCLogWarning(SC_WARN_DPDK_CONF, "%s and %s are not on the same NUMA node", iconf->iface,
1094  iconf->out_iface);
1095  }
1096 
1097  retval = DeviceValidateOutIfaceConfig(iconf);
1098  if (retval != 0) {
1099  // Error will be written out by the validation function
1100  SCReturnInt(retval);
1101  }
1102  }
1103  SCReturnInt(0);
1104 }
1105 
1106 static int DeviceConfigure(DPDKIfaceConfig *iconf)
1107 {
1108  SCEnter();
1109  // configure device
1110  int retval;
1111  struct rte_eth_dev_info dev_info;
1112  struct rte_eth_conf port_conf;
1113 
1114  retval = rte_eth_dev_get_port_by_name(iconf->iface, &(iconf->port_id));
1115  if (retval < 0) {
1116  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) when getting port id of %s Is device enabled?",
1117  retval, iconf->iface);
1118  SCReturnInt(retval);
1119  }
1120 
1121  if (!rte_eth_dev_is_valid_port(iconf->port_id)) {
1122  SCLogError(SC_ERR_DPDK_INIT, "Specified port %d is invalid", iconf->port_id);
1123  SCReturnInt(retval);
1124  }
1125 
1126  retval = rte_eth_dev_socket_id(iconf->port_id);
1127  if (retval < 0) {
1128  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) invalid socket id (port %s)", retval,
1129  iconf->iface);
1130  SCReturnInt(retval);
1131  } else {
1132  iconf->socket_id = retval;
1133  }
1134 
1135  retval = rte_eth_dev_info_get(iconf->port_id, &dev_info);
1136  if (retval != 0) {
1137  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) during getting device info (port %s)", retval,
1138  iconf->iface);
1139  SCReturnInt(retval);
1140  }
1141 
1142  if (iconf->nb_rx_queues > dev_info.max_rx_queues) {
1144  "Number of configured RX queues of %s is higher than maximum allowed (%" PRIu16 ")",
1145  iconf->iface, dev_info.max_rx_queues);
1146  SCReturnInt(-ERANGE);
1147  }
1148 
1149  if (iconf->nb_tx_queues > dev_info.max_tx_queues) {
1151  "Number of configured TX queues of %s is higher than maximum allowed (%" PRIu16 ")",
1152  iconf->iface, dev_info.max_tx_queues);
1153  SCReturnInt(-ERANGE);
1154  }
1155 
1156  retval = DeviceValidateMTU(iconf, &dev_info);
1157  if (retval != 0)
1158  return retval;
1159 
1160  DeviceInitPortConf(iconf, &dev_info, &port_conf);
1161  if (port_conf.rxmode.offloads & DEV_RX_OFFLOAD_CHECKSUM) {
1162  // Suricata does not need recalc checksums now
1163  iconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
1164  }
1165 
1166  retval = rte_eth_dev_configure(
1167  iconf->port_id, iconf->nb_rx_queues, iconf->nb_tx_queues, &port_conf);
1168  if (retval != 0) {
1169  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) during configuring the device (port %u)",
1170  retval, iconf->port_id);
1171  SCReturnInt(retval);
1172  }
1173 
1174  retval = rte_eth_dev_adjust_nb_rx_tx_desc(
1175  iconf->port_id, &iconf->nb_rx_desc, &iconf->nb_tx_desc);
1176  if (retval != 0) {
1178  "Error (err=%d) during adjustment of device queues descriptors (port %u)", retval,
1179  iconf->port_id);
1180  SCReturnInt(retval);
1181  }
1182 
1183  retval = iconf->flags & DPDK_MULTICAST ? rte_eth_allmulticast_enable(iconf->port_id)
1184  : rte_eth_allmulticast_disable(iconf->port_id);
1185  if (retval == -ENOTSUP) {
1186  retval = rte_eth_allmulticast_get(iconf->port_id);
1187  // when multicast is enabled but set to disable or vice versa
1188  if ((retval == 1 && !(iconf->flags & DPDK_MULTICAST)) ||
1189  (retval == 0 && (iconf->flags & DPDK_MULTICAST))) {
1191  "Allmulticast setting of port (%" PRIu16
1192  ") can not be configured. Set it to %s",
1193  iconf->port_id, retval == 1 ? "true" : "false");
1194  } else if (retval < 0) {
1195  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) Unable to get multicast mode on port %u",
1196  retval, iconf->port_id);
1197  SCReturnInt(retval);
1198  }
1199 
1200  if (retval < 0) {
1201  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) Unable to get multicast mode on port %u",
1202  retval, iconf->port_id);
1203  SCReturnInt(retval);
1204  }
1205  } else if (retval < 0) {
1206  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) when en/disabling multicast on port %u",
1207  retval, iconf->port_id);
1208  SCReturnInt(retval);
1209  }
1210 
1211  retval = iconf->flags & DPDK_PROMISC ? rte_eth_promiscuous_enable(iconf->port_id)
1212  : rte_eth_promiscuous_disable(iconf->port_id);
1213  if (retval == -ENOTSUP) {
1214  retval = rte_eth_promiscuous_get(iconf->port_id);
1215  if ((retval == 1 && !(iconf->flags & DPDK_PROMISC)) ||
1216  (retval == 0 && (iconf->flags & DPDK_PROMISC))) {
1218  "Promiscuous setting of port (%" PRIu16 ") can not be configured. Set it to %s",
1219  iconf->port_id, retval == 1 ? "true" : "false");
1221  } else if (retval < 0) {
1222  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) Unable to get promiscuous mode on port %u",
1223  retval, iconf->port_id);
1224  SCReturnInt(retval);
1225  }
1226  } else if (retval < 0) {
1227  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) when enabling promiscuous mode on port %u",
1228  retval, iconf->port_id);
1230  }
1231 
1232  // set maximum transmission unit
1233  SCLogConfig("Setting MTU of %s to %dB", iconf->iface, iconf->mtu);
1234  retval = rte_eth_dev_set_mtu(iconf->port_id, iconf->mtu);
1235  if (retval == -ENOTSUP) {
1237  "Changing MTU on port %u is not supported, ignoring the setting...",
1238  iconf->port_id);
1239  // if it is not possible to set the MTU, retrieve it
1240  retval = rte_eth_dev_get_mtu(iconf->port_id, &iconf->mtu);
1241  if (retval < 0) {
1242  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) Unable to retrieve MTU from port %u",
1243  retval, iconf->port_id);
1244  SCReturnInt(retval);
1245  }
1246  } else if (retval < 0) {
1247  SCLogError(SC_ERR_DPDK_INIT, "Error (err=%d) when setting MTU to %u on port %u", retval,
1248  iconf->mtu, iconf->port_id);
1249  SCReturnInt(retval);
1250  }
1251 
1252  retval = DeviceConfigureQueues(iconf, &dev_info, &port_conf);
1253  if (retval < 0) {
1254  SCReturnInt(retval);
1255  }
1256 
1257  retval = DeviceConfigureIPS(iconf);
1258  if (retval < 0) {
1259  SCReturnInt(retval);
1260  }
1261 
1262  SCReturnInt(0);
1263 }
1264 
1265 static void *ParseDpdkConfigAndConfigureDevice(const char *iface)
1266 {
1267  int retval;
1268  DPDKIfaceConfig *iconf = ConfigParse(iface);
1269  if (iconf == NULL) {
1270  FatalError(SC_ERR_DPDK_CONF, "DPDK configuration could not be parsed");
1271  }
1272 
1273  if (DeviceConfigure(iconf) != 0) {
1274  iconf->DerefFunc(iconf);
1275  retval = rte_eal_cleanup();
1276  if (retval != 0)
1277  FatalError(SC_ERR_DPDK_EAL_INIT, "EAL cleanup failed: %s", strerror(-retval));
1278 
1279  FatalError(SC_ERR_DPDK_CONF, "Device %s fails to configure", iface);
1280  }
1281 
1282  SC_ATOMIC_RESET(iconf->ref);
1283  (void)SC_ATOMIC_ADD(iconf->ref, iconf->threads);
1284  // This counter is increased by worker threads that individually pick queue IDs.
1285  SC_ATOMIC_RESET(iconf->queue_id);
1286  return iconf;
1287 }
1288 
1289 /**
1290  * \brief extract information from config file
1291  *
1292  * The returned structure will be freed by the thread init function.
1293  * This is thus necessary to or copy the structure before giving it
1294  * to thread or to reparse the file for each thread (and thus have
1295  * new structure.
1296  *
1297  * After configuration is loaded, DPDK also configures the device according to the settings.
1298  *
1299  * \return a DPDKIfaceConfig corresponding to the interface name
1300  */
1301 
1302 static int DPDKConfigGetThreadsCount(void *conf)
1303 {
1304  if (conf == NULL)
1305  FatalError(SC_ERR_DPDK_CONF, "Configuration file is NULL");
1306 
1307  DPDKIfaceConfig *dpdk_conf = (DPDKIfaceConfig *)conf;
1308  return dpdk_conf->threads;
1309 }
1310 
1311 #endif /* HAVE_DPDK */
1312 
1313 const char *RunModeDpdkGetDefaultMode(void)
1314 {
1315  return "workers";
1316 }
1317 
1319 {
1321  "Workers DPDK mode, each thread does all"
1322  " tasks from acquisition to logging",
1324 }
1325 
1326 /**
1327  * \brief Workers version of the DPDK processing.
1328  *
1329  * Start N threads with each thread doing all the work.
1330  *
1331  */
1333 {
1334  SCEnter();
1335 #ifdef HAVE_DPDK
1336  int ret;
1337 
1339  TimeModeSetLive();
1340 
1341  InitEal();
1342  ret = RunModeSetLiveCaptureWorkers(ParseDpdkConfigAndConfigureDevice, DPDKConfigGetThreadsCount,
1343  "ReceiveDPDK", "DecodeDPDK", thread_name_workers, NULL);
1344  if (ret != 0) {
1345  FatalError(SC_ERR_FATAL, "Unable to start runmode");
1346  }
1347 
1348  SCLogDebug("RunModeIdsDpdkWorkers initialised");
1349 
1350 #endif /* HAVE_DPDK */
1351  SCReturnInt(0);
1352 }
1353 
1354 /**
1355  * @}
1356  */
thread_name_workers
const char * thread_name_workers
Definition: runmodes.c:80
DPDKIfaceConfigAttributes_::checksum_checks_offload
const char * checksum_checks_offload
Definition: runmode-dpdk.h:31
util-byte.h
SC_ERR_DPDK_INIT
@ SC_ERR_DPDK_INIT
Definition: util-error.h:373
DPDKIfaceConfigAttributes_::mempool_size
const char * mempool_size
Definition: runmode-dpdk.h:33
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:330
SC_ERR_INVALID_VALUE
@ SC_ERR_INVALID_VALUE
Definition: util-error.h:160
DPDKIfaceConfigAttributes_::promisc
const char * promisc
Definition: runmode-dpdk.h:28
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
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:34
SC_WARN_DPDK_CONF
@ SC_WARN_DPDK_CONF
Definition: util-error.h:377
DPDK_COPY_MODE_IPS
@ DPDK_COPY_MODE_IPS
Definition: source-dpdk.h:31
ConfGetChildValueBoolWithDefault
int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val)
Definition: conf.c:498
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
DPDKIfaceConfigAttributes_::copy_iface
const char * copy_iface
Definition: runmode-dpdk.h:38
RunModeInitialize
void RunModeInitialize(void)
Definition: runmodes.c:946
RunModeIdsDpdkWorkers
int RunModeIdsDpdkWorkers(void)
Workers version of the DPDK processing.
Definition: runmode-dpdk.c:1332
util-runmodes.h
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
CHECKSUM_VALIDATION_DISABLE
@ CHECKSUM_VALIDATION_DISABLE
Definition: decode.h:46
RunmodeGetActive
char * RunmodeGetActive(void)
Definition: runmodes.c:213
StringParseInt32
int StringParseInt32(int32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:613
DPDKIfaceConfig_
Definition: source-dpdk.h:42
util-dpdk-ice.h
ConfGetChildValueIntWithDefault
int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val)
Definition: conf.c:450
MAX
#define MAX(x, y)
Definition: suricata-common.h:376
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:316
CHECKSUM_VALIDATION_ENABLE
@ CHECKSUM_VALIDATION_ENABLE
Definition: decode.h:47
RunModeDpdkGetDefaultMode
const char * RunModeDpdkGetDefaultMode(void)
Definition: runmode-dpdk.c:1313
SC_ERR_DPDK_CONF
@ SC_ERR_DPDK_CONF
Definition: util-error.h:376
DPDKIfaceConfigAttributes_::rx_descriptors
const char * rx_descriptors
Definition: runmode-dpdk.h:35
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:30
DPDK_RX_CHECKSUM_OFFLOAD
#define DPDK_RX_CHECKSUM_OFFLOAD
Definition: source-dpdk.h:40
SCEnter
#define SCEnter(...)
Definition: util-debug.h:298
SC_ERR_DPDK_EAL_INIT
@ SC_ERR_DPDK_EAL_INIT
Definition: util-error.h:374
ConfGetChildValueWithDefault
int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr)
Definition: conf.c:371
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
util-time.h
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:342
SCReturn
#define SCReturn
Definition: util-debug.h:300
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:314
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:215
DPDKIfaceConfigAttributes_::threads
const char * threads
Definition: runmode-dpdk.h:27
TimeModeSetLive
void TimeModeSetLive(void)
Definition: util-time.c:99
DPDKIfaceConfigAttributes_::tx_descriptors
const char * tx_descriptors
Definition: runmode-dpdk.h:36
util-dpdk.h
source-dpdk.h
suricata-common.h
RunModeRegisterNewRunMode
void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:460
DPDK_PROMISC
#define DPDK_PROMISC
Definition: source-dpdk.h:37
ConfNode_::name
char * name
Definition: conf.h:33
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:222
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:255
FatalError
#define FatalError(x,...)
Definition: util-debug.h:530
SC_ATOMIC_RESET
#define SC_ATOMIC_RESET(name)
wrapper for reinitializing an atomic variable.
Definition: util-atomic.h:324
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SCLogWarning
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:242
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
DPDKIfaceConfigAttributes_::multicast
const char * multicast
Definition: runmode-dpdk.h:29
RunModeDpdkRegister
void RunModeDpdkRegister(void)
Definition: runmode-dpdk.c:1318
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:967
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
util-dpdk-i40e.h
runmode-dpdk.h
DPDKIfaceConfigAttributes_::mtu
const char * mtu
Definition: runmode-dpdk.h:32
DPDKIfaceConfigAttributes_::copy_mode
const char * copy_mode
Definition: runmode-dpdk.h:37
UtilCpuGetNumProcessorsOnline
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
Definition: util-cpu.c:106
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:302
DPDK_COPY_MODE_TAP
@ DPDK_COPY_MODE_TAP
Definition: source-dpdk.h:31
DPDK_COPY_MODE_NONE
@ DPDK_COPY_MODE_NONE
Definition: source-dpdk.h:31
DPDK_MULTICAST
#define DPDK_MULTICAST
Definition: source-dpdk.h:38