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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

4.09
/src/source-af-xdp.c
1
/* Copyright (C) 2011-2022 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 afxdppacket AF_XDP running mode
20
 *
21
 *  @{
22
 */
23

24
/**
25
 * \file
26
 *
27
 * \author Richard McConnell <richard_mcconnell@rapid7.com>
28
 *
29
 * AF_XDP socket acquisition support
30
 *
31
 */
32
#define SC_PCAP_DONT_INCLUDE_PCAP_H  1
33
#include "suricata-common.h"
34
#include "suricata.h"
35
#include "decode.h"
36
#include "packet-queue.h"
37
#include "threads.h"
38
#include "threadvars.h"
39
#include "tm-queuehandlers.h"
40
#include "tm-modules.h"
41
#include "tm-threads.h"
42
#include "tm-threads-common.h"
43
#include "conf.h"
44
#include "util-cpu.h"
45
#include "util-datalink.h"
46
#include "util-debug.h"
47
#include "util-device-private.h"
48
#include "util-ebpf.h"
49
#include "util-error.h"
50
#include "util-privs.h"
51
#include "util-optimize.h"
52
#include "util-checksum.h"
53
#include "util-ioctl.h"
54
#include "util-host-info.h"
55
#include "util-sysfs.h"
56
#include "tmqh-packetpool.h"
57
#include "source-af-xdp.h"
58
#include "runmodes.h"
59
#include "flow-storage.h"
60
#include "util-validate.h"
61

62
#ifdef HAVE_AF_XDP
63
#include <net/if.h>
64
#include <bpf/libbpf.h>
65
#include <xdp/xsk.h>
66
#include <xdp/libxdp.h>
67
#endif
68

69
#if HAVE_LINUX_IF_ETHER_H
70
#include <linux/if_ether.h>
71
#endif
72

73
#ifndef HAVE_AF_XDP
74

75
TmEcode NoAFXDPSupportExit(ThreadVars *, const void *, void **);
76

77
void TmModuleReceiveAFXDPRegister(void)
78
{
79
    tmm_modules[TMM_RECEIVEAFXDP].name = "ReceiveAFXDP";
80
    tmm_modules[TMM_RECEIVEAFXDP].ThreadInit = NoAFXDPSupportExit;
81
    tmm_modules[TMM_RECEIVEAFXDP].Func = NULL;
82
    tmm_modules[TMM_RECEIVEAFXDP].ThreadExitPrintStats = NULL;
83
    tmm_modules[TMM_RECEIVEAFXDP].ThreadDeinit = NULL;
84
    tmm_modules[TMM_RECEIVEAFXDP].cap_flags = 0;
85
    tmm_modules[TMM_RECEIVEAFXDP].flags = TM_FLAG_RECEIVE_TM;
86
}
87

88
/**
89
 * \brief Registration Function for DecodeAFXDP.
90
 */
91
void TmModuleDecodeAFXDPRegister(void)
92
{
93
    tmm_modules[TMM_DECODEAFXDP].name = "DecodeAFXDP";
94
    tmm_modules[TMM_DECODEAFXDP].ThreadInit = NoAFXDPSupportExit;
95
    tmm_modules[TMM_DECODEAFXDP].Func = NULL;
96
    tmm_modules[TMM_DECODEAFXDP].ThreadExitPrintStats = NULL;
97
    tmm_modules[TMM_DECODEAFXDP].ThreadDeinit = NULL;
98
    tmm_modules[TMM_DECODEAFXDP].cap_flags = 0;
99
    tmm_modules[TMM_DECODEAFXDP].flags = TM_FLAG_DECODE_TM;
100
}
101

102
/**
103
 * \brief this function prints an error message and exits.
104
 */
105
TmEcode NoAFXDPSupportExit(ThreadVars *tv, const void *initdata, void **data)
106
{
107
    SCLogError("Error creating thread %s: you do not have "
108
               "support for AF_XDP enabled, on Linux host please recompile "
109
               "with --enable-af-xdp",
110
            tv->name);
111
    exit(EXIT_FAILURE);
112
}
113

114
#else /* We have AF_XDP support */
115

UNCOV
116
#define POLL_TIMEOUT      100
×
UNCOV
117
#define NUM_FRAMES_PROD   XSK_RING_PROD__DEFAULT_NUM_DESCS
×
UNCOV
118
#define NUM_FRAMES_CONS   XSK_RING_CONS__DEFAULT_NUM_DESCS
×
UNCOV
119
#define NUM_FRAMES        NUM_FRAMES_PROD
×
UNCOV
120
#define FRAME_SIZE        XSK_UMEM__DEFAULT_FRAME_SIZE
×
UNCOV
121
#define MEM_BYTES         (NUM_FRAMES * FRAME_SIZE * 2)
×
UNCOV
122
#define RECONNECT_TIMEOUT 500000
×
123

124
/* Interface state */
125
enum state { AFXDP_STATE_DOWN, AFXDP_STATE_UP };
126

127
struct XskInitProtect {
128
    SCMutex queue_protect;
129
    SC_ATOMIC_DECLARE(uint8_t, queue_num);
130
} xsk_protect;
131

132
struct UmemInfo {
133
    void *buf;
134
    struct xsk_umem *umem;
135
    struct xsk_ring_prod fq;
136
    struct xsk_ring_cons cq;
137
    struct xsk_umem_config cfg;
138
    int mmap_alignment_flag;
139
};
140

141
struct QueueAssignment {
142
    uint32_t queue_num;
143
    bool assigned;
144
};
145

146
struct XskSockInfo {
147
    struct xsk_ring_cons rx;
148
    struct xsk_ring_prod tx;
149
    struct xsk_socket *xsk;
150

151
    /* Queue assignment structure */
152
    struct QueueAssignment queue;
153

154
    /* Configuration items */
155
    struct xsk_socket_config cfg;
156
    bool enable_busy_poll;
157
    uint32_t busy_poll_time;
158
    uint32_t busy_poll_budget;
159

160
    struct pollfd fd;
161
};
162

163
/**
164
 * \brief Structure to hold thread specific variables.
165
 */
