Merge branch 'net-devmem-allow-rx-buf-size-page_size-per-binding'

Bobby Eshleman says:

====================
net: devmem: allow rx-buf-size > PAGE_SIZE per binding

Every devmem dmabuf binding hands the page_pool PAGE_SIZE niovs today.
On NICs that consume one descriptor per netmem, this caps a single RX
descriptor at PAGE_SIZE and burns CPU on buffer churn.

In this series, we add a bind-time netlink attribute,
NETDEV_A_DMABUF_RX_BUF_SIZE, that lets userspace request a larger niov
size (power of two >= PAGE_SIZE). Drivers must opt in via
queue_mgmt_ops.QCFG_RX_PAGE_SIZE.

Measurements:

Setup: kperf devmem RX/TX cuda, 4 flows, 64 MB messages, 60s, dctcp,
num-rx-queues=4, dmabuf-rx/tx-size-mb=2048, 10 runs per niov size,
mlx5.

   niov       RX dev Gbps   RX flow avg Gbps         app sys %
  -----  ----------------  -----------------  ----------------
     4K  300.63 +/- 53.21    75.16 +/- 13.30   54.15 +/- 10.23
    16K  321.35 +/- 28.20    80.34 +/-  7.05   41.05 +/-  8.87
    32K  347.63 +/-  2.20    86.91 +/-  0.55   44.54 +/-  3.51
    64K  332.11 +/- 14.26    83.03 +/-  3.56   35.47 +/-  3.11

RX app sys % drops ~19% from 4K to 64K.

kperf support (not yet merged):
8837577f92
====================

Link: https://patch.msgid.link/20260805-tcpdm-large-niovs-v8-0-3e0225e2808c@meta.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-07 18:32:41 -07:00
12 changed files with 231 additions and 38 deletions

View File

@@ -6,6 +6,14 @@ doc: >-
netdev configuration over generic netlink.
definitions:
-
type: const
name: page-size
# Dummy value, codegen needs a number. The real value comes from
# the PAGE_SIZE macro in the header below.
value: 0
header: asm/page.h
scope: kernel
-
type: flags
name: xdp-act
@@ -598,6 +606,16 @@ attribute-sets:
type: u32
checks:
min: 1
-
name: rx-page-size
doc: |
Size in bytes of each device page the NIC writes into from the bound
dmabuf. Must be a power of two and >= PAGE_SIZE; defaults to
PAGE_SIZE.
type: u32
checks:
min: page-size
max: u32-max
operations:
list:
@@ -812,6 +830,7 @@ operations:
- ifindex
- fd
- queues
- rx-page-size
reply:
attributes:
- id

View File

@@ -219,6 +219,7 @@ enum {
NETDEV_A_DMABUF_QUEUES,
NETDEV_A_DMABUF_FD,
NETDEV_A_DMABUF_ID,
NETDEV_A_DMABUF_RX_PAGE_SIZE,
__NETDEV_A_DMABUF_MAX,
NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)

View File

