• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22831693654

08 Mar 2026 10:49PM UTC coverage: 18.953%. First build
22831693654

Pull #14992

github

web-flow
Merge 63d2a22b3 into 29834e391
Pull Request #14992: dpdk: segmented mbufs + net_pcap PCAP EOF V6

28 of 110 new or added lines in 2 files covered. (25.45%)

38610 of 203712 relevant lines covered (18.95%)

1451584.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.21
/src/source-dpdk.c
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
 *  \defgroup dpdk DPDK running mode
20
 *
21
 *  @{
22
 */
23

24
/**
25
 * \file
26
 *
27
 * \author Lukas Sismis <lukas.sismis@gmail.com>
28
 *
29
 * DPDK capture interface
30
 *
31
 */
32

33
#include "suricata-common.h"
34
#include "runmodes.h"
35
#include "decode.h"
36
#include "packet.h"
37
#include "source-dpdk.h"
38
#include "suricata.h"
39
#include "threads.h"
40
#include "threadvars.h"
41
#include "tm-threads.h"
42
#include "tmqh-packetpool.h"
43
#include "util-privs.h"
44
#include "util-device-private.h"
45
#include "action-globals.h"
46

47
#ifndef HAVE_DPDK
48

49
TmEcode NoDPDKSupportExit(ThreadVars *, const void *, void **);
50

51
void TmModuleReceiveDPDKRegister(void)
52
{
53
    tmm_modules[TMM_RECEIVEDPDK].name = "ReceiveDPDK";
54
    tmm_modules[TMM_RECEIVEDPDK].ThreadInit = NoDPDKSupportExit;
55
    tmm_modules[TMM_RECEIVEDPDK].Func = NULL;
56
    tmm_modules[TMM_RECEIVEDPDK].ThreadExitPrintStats = NULL;
57
    tmm_modules[TMM_RECEIVEDPDK].ThreadDeinit = NULL;
58
    tmm_modules[TMM_RECEIVEDPDK].cap_flags = 0;
59
    tmm_modules[TMM_RECEIVEDPDK].flags = TM_FLAG_RECEIVE_TM;
60
}
61

62
/**
63
 * \brief Registration Function for DecodeDPDK.
64
 */
65
void TmModuleDecodeDPDKRegister(void)
66
{
67
    tmm_modules[TMM_DECODEDPDK].name = "DecodeDPDK";
68
    tmm_modules[TMM_DECODEDPDK].ThreadInit = NoDPDKSupportExit;
69
    tmm_modules[TMM_DECODEDPDK].Func = NULL;
70
    tmm_modules[TMM_DECODEDPDK].ThreadExitPrintStats = NULL;
71
    tmm_modules[TMM_DECODEDPDK].ThreadDeinit = NULL;
72
    tmm_modules[TMM_DECODEDPDK].cap_flags = 0;
73
    tmm_modules[TMM_DECODEDPDK].flags = TM_FLAG_DECODE_TM;
74
}
75

76
/**
77
 * \brief this function prints an error message and exits.
78
 */
79
TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data)
80
{
81
    FatalError("Error creating thread %s: you do not have "
82
               "support for DPDK enabled, on Linux host please recompile "
83
               "with --enable-dpdk",
84
            tv->name);
85
}
86

87
#else /* We have DPDK support */
88

89
#include "util-affinity.h"
90
#include "util-dpdk.h"
91
#include "util-dpdk-i40e.h"
92
#include "util-dpdk-ice.h"
93
#include "util-dpdk-ixgbe.h"
94
#include "util-dpdk-mlx5.h"
95
#include "util-dpdk-bonding.h"
96
#include <numa.h>
97

98
#define BURST_SIZE 32
17,282,529✔
99
// interrupt mode constants
100
#define MIN_ZERO_POLL_COUNT          10U
2,147,483,647✔
101
#define MIN_ZERO_POLL_COUNT_TO_SLEEP 10U
×
102
#define MINIMUM_SLEEP_TIME_US        1U
×
103
#define STANDARD_SLEEP_TIME_US       100U
2,147,483,647✔
104
#define MAX_EPOLL_TIMEOUT_MS         500U
2,147,483,647✔
105
static rte_spinlock_t intr_lock[RTE_MAX_ETHPORTS];
106
static SC_ATOMIC_DECL_AND_INIT(uint16_t, pcap_workers_left);
107

108
void DPDKPcapWorkersSync(uint16_t workers)
NEW
109
{
×
NEW
110
    SC_ATOMIC_ADD(pcap_workers_left, workers);
×
NEW
111
}
×
112

113
/**
114
 * \brief Structure to hold thread specific variables.
115
 */
116
typedef struct DPDKThreadVars_ {
117
    /* counters */
118
    uint64_t pkts;
119
    ThreadVars *tv;
120
    TmSlot *slot;
121
    LiveDevice *livedev;
122
    ChecksumValidationMode checksum_mode;
123
    bool intr_enabled;
124
    bool is_pcap_iface;
125
    /* references to packet and drop counters */
126
    StatsCounterId capture_dpdk_packets;
127
    StatsCounterId capture_dpdk_rx_errs;
128
    StatsCounterId capture_dpdk_imissed;
129
    StatsCounterId capture_dpdk_rx_no_mbufs;
130
    StatsCounterId capture_dpdk_ierrors;
131
    StatsCounterId capture_dpdk_tx_errs;
132
    unsigned int flags;
133
    uint16_t threads;
134
    /* for IPS */
135
    DpdkCopyModeEnum copy_mode;
136
    uint16_t out_port_id;
137
    /* Entry in the peers_list */
138

139
    uint64_t bytes;
140
    uint64_t accepted;
141
    uint64_t dropped;
142
    uint16_t port_id;
143
    uint16_t queue_id;
144
    int32_t port_socket_id;
145
    struct rte_mbuf *received_mbufs[BURST_SIZE];
146
    DPDKWorkerSync *workers_sync;
147
} DPDKThreadVars;
148

149
static TmEcode ReceiveDPDKThreadInit(ThreadVars *, const void *, void **);
150
static TmEcode ReceiveDPDKThreadDeinit(ThreadVars *, void *);
151
static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot);
152