166
typedef struct AFXDPThreadVars_ {
167
    ThreadVars *tv;
168
    TmSlot *slot;
169
    LiveDevice *livedev;
170

171
    /* thread specific socket */
172
    int promisc;
173
    int threads;
174

175
    char iface[AFXDP_IFACE_NAME_LENGTH];
176
    uint32_t ifindex;
177

178
    /* AF_XDP structure */
179
    struct UmemInfo umem;
180
    struct XskSockInfo xsk;
181
    uint32_t gro_flush_timeout;
182
    uint32_t napi_defer_hard_irqs;
183
    uint32_t prog_id;
184

185
    /* Handle state */
186
    uint8_t afxdp_state;
187

188
    /* Stats parameters */
189
    uint64_t pkts;
190
    uint64_t bytes;
191
    StatsCounterId capture_afxdp_packets;
192
    StatsCounterId capture_kernel_drops;
193
    StatsCounterId capture_afxdp_poll;
194
    StatsCounterId capture_afxdp_poll_timeout;
195
    StatsCounterId capture_afxdp_poll_failed;
196
    StatsCounterId capture_afxdp_empty_reads;
197
    StatsCounterId capture_afxdp_failed_reads;
198
    StatsCounterId capture_afxdp_acquire_pkt_failed;
199
} AFXDPThreadVars;
200

201
static TmEcode ReceiveAFXDPThreadInit(ThreadVars *, const void *, void **);
202
static void ReceiveAFXDPThreadExitStats(ThreadVars *, void *);
203
static TmEcode ReceiveAFXDPThreadDeinit(ThreadVars *, void *);
204
static TmEcode ReceiveAFXDPLoop(ThreadVars *tv, void *data, void *slot);
205

206
static TmEcode DecodeAFXDPThreadInit(ThreadVars *, const void *, void **);
207
static TmEcode DecodeAFXDPThreadDeinit(ThreadVars *tv, void *data);
208
static TmEcode DecodeAFXDP(ThreadVars *, Packet *, void *);
209

210
/**
211
 * \brief Registration Function for RecieveAFXDP.
212
 * \todo Unit tests are needed for this module.
213
 */
214
void TmModuleReceiveAFXDPRegister(void)
215
{
2✔
216
    tmm_modules[TMM_RECEIVEAFXDP].name = "ReceiveAFXDP";
2✔
217
    tmm_modules[TMM_RECEIVEAFXDP].ThreadInit = ReceiveAFXDPThreadInit;
2✔
218
    tmm_modules[TMM_RECEIVEAFXDP].Func = NULL;
2✔
219
    tmm_modules[TMM_RECEIVEAFXDP].PktAcqLoop = ReceiveAFXDPLoop;
2✔
220
    tmm_modules[TMM_RECEIVEAFXDP].PktAcqBreakLoop = NULL;
2✔
221
    tmm_modules[TMM_RECEIVEAFXDP].ThreadExitPrintStats = ReceiveAFXDPThreadExitStats;
2✔
222
    tmm_modules[TMM_RECEIVEAFXDP].ThreadDeinit = ReceiveAFXDPThreadDeinit;
2✔
223
    tmm_modules[TMM_RECEIVEAFXDP].cap_flags = SC_CAP_NET_RAW;
2✔
224
    tmm_modules[TMM_RECEIVEAFXDP].flags = TM_FLAG_RECEIVE_TM;
2✔
225
}
2✔
226

227
/**
228
 * \brief Registration Function for DecodeAFXDP.
229
 * \todo Unit tests are needed for this module.
230
 */
231
void TmModuleDecodeAFXDPRegister(void)
232
{
2✔
233
    tmm_modules[TMM_DECODEAFXDP].name = "DecodeAFXDP";
2✔
234
    tmm_modules[TMM_DECODEAFXDP].ThreadInit = DecodeAFXDPThreadInit;
2✔
235
    tmm_modules[TMM_DECODEAFXDP].Func = DecodeAFXDP;
2✔
236
    tmm_modules[TMM_DECODEAFXDP].ThreadExitPrintStats = NULL;
2✔
237
    tmm_modules[TMM_DECODEAFXDP].ThreadDeinit = DecodeAFXDPThreadDeinit;
2✔
238
    tmm_modules[TMM_DECODEAFXDP].cap_flags = 0;
2✔
239
    tmm_modules[TMM_DECODEAFXDP].flags = TM_FLAG_DECODE_TM;
2✔
240
}
2✔
241

242
static inline void AFXDPDumpCounters(AFXDPThreadVars *ptv)
UNCOV
243
{
×
UNCOV
244
    struct xdp_statistics stats;
×
UNCOV
245
    socklen_t len = sizeof(struct xdp_statistics);
×
UNCOV
246
    int fd = xsk_socket__fd(ptv->xsk.xsk);
×
247

UNCOV
248
    if (getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &len) >= 0) {
×
UNCOV
249
        uint64_t rx_dropped = stats.rx_dropped + stats.rx_invalid_descs + stats.rx_ring_full;
×
250

UNCOV
251
        StatsCounterAddI64(&ptv->tv->stats, ptv->capture_kernel_drops,
×
UNCOV
252
                rx_dropped - StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_kernel_drops));
×
UNCOV
253
        StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_packets, ptv->pkts);
×
254

UNCOV
255
        (void)SC_ATOMIC_SET(ptv->livedev->drop, rx_dropped);
×
UNCOV
256
        (void)SC_ATOMIC_ADD(ptv->livedev->pkts, ptv->pkts);
×
257

UNCOV
258
        SCLogDebug("(%s) Kernel: Packets %" PRIu64 ", bytes %" PRIu64 ", dropped %" PRIu64 "",
×
UNCOV
259
                ptv->tv->name,
×
UNCOV
260
                StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_afxdp_packets), ptv->bytes,
×
UNCOV
261
                StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_kernel_drops));
×
262

UNCOV
263
        ptv->pkts = 0;
×
UNCOV
264
    }
×
UNCOV
265
}
×
266

