Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/runmode-dpdk.c
Line
Count
Source
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
386
    if (!threading_set_cpu_affinity) {
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 MempoolSizeCalculate(
534
        const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
535
{
536
    uint32_t sz = iconf->nb_rx_queues * iconf->nb_rx_desc + iconf->nb_tx_queues * iconf->nb_tx_desc;
537
    if (!iconf->nb_tx_queues || !iconf->nb_tx_desc)
538
        sz *= 2; // double to have enough space for RX descriptors
539
540
    if (dev_info != NULL) {
541
        if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
542
            sz = BondingMempoolSizeCalculate(iconf->port_id, dev_info, sz);
543
        }
544
    }
545
546
    return sz;
547
}
548
549
static int ConfigSetMempoolSize(
550
        DPDKIfaceConfig *iconf, const char *entry_str, const struct rte_eth_dev_info *dev_info)
551
{
552
    SCEnter();
553
    if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
554
        // calculate the mempool size based on the number of:
555
        //   - RX / TX queues
556
        //   - RX / TX descriptors
557
        bool err = false;
558
        if (iconf->nb_rx_queues == 0) {
559
            // in IDS mode, we don't need TX queues
560
            SCLogError("%s: cannot autocalculate mempool size without RX queues", iconf->iface);
561
            err = true;
562
        }
563
564
        if (iconf->nb_rx_desc == 0) {
565
            SCLogError(
566
                    "%s: cannot autocalculate mempool size without RX descriptors", iconf->iface);
567
            err = true;
568
        }
569
570
        if (err) {
571
            SCReturnInt(-EINVAL);
572
        }
573
574
        iconf->mempool_size = MempoolSizeCalculate(iconf, dev_info);
575
        SCReturnInt(0);
576
    }
577
578
    if (StringParseUint32(&iconf->mempool_size, 10, 0, entry_str) < 0) {
579
        SCLogError("%s: mempool size entry contain non-numerical characters - \"%s\"", iconf->iface,
580
                entry_str);
581
        SCReturnInt(-EINVAL);
582
    }
583
584
    uint32_t required_mp_size = MempoolSizeCalculate(iconf, dev_info);
585
    if (required_mp_size >
586
            iconf->mempool_size + 1) { // +1 to mask mempool size advice given in Suricata 7.0.x -
587
                                       // mp_size should be n = (2^q - 1)
588
        SCLogError("%s: mempool size is likely too small for the number of descriptors and queues, "
589
                   "set to \"auto\" or adjust to the value of \"%" PRIu32 "\"",
590
                iconf->iface, required_mp_size);
591
        SCReturnInt(-ERANGE);
592
    }
593
594
    if (iconf->mempool_size == 0) {
595
        SCLogError("%s: mempool size requires a positive integer", iconf->iface);
596
        SCReturnInt(-ERANGE);
597
    }
598
599
    SCReturnInt(0);
600
}
601
602
static uint32_t MempoolCacheSizeCalculate(uint32_t mp_sz)
603
{
604
    // It is advised to have mempool cache size lower or equal to:
605
    //   RTE_MEMPOOL_CACHE_MAX_SIZE (by default 512) and "mempool-size / 1.5"
606
    // and at the same time "mempool-size modulo cache_size == 0".
607
    uint32_t max_cache_size = MIN(RTE_MEMPOOL_CACHE_MAX_SIZE, (uint32_t)(mp_sz / 1.5));
608
    return GreatestDivisorUpTo(mp_sz, max_cache_size);
609
}
610
611
static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str)
612
{
613
    SCEnter();
614
    if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
615
        // calculate the mempool size based on the mempool size (it needs to be already filled in)
616
        if (iconf->mempool_size == 0) {
617
            SCLogError("%s: cannot calculate mempool cache size of a mempool with size %d",
618
                    iconf->iface, iconf->mempool_size);
619
            SCReturnInt(-EINVAL);
620
        }
621
622
        iconf->mempool_cache_size_auto = true;
623
        SCReturnInt(0);
624
    }
625
626
    iconf->mempool_cache_size_auto = false;
627
    if (StringParseUint32(&iconf->mempool_cache_size, 10, 0, entry_str) < 0) {
628
        SCLogError("%s: mempool cache size entry contain non-numerical characters - \"%s\"",
629
                iconf->iface, entry_str);
630
        SCReturnInt(-EINVAL);
631
    }
632
633
    if (iconf->mempool_cache_size <= 0 || iconf->mempool_cache_size > RTE_MEMPOOL_CACHE_MAX_SIZE) {
634
        SCLogError("%s: mempool cache size requires a positive number smaller than %" PRIu32,
635
                iconf->iface, RTE_MEMPOOL_CACHE_MAX_SIZE);
636
        SCReturnInt(-ERANGE);
637
    }
638
639
    SCReturnInt(0);
640
}
641
642
static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc)
643
{
644
    SCEnter();
645
    if (entry_str == NULL || entry_str[0] == '\0') {
646
        SCLogInfo("%s: number of RX descriptors not found, going with: %s", iconf->iface,
647
                DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS);
648
        entry_str = DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS;
649
    }
650
651
    if (strcmp(entry_str, "auto") == 0) {
652
        iconf->nb_rx_desc = (uint16_t)GreatestPowOf2UpTo(max_desc);
653
        SCReturnInt(0);
654
    }
655
656
    if (StringParseUint16(&iconf->nb_rx_desc, 10, 0, entry_str) < 0) {
657
        SCLogError("%s: RX descriptors entry contains non-numerical characters - \"%s\"",
658
                iconf->iface, entry_str);
659
        SCReturnInt(-EINVAL);
660
    }
661
662
    if (iconf->nb_rx_desc == 0) {
663
        SCLogError("%s: positive number of RX descriptors is required", iconf->iface);
664
        SCReturnInt(-ERANGE);
665
    } else if (iconf->nb_rx_desc > max_desc) {
666
        SCLogError("%s: number of RX descriptors cannot exceed %" PRIu16, iconf->iface, max_desc);
667
        SCReturnInt(-ERANGE);
668
    }
669
670
    SCReturnInt(0);
671
}
672
673
static int ConfigSetTxDescriptors(
674
        DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc, bool iface_sends_pkts)
675
{
676
    SCEnter();
677
    if (entry_str == NULL || entry_str[0] == '\0') {
678
        SCLogInfo("%s: number of TX descriptors not found, going with: %s", iconf->iface,
679
                DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS);
680
        entry_str = DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS;
681
    }
682
683
    if (strcmp(entry_str, "auto") == 0) {
684
        if (iface_sends_pkts) {
685
            iconf->nb_tx_desc = (uint16_t)GreatestPowOf2UpTo(max_desc);
686
        } else {
687
            iconf->nb_tx_desc = 0;
688
        }
689
        SCReturnInt(0);
690
    }
691
692
    if (StringParseUint16(&iconf->nb_tx_desc, 10, 0, entry_str) < 0) {
693
        SCLogError("%s: TX descriptors entry contains non-numerical characters - \"%s\"",
694
                iconf->iface, entry_str);
695
        SCReturnInt(-EINVAL);
696
    }
697
698
    if (iconf->nb_tx_desc == 0 && iface_sends_pkts) {
699
        SCLogError("%s: positive number of TX descriptors is required", iconf->iface);
700
        SCReturnInt(-ERANGE);
701
    } else if (iconf->nb_tx_desc > max_desc) {
702
        SCLogError("%s: number of TX descriptors cannot exceed %" PRIu16, iconf->iface, max_desc);
703
        SCReturnInt(-ERANGE);
704
    }
705
706
    SCReturnInt(0);
707
}
708
709
static int ConfigSetRSSHashFunctions(DPDKIfaceConfig *iconf, const char *entry_str)
710
{
711
    SCEnter();
712
    if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
713
        iconf->rss_hf = DPDK_CONFIG_DEFAULT_RSS_HASH_FUNCTIONS;
714
        SCReturnInt(0);
715
    }
716
717
    if (StringParseUint64(&iconf->rss_hf, 0, 0, entry_str) < 0) {
718
        SCLogError("%s: RSS hash functions entry contain non-numerical characters - \"%s\"",
719
                iconf->iface, entry_str);
720
        SCReturnInt(-EINVAL);
721
    }
722
723
    SCReturnInt(0);
