pull/16208/merge
Aboussejra 12 hours ago committed by GitHub
commit b0ef8af338
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -82,6 +82,16 @@ void RunModeIdsAFXDPRegister(void)
#define DEFAULT_BUSY_POLL_BUDGET 64
#define DEFAULT_GRO_FLUSH_TIMEOUT 2000000
#define DEFAULT_NAPI_HARD_IRQS 2
#define DEFAULT_RX_RING_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS
#define DEFAULT_UMEM_FRAMES (XSK_RING_PROD__DEFAULT_NUM_DESCS * 2)
#define DEFAULT_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
/* Function to check if x is power of 2
* https://www.geeksforgeeks.org/c/c-program-to-find-whether-a-no-is-power-of-two/ */
static bool isPowerOfTwo(uint32_t x)
{
return x && (!(x & (x - 1)));
}
static void AFXDPDerefConfig(void *conf)
{
@ -177,6 +187,10 @@ static void *ParseAFXDPConfig(const char *iface)
aconf->gro_flush_timeout = DEFAULT_GRO_FLUSH_TIMEOUT;
aconf->napi_defer_hard_irqs = DEFAULT_NAPI_HARD_IRQS;
aconf->mem_alignment = XSK_UMEM__DEFAULT_FLAGS;
SC_ATOMIC_INIT(aconf->queue_idx);
aconf->rx_ring_size = DEFAULT_RX_RING_SIZE;
aconf->umem_frames = DEFAULT_UMEM_FRAMES;
aconf->frame_size = DEFAULT_FRAME_SIZE;
/* Find initial node */
af_xdp_node = SCConfGetNode("af-xdp");
@ -251,6 +265,38 @@ static void *ParseAFXDPConfig(const char *iface)
}
}
/* UMEM count of frames */
if (SCConfGetChildValueIntWithDefault(if_root, if_default, "umem-frames", &conf_val_int) == 1) {
if (conf_val_int > 0) {
aconf->umem_frames = (uint32_t)conf_val_int;
}
}
if (!isPowerOfTwo(aconf->umem_frames)) {
FatalError("%s: af-xdp umem-frames (%u) must be a power of two", aconf->iface,
aconf->umem_frames);
}
aconf->rx_ring_size = aconf->umem_frames / 2;
/* Size of one UMEM frame in bytes. Must be a power of two. */
if (SCConfGetChildValueIntWithDefault(if_root, if_default, "frame-size", &conf_val_int) == 1) {
if (conf_val_int > 0) {
aconf->frame_size = (uint32_t)conf_val_int;
}
}
if (!isPowerOfTwo(aconf->frame_size)) {
FatalError("%s: af-xdp frame-size (%u) must be a power of two", aconf->iface,
aconf->frame_size);
}
SCLogConfig("%s: af-xdp: rx-ring-size %u, umem %u frames of %u bytes: %" PRIu64
" bytes (%.1f MiB) per thread, %" PRIu64 " bytes (%.1f MiB) over %d threads",
aconf->iface, aconf->rx_ring_size, aconf->umem_frames, aconf->frame_size,
(uint64_t)aconf->umem_frames * aconf->frame_size,
(double)aconf->umem_frames * aconf->frame_size / (1024 * 1024),
(uint64_t)aconf->umem_frames * aconf->frame_size * aconf->threads,
(double)aconf->umem_frames * aconf->frame_size * aconf->threads / (1024 * 1024),
aconf->threads);
/* Busy polling options */
if (SCConfGetChildValueBoolWithDefault(if_root, if_default, "enable-busy-poll", &conf_val) ==
1) {

@ -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);

@ -42,6 +42,13 @@ typedef struct AFXDPIfaceConfig {
uint32_t gro_flush_timeout;
uint32_t napi_defer_hard_irqs;
/* UMEM size in frames and derived RX ring depth, per thread */
uint32_t umem_frames;
uint32_t rx_ring_size;
/* Size of one UMEM frame in bytes */
uint32_t frame_size;
SC_ATOMIC_DECLARE(uint32_t, queue_idx);
SC_ATOMIC_DECLARE(unsigned int, ref);
void (*DerefFunc)(void *);
} AFXDPIfaceConfig;

@ -785,6 +785,12 @@ af-xdp:
# Note: unaligned chunk mode uses hugepages, so the required number
# of pages must be available.
#mem-unaligned: no
# UMEM size, expressed in frames of frame-size bytes (power of two)
#umem-frames: 4096
# Size of one UMEM frame in bytes. A frame holds a single packet, so
# it must be large enough for the biggest packet (MTU + headroom).
# Valid values are effectively 2048 or 4096: a power of two.
#frame-size: 4096
# The following options configure the prefer-busy-polling socket
# options. The polling time and budget can be edited here.
# Possible values are:

Loading…
Cancel
Save