267
/**
268
 * \brief Init function for socket creation.
269
 *
270
 * Mutex used to synchronise initialisation - each socket opens a
271
 * different queue. The specific order in which each queue is
272
 * opened is not important, but it is vital the queue_num's
273
 * are different.
274
 *
275
 * \param tv pointer to ThreadVars
276
 */
277
TmEcode AFXDPQueueProtectionInit(void)
UNCOV
278
{
×
UNCOV
279
    SCEnter();
×
280

UNCOV
281
    SCMutexInit(&xsk_protect.queue_protect, NULL);
×
UNCOV
282
    SC_ATOMIC_SET(xsk_protect.queue_num, 0);
×
UNCOV
283
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
284
}
×
285

286
static TmEcode AFXDPAssignQueueID(AFXDPThreadVars *ptv)
UNCOV
287
{
×
UNCOV
288
    if (!ptv->xsk.queue.assigned) {
×
UNCOV
289
        ptv->xsk.queue.queue_num = SC_ATOMIC_GET(xsk_protect.queue_num);
×
UNCOV
290
        SC_ATOMIC_ADD(xsk_protect.queue_num, 1);
×
291

292
        /* Queue only needs assigned once, on startup */
UNCOV
293
        ptv->xsk.queue.assigned = true;
×
UNCOV
294
    }
×
UNCOV
295
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
296
}
×
297

298
static void AFXDPAllThreadsRunning(AFXDPThreadVars *ptv)
UNCOV
299
{
×
UNCOV
300
    SCMutexLock(&xsk_protect.queue_protect);
×
UNCOV
301
    if ((ptv->threads - 1) == (int)ptv->xsk.queue.queue_num) {
×
UNCOV
302
        SCLogDebug("All AF_XDP capture threads are running.");
×
UNCOV
303
    }
×
UNCOV
304
    SCMutexUnlock(&xsk_protect.queue_protect);
×
UNCOV
305
}
×
306

307
static TmEcode AcquireBuffer(AFXDPThreadVars *ptv)
UNCOV
308
{
×
UNCOV
309
    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | ptv->umem.mmap_alignment_flag;
×
UNCOV
310
    ptv->umem.buf = mmap(NULL, MEM_BYTES, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
×
311

UNCOV
312
    if (ptv->umem.buf == MAP_FAILED) {
×
UNCOV
313
        SCLogError("mmap: failed to acquire memory");
×
UNCOV
314
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
315
    }
×
316

UNCOV
317
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
318
}
×
319

320
static TmEcode ConfigureXSKUmem(AFXDPThreadVars *ptv)
UNCOV
321
{
×
UNCOV
322
    if (xsk_umem__create(&ptv->umem.umem, ptv->umem.buf, MEM_BYTES, &ptv->umem.fq, &ptv->umem.cq,
×
UNCOV
323
                &ptv->umem.cfg)) {
×
UNCOV
324
        SCLogError("failed to create umem: %s", strerror(errno));
×
UNCOV
325
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
326
    }
×
327

UNCOV
328
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
329
}
×
330

331
static TmEcode InitFillRing(AFXDPThreadVars *ptv, const uint32_t cnt)
UNCOV
332
{
×
UNCOV
333
    uint32_t idx_fq = 0;
×
334

UNCOV
335
    uint32_t ret = xsk_ring_prod__reserve(&ptv->umem.fq, cnt, &idx_fq);
×
UNCOV
336
    if (ret != cnt) {
×
UNCOV
337
        SCLogError("Failed to initialise the fill ring.");
×
UNCOV
338
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
339
    }
×
340

UNCOV
341
    for (uint32_t i = 0; i < cnt; i++) {
×
UNCOV
342
        *xsk_ring_prod__fill_addr(&ptv->umem.fq, idx_fq++) = i * FRAME_SIZE;
×
UNCOV
343
    }
×
344

UNCOV
345
    xsk_ring_prod__submit(&ptv->umem.fq, cnt);
×
UNCOV
346
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
347
}
×
348

349
/**
350
 * \brief Linux knobs are tuned to enable a NAPI polling context
351
 *
352
 * \param tv pointer to AFXDPThreadVars
353
 */
354
static TmEcode WriteLinuxTunables(AFXDPThreadVars *ptv)
UNCOV
355
{
×
UNCOV
356
    char fname[SYSFS_MAX_FILENAME_SIZE];
×
357

UNCOV
358
    if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/gro_flush_timeout", ptv->iface) <
×
UNCOV
359
            0) {
×
UNCOV
360
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
361
    }
×
362

UNCOV
363
    if (SysFsWriteValue(fname, ptv->gro_flush_timeout) != TM_ECODE_OK) {
×
UNCOV
364
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
365
    }
×
366

UNCOV
367
    if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/napi_defer_hard_irqs", ptv->iface) <
×
UNCOV
368
            0) {
×
UNCOV
369
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
370
    }
×
371

UNCOV
372
    if (SysFsWriteValue(fname, ptv->napi_defer_hard_irqs) != TM_ECODE_OK) {
×
UNCOV
373
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
374
    }
×
375

UNCOV
376
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
377
}
×
378

379
static TmEcode ConfigureBusyPolling(AFXDPThreadVars *ptv)
UNCOV
380
{
×
UNCOV
381
    if (!ptv->xsk.enable_busy_poll) {
×
UNCOV
382
        SCReturnInt(TM_ECODE_OK);
×
UNCOV
383
    }
×
384

385
    /* Kernel version must be >= 5.11 to avail of SO_PREFER_BUSY_POLL
386
     * see linux commit: 7fd3253a7de6a317a0683f83739479fb880bffc8
387
     */
UNCOV
388
    if (!SCKernelVersionIsAtLeast(5, 11)) {
×
UNCOV
389
        SCLogWarning("Kernel version older than required: v5.11,"
×
UNCOV
390
                     " upgrade kernel version to use 'enable-busy-poll' option.");
×
UNCOV
391
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
392
    }
×
393

UNCOV
394
#if defined SO_PREFER_BUSY_POLL && defined SO_BUSY_POLL && defined SO_BUSY_POLL_BUDGET
×
UNCOV
395
    const int fd = xsk_socket__fd(ptv->xsk.xsk);
×
UNCOV
396
    int sock_opt = 1;
×
397

UNCOV
398
    if (WriteLinuxTunables(ptv) != TM_ECODE_OK) {
×
UNCOV
399
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
400
    }
×
401

UNCOV
402
    if (setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL, (void *)&sock_opt, sizeof(sock_opt)) < 0) {
×
UNCOV
403
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
404
    }