724
}
725
726
static int ConfigSetMtu(DPDKIfaceConfig *iconf, intmax_t entry_int)
727
{
728
    SCEnter();
729
    if (entry_int < RTE_ETHER_MIN_MTU || entry_int > RTE_ETHER_MAX_JUMBO_FRAME_LEN) {
730
        SCLogError("%s: MTU size can only be between %" PRIu32 " and %" PRIu32, iconf->iface,
731
                RTE_ETHER_MIN_MTU, RTE_ETHER_MAX_JUMBO_FRAME_LEN);
732
        SCReturnInt(-ERANGE);
733
    }
734
735
    iconf->mtu = (uint16_t)entry_int;
736
    SCReturnInt(0);
737
}
738
739
static int ConfigSetLinkupTimeout(DPDKIfaceConfig *iconf, intmax_t entry_int)
740
{
741
    SCEnter();
742
    if (entry_int < 0 || entry_int > UINT16_MAX) {
743
        SCLogError("%s: Link-up waiting timeout needs to be a positive number (up to %u) or 0 to "
744
                   "disable",
745
                iconf->iface, UINT16_MAX);
746
        SCReturnInt(-ERANGE);
747
    }
748
749
    iconf->linkup_timeout = (uint16_t)entry_int;
750
    SCReturnInt(0);
751
}
752
753
static bool ConfigSetPromiscuousMode(DPDKIfaceConfig *iconf, int entry_bool)
754
{
755
    SCEnter();
756
    if (entry_bool)
757
        iconf->flags |= DPDK_PROMISC;
758
759
    SCReturnBool(true);
760
}
761
762
static bool ConfigSetMulticast(DPDKIfaceConfig *iconf, int entry_bool)
763
{
764
    SCEnter();
765
    if (entry_bool)
766
        iconf->flags |= DPDK_MULTICAST; // enable
767
768
    SCReturnBool(true);
769
}
770
771
static int ConfigSetChecksumChecks(DPDKIfaceConfig *iconf, int entry_bool)
772
{
773
    SCEnter();
774
    if (entry_bool)
775
        iconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
776
777
    SCReturnInt(0);
778
}
779
780
static int ConfigSetChecksumOffload(DPDKIfaceConfig *iconf, int entry_bool)
781
{
782
    SCEnter();
783
    if (entry_bool)
784
        iconf->flags |= DPDK_RX_CHECKSUM_OFFLOAD;
785
786
    SCReturnInt(0);
787
}
788
789
static void ConfigSetVlanStrip(DPDKIfaceConfig *iconf, int entry_bool)
790
{
791
    SCEnter();
792
    iconf->vlan_strip_enabled = entry_bool;
793
    SCReturn;
794
}
795
796
static int ConfigSetCopyIface(DPDKIfaceConfig *iconf, const char *entry_str)
797
{
798
    SCEnter();
799
    int retval;
800
801
    if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "none") == 0) {
802
        iconf->out_iface = NULL;
803
        SCReturnInt(0);
804
    }
805
806
    retval = rte_eth_dev_get_port_by_name(entry_str, &iconf->out_port_id);
807
    if (retval < 0) {
808
        SCLogError("%s: copy interface (%s) not found: %s", iconf->iface, entry_str,
809
                rte_strerror(-retval));
810
        SCReturnInt(retval);
811
    }
812
813
    iconf->out_iface = entry_str;
814
    SCReturnInt(0);
815
}
816
817
static int ConfigSetCopyMode(DPDKIfaceConfig *iconf, const char *entry_str)
818
{
819
    SCEnter();
820
    if (entry_str == NULL) {
821
        SCLogWarning("%s: no copy mode specified, changing to %s ", iconf->iface,
822
                DPDK_CONFIG_DEFAULT_COPY_MODE);
823
        entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
824
    }
825
826
    if (strcmp(entry_str, "none") != 0 && strcmp(entry_str, "tap") != 0 &&
827
            strcmp(entry_str, "ips") != 0) {
828
        SCLogWarning("%s: copy mode \"%s\" is not one of the possible values (none|tap|ips). "
829
                     "Changing to %s",
830
                entry_str, iconf->iface, DPDK_CONFIG_DEFAULT_COPY_MODE);
831
        entry_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
832
    }
833
834
    if (strcmp(entry_str, "none") == 0) {
835
        iconf->copy_mode = DPDK_COPY_MODE_NONE;
836
    } else if (strcmp(entry_str, "tap") == 0) {
837
        iconf->copy_mode = DPDK_COPY_MODE_TAP;
838
    } else if (strcmp(entry_str, "ips") == 0) {
839
        iconf->copy_mode = DPDK_COPY_MODE_IPS;
840
    }
841
842
    SCReturnInt(0);
843
}
844
845
static int ConfigSetCopyIfaceSettings(DPDKIfaceConfig *iconf, const char *iface, const char *mode)
846
{
847
    SCEnter();
848
    int retval;
849
850
    retval = ConfigSetCopyIface(iconf, iface);
851
    if (retval < 0)
852
        SCReturnInt(retval);
853
854
    retval = ConfigSetCopyMode(iconf, mode);
855
    if (retval < 0)
856
        SCReturnInt(retval);
857
858
    if (iconf->copy_mode == DPDK_COPY_MODE_NONE) {
859
        if (iconf->out_iface != NULL)
860
            iconf->out_iface = NULL;
861
        SCReturnInt(0);
862
    }
863
864
    if (iconf->out_iface == NULL || strlen(iconf->out_iface) <= 0) {
865
        SCLogError("%s: copy mode enabled but interface not set", iconf->iface);
866
        SCReturnInt(-EINVAL);
867
    }
868
869
    SCReturnInt(0);
870
}
871
872
static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface)
873
{
874
    SCEnter();
875
    int retval;
876
    SCConfNode *if_root;
877
    SCConfNode *if_default;
878
    const char *entry_str = NULL;
879
    intmax_t entry_int = 0;
880
    int entry_bool = 0;
881
    const char *copy_iface_str = NULL;
882
    const char *copy_mode_str = NULL;
883
884
    ConfigSetIface(iconf, iface);
885
    struct rte_eth_dev_info dev_info = { 0 };
886
    retval = rte_eth_dev_info_get(iconf->port_id, &dev_info);
887
    if (retval < 0) {
888
        SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-retval));
889
        SCReturnInt(retval);
890
    }
891
892
    retval = SCConfSetRootAndDefaultNodes("dpdk.interfaces", iconf->iface, &if_root, &if_default);
893
    if (retval < 0) {
894
        FatalError("failed to find DPDK configuration for the interface %s", iconf->iface);
895
    }
896
897
    retval = SCConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.threads, &entry_str) != 1
898
                     ? ConfigSetThreads(iconf, DPDK_CONFIG_DEFAULT_THREADS)
899
                     : ConfigSetThreads(iconf, entry_str);
900
    if (retval < 0)
901
        SCReturnInt(retval);
902
903
    bool irq_enable;
904
    retval = SCConfGetChildValueBoolWithDefault(
905
            if_root, if_default, dpdk_yaml.irq_mode, &entry_bool);
906
    if (retval != 1) {
907
        irq_enable = DPDK_CONFIG_DEFAULT_INTERRUPT_MODE;
908
    } else {
909
        irq_enable = entry_bool ? true : false;
910
    }
911
    retval = ConfigSetInterruptMode(iconf, irq_enable);
912
    if (retval != true)
913
        SCReturnInt(-EINVAL);
914
915
    retval = SCConfGetChildValueWithDefault(
916
            if_root, if_default, dpdk_yaml.copy_mode, &copy_mode_str);
917
    if (retval != 1) {
918
        copy_mode_str = DPDK_CONFIG_DEFAULT_COPY_MODE;
919
    }
920
921
    retval = SCConfGetChildValueWithDefault(
922
                     if_root, if_default, dpdk_yaml.rx_descriptors, &entry_str) != 1
923
                     ? ConfigSetRxDescriptors(iconf, DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS,
924
                               dev_info.rx_desc_lim.nb_max)
925
                     : ConfigSetRxDescriptors(iconf, entry_str, dev_info.rx_desc_lim.nb_max);
926
    if (retval < 0)
927
        SCReturnInt(retval);
928
929
    bool iface_sends_pkts = ConfigIfaceSendsPkts(copy_mode_str);
930
    retval = SCConfGetChildValueWithDefault(
931
                     if_root, if_default, dpdk_yaml.tx_descriptors, &entry_str) != 1
932
                     ? ConfigSetTxDescriptors(iconf, DPDK_CONFIG_DEFAULT_TX_DESCRIPTORS,
933
                               dev_info.tx_desc_lim.nb_max, iface_sends_pkts)
934
                     : ConfigSetTxDescriptors(
935
                               iconf, entry_str, dev_info.tx_desc_lim.nb_max, iface_sends_pkts);
936
    if (retval < 0)
937
        SCReturnInt(retval);
938
939
    // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
940
    retval = ConfigSetRxQueues(iconf, iconf->threads, dev_info.max_rx_queues);
941
    if (retval < 0) {
942
        SCLogError("%s: too many threads configured - reduce thread count to: %" PRIu16,
943
                iconf->iface, dev_info.max_rx_queues);
944
        SCReturnInt(retval);
945
    }
946
947
    // currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
948
    uint16_t tx_queues = iconf->nb_tx_desc > 0 ? iconf->threads : 0;
949
    retval = ConfigSetTxQueues(iconf, tx_queues, dev_info.max_tx_queues, iface_sends_pkts);
950
    if (retval < 0) {
951
        SCLogError("%s: too many threads configured - reduce thread count to: %" PRIu16,
952
                iconf->iface, dev_info.max_tx_queues);
953
        SCReturnInt(retval);
954
    }
955
956
    retval = SCConfGetChildValueWithDefault(
957
                     if_root, if_default, dpdk_yaml.mempool_size, &entry_str) != 1
958
                     ? ConfigSetMempoolSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE, &dev_info)
959
                     : ConfigSetMempoolSize(iconf, entry_str, &dev_info);
960
    if (retval < 0)
961
        SCReturnInt(retval);
962
963
    retval = SCConfGetChildValueWithDefault(
964
                     if_root, if_default, dpdk_yaml.mempool_cache_size, &entry_str) != 1
965
                     ? ConfigSetMempoolCacheSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE)
966
                     : ConfigSetMempoolCacheSize(iconf, entry_str);
967
    if (retval < 0)
