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,
"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,
Mina Almasry <almasrymina@google.com>
Subject: Re: [RFC net-next 13/15] eth: fbnic: Support AF_XDP zero-copy receive
Date: Mon, 5 Oct 2026 10:51:21 -0700 [thread overview]
Message-ID: <asPhAnm830qFxGMv@devvm7509.cco0.facebook.com> (raw)
In-Reply-To: <20261002190018.696925-14-bjorn@kernel.org>
On 10/02, Björn Töpel wrote:
> fbnic gets RX buffers from page_pool. Use the XSK buffer pool as the
> RX queue's page-pool memory provider, so allocation, DMA sync,
> recycling and refill stay in page_pool. Only aligned 4 KiB UMEM
> chunks are supported.
>
> Each UMEM frame on the header queue must hold one packet. Raise the
> header-split threshold to at least 3072 bytes, more than half of a
> 4 KiB page, so the device finishes the frame after one header. Cap
> it to the space left in the frame after the headroom. An MTU above
> the threshold needs a socket with XDP_USE_SG and an XDP program with
> frags support. With XDP_USE_SG, the payload queue also uses UMEM
> frames, and the device uses each frame for one descriptor only.
> Without it, the payload queue uses a normal page pool. If the device
> does not finish a provider frame after one descriptor, drop the
> packet.
>
> The BDQ refill loop now alternates header and payload buffers on all
> queues, so two rings that share one finite provider stay balanced.
> It keeps NAPI scheduled while the provider still has buffers.
>
> Provider frames are never split, so they get no fragment bias. A
> redirected frame can be recycled before its old BDQ slot is cleaned,
> and a stale bias would corrupt the new allocation.
>
> The headroom comes from the queue configuration. It must be at least
> XDP_PACKET_HEADROOM, a multiple of 128 bytes, and fit the hardware
> field; otherwise queue validation fails. MTU, ring parameter and XDP
> program changes that do not fit an active provider are rejected.
>
> fbnic did not support XDP_REDIRECT. Add it, with xdp_do_flush(), and
> advertise it. This also enables copy-mode AF_XDP and the other
> redirect targets on fbnic. Do not advertise AF_XDP zero copy until
> TX support is added.
>
> Signed-off-by: Björn Töpel <bjorn@kernel.org>
> ---
> .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 5 +
> .../net/ethernet/meta/fbnic/fbnic_netdev.c | 140 ++++++-
> .../net/ethernet/meta/fbnic/fbnic_netdev.h | 4 +
> drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 350 +++++++++++++-----
> drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 6 +
> 5 files changed, 402 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> index e774740fcb5d..188abe0ead14 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> @@ -385,6 +385,11 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
> return -EINVAL;
> }
>
> + err = fbnic_xsk_validate(fbn, fbn->xdp_prog, netdev->mtu,
> + kernel_ring->hds_thresh, extack);
> + if (err)
> + return err;
> +
> if (!netif_running(netdev)) {
> fbnic_set_rings(fbn, ring, kernel_ring);
> return 0;
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
> index 8a6703afca38..038e91ef14e4 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
> @@ -5,6 +5,8 @@
> #include <linux/ipv6.h>
> #include <linux/types.h>
> #include <net/netdev_queues.h>
> +#include <net/netdev_rx_queue.h>
> +#include <net/xdp_sock_drv.h>
>
> #include "fbnic.h"
> #include "fbnic_netdev.h"
> @@ -276,6 +278,8 @@ static int fbnic_set_mac(struct net_device *netdev, void *p)
> static int fbnic_change_mtu(struct net_device *dev, int new_mtu)
> {
> struct fbnic_net *fbn = netdev_priv(dev);
> + struct netlink_ext_ack extack = {};
> + int err;
>
> if (fbnic_check_split_frames(fbn->xdp_prog, new_mtu, fbn->hds_thresh)) {
> dev_err(&dev->dev,
> @@ -285,6 +289,15 @@ static int fbnic_change_mtu(struct net_device *dev, int new_mtu)
> return -EINVAL;
> }
>
> + err = fbnic_xsk_validate(fbn, fbn->xdp_prog, new_mtu,
> + fbn->hds_thresh, &extack);
> + if (err) {
> + if (extack._msg)
> + netdev_err(dev, "%s\n", extack._msg);
> +
> + return err;
> + }
> +
> WRITE_ONCE(dev->mtu, new_mtu);
>
> return 0;
> @@ -534,26 +547,123 @@ bool fbnic_check_split_frames(struct bpf_prog *prog, unsigned int mtu,
> return mtu + ETH_HLEN > hds_thresh;
> }
>
> +u32 fbnic_xsk_hds_thresh(u32 headroom, u32 hds_thresh)
> +{
> + u32 max_hds;
> +
> + /* Reserve more than half a device page for each header so the device
> + * retires the provider frame after one descriptor.
> + */
> + static_assert(2 * FBNIC_XSK_HDS_THRESH > FBNIC_BD_PAGE_SIZE);
> +
> + max_hds = FBNIC_BD_PAGE_SIZE - headroom - FBNIC_RX_TROOM -
> + FBNIC_RX_PAD;
> +
> + return min(max_t(u32, hds_thresh, FBNIC_XSK_HDS_THRESH), max_hds);
> +}
> +
> +static int fbnic_xsk_validate_frames(struct xsk_buff_pool *pool,
> + struct bpf_prog *prog,
> + unsigned int mtu, u32 hds_thresh,
> + struct netlink_ext_ack *extack)
> +{
> + u32 xsk_hds_thresh;
> +
> + xsk_hds_thresh = fbnic_xsk_hds_thresh(xsk_pool_get_headroom(pool),
> + hds_thresh);
> +
> + if (mtu + ETH_HLEN <= xsk_hds_thresh)
> + return 0;
> +
> + if (!xsk_pool_uses_sg(pool)) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "AF_XDP zero-copy socket requires XDP_USE_SG");
> + return -EOPNOTSUPP;
> + }
> +
> + if (fbnic_check_split_frames(prog, mtu, xsk_hds_thresh)) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "AF_XDP zero-copy socket requires XDP frags");
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +int fbnic_xsk_validate(struct fbnic_net *fbn, struct bpf_prog *prog,
> + unsigned int mtu, u32 hds_thresh,
> + struct netlink_ext_ack *extack)
> +{
> + struct net_device *netdev = fbn->netdev;
> + struct xsk_buff_pool *pool;
> + unsigned int qid;
> + int err;
> +
> + for (qid = 0; qid < fbn->num_rx_queues; qid++) {
> + pool = xsk_get_pool_from_rxq(netdev, qid);
> + if (!pool)
> + continue;
> +
> + err = fbnic_xsk_validate_frames(pool, prog, mtu, hds_thresh,
> + extack);
> + if (err)
> + return err;
> + }
> +
> + return 0;
> +}
> +
> +static int fbnic_xsk_setup_pool(struct net_device *netdev,
> + struct xsk_buff_pool *pool, u16 queue_id,
> + struct netlink_ext_ack *extack)
> +{
> + struct fbnic_net *fbn = netdev_priv(netdev);
> + int err;
> +
> + if (queue_id >= fbn->num_rx_queues)
> + return -EINVAL;
> +
> + if (!pool)
> + return xsk_pool_setup_page_pool(netdev, NULL, queue_id, extack);
> +
> + err = fbnic_xsk_validate_frames(pool, fbn->xdp_prog, netdev->mtu,
> + fbn->hds_thresh, extack);
> + if (err)
> + return err;
> +
> + return xsk_pool_setup_page_pool(netdev, pool, queue_id, extack);
> +}
> +
> static int fbnic_bpf(struct net_device *netdev, struct netdev_bpf *bpf)
> {
> struct bpf_prog *prog = bpf->prog, *prev_prog;
> struct fbnic_net *fbn = netdev_priv(netdev);
> + int err;
>
> - if (bpf->command != XDP_SETUP_PROG)
> + switch (bpf->command) {
> + case XDP_SETUP_PROG:
> + if (fbnic_check_split_frames(prog, netdev->mtu,
> + fbn->hds_thresh)) {
> + NL_SET_ERR_MSG_MOD(bpf->extack,
> + "MTU too high, or HDS threshold is too low for single buffer XDP");
> + return -EOPNOTSUPP;
> + }
> +
> + err = fbnic_xsk_validate(fbn, prog, netdev->mtu,
> + fbn->hds_thresh, bpf->extack);
> + if (err)
> + return err;
> +
> + prev_prog = xchg(&fbn->xdp_prog, prog);
> + if (prev_prog)
> + bpf_prog_put(prev_prog);
> + return 0;
[..]
> + case XDP_SETUP_XSK_POOL:
> + return fbnic_xsk_setup_pool(netdev, bpf->xsk.pool,
> + bpf->xsk.queue_id, bpf->extack);
Is there a good reason to ask drivers to call us back with
xsk_pool_setup_page_pool? For the PP mode, maybe we should add new
XSK_VALIDATE_POOL or something? So most of that fbnic_xsk_setup_pool stays
in core?
I guess I'm mentally trying to have a clear separation between
pp vs non-pp modes. Even that whole xsk_buff_pool might be legacy non-pp
artifact? New drivers shouldn't bother with it? Or is it too much?
next prev parent reply other threads:[~2026-10-05 17:51 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 19:00 [RFC net-next 00/15] xsk: Zero copy through page-pool memory providers Björn Töpel
2026-10-02 19:00 ` [RFC net-next 01/15] xdp: Size zero-copy skb heads by their contents Björn Töpel
2026-10-02 19:00 ` [RFC net-next 02/15] eth: fbnic: Report the logical XDP RX queue Björn Töpel
2026-10-02 19:00 ` [RFC net-next 03/15] net: Add memory provider capabilities Björn Töpel
2026-10-03 4:13 ` Mina Almasry
2026-10-09 14:54 ` Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:54 ` Björn Töpel
2026-10-05 16:26 ` Stanislav Fomichev
2026-10-12 13:34 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 04/15] net: Let memory providers set RX buffer headroom Björn Töpel
2026-10-05 16:52 ` Stanislav Fomichev
2026-10-12 13:35 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 05/15] page_pool: Extend memory provider operations Björn Töpel
2026-10-05 16:51 ` Stanislav Fomichev
2026-10-12 13:53 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 06/15] xdp: Track non-page netmem in receive buffers Björn Töpel
2026-10-05 17:01 ` Stanislav Fomichev
2026-10-12 14:12 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 07/15] xsk: Keep the DMA mapping in the buffer pool Björn Töpel
2026-10-02 19:00 ` [RFC net-next 08/15] xsk: Handle a detached FILL ring in RX wakeup Björn Töpel
2026-10-02 19:00 ` [RFC net-next 09/15] xsk: Add a page-pool memory provider for UMEM Björn Töpel
2026-10-05 17:38 ` Stanislav Fomichev
2026-10-12 14:14 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 10/15] xsk: Add RX helpers for page-pool drivers Björn Töpel
2026-10-02 19:00 ` [RFC net-next 11/15] xdp: Copy provider buffers on pass and redirect Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:55 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 12/15] xsk: Receive provider UMEM without copying Björn Töpel
2026-10-02 19:00 ` [RFC net-next 13/15] eth: fbnic: Support AF_XDP zero-copy receive Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:56 ` Björn Töpel
2026-10-05 17:51 ` Stanislav Fomichev [this message]
2026-10-12 14:16 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 14/15] eth: fbnic: Support AF_XDP zero-copy transmit Björn Töpel
2026-10-02 19:00 ` [RFC net-next 15/15] Documentation: xsk: Document 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=asPhAnm830qFxGMv@devvm7509.cco0.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=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.