153
static TmEcode DecodeDPDKThreadInit(ThreadVars *, const void *, void **);
154
static TmEcode DecodeDPDKThreadDeinit(ThreadVars *tv, void *data);
155
static TmEcode DecodeDPDK(ThreadVars *, Packet *, void *);
156

157
static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset);
158
static bool InterruptsRXEnable(uint16_t port_id, uint16_t queue_id)
159
{
×
160
    uint32_t event_data = (uint32_t)port_id << UINT16_WIDTH | queue_id;
×
161
    int32_t ret = rte_eth_dev_rx_intr_ctl_q(port_id, queue_id, RTE_EPOLL_PER_THREAD,
×
162
            RTE_INTR_EVENT_ADD, (void *)((uintptr_t)event_data));
×
163

164
    if (ret != 0) {
×
165
        SCLogError("%s-Q%d: failed to enable interrupt mode: %s", DPDKGetPortNameByPortID(port_id),
×
166
                queue_id, rte_strerror(-ret));
×
167
        return false;
×
168
    }
×
169
    return true;
×
170
}
×
171

172
static inline uint32_t InterruptsSleepHeuristic(uint32_t no_pkt_polls_count)
173
{
×
174
    if (no_pkt_polls_count < MIN_ZERO_POLL_COUNT_TO_SLEEP)
×
175
        return MINIMUM_SLEEP_TIME_US;
×
176

177
    return STANDARD_SLEEP_TIME_US;
×
178
}
×
179

180
static inline void InterruptsTurnOnOff(uint16_t port_id, uint16_t queue_id, bool on)
181
{
×
182
    rte_spinlock_lock(&(intr_lock[port_id]));
×
183

184
    if (on)
×
185
        rte_eth_dev_rx_intr_enable(port_id, queue_id);
×
186
    else
×
187
        rte_eth_dev_rx_intr_disable(port_id, queue_id);
×
188

189
    rte_spinlock_unlock(&(intr_lock[port_id]));
×
190
}
×
191

192
static inline void DPDKFreeMbufArray(
193
        struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset)
194
{
×
195
    for (int i = offset; i < mbuf_cnt; i++) {
×
196
        rte_pktmbuf_free(mbuf_array[i]);
×
197
    }
×
198
}
×
199

200
static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
201
{
16✔
202
    if (strcmp(driver_name, "net_bonding") == 0)
16✔
203
        driver_name = BondingDeviceDriverGet(ptv->port_id);
6✔
204
    if (strcmp(driver_name, "net_i40e") == 0)
16✔
205
        i40eDeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
×
206
    else if (strcmp(driver_name, "net_ixgbe") == 0)
16✔
207
        ixgbeDeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
×
208
    else if (strcmp(driver_name, "net_ice") == 0)
16✔
209
        iceDeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
×
210
    else if (strcmp(driver_name, "mlx5_pci") == 0)
16✔
211
        mlx5DeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
×
212
}
16✔
213

214
static void DevicePreClosePMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
215
{
16✔
216
    if (strcmp(driver_name, "net_bonding") == 0) {
16✔
217
        driver_name = BondingDeviceDriverGet(ptv->port_id);
6✔
218
    }
6✔
219

220
    if (
16✔
221
#if RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0)
16✔
222
            strcmp(driver_name, "net_i40e") == 0 ||
16✔
223
#endif /* RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0) */
16✔
224
            strcmp(driver_name, "net_ixgbe") == 0 || strcmp(driver_name, "net_ice") == 0 ||
16✔
225
            strcmp(driver_name, "mlx5_pci") == 0) {
16✔
226
        // Flush the RSS rules that have been inserted in the post start section
227
        struct rte_flow_error flush_error = { 0 };
×
228
        int32_t retval = rte_flow_flush(ptv->port_id, &flush_error);
×
229
        if (retval != 0) {
×
230
            SCLogError("%s: unable to flush rte_flow rules: %s Flush error msg: %s",
×
231
                    ptv->livedev->dev, rte_strerror(-retval), flush_error.message);
×
232
        }
×
233
    }
×
234
}
16✔
235

236
/**
237
 * Attempts to retrieve NUMA node id on which the caller runs
238
 * @return NUMA id on success, -1 otherwise
239
 */
240
static int GetNumaNode(void)
241
{
24✔
242
    int cpu = 0;
24✔
243
    int node = -1;
24✔
244

245
#if defined(__linux__)
24✔
246
    cpu = sched_getcpu();
24✔
247
    node = numa_node_of_cpu(cpu);
24✔
248
#else
249
    SCLogWarning("NUMA node retrieval is not supported on this OS.");
250
#endif
251

252
    return node;
24✔
253
}
24✔
254

255
/**
256
 * \brief Registration Function for ReceiveDPDK.
257
 * \todo Unit tests are needed for this module.
258
 */
259
void TmModuleReceiveDPDKRegister(void)
260
{
27✔
261
    tmm_modules[TMM_RECEIVEDPDK].name = "ReceiveDPDK";
27✔
262
    tmm_modules[TMM_RECEIVEDPDK].ThreadInit = ReceiveDPDKThreadInit;
27✔
263
    tmm_modules[TMM_RECEIVEDPDK].Func = NULL;
27✔
264
    tmm_modules[TMM_RECEIVEDPDK].PktAcqLoop = ReceiveDPDKLoop;
27✔
265
    tmm_modules[TMM_RECEIVEDPDK].PktAcqBreakLoop = NULL;
27✔
266
    tmm_modules[TMM_RECEIVEDPDK].ThreadExitPrintStats = NULL;
27✔
267
    tmm_modules[TMM_RECEIVEDPDK].ThreadDeinit = ReceiveDPDKThreadDeinit;
27✔
268
    tmm_modules[TMM_RECEIVEDPDK].cap_flags = SC_CAP_NET_RAW;
27✔
269
    tmm_modules[TMM_RECEIVEDPDK].flags = TM_FLAG_RECEIVE_TM;
27✔
270
}
27✔
271

272
/**
273
 * \brief Registration Function for DecodeDPDK.
274
 * \todo Unit tests are needed for this module.
275
 */