968
        SCReturnInt(retval);
969
970
    retval = SCConfGetChildValueIntWithDefault(if_root, if_default, dpdk_yaml.mtu, &entry_int) != 1
971
                     ? ConfigSetMtu(iconf, DPDK_CONFIG_DEFAULT_MTU)
972
                     : ConfigSetMtu(iconf, entry_int);
973
    if (retval < 0)
974
        SCReturnInt(retval);
975
976
    retval = SCConfGetChildValueWithDefault(if_root, if_default, dpdk_yaml.rss_hf, &entry_str) != 1
977
                     ? ConfigSetRSSHashFunctions(iconf, NULL)
978
                     : ConfigSetRSSHashFunctions(iconf, entry_str);
979
    if (retval < 0)
980
        SCReturnInt(retval);
981
982
    retval = SCConfGetChildValueBoolWithDefault(
983
                     if_root, if_default, dpdk_yaml.promisc, &entry_bool) != 1
984
                     ? ConfigSetPromiscuousMode(iconf, DPDK_CONFIG_DEFAULT_PROMISCUOUS_MODE)
985
                     : ConfigSetPromiscuousMode(iconf, entry_bool);
986
    if (retval != true)
987
        SCReturnInt(-EINVAL);
988
989
    retval = SCConfGetChildValueBoolWithDefault(
990
                     if_root, if_default, dpdk_yaml.multicast, &entry_bool) != 1
991
                     ? ConfigSetMulticast(iconf, DPDK_CONFIG_DEFAULT_MULTICAST_MODE)
992
                     : ConfigSetMulticast(iconf, entry_bool);
993
    if (retval != true)
994
        SCReturnInt(-EINVAL);
995
996
    retval = SCConfGetChildValueBoolWithDefault(
997
                     if_root, if_default, dpdk_yaml.checksum_checks, &entry_bool) != 1
998
                     ? ConfigSetChecksumChecks(iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION)
999
                     : ConfigSetChecksumChecks(iconf, entry_bool);
1000
    if (retval < 0)
1001
        SCReturnInt(retval);
1002
1003
    retval = SCConfGetChildValueBoolWithDefault(
1004
                     if_root, if_default, dpdk_yaml.checksum_checks_offload, &entry_bool) != 1
1005
                     ? ConfigSetChecksumOffload(
1006
                               iconf, DPDK_CONFIG_DEFAULT_CHECKSUM_VALIDATION_OFFLOAD)
1007
                     : ConfigSetChecksumOffload(iconf, entry_bool);
1008
    if (retval < 0)
1009
        SCReturnInt(retval);
1010
1011
    retval = SCConfGetChildValueBoolWithDefault(
1012
            if_root, if_default, dpdk_yaml.vlan_strip_offload, &entry_bool);
1013
    if (retval != 1) {
1014
        ConfigSetVlanStrip(iconf, DPDK_CONFIG_DEFAULT_VLAN_STRIP);
1015
    } else {
1016
        ConfigSetVlanStrip(iconf, entry_bool);
1017
    }
1018
1019
    retval = SCConfGetChildValueIntWithDefault(
1020
                     if_root, if_default, dpdk_yaml.linkup_timeout, &entry_int) != 1
1021
                     ? ConfigSetLinkupTimeout(iconf, DPDK_CONFIG_DEFAULT_LINKUP_TIMEOUT)
1022
                     : ConfigSetLinkupTimeout(iconf, entry_int);
1023
    if (retval < 0)
1024
        SCReturnInt(retval);
1025
1026
    retval = SCConfGetChildValueWithDefault(
1027
            if_root, if_default, dpdk_yaml.copy_iface, &copy_iface_str);
1028
    if (retval != 1) {
1029
        copy_iface_str = DPDK_CONFIG_DEFAULT_COPY_INTERFACE;
1030
    }
1031
1032
    retval = ConfigSetCopyIfaceSettings(iconf, copy_iface_str, copy_mode_str);
1033
    if (retval < 0)
1034
        SCReturnInt(retval);
1035
1036
    SCReturnInt(0);
