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 07/11] xsk: Deliver provider chunks without copying
Date: Wed, 11 Nov 2026 15:20:41 -0800 [thread overview]
Message-ID: <avT3vVT8iyKqyW8q@devvm16445.scu0.facebook.com> (raw)
In-Reply-To: <20261110102039.1002605-8-bjorn@kernel.org>
On 11/10, Björn Töpel wrote:
> A provider socket still receives through the copy path, which takes
> FILL entries without the provider's ownership checks: a chunk that a
> page pool holds could be handed out twice. No driver opts in yet.
>
> Put packets whose buffers all belong to the socket's provider on the
> RX ring as they are, and copy others into chunks the provider claims.
> Only the queue NAPI may produce to such a socket, so generic XDP and
> CPUMAP redirects to it are dropped.
>
> A device may place payload at chunk offset 0, as fbnic does, so only
> the first buffer of a packet keeps the UMEM headroom. Such buffers may
> be sent back as they are, so only descriptors with XDP_TX_METADATA
> need room for TX metadata in front.
>
> Signed-off-by: Björn Töpel <bjorn@kernel.org>
> ---
> Documentation/networking/af_xdp.rst | 6 +-
> Documentation/networking/xsk-tx-metadata.rst | 3 +-
> include/net/page_pool/memory_provider.h | 2 +
> net/core/page_pool.c | 34 +++-
> net/xdp/xsk.c | 82 ++++++++-
> net/xdp/xsk.h | 5 +
> net/xdp/xsk_pp.c | 165 +++++++++++++++++++
> net/xdp/xsk_queue.h | 18 +-
> 8 files changed, 304 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst
> index cc3f0d16b28f..e73a0005e169 100644
> --- a/Documentation/networking/af_xdp.rst
> +++ b/Documentation/networking/af_xdp.rst
> @@ -428,8 +428,10 @@ area and that your largest packet size can be 2K.
> There is also an option to set the headroom of each single buffer in
> the UMEM. If you set this to N bytes, it means that the packet will
> start N bytes into the buffer leaving the first N bytes for the
> -application to use. The final option is the flags field, but it will
> -be dealt with in separate sections for each UMEM flag.
> +application to use. In a multi-buffer packet, only the first buffer is
> +guaranteed this headroom; the others may start at offset 0 of their
> +chunk. The final option is the flags field, but it will be dealt with
> +in separate sections for each UMEM flag.
>
> SO_BINDTODEVICE setsockopt
> --------------------------
> diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst
> index f240930ca1df..8bb74a569c26 100644
> --- a/Documentation/networking/xsk-tx-metadata.rst
> +++ b/Documentation/networking/xsk-tx-metadata.rst
> @@ -59,7 +59,8 @@ The flags field enables the particular offload:
> Besides the flags above, in order to trigger the offloads, the first
> packet's ``struct xdp_desc`` descriptor should set ``XDP_TX_METADATA``
> bit in the ``options`` field. Also note that in a multi-buffer packet
> -only the first chunk should carry the metadata.
> +only the first chunk should carry the metadata. Only a descriptor with
> +``XDP_TX_METADATA`` needs ``tx_metadata_len`` bytes in front of it.
>
> Software TX Checksum
> ====================
> diff --git a/include/net/page_pool/memory_provider.h b/include/net/page_pool/memory_provider.h
> index daec73c9dcee..849db08513b8 100644
> --- a/include/net/page_pool/memory_provider.h
> +++ b/include/net/page_pool/memory_provider.h
> @@ -49,6 +49,8 @@ struct memory_provider_ops {
> bool net_mp_niov_set_dma_addr(struct net_iov *niov, dma_addr_t addr);
> void net_mp_niov_set_page_pool(struct page_pool *pool, struct net_iov *niov);
> void net_mp_niov_clear_page_pool(struct net_iov *niov);
> +void net_mp_release_page_pool_bulk(struct page_pool *pool,
> + netmem_ref *netmems, u32 count);
>
> int netif_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx,
> const struct pp_memory_provider_params *p,
> diff --git a/net/core/page_pool.c b/net/core/page_pool.c
> index e897e79d31f1..56c299f2280d 100644
> --- a/net/core/page_pool.c
> +++ b/net/core/page_pool.c
> @@ -1401,7 +1401,7 @@ bool net_mp_niov_set_dma_addr(struct net_iov *niov, dma_addr_t addr)
> }
>
> /* Associate a niov with a page pool. Should follow with a matching
> - * net_mp_niov_clear_page_pool()
> + * net_mp_niov_clear_page_pool() or net_mp_release_page_pool_bulk()
> */
> void net_mp_niov_set_page_pool(struct page_pool *pool, struct net_iov *niov)
> {
> @@ -1422,3 +1422,35 @@ void net_mp_niov_clear_page_pool(struct net_iov *niov)
>
> page_pool_clear_pp_info(netmem);
> }
> +
> +/**
> + * net_mp_release_page_pool_bulk() - take net_iovs back from a page pool
> + * @pool: page pool that holds one reference to each net_iov
> + * @netmems: net_iovs of the memory provider of @pool
> + * @count: number of entries in @netmems
> + *
> + * A memory provider takes net_iovs out of a page pool without
> + * ->release_netmem(), for example to give them to userspace. @pool may be
> + * freed on return.
> + */
> +void net_mp_release_page_pool_bulk(struct page_pool *pool,
> + netmem_ref *netmems, u32 count)
> +{
> + bool trace = trace_page_pool_state_release_enabled();
> + atomic_t *release_cnt = &pool->pages_state_release_cnt;
> + int released;
> + u32 i;
> +
> + for (i = 0; i < count; i++) {
> + DEBUG_NET_WARN_ON_ONCE(netmem_get_pp(netmems[i]) != pool);
> + page_pool_clear_pp_info(netmems[i]);
> + if (!trace)
> + continue;
> +
> + released = atomic_inc_return_relaxed(release_cnt);
> + trace_page_pool_state_release(pool, netmems[i], released);
> + }
> +
> + if (!trace)
> + atomic_add(count, release_cnt);
> +}
> diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
> index 113b0b08356d..b419c673e3f1 100644
> --- a/net/xdp/xsk.c
> +++ b/net/xdp/xsk.c
> @@ -386,6 +386,54 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
> return -ENOMEM;
> }
>
> +static int xsk_pp_rcv_copy(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
> +{
> + u32 frame_size = __xsk_pool_get_rx_frame_size(xs->pool);
> + u32 headroom = xsk_pool_get_headroom(xs->pool);
> + void *copy_from = xsk_copy_xdp_start(xdp);
> + u32 from_len, meta_len, rem, num_desc, i;
> + u64 addrs[MAX_SKB_FRAGS + 1];
> + skb_frag_t *frag = NULL;
> + u32 to_len, copied;
> + void *to;
> +
> + from_len = xdp->data_end - copy_from;
> + meta_len = xdp->data - copy_from;
> + rem = len + meta_len;
> +
> + num_desc = (len - 1) / frame_size + 1;
> + if (num_desc > ARRAY_SIZE(addrs)) {
> + xs->rx_dropped++;
> + return -ENOSPC;
> + }
> + if (xskq_prod_nb_free(xs->rx, num_desc) < num_desc) {
> + xs->rx_queue_full++;
> + return -ENOBUFS;
> + }
> + if (!xsk_pp_claim_copy(xs->pool->pp, addrs, num_desc)) {
> + xs->rx_dropped++;
> + return -ENOMEM;
> + }
> +
> + if (xdp_buff_has_frags(xdp))
> + frag = &xdp_get_shared_info_from_buff(xdp)->frags[0];
> +
> + for (i = 0; rem && i < num_desc; i++) {
> + to = xp_raw_get_data(xs->pool, addrs[i] + headroom) - meta_len;
> + to_len = frame_size + meta_len;
> + copied = xsk_copy_xdp(to, ©_from, to_len, &from_len, &frag,
> + rem);
> + rem -= copied;
> +
> + __xskq_prod_reserve_desc(xs->rx, addrs[i] + headroom,
> + copied - meta_len,
> + rem ? XDP_PKT_CONTD : 0);
> + meta_len = 0;
> + }
> +
> + return 0;
> +}
> +
> static bool xsk_tx_writeable(struct xdp_sock *xs)
> {
> if (xskq_cons_present_entries(xs->tx) > xs->tx->nentries / 2)
> @@ -453,8 +501,14 @@ static int xsk_rcv_check(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
>
> static void xsk_flush(struct xdp_sock *xs)
> {
> + struct xsk_pp *pp = xs->pool->pp;
> +
> + if (pp)
> + xsk_pp_flush(pp);
> xskq_prod_submit(xs->rx);
> - __xskq_cons_release(xs->pool->fq);
> + /* A provider releases FILL entries under its lock. */
> + if (!pp)
> + __xskq_cons_release(xs->pool->fq);
> sock_def_readable(&xs->sk);
optional nit:
if (pp) {
pp_flush
prod_submit
} else {
prod_submit
cons_release
}
sock_def_readable
(hard to follow these scattered if(pp) checks :-( )
> }
>
> @@ -464,6 +518,11 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
> int err;
>
> err = xsk_rcv_check(xs, xdp, len);
> + /* Only the NAPI of the queue feeds a memory provider socket. */
> + if (!err && xs->pool->pp) {
> + xs->rx_dropped++;
> + err = -EOPNOTSUPP;
> + }
This is confusing? Why even call xsk_rcv_check for pp case?
> if (!err) {
> spin_lock_bh(&xs->pool->rx_lock);
> err = __xsk_rcv(xs, xdp, len);
> @@ -488,7 +547,26 @@ static int xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
> return xsk_rcv_zc(xs, xdp, len);
> }
>
> - err = __xsk_rcv(xs, xdp, len);
> + if (!xs->pool->pp) {
> + err = __xsk_rcv(xs, xdp, len);
> + } else {
[..]
> + /* A CPUMAP program runs XDP on another CPU, not in NAPI. */
> + if (unlikely(!xdp_rxq_info_is_reg(xdp->rxq))) {
> + xs->rx_dropped++;
> + return -EINVAL;
> + }
> +
> + err = xsk_pp_rcv_zc(xs->pool->pp, xs, xdp);
> + if (err != -EXDEV)
> + return err;
> +
> + /* Copy only packets of the queue, from its NAPI */
> + if (unlikely(!xsk_pp_queue_buf(xs->pool->pp, xdp))) {
> + xs->rx_dropped++;
> + return -EINVAL;
> + }
> + err = xsk_pp_rcv_copy(xs, xdp, len);
Move this into __xsk_rcv_pp ?
next prev parent reply other threads:[~2026-11-11 23:21 UTC|newest]
Thread overview: 40+ 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-11 12:41 ` Björn Töpel
2026-11-11 23:01 ` Stanislav Fomichev
2026-11-11 22:41 ` netdev-bot+sashiko
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-11 13:27 ` Björn Töpel
2026-11-11 23:05 ` Stanislav Fomichev
2026-11-11 22:41 ` netdev-bot+sashiko
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-11 13:51 ` Björn Töpel
2026-11-10 23:02 ` Stanislav Fomichev
2026-11-11 13:59 ` Björn Töpel
2026-11-11 23:09 ` Stanislav Fomichev
2026-11-11 22:41 ` netdev-bot+sashiko
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
2026-11-11 14:01 ` Björn Töpel
2026-11-11 8:59 ` Magnus Karlsson
2026-11-11 19:26 ` Björn Töpel
2026-11-11 22:41 ` netdev-bot+sashiko
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-11 19:37 ` Björn Töpel
2026-11-11 23:13 ` Stanislav Fomichev
2026-11-11 22:41 ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 07/11] xsk: Deliver provider chunks without copying Björn Töpel
2026-11-11 22:41 ` netdev-bot+sashiko
2026-11-11 23:20 ` Stanislav Fomichev [this message]
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-11 21:45 ` Dimitri Daskalakis
2026-11-11 22:41 ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 11/11] eth: fbnic: Support AF_XDP page pool zero copy Björn Töpel
2026-11-11 22:41 ` netdev-bot+sashiko
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=avT3vVT8iyKqyW8q@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®