276
void TmModuleDecodeDPDKRegister(void)
277
{
27✔
278
    tmm_modules[TMM_DECODEDPDK].name = "DecodeDPDK";
27✔
279
    tmm_modules[TMM_DECODEDPDK].ThreadInit = DecodeDPDKThreadInit;
27✔
280
    tmm_modules[TMM_DECODEDPDK].Func = DecodeDPDK;
27✔
281
    tmm_modules[TMM_DECODEDPDK].ThreadExitPrintStats = NULL;
27✔
282
    tmm_modules[TMM_DECODEDPDK].ThreadDeinit = DecodeDPDKThreadDeinit;
27✔
283
    tmm_modules[TMM_DECODEDPDK].cap_flags = 0;
27✔
284
    tmm_modules[TMM_DECODEDPDK].flags = TM_FLAG_DECODE_TM;
27✔
285
}
27✔
286

287
static inline void DPDKDumpCounters(DPDKThreadVars *ptv)
288
{
198✔
289
    /* Some NICs (e.g. Intel) do not support queue statistics and the drops can be fetched only on
290
     * the port level. Therefore setting it to the first worker to have at least continuous update
291
     * on the dropped packets. */
292
    if (ptv->queue_id == 0) {
198✔
293
        struct rte_eth_stats eth_stats;
121✔
294
        int retval = rte_eth_stats_get(ptv->port_id, &eth_stats);
121✔
295
        if (unlikely(retval != 0)) {
121✔
296
            SCLogError("%s: failed to get stats: %s", ptv->livedev->dev, rte_strerror(-retval));
×
297
            return;
×
298
        }
×
299

300
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_packets,
121✔
301
                ptv->pkts + eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
121✔
302
        SC_ATOMIC_SET(ptv->livedev->pkts,
121✔
303
                eth_stats.ipackets + eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
121✔
304
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_rx_errs,
121✔
305
                eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
121✔
306
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_imissed, eth_stats.imissed);
121✔
307
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_rx_no_mbufs, eth_stats.rx_nombuf);
121✔
308
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_ierrors, eth_stats.ierrors);
121✔
309
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_tx_errs, eth_stats.oerrors);
121✔
310
        SC_ATOMIC_SET(
121✔
311
                ptv->livedev->drop, eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
121✔
312
    } else {
121✔
313
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_dpdk_packets, ptv->pkts);
77✔
314
    }
77✔
315
}
198✔
316

317
static void DPDKReleasePacket(Packet *p)
318
{
99,566,451✔
319
    int retval;
99,566,451✔
320
    /* Need to be in copy mode and need to detect early release
321
       where Ethernet header could not be set (and pseudo packet)
322
       When enabling promiscuous mode on Intel cards, 2 ICMPv6 packets are generated.
323
       These get into the infinite cycle between the NIC and the switch in some cases */
324
    if ((p->dpdk_v.copy_mode == DPDK_COPY_MODE_TAP ||
99,566,451✔
325
                (p->dpdk_v.copy_mode == DPDK_COPY_MODE_IPS && !PacketCheckAction(p, ACTION_DROP)))
100,800,684✔
326
#if defined(RTE_LIBRTE_I40E_PMD) || defined(RTE_LIBRTE_IXGBE_PMD) || defined(RTE_LIBRTE_ICE_PMD)
327
            && !(PacketIsICMPv6(p) && PacketGetICMPv6(p)->type == 143)
328
#endif
329
    ) {
99,566,451✔
330
        BUG_ON(PKT_IS_PSEUDOPKT(p));
40,660,096✔
331
        retval =
40,751,179✔
332
                rte_eth_tx_burst(p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id, &p->dpdk_v.mbuf, 1);
40,751,179✔
333
        // rte_eth_tx_burst can return only 0 (failure) or 1 (success) because we are only
334
        // transmitting burst of size 1 and the function rte_eth_tx_burst returns number of
335
        // successfully sent packets.
336
        if (unlikely(retval < 1)) {
40,751,179✔
337
            // sometimes a repeated transmit can help to send out the packet
338
            rte_delay_us(DPDK_BURST_TX_WAIT_US);
×
339
            retval = rte_eth_tx_burst(
×
340
                    p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id, &p->dpdk_v.mbuf, 1);
×
341
            if (unlikely(retval < 1)) {
×
342
                SCLogDebug("Unable to transmit the packet on port %u queue %u",
×
343
                        p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id);
×
344
                rte_pktmbuf_free(p->dpdk_v.mbuf);
×
345
                p->dpdk_v.mbuf = NULL;
×
346
            }
×
347
        }
×
348
    } else {
58,906,355✔
349
        rte_pktmbuf_free(p->dpdk_v.mbuf);
58,906,355✔
350
        p->dpdk_v.mbuf = NULL;
58,906,355✔
351
    }
58,906,355✔
352

353
    PacketFreeOrRelease(p);
99,657,534✔
354
}
99,657,534✔
355

356
static TmEcode ReceiveDPDKLoopInit(ThreadVars *tv, DPDKThreadVars *ptv)
357
{
23✔
358
    SCEnter();
23✔
359
    // Indicate that the thread is actually running its application level
360
    // code (i.e., it can poll packets)
361
    TmThreadsSetFlag(tv, THV_RUNNING);
23✔
362
    PacketPoolWait();
23✔
363

364
    rte_eth_stats_reset(ptv->port_id);
23✔
365
    rte_eth_xstats_reset(ptv->port_id);
23✔
366

367
    if (ptv->intr_enabled && !InterruptsRXEnable(ptv->port_id, ptv->queue_id))
23✔
368
        SCReturnInt(TM_ECODE_FAILED);
×
369

370
    SCReturnInt(TM_ECODE_OK);
23✔
371
}
23✔
372

373
static inline void LoopHandleTimeoutOnIdle(ThreadVars *tv)
374
{
13,398,714✔
375
    static thread_local uint64_t last_timeout_msec = 0;
13,398,714✔
376
    SCTime_t t = TimeGet();
13,398,714✔
377
    uint64_t msecs = SCTIME_MSECS(t);
13,398,714✔
378
    if (msecs > last_timeout_msec + 100) {
13,398,714✔
379
        TmThreadsCaptureHandleTimeout(tv, NULL);
20✔
380
        last_timeout_msec = msecs;
20✔
381
    }
20✔
382
}
13,398,714✔
383