1037
}
1038
1039
static bool ConfigThreadsGenericIsValid(uint16_t iface_threads, ThreadsAffinityType *wtaf)
1040
{
1041
    static uint32_t total_cpus = 0;
1042
    total_cpus += iface_threads;
1043
    if (wtaf == NULL) {
1044
        SCLogError("Specify worker-cpu-set list in the threading section");
1045
        return false;
1046
    }
1047
    if (total_cpus > UtilAffinityGetAffinedCPUNum(wtaf)) {
1048
        SCLogError("Interfaces requested more cores than configured in the worker-cpu-set "
1049
                   "threading section (requested %d configured %d",
1050
                total_cpus, UtilAffinityGetAffinedCPUNum(wtaf));
1051
        return false;
1052
    }
1053
1054
    return true;
1055
}
1056
1057
static bool ConfigThreadsInterfaceIsValid(uint16_t iface_threads, ThreadsAffinityType *itaf)
1058
{
1059
    if (iface_threads > UtilAffinityGetAffinedCPUNum(itaf)) {
1060
        SCLogError("Interface requested more cores than configured in the interface-specific "
1061
                   "threading section (requested %d configured %d",
1062
                iface_threads, UtilAffinityGetAffinedCPUNum(itaf));
1063
        return false;
1064
    }
1065
1066
    return true;
1067
}
1068
1069
static bool ConfigIsThreadingValid(uint16_t iface_threads, const char *iface)
1070
{
1071
    ThreadsAffinityType *itaf = GetAffinityTypeForNameAndIface("worker-cpu-set", iface);
1072
    ThreadsAffinityType *wtaf = GetAffinityTypeForNameAndIface("worker-cpu-set", NULL);
1073
    if (itaf && !ConfigThreadsInterfaceIsValid(iface_threads, itaf)) {
1074
        return false;
1075
    } else if (itaf == NULL && !ConfigThreadsGenericIsValid(iface_threads, wtaf)) {
1076
        return false;
1077
    }
1078
    return true;
1079
}
1080
1081
static DPDKIfaceConfig *ConfigParse(const char *iface)
1082
{
1083
    SCEnter();
1084
    int retval;
1085
    DPDKIfaceConfig *iconf = NULL;
1086
    if (iface == NULL)
1087
        FatalError("DPDK interface is NULL");
1088
1089
    ConfigInit(&iconf);
1090
    retval = ConfigLoad(iconf, iface);
1091
    if (retval < 0 || !ConfigIsThreadingValid(iconf->threads, iface)) {
1092
        iconf->DerefFunc(iconf);
1093
        SCReturnPtr(NULL, "void *");
1094
    }
1095
1096
    SCReturnPtr(iconf, "DPDKIfaceConfig *");
1097
}
1098
1099
static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const char *driver_name)
1100
{
1101
    if (strcmp(driver_name, "net_i40e") == 0)
1102
        i40eDeviceSetRSSConf(rss_conf);
1103
    if (strcmp(driver_name, "net_ice") == 0)
1104
        iceDeviceSetRSSConf(rss_conf);
1105
    if (strcmp(driver_name, "net_ixgbe") == 0)
1106
        ixgbeDeviceSetRSSHashFunction(&rss_conf->rss_hf);
1107
    if (strcmp(driver_name, "net_e1000_igb") == 0)
1108
        rss_conf->rss_hf = (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_IPV6_EX);
1109
}
1110
1111
// Returns -1 if no bit is set
1112
static int32_t GetFirstSetBitPosition(uint64_t bits)
1113
{
1114
    for (int32_t i = 0; i < 64; i++) {
1115
        if (bits & BIT_U64(i))
1116
            return i;
1117
    }
1118
    return -1;
1119
}
1120
1121
static void DumpRSSFlags(const uint64_t requested, const uint64_t actual)
1122
{
1123
    SCLogConfig("REQUESTED (groups):");
1124
1125
    SCLogConfig(
1126
            "RTE_ETH_RSS_IP %sset", ((requested & RTE_ETH_RSS_IP) == RTE_ETH_RSS_IP) ? "" : "NOT ");
1127
    SCLogConfig("RTE_ETH_RSS_TCP %sset",
1128
            ((requested & RTE_ETH_RSS_TCP) == RTE_ETH_RSS_TCP) ? "" : "NOT ");
1129
    SCLogConfig("RTE_ETH_RSS_UDP %sset",
1130
            ((requested & RTE_ETH_RSS_UDP) == RTE_ETH_RSS_UDP) ? "" : "NOT ");
1131
    SCLogConfig("RTE_ETH_RSS_SCTP %sset",
1132
            ((requested & RTE_ETH_RSS_SCTP) == RTE_ETH_RSS_SCTP) ? "" : "NOT ");
1133
    SCLogConfig("RTE_ETH_RSS_TUNNEL %sset",
1134
            ((requested & RTE_ETH_RSS_TUNNEL) == RTE_ETH_RSS_TUNNEL) ? "" : "NOT ");
1135
1136
    SCLogConfig("REQUESTED (individual):");
1137
    SCLogConfig("RTE_ETH_RSS_IPV4 (Bit position: %d) %sset",
1138
            GetFirstSetBitPosition(RTE_ETH_RSS_IPV4), (requested & RTE_ETH_RSS_IPV4) ? "" : "NOT ");
1139
    SCLogConfig("RTE_ETH_RSS_FRAG_IPV4 (Bit position: %d) %sset",
1140
            GetFirstSetBitPosition(RTE_ETH_RSS_FRAG_IPV4),
1141
            (requested & RTE_ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
1142
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_TCP (Bit position: %d) %sset",
1143
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_TCP),
1144
            (requested & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
1145
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_UDP (Bit position: %d) %sset",
1146
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_UDP),
1147
            (requested & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
1148
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_SCTP (Bit position: %d) %sset",
1149
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_SCTP),
1150
            (requested & RTE_ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
1151
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_OTHER (Bit position: %d) %sset",
1152
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV4_OTHER),
1153
            (requested & RTE_ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
1154
    SCLogConfig("RTE_ETH_RSS_IPV6 (Bit position: %d) %sset",
1155
            GetFirstSetBitPosition(RTE_ETH_RSS_IPV6), (requested & RTE_ETH_RSS_IPV6) ? "" : "NOT ");
1156
    SCLogConfig("RTE_ETH_RSS_FRAG_IPV6 (Bit position: %d) %sset",
1157
            GetFirstSetBitPosition(RTE_ETH_RSS_FRAG_IPV6),
1158
            (requested & RTE_ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
1159
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_TCP (Bit position: %d) %sset",
1160
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_TCP),
1161
            (requested & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
1162
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_UDP (Bit position: %d) %sset",
1163
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_UDP),
1164
            (requested & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
1165
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_SCTP (Bit position: %d) %sset",
1166
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_SCTP),
1167
            (requested & RTE_ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
1168
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_OTHER (Bit position: %d) %sset",
1169
            GetFirstSetBitPosition(RTE_ETH_RSS_NONFRAG_IPV6_OTHER),
1170
            (requested & RTE_ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
1171
1172
    SCLogConfig("RTE_ETH_RSS_L2_PAYLOAD (Bit position: %d) %sset",
1173
            GetFirstSetBitPosition(RTE_ETH_RSS_L2_PAYLOAD),
1174
            (requested & RTE_ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
1175
    SCLogConfig("RTE_ETH_RSS_IPV6_EX (Bit position: %d) %sset",
1176
            GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_EX),
1177
            (requested & RTE_ETH_RSS_IPV6_EX) ? "" : "NOT ");
1178
    SCLogConfig("RTE_ETH_RSS_IPV6_TCP_EX (Bit position: %d) %sset",
1179
            GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_TCP_EX),
1180
            (requested & RTE_ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
1181
    SCLogConfig("RTE_ETH_RSS_IPV6_UDP_EX (Bit position: %d) %sset",
1182
            GetFirstSetBitPosition(RTE_ETH_RSS_IPV6_UDP_EX),
1183
            (requested & RTE_ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
1184
1185
    SCLogConfig("RTE_ETH_RSS_PORT (Bit position: %d) %sset",
1186
            GetFirstSetBitPosition(RTE_ETH_RSS_PORT), (requested & RTE_ETH_RSS_PORT) ? "" : "NOT ");
1187
    SCLogConfig("RTE_ETH_RSS_VXLAN (Bit position: %d) %sset",
1188
            GetFirstSetBitPosition(RTE_ETH_RSS_VXLAN),
1189
            (requested & RTE_ETH_RSS_VXLAN) ? "" : "NOT ");
1190
    SCLogConfig("RTE_ETH_RSS_NVGRE (Bit position: %d) %sset",
1191
            GetFirstSetBitPosition(RTE_ETH_RSS_NVGRE),
1192
            (requested & RTE_ETH_RSS_NVGRE) ? "" : "NOT ");
1193
    SCLogConfig("RTE_ETH_RSS_GTPU (Bit position: %d) %sset",
1194
            GetFirstSetBitPosition(RTE_ETH_RSS_GTPU), (requested & RTE_ETH_RSS_GTPU) ? "" : "NOT ");
1195
1196
    SCLogConfig("RTE_ETH_RSS_L3_SRC_ONLY (Bit position: %d) %sset",
1197
            GetFirstSetBitPosition(RTE_ETH_RSS_L3_SRC_ONLY),
1198
            (requested & RTE_ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
1199
    SCLogConfig("RTE_ETH_RSS_L3_DST_ONLY (Bit position: %d) %sset",
1200
            GetFirstSetBitPosition(RTE_ETH_RSS_L3_DST_ONLY),
1201
            (requested & RTE_ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
1202
    SCLogConfig("RTE_ETH_RSS_L4_SRC_ONLY (Bit position: %d) %sset",
1203
            GetFirstSetBitPosition(RTE_ETH_RSS_L4_SRC_ONLY),
1204
            (requested & RTE_ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
1205
    SCLogConfig("RTE_ETH_RSS_L4_DST_ONLY (Bit position: %d) %sset",
1206
            GetFirstSetBitPosition(RTE_ETH_RSS_L4_DST_ONLY),
1207
            (requested & RTE_ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
1208
    SCLogConfig("ACTUAL (group):");
1209
    SCLogConfig(
1210
            "RTE_ETH_RSS_IP %sset", ((actual & RTE_ETH_RSS_IP) == RTE_ETH_RSS_IP) ? "" : "NOT ");
1211
    SCLogConfig(
1212
            "RTE_ETH_RSS_TCP %sset", ((actual & RTE_ETH_RSS_TCP) == RTE_ETH_RSS_TCP) ? "" : "NOT ");
1213
    SCLogConfig(
1214
            "RTE_ETH_RSS_UDP %sset", ((actual & RTE_ETH_RSS_UDP) == RTE_ETH_RSS_UDP) ? "" : "NOT ");
1215
    SCLogConfig("RTE_ETH_RSS_SCTP %sset",
1216
            ((actual & RTE_ETH_RSS_SCTP) == RTE_ETH_RSS_SCTP) ? "" : "NOT ");
1217
    SCLogConfig("RTE_ETH_RSS_TUNNEL %sset",
1218
            ((actual & RTE_ETH_RSS_TUNNEL) == RTE_ETH_RSS_TUNNEL) ? "" : "NOT ");
1219
1220
    SCLogConfig("ACTUAL (individual flags):");
1221
    SCLogConfig("RTE_ETH_RSS_IPV4 %sset", (actual & RTE_ETH_RSS_IPV4) ? "" : "NOT ");
1222
    SCLogConfig("RTE_ETH_RSS_FRAG_IPV4 %sset", (actual & RTE_ETH_RSS_FRAG_IPV4) ? "" : "NOT ");
1223
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_TCP %sset",
1224
            (actual & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? "" : "NOT ");
1225
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_UDP %sset",
1226
            (actual & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? "" : "NOT ");
1227
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_SCTP %sset",
1228
            (actual & RTE_ETH_RSS_NONFRAG_IPV4_SCTP) ? "" : "NOT ");
1229
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV4_OTHER %sset",
1230
            (actual & RTE_ETH_RSS_NONFRAG_IPV4_OTHER) ? "" : "NOT ");
1231
    SCLogConfig("RTE_ETH_RSS_IPV6 %sset", (actual & RTE_ETH_RSS_IPV6) ? "" : "NOT ");
1232
    SCLogConfig("RTE_ETH_RSS_FRAG_IPV6 %sset", (actual & RTE_ETH_RSS_FRAG_IPV6) ? "" : "NOT ");
1233
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_TCP %sset",
1234
            (actual & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? "" : "NOT ");
1235
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_UDP %sset",
1236
            (actual & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? "" : "NOT ");
1237
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_SCTP %sset",
1238
            (actual & RTE_ETH_RSS_NONFRAG_IPV6_SCTP) ? "" : "NOT ");
1239
    SCLogConfig("RTE_ETH_RSS_NONFRAG_IPV6_OTHER %sset",
1240
            (actual & RTE_ETH_RSS_NONFRAG_IPV6_OTHER) ? "" : "NOT ");
1241
1242
    SCLogConfig("RTE_ETH_RSS_L2_PAYLOAD %sset", (actual & RTE_ETH_RSS_L2_PAYLOAD) ? "" : "NOT ");
1243
    SCLogConfig("RTE_ETH_RSS_IPV6_EX %sset", (actual & RTE_ETH_RSS_IPV6_EX) ? "" : "NOT ");
1244
    SCLogConfig("RTE_ETH_RSS_IPV6_TCP_EX %sset", (actual & RTE_ETH_RSS_IPV6_TCP_EX) ? "" : "NOT ");
1245
    SCLogConfig("RTE_ETH_RSS_IPV6_UDP_EX %sset", (actual & RTE_ETH_RSS_IPV6_UDP_EX) ? "" : "NOT ");
1246
1247
    SCLogConfig("RTE_ETH_RSS_PORT %sset", (actual & RTE_ETH_RSS_PORT) ? "" : "NOT ");
1248
    SCLogConfig("RTE_ETH_RSS_VXLAN %sset", (actual & RTE_ETH_RSS_VXLAN) ? "" : "NOT ");
1249
    SCLogConfig("RTE_ETH_RSS_NVGRE %sset", (actual & RTE_ETH_RSS_NVGRE) ? "" : "NOT ");
1250
    SCLogConfig("RTE_ETH_RSS_GTPU %sset", (actual & RTE_ETH_RSS_GTPU) ? "" : "NOT ");
1251
1252
    SCLogConfig("RTE_ETH_RSS_L3_SRC_ONLY %sset", (actual & RTE_ETH_RSS_L3_SRC_ONLY) ? "" : "NOT ");
1253
    SCLogConfig("RTE_ETH_RSS_L3_DST_ONLY %sset", (actual & RTE_ETH_RSS_L3_DST_ONLY) ? "" : "NOT ");
1254
    SCLogConfig("RTE_ETH_RSS_L4_SRC_ONLY %sset", (actual & RTE_ETH_RSS_L4_SRC_ONLY) ? "" : "NOT ");
1255
    SCLogConfig("RTE_ETH_RSS_L4_DST_ONLY %sset", (actual & RTE_ETH_RSS_L4_DST_ONLY) ? "" : "NOT ");
1256
}
1257
1258
static void DumpRXOffloadCapabilities(const uint64_t rx_offld_capa)
1259
{
1260
    SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_STRIP - %savailable",
1261
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_STRIP ? "" : "NOT ");
1262
    SCLogConfig("RTE_ETH_RX_OFFLOAD_IPV4_CKSUM - %savailable",
1263
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_IPV4_CKSUM ? "" : "NOT ");
1264
    SCLogConfig("RTE_ETH_RX_OFFLOAD_UDP_CKSUM - %savailable",
1265
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_UDP_CKSUM ? "" : "NOT ");
1266
    SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_CKSUM - %savailable",
1267
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_CKSUM ? "" : "NOT ");
1268
    SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_LRO - %savailable",
1269
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_LRO ? "" : "NOT ");
1270
    SCLogConfig("RTE_ETH_RX_OFFLOAD_QINQ_STRIP - %savailable",
1271
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_QINQ_STRIP ? "" : "NOT ");
1272
    SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM - %savailable",
1273
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM ? "" : "NOT ");
1274
    SCLogConfig("RTE_ETH_RX_OFFLOAD_MACSEC_STRIP - %savailable",
1275
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_MACSEC_STRIP ? "" : "NOT ");
1276
#if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0)
1277
    SCLogConfig("RTE_ETH_RX_OFFLOAD_HEADER_SPLIT - %savailable",
1278
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_HEADER_SPLIT ? "" : "NOT ");
1279
#endif
1280
    SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_FILTER - %savailable",
1281
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_FILTER ? "" : "NOT ");
1282
    SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_EXTEND - %savailable",
1283
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND ? "" : "NOT ");
1284
    SCLogConfig("RTE_ETH_RX_OFFLOAD_SCATTER - %savailable",
1285
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCATTER ? "" : "NOT ");
1286
    SCLogConfig("RTE_ETH_RX_OFFLOAD_TIMESTAMP - %savailable",
1287
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP ? "" : "NOT ");
1288
    SCLogConfig("RTE_ETH_RX_OFFLOAD_SECURITY - %savailable",
1289
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_SECURITY ? "" : "NOT ");
1290
    SCLogConfig("RTE_ETH_RX_OFFLOAD_KEEP_CRC - %savailable",
1291
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_KEEP_CRC ? "" : "NOT ");
1292
    SCLogConfig("RTE_ETH_RX_OFFLOAD_SCTP_CKSUM - %savailable",
1293
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCTP_CKSUM ? "" : "NOT ");
1294
    SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM - %savailable",
1295
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM ? "" : "NOT ");
1296
    SCLogConfig("RTE_ETH_RX_OFFLOAD_RSS_HASH - %savailable",
1297
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH ? "" : "NOT ");
1298
#if RTE_VERSION >= RTE_VERSION_NUM(20, 11, 0, 0)
1299
    SCLogConfig("RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT - %savailable",
1300
            rx_offld_capa & RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT ? "" : "NOT ");
1301
#endif
1302
}
1303
1304
static int DeviceValidateMTU(const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
1305
{
1306
    SCEnter();
1307
    if (iconf->mtu > dev_info->max_mtu || iconf->mtu < dev_info->min_mtu) {
1308
        SCLogError("%s: MTU out of bounds. "
1309
                   "Min MTU: %" PRIu16 " Max MTU: %" PRIu16,
1310
                iconf->iface, dev_info->min_mtu, dev_info->max_mtu);
1311
        SCReturnInt(-ERANGE);
1312
    }
1313
1314
#if RTE_VERSION < RTE_VERSION_NUM(21, 11, 0, 0)
1315
    // check if jumbo frames are set and are available
1316
    if (iconf->mtu > RTE_ETHER_MAX_LEN &&
1317
            !(dev_info->rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME)) {
1318
        SCLogError("%s: jumbo frames not supported, set MTU to 1500", iconf->iface);
1319
        SCReturnInt(-EINVAL);
1320
    }
1321
#endif
1322
1323
    SCReturnInt(0);
1324
}
1325
1326
static void DeviceSetMTU(struct rte_eth_conf *port_conf, uint16_t mtu)
1327
{
1328
#if RTE_VERSION >= RTE_VERSION_NUM(21, 11, 0, 0)
1329
    port_conf->rxmode.mtu = mtu;
1330
#else
1331
    port_conf->rxmode.max_rx_pkt_len = mtu;
1332
    if (mtu > RTE_ETHER_MAX_LEN) {
1333
        port_conf->rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
1334
    }
1335
#endif
1336
}
1337
1338
static void PortConfSetInterruptMode(const DPDKIfaceConfig *iconf, struct rte_eth_conf *port_conf)
1339
{
1340
    SCLogConfig("%s: interrupt mode is %s", iconf->iface,
1341
            iconf->flags & DPDK_IRQ_MODE ? "enabled" : "disabled");
1342
    if (iconf->flags & DPDK_IRQ_MODE)
1343
        port_conf->intr_conf.rxq = 1;
1344
}
1345
1346
static void PortConfSetRSSConf(const DPDKIfaceConfig *iconf,
1347
        const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1348
{
1349
    if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH) {
1350
        if (iconf->nb_rx_queues > 1) {
1351
            SCLogConfig("%s: RSS enabled for %d queues", iconf->iface, iconf->nb_rx_queues);
1352
            port_conf->rx_adv_conf.rss_conf = (struct rte_eth_rss_conf){
1353
                .rss_key = RSS_HKEY,
1354
                .rss_key_len = RSS_HKEY_LEN,
1355
                .rss_hf = iconf->rss_hf,
1356
            };
1357
1358
            const char *dev_driver = dev_info->driver_name;
1359
            if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
1360
                dev_driver = BondingDeviceDriverGet(iconf->port_id);
1361
            }
1362
1363
            DeviceSetPMDSpecificRSS(&port_conf->rx_adv_conf.rss_conf, dev_driver);
1364
1365
            uint64_t rss_hf_tmp =
1366
                    port_conf->rx_adv_conf.rss_conf.rss_hf & dev_info->flow_type_rss_offloads;
1367
            if (port_conf->rx_adv_conf.rss_conf.rss_hf != rss_hf_tmp) {
1368
                DumpRSSFlags(port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
1369
1370
                SCLogWarning("%s: modified RSS hash function based on hardware support: "
1371
                             "requested:%#" PRIx64 ", configured:%#" PRIx64,
1372
                        iconf->iface, port_conf->rx_adv_conf.rss_conf.rss_hf, rss_hf_tmp);
1373
                port_conf->rx_adv_conf.rss_conf.rss_hf = rss_hf_tmp;
1374
            }
1375
            port_conf->rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
1376
        } else {
1377
            SCLogConfig("%s: RSS not enabled", iconf->iface);
1378
            port_conf->rx_adv_conf.rss_conf.rss_key = NULL;
1379
            port_conf->rx_adv_conf.rss_conf.rss_hf = 0;
1380
        }
1381
    } else {
1382
        SCLogConfig("%s: RSS not supported", iconf->iface);
1383
    }
1384
}
1385
1386
static void PortConfSetChsumOffload(const DPDKIfaceConfig *iconf,
1387
        const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1388
{
1389
    if (iconf->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
1390
        SCLogConfig("%s: checksum validation disabled", iconf->iface);
1391
    } else if ((dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_CHECKSUM) ==
1392
               RTE_ETH_RX_OFFLOAD_CHECKSUM) { // multibit comparison to make sure all bits are set
1393
        if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
1394
                iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD) {
1395
            SCLogConfig("%s: IP, TCP and UDP checksum validation offloaded", iconf->iface);
1396
            port_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
1397
        } else if (iconf->checksum_mode == CHECKSUM_VALIDATION_ENABLE &&
1398
                   !(iconf->flags & DPDK_RX_CHECKSUM_OFFLOAD)) {
1399
            SCLogConfig("%s: checksum validation enabled (but can be offloaded)", iconf->iface);
1400
        }
1401
    }
1402
}
1403
1404
static void PortConfSetVlanOffload(const DPDKIfaceConfig *iconf,
1405
        const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1406
{
1407
    if (iconf->vlan_strip_enabled) {
1408
        if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_VLAN_STRIP) {
1409
            port_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_STRIP;
1410
            SCLogConfig("%s: hardware VLAN stripping enabled", iconf->iface);
1411
        } else {
1412
            SCLogWarning("%s: hardware VLAN stripping enabled but not supported, disabling",
1413
                    iconf->iface);
1414
        }
1415
    }
1416
}
1417
1418
static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
1419
        const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf)
1420
{
1421
    DumpRXOffloadCapabilities(dev_info->rx_offload_capa);
1422
    *port_conf = (struct rte_eth_conf){
1423
            .rxmode = {
1424
                    .mq_mode = RTE_ETH_MQ_RX_NONE,
1425
                    .offloads = 0, // turn every offload off to prevent any packet modification
1426
            },
1427
            .txmode = {
1428
                    .mq_mode = RTE_ETH_MQ_TX_NONE,
1429
                    .offloads = 0,
1430
            },
1431
    };
1432
1433
    PortConfSetInterruptMode(iconf, port_conf);
1434
1435
    // configure RX offloads
1436
    PortConfSetRSSConf(iconf, dev_info, port_conf);
1437
    PortConfSetChsumOffload(iconf, dev_info, port_conf);
1438
    DeviceSetMTU(port_conf, iconf->mtu);
1439
    PortConfSetVlanOffload(iconf, dev_info, port_conf);
1440
1441
    if (dev_info->tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) {
1442
        port_conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1443
    }
1444
}
1445
1446
static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info,
1447
        const struct rte_eth_conf *port_conf)
1448
{
1449
    SCEnter();
1450
    int retval;
1451
    struct rte_eth_rxconf rxq_conf;
1452
    struct rte_eth_txconf txq_conf;
1453
1454
    retval = DPDKDeviceResourcesInit(&(iconf->pkt_mempools), iconf->nb_rx_queues);
1455
    if (retval < 0) {
1456
        goto cleanup;
1457
    }
1458
1459
    // +4 for VLAN header
1460
    uint16_t mtu_size = iconf->mtu + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN + 4;
1461
    uint16_t mbuf_size = ROUNDUP(mtu_size, 1024) + RTE_PKTMBUF_HEADROOM;
1462
    // ceil the div so e.g. mp_size of 262144 and 262143 both lead to 65535 on 4 rx queues
1463
    uint32_t q_mp_sz = (iconf->mempool_size + iconf->nb_rx_queues - 1) / iconf->nb_rx_queues - 1;
1464
    uint32_t q_mp_cache_sz = iconf->mempool_cache_size_auto ? MempoolCacheSizeCalculate(q_mp_sz)
1465
                                                            : iconf->mempool_cache_size;
1466
    SCLogInfo("%s: creating %u packet mempools of size %u, cache size %u, mbuf size %u",
1467
            iconf->iface, iconf->nb_rx_queues, q_mp_sz, q_mp_cache_sz, mbuf_size);
1468
    for (int i = 0; i < iconf->nb_rx_queues; i++) {
1469
        char mempool_name[64];
1470
        snprintf(mempool_name, sizeof(mempool_name), "mp_%d_%.20s", i, iconf->iface);
1471
        iconf->pkt_mempools->pkt_mp[i] = rte_pktmbuf_pool_create(
1472
                mempool_name, q_mp_sz, q_mp_cache_sz, 0, mbuf_size, (int)iconf->socket_id);
1473
        if (iconf->pkt_mempools->pkt_mp[i] == NULL) {
1474
            retval = -rte_errno;
1475
            SCLogError("%s: rte_pktmbuf_pool_create failed with code %d (mempool: %s) - %s",
1476
                    iconf->iface, rte_errno, mempool_name, rte_strerror(rte_errno));
1477
            goto cleanup;
1478
        }
1479
    }
1480
1481
    for (uint16_t queue_id = 0; queue_id < iconf->nb_rx_queues; queue_id++) {
1482
        rxq_conf = dev_info->default_rxconf;
1483
        rxq_conf.offloads = port_conf->rxmode.offloads;
1484
        rxq_conf.rx_thresh.hthresh = 0;
1485
        rxq_conf.rx_thresh.pthresh = 0;
1486
        rxq_conf.rx_thresh.wthresh = 0;
1487
        rxq_conf.rx_free_thresh = 0;
1488
        rxq_conf.rx_drop_en = 0;
1489
        SCLogConfig("%s: setting up RX queue %d: rx_desc: %u offloads: 0x%" PRIx64
1490
                    " hthresh: %" PRIu8 " pthresh: %" PRIu8 " wthresh: %" PRIu8
1491
                    " free_thresh: %" PRIu16 " drop_en: %" PRIu8,
1492
                iconf->iface, queue_id, iconf->nb_rx_desc, rxq_conf.offloads,
1493
                rxq_conf.rx_thresh.hthresh, rxq_conf.rx_thresh.pthresh, rxq_conf.rx_thresh.wthresh,
1494
                rxq_conf.rx_free_thresh, rxq_conf.rx_drop_en);
1495
1496
        retval = rte_eth_rx_queue_setup(iconf->port_id, queue_id, iconf->nb_rx_desc,
1497
                (unsigned int)iconf->socket_id, &rxq_conf, iconf->pkt_mempools->pkt_mp[queue_id]);
1498
        if (retval < 0) {
1499
            SCLogError("%s: failed to setup RX queue %u: %s", iconf->iface, queue_id,
1500
                    rte_strerror(-retval));
1501
            goto cleanup;
1502
        }
1503
    }
1504
1505
    for (uint16_t queue_id = 0; queue_id < iconf->nb_tx_queues; queue_id++) {
1506
        txq_conf = dev_info->default_txconf;
1507
        txq_conf.offloads = port_conf->txmode.offloads;
1508
        SCLogConfig("%s: setting up TX queue %d: tx_desc: %" PRIu16 " tx: offloads: 0x%" PRIx64
1509
                    " hthresh: %" PRIu8 " pthresh: %" PRIu8 " wthresh: %" PRIu8
1510
                    " tx_free_thresh: %" PRIu16 " tx_rs_thresh: %" PRIu16
1511
                    " txq_deferred_start: %" PRIu8,
1512
                iconf->iface, queue_id, iconf->nb_tx_desc, txq_conf.offloads,
1513
                txq_conf.tx_thresh.hthresh, txq_conf.tx_thresh.pthresh, txq_conf.tx_thresh.wthresh,
1514
                txq_conf.tx_free_thresh, txq_conf.tx_rs_thresh, txq_conf.tx_deferred_start);
1515
        retval = rte_eth_tx_queue_setup(iconf->port_id, queue_id, iconf->nb_tx_desc,
1516
                (unsigned int)iconf->socket_id, &txq_conf);
1517
        if (retval < 0) {
1518
            SCLogError("%s: failed to setup TX queue %u: %s", iconf->iface, queue_id,
1519
                    rte_strerror(-retval));
1520
            retval = -1; // the error code explained, informing about failure
1521
            goto cleanup;
1522
        }
1523
    }
1524
1525
    SCReturnInt(0);
1526
1527
cleanup:
1528
    DPDKDeviceResourcesDeinit(&iconf->pkt_mempools);
1529
    SCReturnInt(retval);
1530
}
1531
1532
static int DeviceValidateOutIfaceConfig(DPDKIfaceConfig *iconf)
1533
{
1534
    SCEnter();
1535
    int retval;
1536
    DPDKIfaceConfig *out_iconf = NULL;
1537
    ConfigInit(&out_iconf);
1538
    if (out_iconf == NULL) {
1539
        FatalError("Copy interface of the interface \"%s\" is NULL", iconf->iface);
1540
    }
1541
1542
    retval = ConfigLoad(out_iconf, iconf->out_iface);
1543
    if (retval < 0) {
1544
        SCLogError("%s: fail to load config of interface", iconf->out_iface);
1545
        out_iconf->DerefFunc(out_iconf);
1546
        SCReturnInt(-EINVAL);
1547
    }
1548
1549
    if (iconf->nb_rx_queues != out_iconf->nb_tx_queues) {
1550
        // the other direction is validated when the copy interface is configured
1551
        SCLogError("%s: configured %d RX queues but copy interface %s has %d TX queues"
1552
                   " - number of queues must be equal",
1553
                iconf->iface, iconf->nb_rx_queues, out_iconf->iface, out_iconf->nb_tx_queues);
1554
        out_iconf->DerefFunc(out_iconf);
1555
        SCReturnInt(-EINVAL);
1556
    } else if (iconf->mtu != out_iconf->mtu) {
1557
        SCLogError("%s: configured MTU of %d but copy interface %s has MTU set to %d"
1558
                   " - MTU must be equal",
1559
                iconf->iface, iconf->mtu, out_iconf->iface, out_iconf->mtu);
1560
        out_iconf->DerefFunc(out_iconf);
1561
        SCReturnInt(-EINVAL);
1562
    } else if (iconf->copy_mode != out_iconf->copy_mode) {
1563
        SCLogError("%s: copy modes of interfaces %s and %s are not equal", iconf->iface,
1564
                iconf->iface, out_iconf->iface);
1565
        out_iconf->DerefFunc(out_iconf);
1566
        SCReturnInt(-EINVAL);
1567
    } else if (strcmp(iconf->iface, out_iconf->out_iface) != 0) {
1568
        // check if the other iface has the current iface set as a copy iface
1569
        SCLogError("%s: copy interface of %s is not set to %s", iconf->iface, out_iconf->iface,
1570
                iconf->iface);
1571
        out_iconf->DerefFunc(out_iconf);
1572
        SCReturnInt(-EINVAL);
1573
    }
1574
1575
    out_iconf->DerefFunc(out_iconf);
1576
    SCReturnInt(0);
1577
}
1578
1579
static int DeviceConfigureIPS(DPDKIfaceConfig *iconf)
1580
{
1581
    SCEnter();
1582
    if (iconf->out_iface != NULL) {
1583
        if (!rte_eth_dev_is_valid_port(iconf->out_port_id)) {
1584
            SCLogError("%s: retrieved copy interface port ID \"%d\" is invalid or the device is "
1585
                       "not attached ",
1586
                    iconf->iface, iconf->out_port_id);
1587
            SCReturnInt(-ENODEV);
1588
        }
1589
        int32_t out_port_socket_id;
1590
        int retval = DPDKDeviceSetSocketID(iconf->out_port_id, &out_port_socket_id);
1591
        if (retval < 0) {
1592
            SCLogError("%s: invalid socket id: %s", iconf->out_iface, rte_strerror(-retval));
1593
            SCReturnInt(retval);
1594
        }
1595
1596
        if (iconf->socket_id != out_port_socket_id) {
1597
            SCLogWarning(
1598
                    "%s: out iface %s is not on the same NUMA node (%s - NUMA %d, %s - NUMA %d)",
1599
                    iconf->iface, iconf->out_iface, iconf->iface, iconf->socket_id,
1600
                    iconf->out_iface, out_port_socket_id);
1601
        }
1602
1603
        retval = DeviceValidateOutIfaceConfig(iconf);
1604
        if (retval != 0) {
1605
            // Error will be written out by the validation function
1606
            SCReturnInt(retval);
1607
        }
1608
1609
        if (iconf->copy_mode == DPDK_COPY_MODE_IPS)
1610
            SCLogInfo("%s: DPDK IPS mode activated: %s->%s", iconf->iface, iconf->iface,
1611
                    iconf->out_iface);
1612
        else if (iconf->copy_mode == DPDK_COPY_MODE_TAP)
1613
            SCLogInfo("%s: DPDK TAP mode activated: %s->%s", iconf->iface, iconf->iface,
1614
                    iconf->out_iface);
1615
    }
1616
    SCReturnInt(0);
1617
}
1618
1619
/**
1620
 * Function verifies changes in e.g. device info after configuration has
1621
 * happened. Sometimes (e.g. DPDK Bond PMD with Intel NICs i40e/ixgbe) change
1622
 * device info only after the device configuration.
1623
 * @param iconf
1624
 * @param dev_info
1625
 * @return 0 on success, -EAGAIN when reconfiguration is needed, <0 on failure
1626
 */
1627
static int32_t DeviceVerifyPostConfigure(
1628
        const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
1629
{
1630
    SCEnter();
1631
    struct rte_eth_dev_info post_conf_dev_info = { 0 };
1632
    int32_t ret = rte_eth_dev_info_get(iconf->port_id, &post_conf_dev_info);
1633
    if (ret < 0) {
1634
        SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-ret));
1635
        SCReturnInt(ret);
1636
    }
1637
1638
    if (dev_info->flow_type_rss_offloads != post_conf_dev_info.flow_type_rss_offloads ||
1639
            dev_info->rx_offload_capa != post_conf_dev_info.rx_offload_capa ||
1640
            dev_info->tx_offload_capa != post_conf_dev_info.tx_offload_capa ||
1641
            dev_info->max_rx_queues != post_conf_dev_info.max_rx_queues ||
1642
            dev_info->max_tx_queues != post_conf_dev_info.max_tx_queues ||
1643
            dev_info->max_mtu != post_conf_dev_info.max_mtu) {
1644
        SCLogWarning("%s: device information severely changed after configuration, reconfiguring",
1645
                iconf->iface);
1646
        return -EAGAIN;
1647
    }
1648
1649
    if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
1650
        ret = BondingAllDevicesSameDriver(iconf->port_id);
1651
        if (ret < 0) {
1652
            SCLogError("%s: bond port uses port with different DPDK drivers", iconf->iface);
1653
            SCReturnInt(ret);
1654
        }
1655
    }
1656
1657
    return 0;
1658
}
1659
1660
static int DeviceConfigure(DPDKIfaceConfig *iconf)
1661
{
1662
    SCEnter();
1663
    if (!rte_eth_dev_is_valid_port(iconf->port_id)) {
1664
        SCLogError("%s: retrieved port ID \"%d\" is invalid or the device is not attached ",
1665
                iconf->iface, iconf->port_id);
1666
        SCReturnInt(-ENODEV);
1667
    }
1668
1669
    int32_t retval = DPDKDeviceSetSocketID(iconf->port_id, &iconf->socket_id);
1670
    if (retval < 0) {
1671
        SCLogError("%s: invalid socket id: %s", iconf->iface, rte_strerror(-retval));
1672
        SCReturnInt(retval);
1673
    }
1674
1675
    struct rte_eth_dev_info dev_info = { 0 };
1676
    retval = rte_eth_dev_info_get(iconf->port_id, &dev_info);
1677
    if (retval < 0) {
1678
        SCLogError("%s: getting device info failed: %s", iconf->iface, rte_strerror(-retval));
1679
        SCReturnInt(retval);
1680
    }
1681
1682
    if (iconf->nb_rx_queues > dev_info.max_rx_queues) {
1683
        SCLogError("%s: configured RX queues %u is higher than device maximum (%" PRIu16 ")",
1684
                iconf->iface, iconf->nb_rx_queues, dev_info.max_rx_queues);
1685
        SCReturnInt(-ERANGE);
1686
    }
1687
1688
    if (iconf->nb_tx_queues > dev_info.max_tx_queues) {
1689
        SCLogError("%s: configured TX queues %u is higher than device maximum (%" PRIu16 ")",
1690
                iconf->iface, iconf->nb_tx_queues, dev_info.max_tx_queues);
1691
        SCReturnInt(-ERANGE);
1692
    }
1693
1694
    retval = DeviceValidateMTU(iconf, &dev_info);
1695
    if (retval < 0)
1696
        return retval;
1697
1698
    struct rte_eth_conf port_conf = { 0 };
1699
    DeviceInitPortConf(iconf, &dev_info, &port_conf);
1700
    if (port_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) {
1701
        // Suricata does not need recalc checksums now
1702
        iconf->checksum_mode = CHECKSUM_VALIDATION_OFFLOAD;
1703
    }
1704
1705
    retval = rte_eth_dev_configure(
1706
            iconf->port_id, iconf->nb_rx_queues, iconf->nb_tx_queues, &port_conf);
1707
    if (retval < 0) {
1708
        SCLogError("%s: failed to configure the device: %s", iconf->iface, rte_strerror(-retval));
1709
        SCReturnInt(retval);
1710
    }
1711
1712
    retval = DeviceVerifyPostConfigure(iconf, &dev_info);
1713
    if (retval < 0)
1714
        return retval;
1715
1716
    uint16_t tmp_nb_rx_desc = iconf->nb_rx_desc;
1717
    uint16_t tmp_nb_tx_desc = iconf->nb_tx_desc;
1718
    retval = rte_eth_dev_adjust_nb_rx_tx_desc(
1719
            iconf->port_id, &iconf->nb_rx_desc, &iconf->nb_tx_desc);
1720
    if (retval != 0) {
1721
        SCLogError("%s: failed to adjust device queue descriptors: %s", iconf->iface,
1722
                rte_strerror(-retval));
1723
        SCReturnInt(retval);
1724
    } else if (tmp_nb_rx_desc != iconf->nb_rx_desc || tmp_nb_tx_desc != iconf->nb_tx_desc) {
1725
        SCLogWarning("%s: device queue descriptors adjusted (RX: from %u to %u, TX: from %u to %u)",
1726
                iconf->iface, tmp_nb_rx_desc, iconf->nb_rx_desc, tmp_nb_tx_desc, iconf->nb_tx_desc);
1727
    }
1728
1729
    retval = iconf->flags & DPDK_MULTICAST ? rte_eth_allmulticast_enable(iconf->port_id)
1730
                                           : rte_eth_allmulticast_disable(iconf->port_id);
1731
    if (retval == -ENOTSUP) {
1732
        retval = rte_eth_allmulticast_get(iconf->port_id);
1733
        // when multicast is enabled but set to disable or vice versa
1734
        if ((retval == 1 && !(iconf->flags & DPDK_MULTICAST)) ||
1735
                (retval == 0 && (iconf->flags & DPDK_MULTICAST))) {
1736
            SCLogWarning("%s: cannot configure allmulticast, the port is %sin allmulticast mode",
1737
                    iconf->iface, retval == 1 ? "" : "not ");
1738
        } else if (retval < 0) {
1739
            SCLogError("%s: failed to get multicast mode: %s", iconf->iface, rte_strerror(-retval));
1740
            SCReturnInt(retval);
1741
        }
1742
    } else if (retval < 0) {
1743
        SCLogError("%s: error when changing multicast setting: %s", iconf->iface,
1744
                rte_strerror(-retval));
1745
        SCReturnInt(retval);
1746
    }
1747
1748
    retval = iconf->flags & DPDK_PROMISC ? rte_eth_promiscuous_enable(iconf->port_id)
1749
                                         : rte_eth_promiscuous_disable(iconf->port_id);
1750
    if (retval == -ENOTSUP) {
1751
        retval = rte_eth_promiscuous_get(iconf->port_id);
1752
        if ((retval == 1 && !(iconf->flags & DPDK_PROMISC)) ||
1753
                (retval == 0 && (iconf->flags & DPDK_PROMISC))) {
1754
            SCLogError("%s: cannot configure promiscuous mode, the port is in %spromiscuous mode",
1755
                    iconf->iface, retval == 1 ? "" : "non-");
1756
            SCReturnInt(TM_ECODE_FAILED);
1757
        } else if (retval < 0) {
1758
            SCLogError(
1759
                    "%s: failed to get promiscuous mode: %s", iconf->iface, rte_strerror(-retval));
1760
            SCReturnInt(retval);
1761
        }
1762
    } else if (retval < 0) {
1763
        SCLogError("%s: error when changing promiscuous setting: %s", iconf->iface,
1764
                rte_strerror(-retval));
1765
        SCReturnInt(TM_ECODE_FAILED);
1766
    }
1767
1768
    // set maximum transmission unit
1769
    SCLogConfig("%s: setting MTU to %d", iconf->iface, iconf->mtu);
1770
    retval = rte_eth_dev_set_mtu(iconf->port_id, iconf->mtu);
1771
    if (retval == -ENOTSUP) {
1772
        // if it is not possible to set the MTU, retrieve it
1773
        retval = rte_eth_dev_get_mtu(iconf->port_id, &iconf->mtu);
1774
        if (retval < 0) {
1775
            SCLogError("%s: failed to retrieve MTU: %s", iconf->iface, rte_strerror(-retval));
1776
            SCReturnInt(retval);
1777
        }
1778
        SCLogWarning(
1779
                "%s: changing MTU is not supported, current MTU: %u", iconf->iface, iconf->mtu);
1780
    } else if (retval < 0) {
1781
        SCLogError(
1782
                "%s: failed to set MTU to %u: %s", iconf->iface, iconf->mtu, rte_strerror(-retval));
1783
        SCReturnInt(retval);
1784
    }
1785
1786
    retval = DeviceConfigureQueues(iconf, &dev_info, &port_conf);
1787
    if (retval < 0) {
1788
        SCReturnInt(retval);
1789
    }
1790
1791
    retval = DeviceConfigureIPS(iconf);
1792
    if (retval < 0) {
1793
        SCReturnInt(retval);
1794
    }
1795
1796
    SCReturnInt(0);
1797
}
1798
1799
static void *ParseDpdkConfigAndConfigureDevice(const char *iface)
1800
{
1801
    int retval;
1802
    DPDKIfaceConfig *iconf = ConfigParse(iface);
1803
    if (iconf == NULL) {
1804
        FatalError("DPDK configuration could not be parsed");
1805
    }
1806
1807
    retval = DeviceConfigure(iconf);
1808
    if (retval == -EAGAIN) {
1809
        // for e.g. bonding PMD it needs to be reconfigured
1810
        retval = DeviceConfigure(iconf);
1811
    }
1812
1813
    if (retval < 0) { // handles both configure attempts
1814
        iconf->DerefFunc(iconf);
1815
        if (rte_eal_cleanup() != 0)
1816
            FatalError("EAL cleanup failed: %s", rte_strerror(-retval));
1817
1818
        if (retval == -ENOMEM) {
1819
            FatalError("%s: memory allocation failed - consider"
1820
                       "%s freeing up some memory.",
1821
                    iface,
1822
                    rte_eal_has_hugepages() != 0 ? " increasing the number of hugepages or" : "");
1823
        } else {
1824
            FatalError("%s: failed to configure", iface);
1825
        }
1826
    }
1827
1828
    SC_ATOMIC_RESET(iconf->ref);
1829
    (void)SC_ATOMIC_ADD(iconf->ref, iconf->threads);
1830
    // This counter is increased by worker threads that individually pick queue IDs.
1831
    SC_ATOMIC_RESET(iconf->queue_id);
1832
    SC_ATOMIC_RESET(iconf->inconsistent_numa_cnt);
1833
    iconf->workers_sync = SCCalloc(1, sizeof(*iconf->workers_sync));
1834
    if (iconf->workers_sync == NULL) {
1835
        FatalError("Failed to allocate memory for workers_sync");
1836
    }
1837
    SC_ATOMIC_RESET(iconf->workers_sync->worker_checked_in);
1838
    iconf->workers_sync->worker_cnt = iconf->threads;
1839
1840
    // initialize LiveDev DPDK values
1841
    LiveDevice *ldev_instance = LiveGetDevice(iface);
1842
    if (ldev_instance == NULL) {
1843
        FatalError("Device %s is not registered as a live device", iface);
1844
    }
1845
    ldev_instance->dpdk_vars = iconf->pkt_mempools;
1846
    iconf->pkt_mempools = NULL;
1847
    return iconf;
1848
}
1849
1850
/**
1851
 * \brief extract information from config file
1852
 *
1853
 * The returned structure will be freed by the thread init function.
1854
 * This is thus necessary to or copy the structure before giving it
1855
 * to thread or to reparse the file for each thread (and thus have
1856
 * new structure.
1857
 *
1858
 * After configuration is loaded, DPDK also configures the device according to the settings.
1859
 *
1860
 * \return a DPDKIfaceConfig corresponding to the interface name
1861
 */
1862
1863
static int DPDKConfigGetThreadsCount(void *conf)
1864
{
1865
    if (conf == NULL)
1866
        FatalError("Configuration file is NULL");
1867
1868
    DPDKIfaceConfig *dpdk_conf = (DPDKIfaceConfig *)conf;
1869
    return dpdk_conf->threads;
1870
}
1871
1872
#endif /* HAVE_DPDK */
1873
1874
static int DPDKRunModeIsIPS(void)
1875
0
{
1876
    /* Find initial node */
1877
0
    const char dpdk_node_query[] = "dpdk.interfaces";
1878
0
    SCConfNode *dpdk_node = SCConfGetNode(dpdk_node_query);
1879
0
    if (dpdk_node == NULL) {
1880
0
        FatalError("Unable to get %s configuration node", dpdk_node_query);
1881
0
    }
1882
1883
0
    const char default_iface[] = "default";
1884
0
    SCConfNode *if_default = SCConfNodeLookupKeyValue(dpdk_node, "interface", default_iface);
1885
0
    int nlive = LiveGetDeviceCount();
1886
0
    bool has_ips = false;
1887
0
    bool has_ids = false;
1888
0
    for (int ldev = 0; ldev < nlive; ldev++) {
1889
0
        const char *live_dev = LiveGetDeviceName(ldev);
1890
0
        if (live_dev == NULL)
1891
0
            FatalError("Unable to get device id %d from LiveDevice list", ldev);
1892
1893
0
        SCConfNode *if_root = ConfFindDeviceConfig(dpdk_node, live_dev);
1894
0
        if (if_root == NULL) {
1895
0
            if (if_default == NULL)
1896
0
                FatalError("Unable to get %s or %s  interface", live_dev, default_iface);
1897
1898
0
            if_root = if_default;
1899
0
        }
1900
1901
0
        const char *copymodestr = NULL;
1902
0
        const char *copyifacestr = NULL;
1903
0
        if (SCConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
1904
0
                SCConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
1905
0
            if (strcmp(copymodestr, "ips") == 0) {
1906
0
                has_ips = true;
1907
0
            } else {
1908
0
                has_ids = true;
1909
0
            }
1910
0
        } else {
1911
0
            has_ids = true;
1912
0
        }
1913
1914
0
        if (has_ids && has_ips) {
1915
0
            FatalError("Copy-mode of interface %s mixes with the previously set copy-modes "
1916
0
                       "(only IDS/TAP and IPS copy-mode combinations are allowed in DPDK",
1917
0
                    live_dev);
1918
0
        }
1919
0
    }
1920
1921
0
    return has_ips;
1922
0
}
1923
1924
static int DPDKRunModeEnableIPS(void)
1925
0
{
1926
0
    int r = DPDKRunModeIsIPS();
1927
0
    if (r == 1) {
1928
0
        SCLogInfo("Setting IPS mode");
1929
0
        EngineModeSetIPS();
1930
0
    }
1931
0
    return r;
1932
0
}
1933
1934
const char *RunModeDpdkGetDefaultMode(void)
1935
0
{
1936
0
    return "workers";
1937
0
}
1938
1939
void RunModeDpdkRegister(void)
1940
87
{
1941
87
    RunModeRegisterNewRunMode(RUNMODE_DPDK, "workers",
1942
87
            "Workers DPDK mode, each thread does all"
1943
87
            " tasks from acquisition to logging",
1944
87
            RunModeIdsDpdkWorkers, DPDKRunModeEnableIPS);
1945
87
}
1946
1947
/**
1948
 * \brief Workers version of the DPDK processing.
1949
 *
1950
 * Start N threads with each thread doing all the work.
1951
 *
1952
 */
1953
int RunModeIdsDpdkWorkers(void)
1954
0
{
1955
0
    SCEnter();
1956
#ifdef HAVE_DPDK
1957
    int ret;
1958
1959
    TimeModeSetLive();
1960
1961
    InitEal();
1962
    ret = RunModeSetLiveCaptureWorkers(ParseDpdkConfigAndConfigureDevice, DPDKConfigGetThreadsCount,
1963
            "ReceiveDPDK", "DecodeDPDK", thread_name_workers, NULL);
1964
    if (ret != 0) {
1965
        FatalError("Unable to start runmode");
1966
    }
1967
1968
    SCLogDebug("RunModeIdsDpdkWorkers initialised");
1969
1970
#endif /* HAVE_DPDK */
1971
0
    SCReturnInt(0);
1972
0
}
1973
1974
/**
1975
 * @}
1976
 */