×
405

UNCOV
406
    sock_opt = ptv->xsk.busy_poll_time;
×
UNCOV
407
    if (setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt, sizeof(sock_opt)) < 0) {
×
UNCOV
408
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
409
    }
×
410

UNCOV
411
    sock_opt = ptv->xsk.busy_poll_budget;
×
UNCOV
412
    if (setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL_BUDGET, (void *)&sock_opt, sizeof(sock_opt)) < 0) {
×
UNCOV
413
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
414
    }
×
415

UNCOV
416
    SCReturnInt(TM_ECODE_OK);
×
417
#else
418
    SCLogWarning(
419
            "Kernel does not support busy poll, upgrade kernel or disable \"enable-busy-poll\".");
420
    SCReturnInt(TM_ECODE_FAILED);
421
#endif
UNCOV
422
}
×
423

424
static void AFXDPSwitchState(AFXDPThreadVars *ptv, int state)
UNCOV
425
{
×
UNCOV
426
    ptv->afxdp_state = (uint8_t)state;
×
UNCOV
427
}
×
428

429
static TmEcode OpenXSKSocket(AFXDPThreadVars *ptv)
UNCOV
430
{
×
UNCOV
431
    int ret;
×
432

UNCOV
433
    SCMutexLock(&xsk_protect.queue_protect);
×
434

UNCOV
435
    if (AFXDPAssignQueueID(ptv) != TM_ECODE_OK) {
×
UNCOV
436
        SCLogError("Failed to assign queue ID");
×
UNCOV
437
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
438
    }
×
439

UNCOV
440
    if ((ret = xsk_socket__create(&ptv->xsk.xsk, ptv->livedev->dev, ptv->xsk.queue.queue_num,
×
UNCOV
441
                 ptv->umem.umem, &ptv->xsk.rx, &ptv->xsk.tx, &ptv->xsk.cfg))) {
×
UNCOV
442
        SCLogError("Failed to create socket: %s", strerror(-ret));
×
UNCOV
443
        SCMutexUnlock(&xsk_protect.queue_protect);
×
UNCOV
444
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
445
    }
×
UNCOV
446
    SCLogDebug("bind to %s on queue %u", ptv->iface, ptv->xsk.queue.queue_num);
×
447

448
    /* For polling and socket options */
UNCOV
449
    ptv->xsk.fd.fd = xsk_socket__fd(ptv->xsk.xsk);
×
UNCOV
450
    ptv->xsk.fd.events = POLLIN;
×
451

452
    /* Set state */
UNCOV
453
    AFXDPSwitchState(ptv, AFXDP_STATE_UP);
×
454

UNCOV
455
    SCMutexUnlock(&xsk_protect.queue_protect);
×
UNCOV
456
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
457
}
×
458

459
static void AFXDPCloseSocket(AFXDPThreadVars *ptv)
UNCOV
460
{
×
UNCOV
461
    if (ptv->xsk.xsk) {
×
UNCOV
462
        xsk_socket__delete(ptv->xsk.xsk);
×
UNCOV
463
        ptv->xsk.xsk = NULL;
×
UNCOV
464
    }
×
465

UNCOV
466
    if (ptv->umem.umem) {
×
UNCOV
467
        xsk_umem__delete(ptv->umem.umem);
×
UNCOV
468
        ptv->umem.umem = NULL;
×
UNCOV
469
    }
×
470

UNCOV
471
    memset(&ptv->umem.fq, 0, sizeof(struct xsk_ring_prod));
×
UNCOV
472
    memset(&ptv->umem.cq, 0, sizeof(struct xsk_ring_cons));
×
UNCOV
473
}
×
474

475
static TmEcode AFXDPSocketCreation(AFXDPThreadVars *ptv)
UNCOV
476
{
×
UNCOV
477
    if (ConfigureXSKUmem(ptv) != TM_ECODE_OK) {
×
UNCOV
478
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
479
    }
×
480

UNCOV
481
    if (InitFillRing(ptv, NUM_FRAMES * 2) != TM_ECODE_OK) {
×
UNCOV
482
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
483
    }
×
484

485
    /* Open AF_XDP socket */
UNCOV
486
    if (OpenXSKSocket(ptv) != TM_ECODE_OK) {
×
UNCOV
487
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
488
    }
×
489

UNCOV
490
    if (ConfigureBusyPolling(ptv) != TM_ECODE_OK) {
×
UNCOV
491
        SCLogWarning("Failed to configure busy polling"
×
UNCOV
492
                     " performance may be reduced.");
×
UNCOV
493
    }
×
494

495
    /* Has the eBPF program successfully bound? */
UNCOV
496
#ifdef HAVE_BPF_XDP_QUERY_ID
×
UNCOV
497
    if (bpf_xdp_query_id(ptv->ifindex, ptv->xsk.cfg.xdp_flags, &ptv->prog_id)) {
×
UNCOV
498
        SCLogError("Failed to attach eBPF program to interface: %s", ptv->livedev->dev);
×
UNCOV
499
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
500
    }
×
501
#else
502
    if (bpf_get_link_xdp_id(ptv->ifindex, &ptv->prog_id, ptv->xsk.cfg.xdp_flags)) {
503
        SCLogError("Failed to attach eBPF program to interface: %s", ptv->livedev->dev);
504
        SCReturnInt(TM_ECODE_FAILED);
505
    }
506
#endif
507

UNCOV
508
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
509
}
×
510

511
/**
512
 * \brief Try to reopen AF_XDP socket
513
 *
514
 * \retval: TM_ECODE_OK in case of success
515
 * TM_ECODE_FAILED if error occurs or a condition is not met.
516
 */
