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