From: Stanislav Fomichev <sdf.kernel@gmail.com>
To: "Björn Töpel" <bjorn@kernel.org>
Cc: Magnus Karlsson <magnus.karlsson@intel.com>,
Maciej Fijalkowski <maciej.fijalkowski@intel.com>,
Stanislav Fomichev <sdf@fomichev.me>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
Alexander Duyck <alexanderduyck@fb.com>,
kernel-team@meta.com, Andrew Lunn <andrew+netdev@lunn.ch>,
Jesper Dangaard Brouer <hawk@kernel.org>,
Ilias Apalodimas <ilias.apalodimas@linaro.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
John Fastabend <john.fastabend@gmail.com>,
Pavel Begunkov <asml.silence@gmail.com>,
Jens Axboe <axboe@kernel.dk>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
netdev@vger.kernel.org, bpf@vger.kernel.org,
io-uring@vger.kernel.org, Mina Almasry <almasrymina@google.com>,
"Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>,
Weiming Shi <bestswngs@gmail.com>,
Nikolay Aleksandrov <razor@blackwall.org>,
David Wei <dw@davidwei.uk>,
Alexander Lobakin <aleksander.lobakin@intel.com>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Stuart Clark <stuclar@meta.com>
Subject: Re: [PATCH net-next v1 05/11] xsk: Install UMEM page pool providers in the core
Date: Tue, 10 Nov 2026 15:50:15 -0800 [thread overview]
Message-ID: <avOtdOaiLFoUgbK9@devvm16445.scu0.facebook.com> (raw)
In-Reply-To: <20261110102039.1002605-6-bjorn@kernel.org>
On 11/10, Björn Töpel wrote:
> A page_pool driver should not need its own AF_XDP setup. When it sets
> netdev_queue_mgmt_ops.xsk_page_pool, a zero-copy bind installs the
> UMEM provider through the queue API, as devmem and io_uring do. The
> driver only judges the chunk size, headroom and multi-buffer mode
> against its MTU and XDP program, in XDP_VALIDATE_XSK_POOL; MTU and
> program changes of a bound device get the same check. The UMEM
> headroom belongs to the socket, so the queue gets it as rx_headroom,
> next to rx_page_size.
>
> After a queue restart, the core checks that the new page pools took
> the provider. A readable provider must back the header pool, where an
> unsplit packet lands, so pools declare the buffers they supply in
> rx_roles. The old queue's pools carry the same provider during the
> check, so a per-queue generation, mp_gen, tells the new ones apart.
>
> Generic XDP runs outside the queue NAPI, so it cannot feed the socket.
>
> The provider needs no xdp_buff_xsk per chunk. The buffer pool
> allocates them only for copy mode and driver zero copy, which saves
> 128 bytes per chunk.
>
> Signed-off-by: Björn Töpel <bjorn@kernel.org>
> ---
> include/linux/netdevice.h | 8 ++
> include/net/netdev_queues.h | 12 ++
> include/net/netdev_rx_queue.h | 2 +
> include/net/page_pool/types.h | 12 ++
> include/net/xdp_sock.h | 4 +
> include/net/xdp_sock_drv.h | 45 +++++++
> include/net/xsk_buff_pool.h | 3 +
> net/core/dev.c | 16 +++
> net/core/netdev_config.c | 2 +
> net/core/netdev_rx_queue.c | 9 +-
> net/core/page_pool.c | 6 +-
> net/core/page_pool_user.c | 25 ++--
> net/xdp/xsk.h | 7 +-
> net/xdp/xsk_buff_pool.c | 69 ++++++++---
> net/xdp/xsk_pp.c | 221 ++++++++++++++++++++++++++++++++++
> 15 files changed, 410 insertions(+), 31 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 435be7880d7e..11e51e684003 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -77,6 +77,7 @@ struct udp_tunnel_info;
> struct udp_tunnel_nic_info;
> struct udp_tunnel_nic;
> struct bpf_prog;
> +struct xsk_rx_check;
> struct xdp_buff;
> struct xdp_frame;
> struct xdp_metadata_ops;
> @@ -1010,6 +1011,8 @@ enum bpf_netdev_command {
> BPF_OFFLOAD_MAP_ALLOC,
> BPF_OFFLOAD_MAP_FREE,
> XDP_SETUP_XSK_POOL,
> + /* Check an AF_XDP page pool setup, see netdev_queue_mgmt_ops */
> + XDP_VALIDATE_XSK_POOL,
> };
>
> struct bpf_prog_offload_ops;
> @@ -1048,6 +1051,11 @@ struct netdev_bpf {
> struct xsk_buff_pool *pool;
> u16 queue_id;
> } xsk;
> + /* XDP_VALIDATE_XSK_POOL */
> + struct {
> + const struct xsk_rx_check *check;
> + struct netlink_ext_ack *extack;
> + } xsk_check;
> };
> };
>
> diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
> index c5335e935b7d..ad5f0420c21d 100644
> --- a/include/net/netdev_queues.h
> +++ b/include/net/netdev_queues.h
> @@ -45,12 +45,15 @@ 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: Space before the packet in a head 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 +159,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,
> };
>
> /**
> @@ -199,6 +204,12 @@ enum {
> *
> * @supported_params: Bitmask of supported parameters, see QCFG_*.
> *
> + * @xsk_page_pool: AF_XDP zero copy installs the UMEM as the page pool
> + * memory provider of the RX queue. The driver selects it
> + * with PP_FLAG_MEM_PROVIDER and PP_RX_ROLE_HEAD, honours
> + * whole buffers and QCFG_RX_HEADROOM, and accepts or
> + * rejects the setup in XDP_VALIDATE_XSK_POOL.
> + *
> * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
> * the interface is closed. @ndo_queue_start and @ndo_queue_stop will only
> * be called for an interface which is open.
> @@ -229,6 +240,7 @@ struct netdev_queue_mgmt_ops {
> struct netlink_ext_ack *extack);
>
> unsigned int supported_params;
> + bool xsk_page_pool;
> };
>
> void netdev_queue_config(struct net_device *dev, int rxq,
> diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h
> index 9415a94d333d..989120cbf452 100644
> --- a/include/net/netdev_rx_queue.h
> +++ b/include/net/netdev_rx_queue.h
> @@ -31,6 +31,8 @@ struct netdev_rx_queue {
> struct napi_struct *napi;
> struct netdev_queue_config qcfg;
> struct pp_memory_provider_params mp_params;
> + /* stamps the page pools of each queue allocation */
> + u32 mp_gen;
>
> /* If a queue is leased, then the lease pointer is always
> * valid. From the physical device it points to the virtual
> diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
> index 0d48c05f1462..e9f3af91e305 100644
> --- a/include/net/page_pool/types.h
> +++ b/include/net/page_pool/types.h
> @@ -40,6 +40,12 @@
> */
> #define PP_FLAG_MEM_PROVIDER BIT(4)
>
> +/* RX buffers a page pool supplies, see page_pool_params.rx_roles */
> +enum pp_rx_role {
> + PP_RX_ROLE_HEAD = BIT(0), /* packet headers */
> + PP_RX_ROLE_PAYLOAD = BIT(1), /* payload after header split */
> +};
> +
> #define PP_FLAG_ALL (PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV | \
> PP_FLAG_SYSTEM_POOL | \
> PP_FLAG_ALLOW_UNREADABLE_NETMEM | \
> @@ -94,6 +100,8 @@ struct pp_alloc_cache {
> * @queue_idx: queue idx this page_pool is being created for.
> * @flags: PP_FLAG_DMA_MAP, PP_FLAG_DMA_SYNC_DEV, PP_FLAG_SYSTEM_POOL,
> * PP_FLAG_ALLOW_UNREADABLE_NETMEM, PP_FLAG_MEM_PROVIDER.
> + * @rx_roles: &enum pp_rx_role mask, for pools that select a memory
> + * provider. Zero means payload buffers.
> */
> struct page_pool_params {
> struct_group_tagged(page_pool_params_fast, fast,
> @@ -110,6 +118,7 @@ struct page_pool_params {
> struct net_device *netdev;
> unsigned int queue_idx;
> unsigned int flags;
> + unsigned int rx_roles;
> /* private: used by test code only */
> void (*init_callback)(netmem_ref netmem, void *arg);
> void *init_arg;
> @@ -182,6 +191,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 {
> @@ -245,6 +255,8 @@ struct page_pool {
>
> void *mp_priv;
> const struct memory_provider_ops *mp_ops;
> + /* queue allocation that selected the provider */
> + u32 mp_gen;
>
> struct xarray dma_mapped;
>
> diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
> index 6e70b320b399..e0e22ef839e1 100644
> --- a/include/net/xdp_sock.h
> +++ b/include/net/xdp_sock.h
> @@ -19,6 +19,10 @@
> struct net_device;
> struct xsk_queue;
> struct xdp_buff;
> +struct memory_provider_ops;
> +
> +/* The memory provider of AF_XDP page pool zero copy */
> +extern const struct memory_provider_ops xsk_pp_ops;
>
> struct xdp_umem {
> void *addrs;
> diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
> index d94aeb506379..5bb1949a0aa7 100644
> --- a/include/net/xdp_sock_drv.h
> +++ b/include/net/xdp_sock_drv.h
> @@ -22,8 +22,29 @@ struct xsk_cb_desc {
> u8 bytes;
> };
>
> +/**
> + * struct xsk_rx_check - AF_XDP page pool RX setup a driver must accept
> + * @buf_size: size of each RX buffer
> + * @headroom: space before the packet in a head buffer, including
> + * XDP_PACKET_HEADROOM. The UMEM headroom is the rest.
> + * @mtu: MTU of the device
> + * @sg: the socket takes packets in more than one buffer
> + * @prog: XDP program to check, or NULL for the current one
> + */
> +struct xsk_rx_check {
> + u32 buf_size;
> + u32 headroom;
> + unsigned int mtu;
> + bool sg;
> + struct bpf_prog *prog;
> +};
> +
> #ifdef CONFIG_XDP_SOCKETS
>
> +int xsk_validate_dev(struct net_device *dev, unsigned int mtu,
> + struct bpf_prog *prog, enum bpf_xdp_mode mode,
> + struct netlink_ext_ack *extack);
> +struct xsk_buff_pool *xsk_rxq_pool(struct net_device *dev, u16 queue_id);
> void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries);
> bool xsk_tx_peek_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc);
> u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max);
> @@ -36,6 +57,11 @@ void xsk_clear_rx_need_wakeup(struct xsk_buff_pool *pool);
> void xsk_clear_tx_need_wakeup(struct xsk_buff_pool *pool);
> bool xsk_uses_need_wakeup(struct xsk_buff_pool *pool);
>
> +static inline bool xsk_pool_uses_sg(struct xsk_buff_pool *pool)
> +{
> + return pool->umem->flags & XDP_UMEM_SG_FLAG;
> +}
> +
> static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool)
> {
> return XDP_PACKET_HEADROOM + pool->headroom;
> @@ -351,6 +377,20 @@ static inline void xsk_buff_raw_dma_sync_for_device(struct xsk_buff_pool *pool,
>
> #else
>
> +static inline int xsk_validate_dev(struct net_device *dev, unsigned int mtu,
> + struct bpf_prog *prog,
> + enum bpf_xdp_mode mode,
> + struct netlink_ext_ack *extack)
> +{
> + return 0;
> +}
> +
> +static inline struct xsk_buff_pool *xsk_rxq_pool(struct net_device *dev,
> + u16 queue_id)
> +{
> + return NULL;
> +}
> +
> static inline void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
> {
> }
> @@ -397,6 +437,11 @@ static inline bool xsk_uses_need_wakeup(struct xsk_buff_pool *pool)
> return false;
> }
>
> +static inline bool xsk_pool_uses_sg(struct xsk_buff_pool *pool)
> +{
> + return false;
> +}
> +
> static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool)
> {
> return 0;
> diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
> index 02e89350faf9..6d7cfdf99a8b 100644
> --- a/include/net/xsk_buff_pool.h
> +++ b/include/net/xsk_buff_pool.h
> @@ -11,6 +11,7 @@
> #include <net/xdp.h>
>
> struct xsk_buff_pool;
> +struct xsk_pp;
> struct xdp_rxq_info;
> struct xsk_cb_desc;
> struct xsk_queue;
> @@ -54,6 +55,8 @@ struct xsk_buff_pool {
> spinlock_t xsk_tx_list_lock;
> refcount_t users;
> struct xdp_umem *umem;
> + /* page pool memory provider, see net/xdp/xsk_pp.c */
> + struct xsk_pp *pp;
> struct work_struct work;
> /* Protects generic receive in shared and non-shared umem mode. */
> spinlock_t rx_lock;
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 663fe3e32ea0..7e985fb82488 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -163,6 +163,7 @@
> #include <net/page_pool/types.h>
> #include <net/page_pool/helpers.h>
> #include <net/page_pool/memory_provider.h>
> +#include <net/xdp_sock_drv.h>
> #include <net/rps.h>
> #include <linux/phy_link_topology.h>
>
> @@ -10535,6 +10536,8 @@ u8 dev_xdp_sb_prog_count(struct net_device *dev)
>
> int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
> {
> + int err;
> +
> if (!dev->netdev_ops->ndo_bpf)
> return -EOPNOTSUPP;
>
> @@ -10552,6 +10555,13 @@ int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
> return -EBUSY;
> }
>
> + if (bpf->command == XDP_SETUP_PROG && bpf->prog) {
> + err = xsk_validate_dev(dev, dev->mtu, bpf->prog, XDP_MODE_DRV,
> + bpf->extack);
> + if (err)
> + return err;
> + }
> +
> return dev->netdev_ops->ndo_bpf(dev, bpf);
> }
> EXPORT_SYMBOL_GPL(netif_xdp_propagate);
> @@ -10629,6 +10639,12 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
> return -EBUSY;
> }
>
> + if (mode != XDP_MODE_HW && prog) {
> + err = xsk_validate_dev(dev, dev->mtu, prog, mode, extack);
> + if (err)
> + return err;
> + }
> +
> memset(&xdp, 0, sizeof(xdp));
> xdp.command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG;
> xdp.extack = extack;
> 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 9e14a747f9b5..4e2f906fbc73 100644
> --- a/net/core/netdev_rx_queue.c
> +++ b/net/core/netdev_rx_queue.c
> @@ -6,6 +6,7 @@
> #include <net/netdev_queues.h>
> #include <net/netdev_rx_queue.h>
> #include <net/page_pool/memory_provider.h>
> +#include <net/xdp_sock.h>
>
> #include "dev.h"
> #include "page_pool_priv.h"
> @@ -141,6 +142,7 @@ static int netdev_rx_queue_reconfig(struct net_device *dev,
> goto err_free_new_mem;
> }
>
> + rxq->mp_gen++;
> err = qops->ndo_queue_mem_alloc(dev, qcfg_new, new_mem, rxq_idx);
> if (err)
> goto err_free_old_mem;
> @@ -235,6 +237,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) {
> @@ -242,7 +248,8 @@ static int __netif_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx,
> return -EEXIST;
> }
> #ifdef CONFIG_XDP_SOCKETS
> - if (rxq->pool) {
> + /* An AF_XDP pool owns the queue, unless it installs its provider. */
> + if (rxq->pool && p->mp_ops != &xsk_pp_ops) {
> NL_SET_ERR_MSG(extack, "designated queue already in use by AF_XDP");
> return -EBUSY;
> }
> diff --git a/net/core/page_pool.c b/net/core/page_pool.c
> index 8237fda598ab..e897e79d31f1 100644
> --- a/net/core/page_pool.c
> +++ b/net/core/page_pool.c
> @@ -215,7 +215,8 @@ bool netmem_can_retain(netmem_ref netmem)
> EXPORT_SYMBOL(netmem_can_retain);
>
> static int page_pool_select_mp(struct page_pool *pool,
> - const struct pp_memory_provider_params *mpp)
> + const struct pp_memory_provider_params *mpp,
> + u32 rxq_mp_gen)
> {
> const struct memory_provider_ops *ops = mpp->mp_ops;
> unsigned int flags = pool->slow.flags;
> @@ -234,6 +235,7 @@ static int page_pool_select_mp(struct page_pool *pool,
>
> pool->mp_priv = mpp->mp_priv;
> pool->mp_ops = ops;
> + pool->mp_gen = rxq_mp_gen;
> return 0;
> }
>
> @@ -326,7 +328,7 @@ static int page_pool_init(struct page_pool *pool,
> netdev_assert_locked(pool->slow.netdev);
> rxq = __netif_get_rx_queue(pool->slow.netdev,
> pool->slow.queue_idx);
> - err = page_pool_select_mp(pool, &rxq->mp_params);
> + err = page_pool_select_mp(pool, &rxq->mp_params, rxq->mp_gen);
> if (err)
> goto free_ptr_ring;
> }
> diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
> index f30f3779624c..b69da0f74756 100644
> --- a/net/core/page_pool_user.c
> +++ b/net/core/page_pool_user.c
> @@ -398,28 +398,37 @@ void page_pool_unlist(struct page_pool *pool)
> mutex_unlock(&page_pools_lock);
> }
>
> +/* Check that the queue allocation that just ran put the provider in every
> + * pool role it needs: headers for a readable provider, payload otherwise.
> + * Pools of earlier allocations do not count.
> + */
> int page_pool_check_memory_provider(struct net_device *dev,
> struct netdev_rx_queue *rxq)
> {
> - void *binding = rxq->mp_params.mp_priv;
> + const struct memory_provider_ops *ops = rxq->mp_params.mp_ops;
> + void *mp_priv = rxq->mp_params.mp_priv;
> + unsigned int need, have = 0;
> struct page_pool *pool;
> struct hlist_node *n;
>
> - if (!binding)
> + if (!mp_priv)
> return 0;
>
> + need = PP_RX_ROLE_PAYLOAD;
> + if (ops->caps & MP_CAP_READABLE)
> + need = PP_RX_ROLE_HEAD;
> +
> mutex_lock(&page_pools_lock);
> hlist_for_each_entry_safe(pool, n, &dev->page_pools, user.list) {
> - if (pool->mp_priv != binding)
> + if (pool->mp_priv != mp_priv || pool->mp_gen != rxq->mp_gen ||
> + pool->slow.queue_idx != get_netdev_rx_queue_index(rxq))
> continue;
>
> - if (pool->slow.queue_idx == get_netdev_rx_queue_index(rxq)) {
> - mutex_unlock(&page_pools_lock);
> - return 0;
> - }
> + have |= pool->slow.rx_roles ? : PP_RX_ROLE_PAYLOAD;
> }
> mutex_unlock(&page_pools_lock);
> - return -ENODATA;
> +
> + return (have & need) == need ? 0 : -ENODATA;
> }
>
> static void page_pool_unreg_netdev_wipe(struct net_device *netdev)
> diff --git a/net/xdp/xsk.h b/net/xdp/xsk.h
> index 4dab7b9a1487..9699e9a499a3 100644
> --- a/net/xdp/xsk.h
> +++ b/net/xdp/xsk.h
> @@ -36,10 +36,13 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs,
> struct xdp_sock __rcu **map_entry);
> struct xsk_pp;
>
> -extern const struct memory_provider_ops xsk_pp_ops;
> -
> struct xsk_pp *xsk_pp_create(struct xsk_buff_pool *pool);
> void xsk_pp_put(struct xsk_pp *pp);
> +bool xsk_pp_supported(struct net_device *dev);
> +int xsk_pp_bind(struct xsk_buff_pool *pool, struct net_device *dev,
> + u16 queue_id);
> +void xsk_pp_unbind(struct xsk_buff_pool *pool);
> +int xp_alloc_heads(struct xsk_buff_pool *pool);
> void xsk_clear_pool_at_qid(struct net_device *dev, u16 queue_id);
> int xsk_reg_pool_at_qid(struct net_device *dev, struct xsk_buff_pool *pool,
> u16 queue_id);
> diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
> index 18966bbdb5b7..c620a0c32c17 100644
> --- a/net/xdp/xsk_buff_pool.c
> +++ b/net/xdp/xsk_buff_pool.c
> @@ -38,6 +38,8 @@ void xp_destroy(struct xsk_buff_pool *pool)
> if (!pool)
> return;
>
> + if (pool->pp)
> + xsk_pp_put(pool->pp);
> kvfree(pool->tx_descs);
> kvfree(pool->heads);
> kvfree(pool);
> @@ -62,18 +64,13 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
> {
> bool unaligned = umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
> struct xsk_buff_pool *pool;
> - struct xdp_buff_xsk *xskb;
> - u32 i, entries;
> + u32 entries;
>
> entries = unaligned ? umem->chunks : 0;
> pool = kvzalloc_flex(*pool, free_heads, entries);
> if (!pool)
> goto out;
>
> - pool->heads = kvzalloc_objs(*pool->heads, umem->chunks);
> - if (!pool->heads)
> - goto out;
> -
> if (xs->tx)
> if (xp_alloc_tx_descs(pool, xs, max_segs))
> goto out;
> @@ -104,10 +101,30 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
> pool->fq = xs->fq_tmp;
> pool->cq = xs->cq_tmp;
>
> - for (i = 0; i < pool->free_heads_cnt; i++) {
> + return pool;
> +
> +out:
> + xp_destroy(pool);
> + return NULL;
> +}
> +
> +/* Only copy mode and driver zero copy use heads */
> +int xp_alloc_heads(struct xsk_buff_pool *pool)
nit: move xp_alloc_heads rework into a separate patch? this one is quite
big already
next prev parent reply other threads:[~2026-11-10 23:52 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 10:20 [PATCH net-next v1 00/11] xsk: Zero copy through page-pool memory providers Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 01/11] net: Get skb fragment addresses through netmem Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 02/11] net: Add memory provider capabilities Björn Töpel
2026-11-10 22:19 ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 03/11] xdp: Copy buffers with restricted lifetime Björn Töpel
2026-11-10 22:32 ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 04/11] xsk: Allocate UMEM chunks through page_pool Björn Töpel
2026-11-10 15:08 ` Magnus Karlsson
2026-11-10 23:02 ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 05/11] xsk: Install UMEM page pool providers in the core Björn Töpel
2026-11-10 23:50 ` Stanislav Fomichev [this message]
2026-11-10 10:20 ` [PATCH net-next v1 06/11] page_pool: Coordinate refill with memory providers Björn Töpel
2026-11-10 23:51 ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 07/11] xsk: Deliver provider chunks without copying Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 08/11] eth: fbnic: Support XDP redirect Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 09/11] eth: fbnic: Use netmem for RX headers and XDP_TX Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 10/11] eth: fbnic: Support RX buffers it cannot split Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 11/11] eth: fbnic: Support AF_XDP page pool zero copy Björn Töpel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=avOtdOaiLFoUgbK9@devvm16445.scu0.facebook.com \
--to=sdf.kernel@gmail.com \
--cc=aleksander.lobakin@intel.com \
--cc=alexanderduyck@fb.com \
--cc=almasrymina@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrii@kernel.org \
--cc=asml.silence@gmail.com \
--cc=ast@kernel.org \
--cc=axboe@kernel.dk \
--cc=bestswngs@gmail.com \
--cc=bjorn@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dw@davidwei.uk \
--cc=eddyz87@gmail.com \
--cc=edumazet@kernel.org \
--cc=emil@etsalapatis.com \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=ilias.apalodimas@linaro.org \
--cc=io-uring@vger.kernel.org \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maciej.fijalkowski@intel.com \
--cc=magnus.karlsson@intel.com \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=mike.marciniszyn@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=razor@blackwall.org \
--cc=rdunlap@infradead.org \
--cc=sdf@fomichev.me \
--cc=skhan@linuxfoundation.org \
--cc=song@kernel.org \
--cc=stuclar@meta.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®