517
static TmEcode AFXDPTryReopen(AFXDPThreadVars *ptv)
UNCOV
518
{
×
UNCOV
519
    AFXDPCloseSocket(ptv);
×
UNCOV
520
    usleep(RECONNECT_TIMEOUT);
×
521

UNCOV
522
    int if_flags = GetIfaceFlags(ptv->iface);
×
UNCOV
523
    if (if_flags == -1) {
×
UNCOV
524
        SCLogDebug("Couldn't get flags for interface '%s'", ptv->iface);
×
UNCOV
525
        goto sock_err;
×
UNCOV
526
    } else if ((if_flags & (IFF_UP | IFF_RUNNING)) == 0) {
×
UNCOV
527
        SCLogDebug("Interface '%s' is down", ptv->iface);
×
UNCOV
528
        goto sock_err;
×
UNCOV
529
    }
×
530

UNCOV
531
    if (AFXDPSocketCreation(ptv) != TM_ECODE_OK) {
×
UNCOV
532
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
533
    }
×
534

UNCOV
535
    SCLogInfo("Interface '%s' is back", ptv->iface);
×
UNCOV
536
    SCReturnInt(TM_ECODE_OK);
×
537

UNCOV
538
sock_err:
×
UNCOV
539
    SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
540
}
×
541

542
/**
543
 * \brief Write packet entry to the fill ring, freeing
544
 * this slot for re/fill with inbound packet descriptor
545
 * \param pointer to Packet
546
 * \retval: None
547
 */
548
static void AFXDPReleasePacket(Packet *p)
UNCOV
549
{
×
UNCOV
550
    *xsk_ring_prod__fill_addr((struct xsk_ring_prod *)p->afxdp_v.fq, p->afxdp_v.fq_idx) =
×
UNCOV
551
            p->afxdp_v.orig;
×
552

UNCOV
553
    PacketFreeOrRelease(p);
×
UNCOV
554
}
×
555

556
static inline int DumpStatsEverySecond(AFXDPThreadVars *ptv, time_t *last_dump)
UNCOV
557
{
×
UNCOV
558
    int stats_dumped = 0;
×
UNCOV
559
    time_t current_time = time(NULL);
×
560

UNCOV
561
    if (current_time != *last_dump) {
×
UNCOV
562
        AFXDPDumpCounters(ptv);
×
UNCOV
563
        *last_dump = current_time;
×
UNCOV
564
        stats_dumped = 1;
×
UNCOV
565
    }
×
566

UNCOV
567
    StatsSyncCountersIfSignalled(&ptv->tv->stats);
×
568

UNCOV
569
    return stats_dumped;
×
UNCOV
570
}
×
571

572
static inline ssize_t WakeupSocket(void *data)
UNCOV
573
{
×
UNCOV
574
    ssize_t res = 0;
×
UNCOV
575
    AFXDPThreadVars *ptv = (AFXDPThreadVars *)data;
×
576

577
    /* Assuming kernel >= 5.11 in use if xdp_busy_poll is enabled */
UNCOV
578
    if (ptv->xsk.enable_busy_poll || xsk_ring_prod__needs_wakeup(&ptv->umem.fq)) {
×
579
        // cppcheck-suppress nullPointer
UNCOV
580
        res = recvfrom(xsk_socket__fd(ptv->xsk.xsk), NULL, 0, MSG_DONTWAIT, NULL, NULL);
×
UNCOV
581
    }
×
582

UNCOV
583
    return res;
×
UNCOV
584
}
×
585

586
/**
587
 * \brief Init function for ReceiveAFXDP.
588
 *
589
 * \param tv pointer to ThreadVars
590
 * \param initdata pointer to the interface passed from the user
591
 * \param data pointer gets populated with AFPThreadVars
592
 *
593
 * \todo Create a general AFP setup function.
594
 */
