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