384
/**
385
 * \brief Decides if it should retry the packet poll or continue with the packet processing
386
 * \return true if the poll should be retried, false otherwise
387
 */
388
static inline bool RXPacketCountHeuristic(ThreadVars *tv, DPDKThreadVars *ptv, uint16_t nb_rx)
389
{
17,249,611✔
390
    static thread_local uint32_t zero_pkt_polls_cnt = 0;
17,249,611✔
391

392
    if (nb_rx > 0) {
17,249,611✔
393
        zero_pkt_polls_cnt = 0;
3,690,071✔
394
        return false;
3,690,071✔
395
    }
3,690,071✔
396

397
    LoopHandleTimeoutOnIdle(tv);
13,559,540✔
398
    if (!ptv->intr_enabled)
13,559,540✔
399
        return true;
13,635,799✔
400

401
    zero_pkt_polls_cnt++;
2,147,483,647✔
402
    if (zero_pkt_polls_cnt <= MIN_ZERO_POLL_COUNT)
2,147,483,647✔
403
        return true;
×
404

405
    uint32_t pwd_idle_hint = InterruptsSleepHeuristic(zero_pkt_polls_cnt);
2,147,483,647✔
406
    if (pwd_idle_hint < STANDARD_SLEEP_TIME_US) {
2,147,483,647✔
407
        rte_delay_us(pwd_idle_hint);
×
408
    } else {
2,147,483,647✔
409
        InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, true);
2,147,483,647✔
410
        struct rte_epoll_event event;
2,147,483,647✔
411
        rte_epoll_wait(RTE_EPOLL_PER_THREAD, &event, 1, MAX_EPOLL_TIMEOUT_MS);
2,147,483,647✔
412
        InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, false);
2,147,483,647✔
413
        return true;
2,147,483,647✔
414
    }
2,147,483,647✔
415

416
    return false;
×
417
}
2,147,483,647✔
418

419
/**
420
 * \brief Initializes a packet from an mbuf
421
 * \return true if the packet was initialized successfully, false otherwise
422
 */
423
static inline Packet *PacketInitFromMbuf(DPDKThreadVars *ptv, struct rte_mbuf *mbuf)
424
{
100,159,036✔
425
    Packet *p = PacketGetFromQueueOrAlloc();
100,159,036✔
426
    if (unlikely(p == NULL)) {
100,159,036✔
427
        return NULL;
×
428
    }
×
429
    PKT_SET_SRC(p, PKT_SRC_WIRE);
100,159,036✔
430
    p->datalink = LINKTYPE_ETHERNET;
100,159,036✔
431
    if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
100,159,036✔
432
        p->flags |= PKT_IGNORE_CHECKSUM;
×
433
    }
×
434

435
    p->ts = TimeGet();
100,159,036✔
436
    p->dpdk_v.mbuf = mbuf;
100,159,036✔
437
    p->ReleasePacket = DPDKReleasePacket;
100,159,036✔
438
    p->dpdk_v.copy_mode = ptv->copy_mode;
100,159,036✔
439
    p->dpdk_v.out_port_id = ptv->out_port_id;
100,159,036✔
440
    p->dpdk_v.out_queue_id = ptv->queue_id;
100,159,036✔
441
    p->livedev = ptv->livedev;
100,159,036✔
442

443
    if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
100,159,036✔
444
        p->flags |= PKT_IGNORE_CHECKSUM;
×
445
    } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_OFFLOAD) {
100,159,036✔
446
        uint64_t ol_flags = p->dpdk_v.mbuf->ol_flags;
×
447
        if ((ol_flags & RTE_MBUF_F_RX_IP_CKSUM_MASK) == RTE_MBUF_F_RX_IP_CKSUM_GOOD &&
×
448
                (ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) == RTE_MBUF_F_RX_L4_CKSUM_GOOD) {
×
449
            SCLogDebug("HW detected GOOD IP and L4 chsum, ignoring validation");
×
450
            p->flags |= PKT_IGNORE_CHECKSUM;
×
451
        } else {
×
452
            if ((ol_flags & RTE_MBUF_F_RX_IP_CKSUM_MASK) == RTE_MBUF_F_RX_IP_CKSUM_BAD) {
×
453
                SCLogDebug("HW detected BAD IP checksum");
×
454
                // chsum recalc will not be triggered but rule keyword check will be
455
                p->l3.csum_set = true;
×
456
                p->l3.csum = 0;
×
457
            }
×
458
            if ((ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) == RTE_MBUF_F_RX_L4_CKSUM_BAD) {
×
459
                SCLogDebug("HW detected BAD L4 chsum");
×
460
                p->l4.csum_set = true;
×
461
                p->l4.csum = 0;
×
462
            }
×
463
        }
×
464
    }
×
465

466
    return p;
100,159,036✔
467
}
100,159,036✔
468

469
static inline void DPDKSegmentedMbufWarning(void)
470
{
×
471
    static thread_local bool segmented_mbufs_warned = false;
×
NEW
472
    if (unlikely(!segmented_mbufs_warned)) {
×
473
        enum rte_proc_type_t eal_t = rte_eal_process_type();
×
474
        if (eal_t == RTE_PROC_SECONDARY) {
×
NEW
475
            SCLogWarning("Segmented mbufs detected! Suricata handles them but for better "
×
NEW
476
                         "performance, try to increase mbuf size in your primary application");
×
NEW
477
        } else {
×
NEW
478
            SCLogWarning("Segmented mbufs detected! Suricata handles them but for better "
×
NEW
479
                         "performance, try to increase MTU in your suricata.yaml");
×
480
        }
×
481
        segmented_mbufs_warned = true;
×
482
    }
×
483
}
×
484