595
static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void **data)
UNCOV
596
{
×
UNCOV
597
    SCEnter();
×
598

UNCOV
599
    AFXDPIfaceConfig *afxdpconfig = (AFXDPIfaceConfig *)initdata;
×
600

UNCOV
601
    if (initdata == NULL) {
×
UNCOV
602
        SCLogError("initdata == NULL");
×
UNCOV
603
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
604
    }
×
605

UNCOV
606
    AFXDPThreadVars *ptv = SCCalloc(1, sizeof(AFXDPThreadVars));
×
UNCOV
607
    if (unlikely(ptv == NULL)) {
×
UNCOV
608
        afxdpconfig->DerefFunc(afxdpconfig);
×
UNCOV
609
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
610
    }
×
611

UNCOV
612
    ptv->tv = tv;
×
613

UNCOV
614
    strlcpy(ptv->iface, afxdpconfig->iface, AFXDP_IFACE_NAME_LENGTH);
×
UNCOV
615
    ptv->iface[AFXDP_IFACE_NAME_LENGTH - 1] = '\0';
×
UNCOV
616
    ptv->ifindex = if_nametoindex(ptv->iface);
×
617

UNCOV
618
    ptv->livedev = LiveGetDevice(ptv->iface);
×
UNCOV
619
    if (ptv->livedev == NULL) {
×
UNCOV
620
        SCLogError("Unable to find Live device");
×
UNCOV
621
        SCFree(ptv);
×
UNCOV
622
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
623
    }
×
624

UNCOV
625
    ptv->promisc = afxdpconfig->promisc;
×
UNCOV
626
    if (ptv->promisc != 0) {
×
627
        /* Force promiscuous mode */
UNCOV
628
        if (SetIfaceFlags(ptv->iface, IFF_PROMISC | IFF_UP) != 0) {
×
UNCOV
629
            SCLogError("Failed to switch interface (%s) to promiscuous, error %s", ptv->iface,
×
UNCOV
630
                    strerror(errno));
×
UNCOV
631
            SCFree(ptv);
×
UNCOV
632
            SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
633
        }
×
UNCOV
634
    }
×
635

UNCOV
636
    ptv->threads = afxdpconfig->threads;
×
637

638
    /* Socket configuration */
UNCOV
639
    ptv->xsk.cfg.rx_size = NUM_FRAMES_CONS;
×
UNCOV
640
    ptv->xsk.cfg.tx_size = NUM_FRAMES_PROD;
×
UNCOV
641
    ptv->xsk.cfg.xdp_flags = afxdpconfig->mode;
×
UNCOV
642
    ptv->xsk.cfg.bind_flags = afxdpconfig->bind_flags;
×
643

644
    /* UMEM configuration */
UNCOV
645
    ptv->umem.cfg.fill_size = NUM_FRAMES_PROD * 2;
×
UNCOV
646
    ptv->umem.cfg.comp_size = NUM_FRAMES_CONS;
×
UNCOV
647
    ptv->umem.cfg.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
×
UNCOV
648
    ptv->umem.cfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
×
UNCOV
649
    ptv->umem.cfg.flags = afxdpconfig->mem_alignment;
×
650

651
    /* Use hugepages if unaligned chunk mode */
UNCOV
652
    if (ptv->umem.cfg.flags == XDP_UMEM_UNALIGNED_CHUNK_FLAG) {
×
UNCOV
653
        ptv->umem.mmap_alignment_flag = MAP_HUGETLB;
×
UNCOV
654
    }
×
655

656
    /* Busy polling configuration */
UNCOV
657
    ptv->xsk.enable_busy_poll = afxdpconfig->enable_busy_poll;
×
UNCOV
658
    ptv->xsk.busy_poll_budget = afxdpconfig->busy_poll_budget;
×
UNCOV
659
    ptv->xsk.busy_poll_time = afxdpconfig->busy_poll_time;
×
UNCOV
660
    ptv->gro_flush_timeout = afxdpconfig->gro_flush_timeout;
×
UNCOV
661
    ptv->napi_defer_hard_irqs = afxdpconfig->napi_defer_hard_irqs;
×
662

663
    /* Stats registration */
UNCOV
664
    ptv->capture_afxdp_packets = StatsRegisterCounter("capture.afxdp_packets", &ptv->tv->stats);
×
UNCOV
665
    ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", &ptv->tv->stats);
×
UNCOV
666
    ptv->capture_afxdp_poll = StatsRegisterCounter("capture.afxdp.poll", &ptv->tv->stats);
×
UNCOV
667
    ptv->capture_afxdp_poll_timeout =
×
UNCOV
668
            StatsRegisterCounter("capture.afxdp.poll_timeout", &ptv->tv->stats);
×
UNCOV
669
    ptv->capture_afxdp_poll_failed =
×
UNCOV
670
            StatsRegisterCounter("capture.afxdp.poll_failed", &ptv->tv->stats);
×
UNCOV
671
    ptv->capture_afxdp_empty_reads =
×
UNCOV
672
            StatsRegisterCounter("capture.afxdp.empty_reads", &ptv->tv->stats);
×
UNCOV
673
    ptv->capture_afxdp_failed_reads =
×
UNCOV
674
            StatsRegisterCounter("capture.afxdp.failed_reads", &ptv->tv->stats);
×
UNCOV
675
    ptv->capture_afxdp_acquire_pkt_failed =
×
UNCOV
676
            StatsRegisterCounter("capture.afxdp.acquire_pkt_failed", &ptv->tv->stats);
×
677

678
    /* Reserve memory for umem  */
UNCOV
679
    if (AcquireBuffer(ptv) != TM_ECODE_OK) {
×
UNCOV
680
        SCFree(ptv);
×
UNCOV
681
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
682
    }
×
683

UNCOV
684
    if (AFXDPSocketCreation(ptv) != TM_ECODE_OK) {
×
UNCOV
685
        ReceiveAFXDPThreadDeinit(tv, ptv);
×
UNCOV
686
        SCReturnInt(TM_ECODE_FAILED);
×
UNCOV
687
    }
×
688

UNCOV
689
    *data = (void *)ptv;
×
UNCOV
690
    afxdpconfig->DerefFunc(afxdpconfig);
×
UNCOV
691
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
692
}
×
693

694
/**
695
 *  \brief Main AF_XDP reading Loop function
696
 */
697
static TmEcode ReceiveAFXDPLoop(ThreadVars *tv, void *data, void *slot)
UNCOV
698
{
×
UNCOV
699
    SCEnter();
×
700

UNCOV
701
    Packet *p;
×
UNCOV
702
    time_t last_dump = 0;
×
UNCOV
703
    struct timeval ts;
×
UNCOV
704
    uint32_t idx_rx = 0, idx_fq = 0, rcvd;
×
UNCOV
705
    int r;
×
UNCOV
706
    AFXDPThreadVars *ptv = (AFXDPThreadVars *)data;
×
UNCOV
707
    TmSlot *s = (TmSlot *)slot;
×
708

UNCOV
709
    ptv->slot = s->slot_next;
×
710

UNCOV
711
    AFXDPAllThreadsRunning(ptv);
×
712

713
    // Indicate that the thread is actually running its application level code (i.e., it can poll
714
    // packets)
UNCOV
715
    TmThreadsSetFlag(tv, THV_RUNNING);
×
716

UNCOV
717
    PacketPoolWait();
×
UNCOV
718
    while (1) {
×
719
        /* Start by checking the state of our interface */
UNCOV
720
        if (unlikely(ptv->afxdp_state == AFXDP_STATE_DOWN)) {
×
UNCOV
721
            do {
×
UNCOV
722
                usleep(RECONNECT_TIMEOUT);
×
UNCOV
723
                if (unlikely(suricata_ctl_flags != 0)) {
×
UNCOV
724
                    break;
×
UNCOV
725
                }
×
UNCOV
726
                r = AFXDPTryReopen(ptv);
×
UNCOV
727
            } while (r != TM_ECODE_OK);
×
UNCOV
728
        }
×
729

UNCOV
730
        if (unlikely(suricata_ctl_flags != 0)) {
×
UNCOV
731
            SCLogDebug("Stopping Suricata!");
×
UNCOV
732
            AFXDPDumpCounters(ptv);
×
UNCOV
733
            break;
×
UNCOV
734
        }
×
735

736
        /* Busy polling is not set, using poll() to maintain (relatively) decent
737
         * performance. xdp_busy_poll must be disabled for kernels < 5.11
738
         */
UNCOV
739
        if (!ptv->xsk.enable_busy_poll) {
×
UNCOV
740
            StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_poll);
×
741

UNCOV
742
            r = poll(&ptv->xsk.fd, 1, POLL_TIMEOUT);
×
743

744
            /* Report poll results */
UNCOV
745
            if (r <= 0) {
×
UNCOV
746
                if (r == 0) {
×
UNCOV
747
                    StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_poll_timeout);
×
UNCOV
748
                } else if (r < 0) {
×
UNCOV
749
                    StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_poll_failed);
×
UNCOV
750
                    SCLogWarning("poll failed with retval %d", r);
×
UNCOV
751
                    AFXDPSwitchState(ptv, AFXDP_STATE_DOWN);
×
UNCOV
752
                }
×
753

UNCOV
754
                DumpStatsEverySecond(ptv, &last_dump);
×
UNCOV
755
                continue;
×
UNCOV
756
            }
