af-xdp: make UMEM size configurable

UMEM size was hardcoded to XSK ring default descriptors * 2 with
default frame size. Add umem-frames and frame-size options to the
af-xdp section so buffer memory can be tuned per interface.

Ticket: #8780
pull/16208/head
amir.boussejra 3 months ago committed by Amir Boussejra
parent 87a05e9aea
commit 3ffd643a16

@ -83,6 +83,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)
{
@ -179,6 +189,9 @@ static void *ParseAFXDPConfig(const char *iface)
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");
@ -253,6 +266,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) {

@ -114,11 +114,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 */
@ -135,6 +130,7 @@ struct UmemInfo {
struct xsk_ring_cons cq;
struct xsk_umem_config cfg;
int mmap_alignment_flag;
uint64_t mem_bytes;
};
struct QueueAssignment {
@ -293,7 +289,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");
@ -305,8 +301,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);
}
@ -325,7 +321,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);
@ -466,7 +462,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);
}
@ -624,15 +620,17 @@ 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;
ptv->xsk.cfg.rx_size = afxdpconfig->rx_ring_size;
ptv->xsk.cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
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;
@ -667,6 +665,11 @@ static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void
ptv->capture_afxdp_acquire_pkt_failed =
StatsRegisterCounter("capture.afxdp.acquire_pkt_failed", &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) {
SCFree(ptv);
@ -883,7 +886,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,12 @@ 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 *);

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