485
static void PrintDPDKPortXstats(uint16_t port_id, const char *port_name)
486
{
16✔
487
    int ret = rte_eth_xstats_get(port_id, NULL, 0);
16✔
488
    if (ret <= 0) {
16✔
489
        SCLogPerf("%s: unable to obtain rte_eth_xstats (%s)", port_name,
×
490
                ret == 0 ? "not supported" : rte_strerror(-ret));
×
491
        return;
×
492
    }
×
493
    unsigned int len = (unsigned int)ret;
16✔
494
    struct rte_eth_xstat_name *xstats_names = NULL;
16✔
495
    struct rte_eth_xstat *xstats = SCCalloc(len, sizeof(*xstats));
16✔
496
    if (xstats == NULL) {
16✔
497
        SCLogWarning("Failed to allocate memory for the rte_eth_xstat structure");
×
498
        return;
×
499
    }
×
500

501
    ret = rte_eth_xstats_get(port_id, xstats, len);
16✔
502
    if (ret < 0 || (unsigned int)ret > len) {
16✔
503
        SCLogPerf("%s: unable to obtain rte_eth_xstats (%s)", port_name,
×
504
                ret < 0 ? rte_strerror(-ret) : "table size too small");
×
505
        goto cleanup;
×
506
    }
×
507
    xstats_names = SCCalloc(len, sizeof(*xstats_names));
16✔
508
    if (xstats_names == NULL) {
16✔
509
        SCLogWarning("Failed to allocate memory for the rte_eth_xstat_name array");
×
510
        goto cleanup;
×
511
    }
×
512
    ret = rte_eth_xstats_get_names(port_id, xstats_names, len);
16✔
513
    if (ret < 0 || (unsigned int)ret > len) {
16✔
514
        SCLogPerf("%s: unable to obtain names of rte_eth_xstats (%s)", port_name,
×
515
                ret < 0 ? rte_strerror(-ret) : "table size too small");
×
516
        goto cleanup;
×
517
    }
×
518
    for (unsigned int i = 0; i < len; i++) {
264✔
519
        if (xstats[i].value > 0)
248✔
520
            SCLogPerf("Port %u (%s) - %s: %" PRIu64, port_id, port_name, xstats_names[i].name,
34✔
521
                    xstats[i].value);
248✔
522
    }
248✔
523

524
cleanup:
16✔
525
    if (xstats != NULL)
16✔
526
        SCFree(xstats);
16✔
527
    if (xstats_names != NULL)
16✔
528
        SCFree(xstats_names);
16✔
529
}
16✔
530

531
static inline void DPDKSegmentedMbufTooLargeWarning(uint32_t pkt_len)
NEW
532
{
×
NEW
533
    static thread_local bool size_warned = false;
×
NEW
534
    if (unlikely(!size_warned)) {
×
NEW
535
        SCLogWarning("Segmented mbuf larger than max payload size (%u > %d), packet will be "
×
NEW
536
                     "truncated",
×
NEW
537
                pkt_len, MAX_PAYLOAD_SIZE);
×
NEW
538
        size_warned = true;
×
NEW
539
    }
×
NEW
540
}
×
541

542
/**
543
 * \brief Handle segmented (chained) mbufs by linearizing them
544
 *
545
 * For segmented mbufs, attempts to linearize the data into a contiguous buffer.
546
 * First tries rte_pktmbuf_linearize() which copies all segment data into the
547
 * first segment. If that fails (not enough tailroom), copies data into the
548
 * packet's internal buffer.
549
 *
550
 * \param p Pointer to the Packet structure
551
 * \param mbuf Pointer to the DPDK mbuf
552
 * \return 0 on success, -1 on failure
553
 */
554
static inline int DPDKSegmentedMbufHandle(Packet *p, struct rte_mbuf *mbuf)
NEW
555
{
×
NEW
556
    if (rte_pktmbuf_linearize(mbuf) == 0) {
×
NEW
557
        PacketSetData(p, rte_pktmbuf_mtod(mbuf, uint8_t *), rte_pktmbuf_pkt_len(mbuf));
×
NEW
558
        return 0;
×
NEW
559
    }
×
560

561
    /* Linearization failed (not enough tailroom), copy to packet buffer */
NEW
562
    uint32_t pkt_len = rte_pktmbuf_pkt_len(mbuf);
×
NEW
563
    uint32_t copy_len = pkt_len;
×
NEW
564
    if (unlikely(pkt_len > MAX_PAYLOAD_SIZE)) {
×
NEW
565
        DPDKSegmentedMbufTooLargeWarning(pkt_len);
×
NEW
566
        copy_len = MAX_PAYLOAD_SIZE;
×
NEW
567
    }
×
568

NEW
569
    uint32_t offset = 0;
×
NEW
570
    for (struct rte_mbuf *seg = mbuf; seg != NULL && offset < copy_len; seg = seg->next) {
×
NEW
571
        uint32_t seg_len = rte_pktmbuf_data_len(seg);
×
NEW
572
        uint32_t to_copy = (offset + seg_len > copy_len) ? (copy_len - offset) : seg_len;
×
NEW
573
        if (PacketCopyDataOffset(p, offset, rte_pktmbuf_mtod(seg, uint8_t *), to_copy) != 0) {
×
NEW
574
            SCLogWarning("Failed to copy segmented mbuf data at offset %u", offset);
×
NEW
575
            return -1;
×
NEW
576
        }
×
NEW
577
        offset += to_copy;
×
NEW
578
    }
×
579

NEW
580
    SET_PKT_LEN(p, copy_len);
×
581

NEW
582
    return 0;
×
NEW
583
}
×
584

585
static void HandleShutdown(DPDKThreadVars *ptv)
586
{
23✔
587
    SCLogDebug("Stopping Suricata!");
23✔
588
    SC_ATOMIC_ADD(ptv->workers_sync->worker_checked_in, 1);
23✔
589
    while (SC_ATOMIC_GET(ptv->workers_sync->worker_checked_in) < ptv->workers_sync->worker_cnt) {
33✔
590
        rte_delay_us(10);
10✔
591
    }
10✔
592
    // Dump counters while device is still running - some drivers (e.g. BNXT) fail
593
    // to report stats after the device is stopped
594
    DPDKDumpCounters(ptv);
23✔
595
    if (ptv->queue_id == 0) {
23✔
596
        PrintDPDKPortXstats(ptv->port_id, ptv->livedev->dev);
16✔
597
        rte_delay_us(20); // wait for all threads to get out of the sync loop
16✔
598
        SC_ATOMIC_SET(ptv->workers_sync->worker_checked_in, 0);
16✔
599
        // If Suricata runs in peered mode, the peer threads might still want to send
600
        // packets to our port. Instead, we know, that we are done with the peered port, so
601
        // we stop it. The peered threads will stop our port.
602
        if (ptv->copy_mode == DPDK_COPY_MODE_TAP || ptv->copy_mode == DPDK_COPY_MODE_IPS) {
16✔
603
            rte_eth_dev_stop(ptv->out_port_id);
2✔
604
        } else {
14✔
605
            // in IDS we stop our port - no peer threads are running
606
            rte_eth_dev_stop(ptv->port_id);
14✔
607
        }
14✔
608
    }
16✔
609
}
23✔
610