×
UNCOV
757
        }
×
758

UNCOV
759
        rcvd = xsk_ring_cons__peek(&ptv->xsk.rx, ptv->xsk.busy_poll_budget, &idx_rx);
×
UNCOV
760
        if (!rcvd) {
×
UNCOV
761
            StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_empty_reads);
×
UNCOV
762
            ssize_t ret = WakeupSocket(ptv);
×
UNCOV
763
            if (ret < 0) {
×
UNCOV
764
                SCLogWarning("recv failed with retval %ld", ret);
×
UNCOV
765
                AFXDPSwitchState(ptv, AFXDP_STATE_DOWN);
×
UNCOV
766
            }
×
UNCOV
767
            DumpStatsEverySecond(ptv, &last_dump);
×
UNCOV
768
            continue;
×
UNCOV
769
        }
×
770

UNCOV
771
        uint32_t res = xsk_ring_prod__reserve(&ptv->umem.fq, rcvd, &idx_fq);
×
UNCOV
772
        while (res != rcvd) {
×
UNCOV
773
            StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_failed_reads);
×
UNCOV
774
            ssize_t ret = WakeupSocket(ptv);
×
UNCOV
775
            if (ret < 0) {
×
UNCOV
776
                SCLogWarning("recv failed with retval %ld", ret);
×
UNCOV
777
                AFXDPSwitchState(ptv, AFXDP_STATE_DOWN);
×
UNCOV
778
                continue;
×
UNCOV
779
            }
×
UNCOV
780
            res = xsk_ring_prod__reserve(&ptv->umem.fq, rcvd, &idx_fq);
×
UNCOV
781
        }
×
782

UNCOV
783
        gettimeofday(&ts, NULL);
×
UNCOV
784
        ptv->pkts += rcvd;
×
UNCOV
785
        for (uint32_t i = 0; i < rcvd; i++) {
×
UNCOV
786
            p = PacketGetFromQueueOrAlloc();
×
UNCOV
787
            if (unlikely(p == NULL)) {
×
UNCOV
788
                StatsCounterIncr(&ptv->tv->stats, ptv->capture_afxdp_acquire_pkt_failed);
×
UNCOV
789
                continue;
×
UNCOV
790
            }
×
791

UNCOV
792
            PKT_SET_SRC(p, PKT_SRC_WIRE);
×
UNCOV
793
            p->datalink = LINKTYPE_ETHERNET;
×
UNCOV
794
            p->livedev = ptv->livedev;
×
UNCOV
795
            p->ReleasePacket = AFXDPReleasePacket;
×
UNCOV
796
            p->flags |= PKT_IGNORE_CHECKSUM;
×
797

UNCOV
798
            p->ts = SCTIME_FROM_TIMEVAL(&ts);
×
799

UNCOV
800
            uint64_t addr = xsk_ring_cons__rx_desc(&ptv->xsk.rx, idx_rx)->addr;
×
UNCOV
801
            uint32_t len = xsk_ring_cons__rx_desc(&ptv->xsk.rx, idx_rx++)->len;
×
UNCOV
802
            uint64_t orig = xsk_umem__extract_addr(addr);
×
UNCOV
803
            addr = xsk_umem__add_offset_to_addr(addr);
×
804

UNCOV
805
            uint8_t *pkt_data = xsk_umem__get_data(ptv->umem.buf, addr);
×
806

UNCOV
807
            ptv->bytes += len;
×
808

UNCOV
809
            p->afxdp_v.fq_idx = idx_fq++;
×
UNCOV
810
            p->afxdp_v.orig = orig;
×
UNCOV
811
            p->afxdp_v.fq = &ptv->umem.fq;
×
812

UNCOV
813
            PacketSetData(p, pkt_data, len);
×
814

UNCOV
815
            if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
×
UNCOV
816
                TmqhOutputPacketpool(ptv->tv, p);
×
UNCOV
817
                SCReturnInt(EXIT_FAILURE);
×
UNCOV
818
            }
×
UNCOV
819
        }
×
820

UNCOV
821
        xsk_ring_prod__submit(&ptv->umem.fq, rcvd);
×
UNCOV
822
        xsk_ring_cons__release(&ptv->xsk.rx, rcvd);
×
823

824
        /* Trigger one dump of stats every second */
UNCOV
825
        DumpStatsEverySecond(ptv, &last_dump);
×
UNCOV
826
    }
×
827

UNCOV
828
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
829
}
×
830

831
/**
832
 * \brief function to unload an AF_XDP program
833
 *
834
 */
