|
|
|
|
@ -112,11 +112,6 @@ TmEcode NoAFXDPSupportExit(ThreadVars *tv, const void *initdata, void **data)
|
|
|
|
|
#else /* We have AF_XDP support */
|
|
|
|
|
|
|
|
|
|
#define POLL_TIMEOUT 100
|
|
|
|
|
#define NUM_FRAMES_PROD XSK_RING_PROD__DEFAULT_NUM_DESCS
|
|
|
|
|
#define NUM_FRAMES_CONS XSK_RING_CONS__DEFAULT_NUM_DESCS
|
|
|
|
|
#define NUM_FRAMES NUM_FRAMES_PROD
|
|
|
|
|
#define FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
|
|
|
|
|
#define MEM_BYTES (NUM_FRAMES * FRAME_SIZE * 2)
|
|
|
|
|
#define RECONNECT_TIMEOUT 500000
|
|
|
|
|
|
|
|
|
|
/* Interface state */
|
|
|
|
|
@ -124,7 +119,6 @@ enum state { AFXDP_STATE_DOWN, AFXDP_STATE_UP };
|
|
|
|
|
|
|
|
|
|
struct XskInitProtect {
|
|
|
|
|
SCMutex queue_protect;
|
|
|
|
|
SC_ATOMIC_DECLARE(uint8_t, queue_num);
|
|
|
|
|
} xsk_protect;
|
|
|
|
|
|
|
|
|
|
struct UmemInfo {
|
|
|
|
|
@ -134,6 +128,7 @@ struct UmemInfo {
|
|
|
|
|
struct xsk_ring_cons cq;
|
|
|
|
|
struct xsk_umem_config cfg;
|
|
|
|
|
int mmap_alignment_flag;
|
|
|
|
|
uint64_t mem_bytes;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct QueueAssignment {
|
|
|
|
|
@ -143,7 +138,6 @@ struct QueueAssignment {
|
|
|
|
|
|
|
|
|
|
struct XskSockInfo {
|
|
|
|
|
struct xsk_ring_cons rx;
|
|
|
|
|
struct xsk_ring_prod tx;
|
|
|
|
|
struct xsk_socket *xsk;
|
|
|
|
|
|
|
|
|
|
/* Queue assignment structure */
|
|
|
|
|
@ -194,6 +188,10 @@ typedef struct AFXDPThreadVars_ {
|
|
|
|
|
StatsCounterId capture_afxdp_empty_reads;
|
|
|
|
|
StatsCounterId capture_afxdp_failed_reads;
|
|
|
|
|
StatsCounterId capture_afxdp_acquire_pkt_failed;
|
|
|
|
|
StatsCounterId capture_afxdp_rx_dropped;
|
|
|
|
|
StatsCounterId capture_afxdp_rx_invalid_descs;
|
|
|
|
|
StatsCounterId capture_afxdp_rx_ring_full;
|
|
|
|
|
StatsCounterId capture_afxdp_fill_ring_empty;
|
|
|
|
|
} AFXDPThreadVars;
|
|
|
|
|
|
|
|
|
|
static TmEcode ReceiveAFXDPThreadInit(ThreadVars *, const void *, void **);
|
|
|
|
|
@ -250,13 +248,30 @@ static inline void AFXDPDumpCounters(AFXDPThreadVars *ptv)
|
|
|
|
|
rx_dropped - StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_kernel_drops));
|
|
|
|
|
StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_packets, ptv->pkts);
|
|
|
|
|
|
|
|
|
|
StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_rx_dropped,
|
|
|
|
|
stats.rx_dropped -
|
|
|
|
|
StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_afxdp_rx_dropped));
|
|
|
|
|
StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_rx_invalid_descs,
|
|
|
|
|
stats.rx_invalid_descs - StatsCounterGetLocalValue(&ptv->tv->stats,
|
|
|
|
|
ptv->capture_afxdp_rx_invalid_descs));
|
|
|
|
|
StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_rx_ring_full,
|
|
|
|
|
stats.rx_ring_full - StatsCounterGetLocalValue(
|
|
|
|
|
&ptv->tv->stats, ptv->capture_afxdp_rx_ring_full));
|
|
|
|
|
StatsCounterAddI64(&ptv->tv->stats, ptv->capture_afxdp_fill_ring_empty,
|
|
|
|
|
stats.rx_fill_ring_empty_descs - StatsCounterGetLocalValue(&ptv->tv->stats,
|
|
|
|
|
ptv->capture_afxdp_fill_ring_empty));
|
|
|
|
|
|
|
|
|
|
(void)SC_ATOMIC_SET(ptv->livedev->drop, rx_dropped);
|
|
|
|
|
(void)SC_ATOMIC_ADD(ptv->livedev->pkts, ptv->pkts);
|
|
|
|
|
|
|
|
|
|
SCLogDebug("(%s) Kernel: Packets %" PRIu64 ", bytes %" PRIu64 ", dropped %" PRIu64 "",
|
|
|
|
|
SCLogDebug("(%s) Kernel: Packets %" PRIu64 ", bytes %" PRIu64 ", dropped %" PRIu64
|
|
|
|
|
" (rx_dropped %" PRIu64 ", rx_ring_full %" PRIu64 ", fill_ring_empty %" PRIu64
|
|
|
|
|
", rx_invalid_descs %" PRIu64 ")",
|
|
|
|
|
ptv->tv->name,
|
|
|
|
|
StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_afxdp_packets), ptv->bytes,
|
|
|
|
|
StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_kernel_drops));
|
|
|
|
|
StatsCounterGetLocalValue(&ptv->tv->stats, ptv->capture_kernel_drops),
|
|
|
|
|
stats.rx_dropped, stats.rx_ring_full, stats.rx_fill_ring_empty_descs,
|
|
|
|
|
stats.rx_invalid_descs);
|
|
|
|
|
|
|
|
|
|
ptv->pkts = 0;
|
|
|
|
|
}
|
|
|
|
|
@ -277,19 +292,6 @@ TmEcode AFXDPQueueProtectionInit(void)
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
|
SCMutexInit(&xsk_protect.queue_protect, NULL);
|
|
|
|
|
SC_ATOMIC_SET(xsk_protect.queue_num, 0);
|
|
|
|
|
SCReturnInt(TM_ECODE_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TmEcode AFXDPAssignQueueID(AFXDPThreadVars *ptv)
|
|
|
|
|
{
|
|
|
|
|
if (!ptv->xsk.queue.assigned) {
|
|
|
|
|
ptv->xsk.queue.queue_num = SC_ATOMIC_GET(xsk_protect.queue_num);
|
|
|
|
|
SC_ATOMIC_ADD(xsk_protect.queue_num, 1);
|
|
|
|
|
|
|
|
|
|
/* Queue only needs assigned once, on startup */
|
|
|
|
|
ptv->xsk.queue.assigned = true;
|
|
|
|
|
}
|
|
|
|
|
SCReturnInt(TM_ECODE_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -305,7 +307,7 @@ static void AFXDPAllThreadsRunning(AFXDPThreadVars *ptv)
|
|
|
|
|
static TmEcode AcquireBuffer(AFXDPThreadVars *ptv)
|
|
|
|
|
{
|
|
|
|
|
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | ptv->umem.mmap_alignment_flag;
|
|
|
|
|
ptv->umem.buf = mmap(NULL, MEM_BYTES, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
|
|
|
|
|
ptv->umem.buf = mmap(NULL, ptv->umem.mem_bytes, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
|
|
|
|
|
|
|
|
|
|
if (ptv->umem.buf == MAP_FAILED) {
|
|
|
|
|
SCLogError("mmap: failed to acquire memory");
|
|
|
|
|
@ -317,8 +319,8 @@ static TmEcode AcquireBuffer(AFXDPThreadVars *ptv)
|
|
|
|
|
|
|
|
|
|
static TmEcode ConfigureXSKUmem(AFXDPThreadVars *ptv)
|
|
|
|
|
{
|
|
|
|
|
if (xsk_umem__create(&ptv->umem.umem, ptv->umem.buf, MEM_BYTES, &ptv->umem.fq, &ptv->umem.cq,
|
|
|
|
|
&ptv->umem.cfg)) {
|
|
|
|
|
if (xsk_umem__create(&ptv->umem.umem, ptv->umem.buf, ptv->umem.mem_bytes, &ptv->umem.fq,
|
|
|
|
|
&ptv->umem.cq, &ptv->umem.cfg)) {
|
|
|
|
|
SCLogError("failed to create umem: %s", strerror(errno));
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
@ -337,7 +339,7 @@ static TmEcode InitFillRing(AFXDPThreadVars *ptv, const uint32_t cnt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cnt; i++) {
|
|
|
|
|
*xsk_ring_prod__fill_addr(&ptv->umem.fq, idx_fq++) = i * FRAME_SIZE;
|
|
|
|
|
*xsk_ring_prod__fill_addr(&ptv->umem.fq, idx_fq++) = (uint64_t)i * ptv->umem.cfg.frame_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xsk_ring_prod__submit(&ptv->umem.fq, cnt);
|
|
|
|
|
@ -352,9 +354,17 @@ static TmEcode InitFillRing(AFXDPThreadVars *ptv, const uint32_t cnt)
|
|
|
|
|
static TmEcode WriteLinuxTunables(AFXDPThreadVars *ptv)
|
|
|
|
|
{
|
|
|
|
|
char fname[SYSFS_MAX_FILENAME_SIZE];
|
|
|
|
|
char ifname[IF_NAMESIZE];
|
|
|
|
|
|
|
|
|
|
if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/gro_flush_timeout", ptv->iface) <
|
|
|
|
|
0) {
|
|
|
|
|
/* The configured interface may be an alternative name (e.g. "mon0"), but
|
|
|
|
|
* sysfs only exposes a directory for the real netdev name. */
|
|
|
|
|
if (if_indextoname(ptv->ifindex, ifname) == NULL) {
|
|
|
|
|
SCLogError("Could not resolve interface name for %s (ifindex %u): %s", ptv->iface,
|
|
|
|
|
ptv->ifindex, strerror(errno));
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/gro_flush_timeout", ifname) < 0) {
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -362,8 +372,7 @@ static TmEcode WriteLinuxTunables(AFXDPThreadVars *ptv)
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/napi_defer_hard_irqs", ptv->iface) <
|
|
|
|
|
0) {
|
|
|
|
|
if (snprintf(fname, SYSFS_MAX_FILENAME_SIZE, "class/net/%s/napi_defer_hard_irqs", ifname) < 0) {
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -430,13 +439,8 @@ static TmEcode OpenXSKSocket(AFXDPThreadVars *ptv)
|
|
|
|
|
|
|
|
|
|
SCMutexLock(&xsk_protect.queue_protect);
|
|
|
|
|
|
|
|
|
|
if (AFXDPAssignQueueID(ptv) != TM_ECODE_OK) {
|
|
|
|
|
SCLogError("Failed to assign queue ID");
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((ret = xsk_socket__create(&ptv->xsk.xsk, ptv->livedev->dev, ptv->xsk.queue.queue_num,
|
|
|
|
|
ptv->umem.umem, &ptv->xsk.rx, &ptv->xsk.tx, &ptv->xsk.cfg))) {
|
|
|
|
|
ptv->umem.umem, &ptv->xsk.rx, NULL, &ptv->xsk.cfg))) {
|
|
|
|
|
SCLogError("Failed to create socket: %s", strerror(-ret));
|
|
|
|
|
SCMutexUnlock(&xsk_protect.queue_protect);
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
@ -476,7 +480,7 @@ static TmEcode AFXDPSocketCreation(AFXDPThreadVars *ptv)
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (InitFillRing(ptv, NUM_FRAMES * 2) != TM_ECODE_OK) {
|
|
|
|
|
if (InitFillRing(ptv, ptv->umem.cfg.fill_size) != TM_ECODE_OK) {
|
|
|
|
|
SCReturnInt(TM_ECODE_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -633,16 +637,18 @@ static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void
|
|
|
|
|
|
|
|
|
|
ptv->threads = afxdpconfig->threads;
|
|
|
|
|
|
|
|
|
|
/* Socket configuration */
|
|
|
|
|
ptv->xsk.cfg.rx_size = NUM_FRAMES_CONS;
|
|
|
|
|
ptv->xsk.cfg.tx_size = NUM_FRAMES_PROD;
|
|
|
|
|
/* Socket configuration. No TX ring is created, AF_XDP capture is receive
|
|
|
|
|
* only, so tx_size is left at 0 and a NULL TX ring is passed at bind. */
|
|
|
|
|
ptv->xsk.cfg.rx_size = afxdpconfig->rx_ring_size;
|
|
|
|
|
ptv->xsk.cfg.xdp_flags = afxdpconfig->mode;
|
|
|
|
|
ptv->xsk.cfg.bind_flags = afxdpconfig->bind_flags;
|
|
|
|
|
|
|
|
|
|
/* UMEM configuration */
|
|
|
|
|
ptv->umem.cfg.fill_size = NUM_FRAMES_PROD * 2;
|
|
|
|
|
ptv->umem.cfg.comp_size = NUM_FRAMES_CONS;
|
|
|
|
|
ptv->umem.cfg.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
|
|
|
|
/* UMEM configuration, the fill ring is sized to hold the whole UMEM so
|
|
|
|
|
* every frame can be handed to the kernel at once. */
|
|
|
|
|
ptv->umem.mem_bytes = (uint64_t)afxdpconfig->umem_frames * afxdpconfig->frame_size;
|
|
|
|
|
ptv->umem.cfg.fill_size = afxdpconfig->umem_frames;
|
|
|
|
|
ptv->umem.cfg.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
|
|
|
|
ptv->umem.cfg.frame_size = afxdpconfig->frame_size;
|
|
|
|
|
ptv->umem.cfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
|
|
|
|
ptv->umem.cfg.flags = afxdpconfig->mem_alignment;
|
|
|
|
|
|
|
|
|
|
@ -658,6 +664,10 @@ static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void
|
|
|
|
|
ptv->gro_flush_timeout = afxdpconfig->gro_flush_timeout;
|
|
|
|
|
ptv->napi_defer_hard_irqs = afxdpconfig->napi_defer_hard_irqs;
|
|
|
|
|
|
|
|
|
|
/* threads of an interface init in parallel, claim a queue index atomically */
|
|
|
|
|
ptv->xsk.queue.queue_num = SC_ATOMIC_ADD(afxdpconfig->queue_idx, 1);
|
|
|
|
|
ptv->xsk.queue.assigned = true;
|
|
|
|
|
|
|
|
|
|
/* Stats registration */
|
|
|
|
|
ptv->capture_afxdp_packets = StatsRegisterCounter("capture.afxdp_packets", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", &ptv->tv->stats);
|
|
|
|
|
@ -672,6 +682,19 @@ static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.failed_reads", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_afxdp_acquire_pkt_failed =
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.acquire_pkt_failed", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_afxdp_rx_dropped =
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.rx_dropped", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_afxdp_rx_invalid_descs =
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.rx_invalid_descs", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_afxdp_rx_ring_full =
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.rx_ring_full", &ptv->tv->stats);
|
|
|
|
|
ptv->capture_afxdp_fill_ring_empty =
|
|
|
|
|
StatsRegisterCounter("capture.afxdp.fill_ring_empty", &ptv->tv->stats);
|
|
|
|
|
|
|
|
|
|
SCLogPerf("%s: (%s) umem params: frame_size=%u frame_nr=%u rx_ring=%u (mem: %" PRIu64
|
|
|
|
|
", %.1f MiB)",
|
|
|
|
|
ptv->iface, tv->name, ptv->umem.cfg.frame_size, ptv->umem.cfg.fill_size,
|
|
|
|
|
ptv->xsk.cfg.rx_size, ptv->umem.mem_bytes, (double)ptv->umem.mem_bytes / (1024 * 1024));
|
|
|
|
|
|
|
|
|
|
/* Reserve memory for umem */
|
|
|
|
|
if (AcquireBuffer(ptv) != TM_ECODE_OK) {
|
|
|
|
|
@ -889,7 +912,7 @@ static TmEcode ReceiveAFXDPThreadDeinit(ThreadVars *tv, void *data)
|
|
|
|
|
xsk_umem__delete(ptv->umem.umem);
|
|
|
|
|
ptv->umem.umem = NULL;
|
|
|
|
|
}
|
|
|
|
|
munmap(ptv->umem.buf, MEM_BYTES);
|
|
|
|
|
munmap(ptv->umem.buf, ptv->umem.mem_bytes);
|
|
|
|
|
|
|
|
|
|
SCFree(ptv);
|
|
|
|
|
SCReturnInt(TM_ECODE_OK);
|
|
|
|
|
|