611
static void PeriodicDPDKDumpCounters(DPDKThreadVars *ptv)
612
{
3,676,366✔
613
    static thread_local SCTime_t last_dump = { 0 };
3,676,366✔
614
    SCTime_t current_time = TimeGet();
3,676,366✔
615
    /* Trigger one dump of stats every second */
616
    if (current_time.secs != last_dump.secs) {
3,676,366✔
617
        DPDKDumpCounters(ptv);
174✔
618
        last_dump = current_time;
174✔
619
    }
174✔
620
}
3,676,366✔
621

622
static inline TmEcode ReceiveDPDKPkts(DPDKThreadVars *ptv, uint16_t nb_rx)
623
{
3,688,893✔
624
    ptv->pkts += (uint64_t)nb_rx;
3,688,893✔
625
    for (uint16_t i = 0; i < nb_rx; i++) {
104,843,603✔
626
        Packet *p = PacketInitFromMbuf(ptv, ptv->received_mbufs[i]);
101,154,710✔
627
        if (p == NULL) {
101,154,710✔
NEW
628
            rte_pktmbuf_free(ptv->received_mbufs[i]);
×
NEW
629
            continue;
×
NEW
630
        }
×
631

632
        if (likely(rte_pktmbuf_is_contiguous(p->dpdk_v.mbuf))) {
103,711,008✔
633
            PacketSetData(p, rte_pktmbuf_mtod(p->dpdk_v.mbuf, uint8_t *),
103,711,008✔
634
                    rte_pktmbuf_pkt_len(p->dpdk_v.mbuf));
103,711,008✔
635
        } else {
2,147,483,647✔
636
            DPDKSegmentedMbufWarning();
2,147,483,647✔
637
            if (DPDKSegmentedMbufHandle(p, p->dpdk_v.mbuf) != 0) {
2,147,483,647✔
NEW
638
                TmqhOutputPacketpool(ptv->tv, p);
×
NEW
639
                continue;
×
NEW
640
            }
×
641
        }
2,147,483,647✔
642

643
        if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
101,154,710✔
NEW
644
            TmqhOutputPacketpool(ptv->tv, p);
×
NEW
645
            DPDKFreeMbufArray(ptv->received_mbufs, nb_rx - i - 1, i + 1);
×
NEW
646
            return TM_ECODE_FAILED;
×
NEW
647
        }
×
648
    }
101,154,710✔
649
    return TM_ECODE_OK;
3,688,893✔
650
}
3,688,893✔
651

652
static TmEcode ReceiveDPDKLoopLive(ThreadVars *tv, DPDKThreadVars *ptv)
653
{
24✔
654
    while (true) {
17,282,552✔
655
        if (unlikely(suricata_ctl_flags != 0)) {
17,282,552✔
656
            HandleShutdown(ptv);
23✔
657
            break;
23✔
658
        }
23✔
659

660
        uint16_t nb_rx =
17,282,529✔
661
                rte_eth_rx_burst(ptv->port_id, ptv->queue_id, ptv->received_mbufs, BURST_SIZE);
17,282,529✔
662
        if (RXPacketCountHeuristic(tv, ptv, nb_rx)) {
17,282,529✔
663
            continue;
13,588,977✔
664
        }
13,588,977✔
665

666
        if (ReceiveDPDKPkts(ptv, nb_rx) != TM_ECODE_OK) {
3,693,552✔
NEW
667
            SCReturnInt(EXIT_FAILURE);
×
668
        }
×
669

670
        PeriodicDPDKDumpCounters(ptv);
3,693,552✔
671
        StatsSyncCountersIfSignalled(&tv->stats);
3,693,552✔
672
    }
3,693,552✔
673

674
    SCReturnInt(TM_ECODE_OK);
24✔
675
}
24✔
676

677
static TmEcode ReceiveDPDKLoopPcap(ThreadVars *tv, DPDKThreadVars *ptv)
NEW
678
{
×
NEW
679
    while (true) {
×
NEW
680
        if (unlikely(suricata_ctl_flags != 0)) {
×
NEW
681
            HandleShutdown(ptv);
×
NEW
682
            break;
×
NEW
683
        }
×
684

NEW
685
        uint16_t nb_rx =
×
NEW
686
                rte_eth_rx_burst(ptv->port_id, ptv->queue_id, ptv->received_mbufs, BURST_SIZE);
×
NEW
687
        if (nb_rx == 0) {
×
NEW
688
            SCLogNotice("%s: PCAP end of file", ptv->livedev->dev);
×
NEW
689
            if (SC_ATOMIC_SUB(pcap_workers_left, 1) == 1) {
×
NEW
690
                EngineStop();
×
NEW
691
            }
×
NEW
692
            HandleShutdown(ptv);
×
NEW
693
            break;
×
NEW
694
        }
×
695

NEW
696
        if (ReceiveDPDKPkts(ptv, nb_rx) != TM_ECODE_OK) {
×
NEW
697
            SCReturnInt(EXIT_FAILURE);
×
NEW
698
        }
×
699

NEW
700
        PeriodicDPDKDumpCounters(ptv);
×
NEW
701
        StatsSyncCountersIfSignalled(&tv->stats);
×
NEW
702
    }
×
703

NEW
704
    SCReturnInt(TM_ECODE_DONE);
×
NEW
705
}
×
706

707
/**
708
 *  \brief Main DPDK reading Loop function
709
 */
