selftests/net: ncdevmem: add -b option to set rx-page-size on bind

Add -b <bytes> to request a non-default niov size via
NETDEV_A_DMABUF_RX_PAGE_SIZE. When the value exceeds PAGE_SIZE,
udmabuf_alloc() switches to an MFD_HUGETLB-backed memfd so each 2 MB
hugepage produces one naturally-aligned sg entry.

Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
Link: https://patch.msgid.link/20260805-tcpdm-large-niovs-v8-2-3e0225e2808c@meta.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Bobby Eshleman
2026-08-05 13:42:44 -07:00
committed by Jakub Kicinski
parent b27a8560ee
commit 3e8c9ec4eb

View File

@@ -40,6 +40,7 @@
#include <linux/uio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -61,6 +62,7 @@
#include <sys/time.h>
#include <linux/memfd.h>
#include <sys/param.h>
#include <linux/dma-buf.h>
#include <linux/errqueue.h>
#include <linux/udmabuf.h>
@@ -79,6 +81,7 @@
#define PAGE_SHIFT 12
#define TEST_PREFIX "ncdevmem"
#define NUM_PAGES 16000
#define MB(x) ((x) << 20)
#ifndef MSG_SOCK_DEVMEM
#define MSG_SOCK_DEVMEM 0x2000000
@@ -100,6 +103,7 @@ static unsigned int dmabuf_id;
static uint32_t tx_dmabuf_id;
static int waittime_ms = 500;
static bool fail_on_linear;
static uint32_t rx_page_size;
/* System state loaded by current_config_load() */
#define MAX_FLOWS 8
@@ -142,6 +146,7 @@ static struct memory_buffer *udmabuf_alloc(size_t size)
{
struct udmabuf_create create;
struct memory_buffer *ctx;
unsigned int memfd_flags;
int ret;
ctx = malloc(sizeof(*ctx));
@@ -156,9 +161,14 @@ static struct memory_buffer *udmabuf_alloc(size_t size)
goto err_free_ctx;
}
ctx->memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
memfd_flags = MFD_ALLOW_SEALING;
if (rx_page_size > getpagesize())
memfd_flags |= MFD_HUGETLB | MFD_HUGE_2MB;
ctx->memfd = memfd_create("udmabuf-test", memfd_flags);
if (ctx->memfd < 0) {
pr_err("[skip,no-memfd]");
pr_err("[skip,no-memfd%s]",
(memfd_flags & MFD_HUGETLB) ? " (need hugepages)" : "");
goto err_close_dev;
}
@@ -168,6 +178,11 @@ static struct memory_buffer *udmabuf_alloc(size_t size)
goto err_close_memfd;
}
if (memfd_flags & MFD_HUGETLB) {
size = roundup(size, MB(2));
ctx->size = size;
}
ret = ftruncate(ctx->memfd, size);
if (ret == -1) {
pr_err("[FAIL,memfd-truncate]");
@@ -699,6 +714,8 @@ static int bind_rx_queue(unsigned int ifindex, unsigned int dmabuf_fd,
netdev_bind_rx_req_set_ifindex(req, ifindex);
netdev_bind_rx_req_set_fd(req, dmabuf_fd);
__netdev_bind_rx_req_set_queues(req, queues, n_queue_index);
if (rx_page_size)
netdev_bind_rx_req_set_rx_page_size(req, rx_page_size);
rsp = netdev_bind_rx(*ys, req);
if (!rsp) {
@@ -1411,7 +1428,7 @@ int main(int argc, char *argv[])
int is_server = 0, opt;
int ret, err = 1;
while ((opt = getopt(argc, argv, "Lls:c:p:v:q:t:f:z:n")) != -1) {
while ((opt = getopt(argc, argv, "Lls:c:p:v:q:t:f:z:nb:")) != -1) {
switch (opt) {
case 'L':
fail_on_linear = true;
@@ -1446,6 +1463,19 @@ int main(int argc, char *argv[])
case 'n':
skip_config = 1;
break;
case 'b': {
unsigned long val;
errno = 0;
val = strtoul(optarg, NULL, 0);
if ((val == ULONG_MAX && errno == ERANGE) ||
val > UINT32_MAX) {
pr_err("invalid rx_page_size: %s", optarg);
return 1;
}
rx_page_size = val;
break;
}
case '?':
fprintf(stderr, "unknown option: %c\n", optopt);
break;