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