710
static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
711
{
24✔
712
    SCEnter();
24✔
713
    DPDKThreadVars *ptv = (DPDKThreadVars *)data;
24✔
714
    ptv->slot = ((TmSlot *)slot)->slot_next;
24✔
715
    TmEcode ret = ReceiveDPDKLoopInit(tv, ptv);
24✔
716
    if (ret != TM_ECODE_OK) {
24✔
NEW
717
        SCReturnInt(ret);
×
NEW
718
    }
×
719

720
    if (ptv->is_pcap_iface)
24✔
NEW
721
        return ReceiveDPDKLoopPcap(tv, ptv);
×
722
    return ReceiveDPDKLoopLive(tv, ptv);
24✔
723
}
24✔
724

725
/**
726
 * \brief Init function for ReceiveDPDK.
727
 *
728
 * \param tv pointer to ThreadVars
729
 * \param initdata pointer to the interface passed from the user
730
 * \param data pointer gets populated with DPDKThreadVars
731
 *
732
 */
733
static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void **data)
734
{
24✔
735
    SCEnter();
24✔
736
    int retval, thread_numa;
24✔
737
    DPDKThreadVars *ptv = NULL;
24✔
738
    DPDKIfaceConfig *dpdk_config = (DPDKIfaceConfig *)initdata;
24✔
739

740
    if (initdata == NULL) {
24✔
741
        SCLogError("DPDK configuration is NULL in thread initialization");
×
742
        goto fail;
×
743
    }
×
744

745
    ptv = SCCalloc(1, sizeof(DPDKThreadVars));
24✔
746
    if (unlikely(ptv == NULL)) {
24✔
747
        SCLogError("Unable to allocate memory");
×
748
        goto fail;
×
749
    }
×
750

751
    ptv->tv = tv;
24✔
752
    ptv->pkts = 0;
24✔
753
    ptv->bytes = 0;
24✔
754
    ptv->livedev = LiveGetDevice(dpdk_config->iface);
24✔
755

756
    ptv->capture_dpdk_packets = StatsRegisterCounter("capture.packets", &ptv->tv->stats);
24✔
757
    ptv->capture_dpdk_rx_errs = StatsRegisterCounter("capture.rx_errors", &ptv->tv->stats);
24✔
758
    ptv->capture_dpdk_tx_errs = StatsRegisterCounter("capture.tx_errors", &ptv->tv->stats);
24✔
759
    ptv->capture_dpdk_imissed = StatsRegisterCounter("capture.dpdk.imissed", &ptv->tv->stats);
24✔
760
    ptv->capture_dpdk_rx_no_mbufs = StatsRegisterCounter("capture.dpdk.no_mbufs", &ptv->tv->stats);
24✔
761
    ptv->capture_dpdk_ierrors = StatsRegisterCounter("capture.dpdk.ierrors", &ptv->tv->stats);
24✔
762

763
    ptv->copy_mode = dpdk_config->copy_mode;
24✔
764
    ptv->checksum_mode = dpdk_config->checksum_mode;
24✔
765

766
    ptv->threads = dpdk_config->threads;
24✔
767
    ptv->intr_enabled = (dpdk_config->flags & DPDK_IRQ_MODE) ? true : false;
24✔
768
    ptv->is_pcap_iface = dpdk_config->is_pcap_iface;
24✔
769
    ptv->port_id = dpdk_config->port_id;
24✔
770
    ptv->out_port_id = dpdk_config->out_port_id;
24✔
771
    ptv->port_socket_id = dpdk_config->socket_id;
24✔
772

773
    thread_numa = GetNumaNode();
24✔
774
    if (thread_numa >= 0 && ptv->port_socket_id != SOCKET_ID_ANY &&
24✔
775
            thread_numa != ptv->port_socket_id) {
24✔
776
        SC_ATOMIC_ADD(dpdk_config->inconsistent_numa_cnt, 1);
×
777
        SCLogPerf("%s: NIC is on NUMA %d, thread on NUMA %d", dpdk_config->iface,
×
778
                ptv->port_socket_id, thread_numa);
×
779
    }
×
780

781
    ptv->workers_sync = dpdk_config->workers_sync;
24✔
782
    uint16_t queue_id = SC_ATOMIC_ADD(dpdk_config->queue_id, 1);
24✔
783
    ptv->queue_id = queue_id;
24✔
784

785
    // the last thread starts the device
786
    if (queue_id == dpdk_config->threads - 1) {
24✔
787
        retval = rte_eth_dev_start(ptv->port_id);
16✔
788
        if (retval < 0) {
16✔
789
            SCLogError("%s: error (%s) during device startup", dpdk_config->iface,
×
790
                    rte_strerror(-retval));
×
791
            goto fail;
×
792
        }
×
793

794
        struct rte_eth_dev_info dev_info;
16✔
795
        retval = rte_eth_dev_info_get(ptv->port_id, &dev_info);
16✔
796
        if (retval != 0) {
16✔
797
            SCLogError("%s: error (%s) when getting device info", dpdk_config->iface,
×
798
                    rte_strerror(-retval));
×
799
            goto fail;
×
800
        }
×
801

802
        uint32_t timeout = dpdk_config->linkup_timeout * 10;
16✔
803
        while (timeout > 0) {
16✔
804
            struct rte_eth_link link = { 0 };
×
805
            retval = rte_eth_link_get_nowait(ptv->port_id, &link);
×
806
            if (retval != 0) {
×
807
                if (retval == -ENOTSUP) {
×
808
                    SCLogInfo("%s: link status not supported, skipping", dpdk_config->iface);
×
809
                } else {
×
810
                    SCLogInfo("%s: error (%s) when getting link status, skipping",
×
811
                            dpdk_config->iface, rte_strerror(-retval));
×
812
                }
×
813
                break;
×
814
            }
×
815
            if (link.link_status) {
×
816
                char link_status_str[RTE_ETH_LINK_MAX_STR_LEN];
×
817
#if RTE_VERSION >= RTE_VERSION_NUM(20, 11, 0, 0)
×
818
#pragma GCC diagnostic push
×
819
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
×
820
                rte_eth_link_to_str(link_status_str, sizeof(link_status_str), &link);
×
821
#pragma GCC diagnostic pop
×
822
#else
823
                snprintf(link_status_str, sizeof(link_status_str),
824
                        "Link Up, speed %u Mbps, %s", // 22 chars + 10 for digits + 11 for duplex
825
                        link.link_speed,
826
                        (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? "full-duplex" : "half-duplex");
827
#endif
828

829
                SCLogInfo("%s: %s", dpdk_config->iface, link_status_str);
×
830
                break;
×
831
            }
×
832

833
            rte_delay_ms(100);
×
834
            timeout--;
×
835
        }
×
836

837
        if (dpdk_config->linkup_timeout && timeout == 0) {
16✔
838
            SCLogWarning("%s: link is down, trying to continue anyway", dpdk_config->iface);
×
839
        }
×
840

841
        // some PMDs requires additional actions only after the device has started
842
        DevicePostStartPMDSpecificActions(ptv, dev_info.driver_name);
16✔
843

844
        uint16_t inconsistent_numa_cnt = SC_ATOMIC_GET(dpdk_config->inconsistent_numa_cnt);
16✔
845
        if (inconsistent_numa_cnt > 0 && ptv->port_socket_id != SOCKET_ID_ANY) {
16✔
846
            SCLogWarning("%s: NIC is on NUMA %d, %u threads on different NUMA node(s)",
×
847
                    dpdk_config->iface, ptv->port_socket_id, inconsistent_numa_cnt);
×
848
        } else if (ptv->port_socket_id == SOCKET_ID_ANY && rte_socket_count() > 1) {
16✔
849
            SCLogNotice(
×
850
                    "%s: unable to determine NIC's NUMA node, degraded performance can be expected",
×
851
                    dpdk_config->iface);
×
852
        }
×
853
        if (ptv->intr_enabled) {
16✔
854
            rte_spinlock_init(&intr_lock[ptv->port_id]);
×
855
        }
×
856
    }
16✔
857

858
    *data = (void *)ptv;
24✔
859
    dpdk_config->DerefFunc(dpdk_config);
24✔
860
    SCReturnInt(TM_ECODE_OK);
24✔
861

862
fail:
×
863
    if (dpdk_config != NULL)
×
864
        dpdk_config->DerefFunc(dpdk_config);
×
865
    if (ptv != NULL)
×
866
        SCFree(ptv);
×
867
    SCReturnInt(TM_ECODE_FAILED);
×
868
}
24✔
869

870
/**
871
 * \brief DeInit function closes dpdk at exit.
872
 * \param tv pointer to ThreadVars
873
 * \param data pointer that gets cast into DPDKThreadVars for ptv
874
 */
875
static TmEcode ReceiveDPDKThreadDeinit(ThreadVars *tv, void *data)
876
{
24✔
877
    SCEnter();
24✔
878
    DPDKThreadVars *ptv = (DPDKThreadVars *)data;
24✔
879

880
    if (ptv->queue_id == 0) {
24✔
881
        struct rte_eth_dev_info dev_info;
16✔
882
        int retval = rte_eth_dev_info_get(ptv->port_id, &dev_info);
16✔
883
        if (retval != 0) {
16✔
884
            SCLogError("%s: error (%s) when getting device info", ptv->livedev->dev,
×
885
                    rte_strerror(-retval));
×
886
            SCReturnInt(TM_ECODE_FAILED);
×
887
        }
×
888

889
        DevicePreClosePMDSpecificActions(ptv, dev_info.driver_name);
16✔
890

891
        if (ptv->workers_sync) {
16✔
892
            SCFree(ptv->workers_sync);
16✔
893
        }
16✔
894
    }
16✔
895

896
    SCFree(ptv);
24✔
897
    SCReturnInt(TM_ECODE_OK);
24✔
898
}
24✔
899

900
/**
901
 * \brief This function passes off to link type decoders.
902
 *
903
 * DecodeDPDK decodes packets from DPDK and passes
904
 * them off to the proper link type decoder.
905
 *
906
 * \param t pointer to ThreadVars
907
 * \param p pointer to the current packet
908
 * \param data pointer that gets cast into DPDKThreadVars for ptv
909
 */
910
static TmEcode DecodeDPDK(ThreadVars *tv, Packet *p, void *data)
911
{
106,269,503✔
912
    SCEnter();
106,269,503✔
913
    DecodeThreadVars *dtv = (DecodeThreadVars *)data;
106,269,503✔
914

915
    BUG_ON(PKT_IS_PSEUDOPKT(p));
106,269,503✔
916

917
    /* update counters */
918
    DecodeUpdatePacketCounters(tv, dtv, p);
103,516,129✔
919

920
    /* If suri has set vlan during reading, we increase vlan counter */
921
    if (p->vlan_idx) {
103,516,129✔
922
        StatsCounterIncr(&tv->stats, dtv->counter_vlan);
×
923
    }
×
924

925
    /* call the decoder */
926
    DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
103,516,129✔
927

928
    PacketDecodeFinalize(tv, dtv, p);
103,516,129✔
929

930
    SCReturnInt(TM_ECODE_OK);
103,516,129✔
931
}
106,269,503✔
932

933
static TmEcode DecodeDPDKThreadInit(ThreadVars *tv, const void *initdata, void **data)
934
{
24✔
935
    SCEnter();
24✔
936
    DecodeThreadVars *dtv = NULL;
24✔
937

938
    dtv = DecodeThreadVarsAlloc(tv);
24✔
939

940
    if (dtv == NULL)
24✔
941
        SCReturnInt(TM_ECODE_FAILED);
×
942

943
    DecodeRegisterPerfCounters(dtv, tv);
24✔
944

945
    *data = (void *)dtv;
24✔
946

947
    SCReturnInt(TM_ECODE_OK);
24✔
948
}
24✔
949

950
static TmEcode DecodeDPDKThreadDeinit(ThreadVars *tv, void *data)
951
{
24✔
952
    SCEnter();
24✔
953
    if (data != NULL)
24✔
954
        DecodeThreadVarsFree(tv, data);
24✔
955
    SCReturnInt(TM_ECODE_OK);
24✔
956
}
24✔
957

958
#endif /* HAVE_DPDK */
959
/* eof */
960
/**
961
 * @}
962
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc