[RFC net-next 04/15] net: Let memory providers set RX buffer headroom
From: Björn Töpel
Date: Fri Oct 02 2026 - 15:01:36 EST
AF_XDP lets userspace choose a headroom in front of the packet data
in each UMEM chunk, and the kernel adds XDP_PACKET_HEADROOM to it. A
driver whose buffers come from an AF_XDP memory provider must put
packets after this headroom. The driver sees only the page pool, so
it has no generic way to learn the value, and nothing checks that
the driver supports it.
Add rx_headroom to the provider parameters and to the queue
configuration. It is the full headroom, including
XDP_PACKET_HEADROOM; zero means the driver default. Add
QCFG_RX_HEADROOM. A provider that sets a headroom can only be
installed on a queue that supports it; otherwise the install fails
with -EOPNOTSUPP. The driver checks the value with the rest of the
queue configuration.
Signed-off-by: Björn Töpel <bjorn@xxxxxxxxxx>
---
include/net/netdev_queues.h | 6 ++++++
include/net/page_pool/types.h | 1 +
net/core/netdev_config.c | 2 ++
net/core/netdev_rx_queue.c | 4 ++++
4 files changed, 13 insertions(+)
diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
index c5335e935b7d..f9eba63a5d78 100644
--- a/include/net/netdev_queues.h
+++ b/include/net/netdev_queues.h
@@ -45,12 +45,16 @@ struct netdev_config {
/**
* struct netdev_queue_config - rendered configuration for an RX queue
* @rx_page_size: Size of one RX page-pool allocation.
+ * @rx_headroom: Headroom before packet data in the first buffer,
+ * including XDP_PACKET_HEADROOM. Zero selects the
+ * driver default.
* @rx_ring_size: Configured size of the regular RX ring.
* @rx_mini_ring_size: Configured size of the RX mini ring.
* @rx_jumbo_ring_size: Configured size of the RX jumbo ring.
*/
struct netdev_queue_config {
u32 rx_page_size;
+ u32 rx_headroom;
u32 rx_ring_size;
u32 rx_mini_ring_size;
u32 rx_jumbo_ring_size;
@@ -156,6 +160,8 @@ void netdev_stat_queue_sum(struct net_device *netdev,
enum {
/* The queue checks and honours the page size qcfg parameter */
QCFG_RX_PAGE_SIZE = 0x1,
+ /* The queue checks and honours the headroom qcfg parameter */
+ QCFG_RX_HEADROOM = 0x2,
};
/**
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index a96376613dda..a673fa35febb 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -172,6 +172,7 @@ struct pp_memory_provider_params {
void *mp_priv;
const struct memory_provider_ops *mp_ops;
u32 rx_page_size;
+ u32 rx_headroom;
};
struct page_pool {
diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c
index 1975de42a60d..97e33764737b 100644
--- a/net/core/netdev_config.c
+++ b/net/core/netdev_config.c
@@ -88,6 +88,8 @@ static int __netdev_queue_config(struct net_device *dev, int rxq_idx,
mpp = &__netif_get_rx_queue(dev, rxq_idx)->mp_params;
if (mpp->rx_page_size)
qcfg->rx_page_size = mpp->rx_page_size;
+ if (mpp->rx_headroom)
+ qcfg->rx_headroom = mpp->rx_headroom;
err = validate_cb(dev, qcfg, extack);
if (err)
return err;
diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
index 610e31d1a717..476289000e78 100644
--- a/net/core/netdev_rx_queue.c
+++ b/net/core/netdev_rx_queue.c
@@ -248,6 +248,10 @@ static int __netif_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx,
NL_SET_ERR_MSG(extack, "device does not support: rx_page_size");
return -EOPNOTSUPP;
}
+ if (p->rx_headroom && !(qops->supported_params & QCFG_RX_HEADROOM)) {
+ NL_SET_ERR_MSG(extack, "device does not support: rx_headroom");
+ return -EOPNOTSUPP;
+ }
rxq = __netif_get_rx_queue(dev, rxq_idx);
if (rxq->mp_params.mp_ops) {
--
2.55.0