@@ -46,7 +46,7 @@ static dma_addr_t net_devmem_get_dma_addr(const struct net_iov *niov)
owner = net_devmem_iov_to_chunk_owner(niov);
return owner->base_dma_addr +
((dma_addr_t)net_iov_idx(niov) << PAGE_SHIFT);
((dma_addr_t)net_iov_idx(niov) << owner->binding->niov_shift);
}
static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref)
@@ -93,13 +93,14 @@ net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding)
ssize_t offset;
ssize_t index;
dma_addr = gen_pool_alloc_owner(binding->chunk_pool, PAGE_SIZE,
dma_addr = gen_pool_alloc_owner(binding->chunk_pool,
1UL << binding->niov_shift,
(void **)&owner);
if (!dma_addr)
return NULL;
offset = dma_addr - owner->base_dma_addr;
index = offset / PAGE_SIZE;
index = offset >> binding->niov_shift;
niov = &owner->area.niovs[index];
niov->desc.pp_magic = 0;
@@ -113,12 +114,13 @@ void net_devmem_free_dmabuf(struct net_iov *niov)
{
struct net_devmem_dmabuf_binding *binding = net_devmem_iov_binding(niov);
unsigned long dma_addr = net_devmem_get_dma_addr(niov);
size_t niov_size = 1UL << binding->niov_shift;
if (WARN_ON(!gen_pool_has_addr(binding->chunk_pool, dma_addr,
PAGE_SIZE)))
niov_size)))
return;
gen_pool_free(binding->chunk_pool, dma_addr, PAGE_SIZE);
gen_pool_free(binding->chunk_pool, dma_addr, niov_size);
}
void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding)
@@ -163,6 +165,9 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx,
u32 xa_idx;
int err;
if (binding->niov_shift != PAGE_SHIFT)
mp_params.rx_page_size = 1U << binding->niov_shift;
err = netif_mp_open_rxq(dev, rxq_idx, &mp_params, extack);
if (err)
return err;
@@ -184,10 +189,12 @@ struct net_devmem_dmabuf_binding *
net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
struct device *dma_dev,
enum dma_data_direction direction,
unsigned int dmabuf_fd, struct netdev_nl_sock *priv,
unsigned int dmabuf_fd, unsigned int niov_shift,
struct netdev_nl_sock *priv,
struct netlink_ext_ack *extack)
{
struct net_devmem_dmabuf_binding *binding;
size_t niov_size = 1UL << niov_shift;
static u32 id_alloc_next;
struct scatterlist *sg;
struct dma_buf *dmabuf;
@@ -213,6 +220,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
binding->dev = dev;
binding->vdev = vdev;
binding->niov_shift = niov_shift;
xa_init_flags(&binding->bound_rxqs, XA_FLAGS_ALLOC);
err = percpu_ref_init(&binding->ref,
@@ -255,11 +263,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
}
}
/* For simplicity we expect to make PAGE_SIZE allocations, but the
* binding can be much more flexible than that. We may be able to
* allocate MTU sized chunks here. Leave that for future work...
*/
binding->chunk_pool = gen_pool_create(PAGE_SHIFT,
binding->chunk_pool = gen_pool_create(niov_shift,
dev_to_node(&dev->dev));
if (!binding->chunk_pool) {
err = -ENOMEM;
@@ -273,9 +277,12 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
size_t len = sg_dma_len(sg);
struct net_iov *niov;
if (!IS_ALIGNED(len, PAGE_SIZE)) {
if (!IS_ALIGNED(dma_addr, niov_size) ||
!IS_ALIGNED(len, niov_size)) {
err = -EINVAL;
NL_SET_ERR_MSG(extack, "dma-buf SG length must be PAGE_SIZE aligned");
NL_SET_ERR_MSG_FMT(extack,
"dmabuf sg entry (addr=%pad, len=%zu) not aligned to niov size %zu",
&dma_addr, len, niov_size);
goto err_free_chunks;
}
@@ -288,7 +295,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
owner->area.base_virtual = virtual;
owner->base_dma_addr = dma_addr;
owner->area.num_niovs = len / PAGE_SIZE;
owner->area.num_niovs = len >> niov_shift;
owner->binding = binding;
err = gen_pool_add_owner(binding->chunk_pool, dma_addr,
@@ -454,7 +461,7 @@ int mp_dmabuf_devmem_init(struct page_pool *pool)
pool->dma_sync = false;
pool->dma_sync_for_cpu = false;
if (pool->p.order != 0)
if (pool->p.order != binding->niov_shift - PAGE_SHIFT)
return -E2BIG;
net_devmem_dmabuf_binding_get(binding);

View File

@@ -71,6 +71,8 @@ struct net_devmem_dmabuf_binding {
*/
struct net_iov **tx_vec;
unsigned int niov_shift;
struct work_struct unbind_w;
};
@@ -93,7 +95,8 @@ struct net_devmem_dmabuf_binding *
net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
struct device *dma_dev,
enum dma_data_direction direction,
unsigned int dmabuf_fd, struct netdev_nl_sock *priv,
unsigned int dmabuf_fd, unsigned int niov_shift,
struct netdev_nl_sock *priv,
struct netlink_ext_ack *extack);
struct net_devmem_dmabuf_binding *net_devmem_lookup_dmabuf(u32 id);
void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding);
@@ -122,10 +125,11 @@ static inline u32 net_devmem_iov_binding_id(const struct net_iov *niov)
static inline unsigned long net_iov_virtual_addr(const struct net_iov *niov)
{
struct net_iov_area *owner = net_iov_owner(niov);
struct dmabuf_genpool_chunk_owner *co =
net_devmem_iov_to_chunk_owner(niov);
return owner->base_virtual +
((unsigned long)net_iov_idx(niov) << PAGE_SHIFT);
return net_iov_owner(niov)->base_virtual +
((unsigned long)net_iov_idx(niov) << co->binding->niov_shift);
}
static inline bool
@@ -175,6 +179,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
struct device *dma_dev,
enum dma_data_direction direction,
unsigned int dmabuf_fd,
unsigned int niov_shift,
struct netdev_nl_sock *priv,
struct netlink_ext_ack *extack)
{

View File

@@ -11,6 +11,7 @@
#include <uapi/linux/netdev.h>
#include <net/netdev_netlink.h>
#include <asm/page.h>
/* Integer value ranges */
static const struct netlink_range_validation netdev_a_page_pool_id_range = {
@@ -27,6 +28,11 @@ static const struct netlink_range_validation netdev_a_napi_defer_hard_irqs_range
.max = S32_MAX,
};
static const struct netlink_range_validation netdev_a_dmabuf_rx_page_size_range = {
.min = PAGE_SIZE,
.max = U32_MAX,
};
/* Common nested types */
const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1] = {
[NETDEV_A_LEASE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
@@ -106,10 +112,11 @@ static const struct nla_policy netdev_qstats_get_nl_policy[NETDEV_A_QSTATS_SCOPE
};
/* NETDEV_CMD_BIND_RX - do */
static const struct nla_policy netdev_bind_rx_nl_policy[NETDEV_A_DMABUF_FD + 1] = {
static const struct nla_policy netdev_bind_rx_nl_policy[NETDEV_A_DMABUF_RX_PAGE_SIZE + 1] = {
[NETDEV_A_DMABUF_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
[NETDEV_A_DMABUF_FD] = { .type = NLA_U32, },
[NETDEV_A_DMABUF_QUEUES] = NLA_POLICY_NESTED(netdev_queue_id_nl_policy),
[NETDEV_A_DMABUF_RX_PAGE_SIZE] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_dmabuf_rx_page_size_range),
};
/* NETDEV_CMD_NAPI_SET - do */
@@ -219,7 +226,7 @@ static const struct genl_split_ops netdev_nl_ops[] = {
.cmd = NETDEV_CMD_BIND_RX,
.doit = netdev_nl_bind_rx_doit,
.policy = netdev_bind_rx_nl_policy,
.maxattr = NETDEV_A_DMABUF_FD,
.maxattr = NETDEV_A_DMABUF_RX_PAGE_SIZE,
.flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{

View File

@@ -12,6 +12,7 @@
#include <uapi/linux/netdev.h>
#include <net/netdev_netlink.h>
#include <asm/page.h>
/* Common nested types */
extern const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1];

View File

@@ -1013,6 +1013,7 @@ netdev_nl_get_dma_dev(struct net_device *netdev, unsigned long *rxq_bitmap,
int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info)
{
struct net_devmem_dmabuf_binding *binding;
unsigned int niov_shift = PAGE_SHIFT;
u32 ifindex, dmabuf_fd, rxq_idx;
struct netdev_nl_sock *priv;
struct net_device *netdev;
@@ -1030,6 +1031,18 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info)
ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]);
dmabuf_fd = nla_get_u32(info->attrs[NETDEV_A_DMABUF_FD]);
if (info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE]) {
u32 rx_page_size = nla_get_u32(info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE]);
if (!is_power_of_2(rx_page_size)) {
NL_SET_ERR_MSG_ATTR(info->extack,
info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE],
"rx-page-size must be a power of 2");
return -EINVAL;
}
niov_shift = ilog2(rx_page_size);
}
priv = genl_sk_priv_get(&netdev_nl_family, NETLINK_CB(skb).sk);
if (IS_ERR(priv))
return PTR_ERR(priv);
@@ -1080,7 +1093,8 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info)
}
binding = net_devmem_bind_dmabuf(netdev, NULL, dma_dev, DMA_FROM_DEVICE,
dmabuf_fd, priv, info->extack);
dmabuf_fd, niov_shift, priv,
info->extack);
if (IS_ERR(binding)) {
err = PTR_ERR(binding);
goto err_rxq_bitmap;
@@ -1221,7 +1235,7 @@ int netdev_nl_bind_tx_doit(struct sk_buff *skb, struct genl_info *info)
binding = net_devmem_bind_dmabuf(bind_dev,
bind_dev != netdev ? netdev : NULL,
dma_dev, DMA_TO_DEVICE, dmabuf_fd,
priv, info->extack);
PAGE_SHIFT, priv, info->extack);
if (IS_ERR(binding)) {
err = PTR_ERR(binding);
goto err_unlock_bind_dev;

View File

@@ -219,6 +219,7 @@ enum {
NETDEV_A_DMABUF_QUEUES,
NETDEV_A_DMABUF_FD,
NETDEV_A_DMABUF_ID,
NETDEV_A_DMABUF_RX_PAGE_SIZE,
__NETDEV_A_DMABUF_MAX,
NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)

View File

@@ -2,7 +2,8 @@
# SPDX-License-Identifier: GPL-2.0
from os import path
from devmem_lib import setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds
from devmem_lib import (setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds,
run_rx_large_niov)
from lib.py import ksft_run, ksft_exit, ksft_disruptive
from lib.py import NetDrvEpEnv
@@ -30,11 +31,17 @@ def check_rx_hds(cfg) -> None:
run_rx_hds(cfg)
def check_rx_large_niov(cfg) -> None:
"""Run the devmem RX test with rx-page-size = 16 KiB."""
run_rx_large_niov(cfg)
def main() -> None:
"""Run the devmem test cases."""
with NetDrvEpEnv(__file__) as cfg:
setup_test(cfg, path.abspath(path.dirname(__file__) + "/ncdevmem"))
ksft_run([check_rx, check_tx, check_tx_chunks, check_rx_hds],
ksft_run([check_rx, check_tx, check_tx_chunks, check_rx_hds,
check_rx_large_niov],
args=(cfg,))
ksft_exit()

View File

@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# pylint: disable=invalid-name,too-many-arguments
"""Shared helpers for devmem TCP selftests."""
import os
import re
from lib.py import (bkg, cmd, defer, ethtool, rand_port, wait_port_listen,
@@ -8,19 +10,82 @@ from lib.py import (bkg, cmd, defer, ethtool, rand_port, wait_port_listen,
NetdevFamily)
def require_devmem(cfg):
"""Probe ncdevmem on cfg.ifname and SKIP the test if devmem isn't supported."""
if not hasattr(cfg, "devmem_probed"):
probe_command = f"{cfg.bin_local} -f {cfg.ifname}"
cfg.devmem_supported = cmd(probe_command, fail=False, shell=True).ret == 0
cfg.devmem_probed = True
RX_PAGE_SIZE_DEFAULT = 0
RX_PAGE_SIZE_16K = 16384
if not cfg.devmem_supported:
PROBE_RX_PAGE_SIZES = (RX_PAGE_SIZE_DEFAULT, RX_PAGE_SIZE_16K)
NR_HUGEPAGES_FILE = "/proc/sys/vm/nr_hugepages"
def _is_aligned(value, alignment):
"""Equivalent of the kernel IS_ALIGNED(value, alignment).
alignment must be a power of two.
"""
return (value & (alignment - 1)) == 0
def _restore_nr_hugepages(nr_hugepages):
with open(NR_HUGEPAGES_FILE, 'w', encoding='utf-8') as f:
f.write(str(nr_hugepages))
def _reserve_hugepages(want=64):
"""Raise nr_hugepages to @want and arrange for it to be restored."""
with open(NR_HUGEPAGES_FILE, 'r+', encoding='utf-8') as f:
nr_hugepages = int(f.read().strip())
if nr_hugepages >= want:
return
f.seek(0)
f.write(str(want))
defer(_restore_nr_hugepages, nr_hugepages)
def _probe_devmem(cfg, rx_page_size):
"""Return True if ncdevmem can bind cfg.ifname at @rx_page_size."""
probe_command = f"{cfg.bin_local} -f {cfg.ifname}"
if rx_page_size != RX_PAGE_SIZE_DEFAULT:
probe_command += f" -b {rx_page_size}"
return cmd(probe_command, fail=False, shell=True).ret == 0
def require_devmem(cfg, rx_page_size=RX_PAGE_SIZE_DEFAULT):
"""Probe ncdevmem on cfg.ifname and SKIP the test if devmem isn't supported."""
if rx_page_size not in PROBE_RX_PAGE_SIZES:
raise RuntimeError(
f"rx-page-size={rx_page_size} is missing from "
f"PROBE_RX_PAGE_SIZES, so it was never probed.")
if not hasattr(cfg, "devmem_supported"):
_reserve_hugepages()
# Probe every size upfront: in nk tests a leased queue may land in
# ncdevmem's queue range and cause the probe to fail.
cfg.devmem_supported = {size: _probe_devmem(cfg, size)
for size in PROBE_RX_PAGE_SIZES}
if not cfg.devmem_supported[RX_PAGE_SIZE_DEFAULT]:
raise KsftSkipEx("Test requires devmem support")
if rx_page_size != RX_PAGE_SIZE_DEFAULT:
page_size = os.sysconf("SC_PAGE_SIZE")
if not _is_aligned(rx_page_size, page_size):
raise KsftSkipEx(
f"rx-page-size={rx_page_size} is invalid for this platform "
f"(must be a multiple of PAGE_SIZE={page_size})")
if not cfg.devmem_supported[rx_page_size]:
raise KsftSkipEx(
f"Test requires devmem rx-page-size={rx_page_size} support")
def configure_nic(cfg):
"""Channels, rings, RSS, queue lease for netkit devmem."""
if not hasattr(cfg, "devmem_supported"):
raise RuntimeError(
"require_devmem() must be called before configure_nic(), which "
"may lease a queue away and make later probes fail.")
if not hasattr(cfg, 'netns'):
return
@@ -75,7 +140,8 @@ def set_flow_rule(cfg, port):
return int(re.search(r'ID (\d+)', output).group(1))
def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False):
def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False,
rx_page_size=RX_PAGE_SIZE_DEFAULT):
"""Build the ncdevmem RX listener command."""
if hasattr(cfg, 'netns'):
flow_rule_id = set_flow_rule(cfg, port)
@@ -95,6 +161,8 @@ def ncdevmem_rx(cfg, port, verify=True, fail_on_linear=False, flow_steer=False):
extras.append("-v 7")
if fail_on_linear:
extras.append("-L")
if rx_page_size != RX_PAGE_SIZE_DEFAULT:
extras.append(f"-b {rx_page_size}")
parts = [cfg.bin_local, "-l", f"-f {ifname}", f"-s {addr}",
f"-p {port}", *extras]
@@ -201,6 +269,33 @@ def run_tx_chunks(cfg):
ksft_eq(socat.stdout.strip(), "hello\nworld")
def run_rx_large_niov(cfg):
"""Run the devmem RX test with a large niov (rx-page-size > PAGE_SIZE).
Sweep payload sizes that straddle the niov boundary: below, equal to,
and above rx_page_size, to exercise sub-niov, exact-niov, and multi-niov
RX paths.
"""
require_devmem(cfg, rx_page_size=RX_PAGE_SIZE_16K)
_reserve_hugepages()
configure_nic(cfg)
netns = getattr(cfg, "netns", None)
for size in [1024, 4096, 8192, 16384, 32768, 65536]:
port = rand_port()
socat = socat_send(cfg, port)
listen_cmd = ncdevmem_rx(cfg, port,
flow_steer=not netns,
rx_page_size=RX_PAGE_SIZE_16K)
data_pipe = (f"yes $(echo -e \x01\x02\x03\x04\x05\x06) | "
f"head -c {size} | {socat}")
with bkg(listen_cmd, exit_wait=True, ns=netns) as ncdevmem:
wait_port_listen(port, proto="tcp", ns=netns)
cmd(data_pipe, host=cfg.remote, shell=True)
ksft_eq(ncdevmem.ret, 0,
f"large-niov failed for payload size {size}")
def run_rx_hds(cfg):
"""Run the HDS test by running devmem RX across a segment size sweep."""
require_devmem(cfg)

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;

View File

@@ -3,7 +3,8 @@
"""Test devmem TCP with netkit."""
import os
from devmem_lib import setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds
from devmem_lib import (setup_test, run_rx, run_tx, run_tx_chunks, run_rx_hds,
run_rx_large_niov)
from lib.py import ksft_run, ksft_exit, ksft_disruptive
from lib.py import NetDrvContEnv
@@ -31,6 +32,11 @@ def check_nk_rx_hds(cfg) -> None:
run_rx_hds(cfg)
def check_nk_rx_large_niov(cfg) -> None:
"""Run the devmem RX large-niov test through netkit."""
run_rx_large_niov(cfg)
def main() -> None:
"""Run the netkit devmem test cases."""
with NetDrvContEnv(__file__, rxqueues=2, primary_rx_redirect=True) as cfg:
@@ -38,7 +44,7 @@ def main() -> None:
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ncdevmem"))
ksft_run([check_nk_rx, check_nk_tx, check_nk_tx_chunks,
check_nk_rx_hds], args=(cfg,))
check_nk_rx_hds, check_nk_rx_large_niov], args=(cfg,))
ksft_exit()