835
static void RunModeAFXDPRemoveProg(char *iface_name)
UNCOV
836
{
×
UNCOV
837
    unsigned int ifindex = if_nametoindex(iface_name);
×
838

UNCOV
839
    struct xdp_multiprog *progs = xdp_multiprog__get_from_ifindex(ifindex);
×
UNCOV
840
    if (progs == NULL) {
×
UNCOV
841
        return;
×
UNCOV
842
    }
×
UNCOV
843
    enum xdp_attach_mode mode = xdp_multiprog__attach_mode(progs);
×
844

UNCOV
845
    struct xdp_program *prog = NULL;
×
846

847
    // loop through the multiprogram struct, removing all the programs
UNCOV
848
    for (prog = xdp_multiprog__next_prog(NULL, progs); prog;
×
UNCOV
849
            prog = xdp_multiprog__next_prog(prog, progs)) {
×
UNCOV
850
        int ret = xdp_program__detach(prog, ifindex, mode, 0);
×
UNCOV
851
        if (ret) {
×
UNCOV
852
            SCLogDebug("Error: cannot detatch XDP program: %s\n", strerror(errno));
×
UNCOV
853
        }
×
UNCOV
854
    }
×
855

UNCOV
856
    prog = xdp_multiprog__main_prog(progs);
×
UNCOV
857
    if (xdp_program__is_attached(prog, ifindex) != XDP_MODE_UNSPEC) {
×
UNCOV
858
        int ret = xdp_program__detach(prog, ifindex, mode, 0);
×
UNCOV
859
        if (ret) {
×
UNCOV
860
            SCLogDebug("Error: cannot detatch XDP program: %s\n", strerror(errno));
×
UNCOV
861
        }
×
UNCOV
862
    }
×
UNCOV
863
}
×
864

865
/**
866
 * \brief DeInit function closes af-xdp socket at exit.
867
 * \param tv pointer to ThreadVars
868
 * \param data pointer that gets cast into AFXDPPThreadVars for ptv
869
 */
870
static SCMutex sync_deinit = SCMUTEX_INITIALIZER;
871

872
static TmEcode ReceiveAFXDPThreadDeinit(ThreadVars *tv, void *data)
UNCOV
873
{
×
UNCOV
874
    AFXDPThreadVars *ptv = (AFXDPThreadVars *)data;
×
875

876
    /*
877
     * If AF_XDP is enabled, the program must be detached before the AF_XDP sockets
878
     * are closed to mitigate a bug that causes an IO_PAGEFAULT in linux kernel
879
     * version 5.19, unknown as of now what other versions this affects.
880
     */
UNCOV
881
    SCMutexLock(&sync_deinit);
×
UNCOV
882
    RunModeAFXDPRemoveProg(ptv->iface);
×
UNCOV
883
    SCMutexUnlock(&sync_deinit);
×
884

UNCOV
885
    if (ptv->xsk.xsk) {
×
UNCOV
886
        xsk_socket__delete(ptv->xsk.xsk);
×
UNCOV
887
        ptv->xsk.xsk = NULL;
×
UNCOV
888
    }
×
889

UNCOV
890
    if (ptv->umem.umem) {
×
UNCOV
891
        xsk_umem__delete(ptv->umem.umem);
×
UNCOV
892
        ptv->umem.umem = NULL;
×
UNCOV
893
    }
×
UNCOV
894
    munmap(ptv->umem.buf, MEM_BYTES);
×
895

UNCOV
896
    SCFree(ptv);
×
UNCOV
897
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
898
}
×
899

900
/**
901
 * \brief This function prints stats to the screen at exit.
902
 * \param tv pointer to ThreadVars
903
 * \param data pointer that gets cast into AFXDPThreadVars for ptv
904
 */
905
static void ReceiveAFXDPThreadExitStats(ThreadVars *tv, void *data)
UNCOV
906
{
×
UNCOV
907
    SCEnter();
×
UNCOV
908
    AFXDPThreadVars *ptv = (AFXDPThreadVars *)data;
×
909

UNCOV
910
    AFXDPDumpCounters(ptv);
×
911

UNCOV
912
    SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", bytes %" PRIu64 ", dropped %" PRIu64 "", tv->name,
×
UNCOV
913
            StatsCounterGetLocalValue(&tv->stats, ptv->capture_afxdp_packets), ptv->bytes,
×
UNCOV
914
            StatsCounterGetLocalValue(&tv->stats, ptv->capture_kernel_drops));
×
UNCOV
915
}
×
916

917
/**
918
 * \brief This function passes off to link type decoders.
919
 *
920
 * DecodeAFXDP decodes packets from AF_XDP and passes
921
 * them off to the proper link type decoder.
922
 *
923
 * \param t pointer to ThreadVars
924
 * \param p pointer to the current packet
925
 * \param data pointer that gets cast into AFXDPThreadVars for ptv
926
 */
927
static TmEcode DecodeAFXDP(ThreadVars *tv, Packet *p, void *data)
UNCOV
928
{
×
UNCOV
929
    SCEnter();
×
930

UNCOV
931
    DecodeThreadVars *dtv = (DecodeThreadVars *)data;
×
932

UNCOV
933
    DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
×
934

935
    /* update counters */
UNCOV
936
    DecodeUpdatePacketCounters(tv, dtv, p);
×
937

938
    /* If suri has set vlan during reading, we increase vlan counter */
UNCOV
939
    if (p->vlan_idx) {
×
UNCOV
940
        StatsCounterIncr(&tv->stats, dtv->counter_vlan);
×
UNCOV
941
    }
×
942

943
    /* call the decoder */
UNCOV
944
    DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
×
945

UNCOV
946
    PacketDecodeFinalize(tv, dtv, p);
×
947

UNCOV
948
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
949
}
×
950

951
static TmEcode DecodeAFXDPThreadInit(ThreadVars *tv, const void *initdata, void **data)
UNCOV
952
{
×
UNCOV
953
    SCEnter();
×
UNCOV
954
    DecodeThreadVars *dtv = DecodeThreadVarsAlloc(tv);
×
UNCOV
955
    if (dtv == NULL)
×
UNCOV
956
        SCReturnInt(TM_ECODE_FAILED);
×
957

UNCOV
958
    DecodeRegisterPerfCounters(dtv, tv);
×
959

UNCOV
960
    *data = (void *)dtv;
×
961

UNCOV
962
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
963
}
×
964

965
static TmEcode DecodeAFXDPThreadDeinit(ThreadVars *tv, void *data)
UNCOV
966
{
×
UNCOV
967
    if (data != NULL)
×
UNCOV
968
        DecodeThreadVarsFree(tv, data);
×
UNCOV
969
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
970
}
×
971

972
#endif /* HAVE_AF_XDP */
973
/* eof */
974
/**
975
 * @}
976
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc