From: Orgad Shaneh <orgads@gmail.com>
To: Haiyang Zhang <haiyangz@microsoft.com>,
Wei Liu <wei.liu@kernel.org>, Dexuan Cui <decui@microsoft.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, linux-hyperv@vger.kernel.org,
linux-rdma@vger.kernel.org, bpf@vger.kernel.org,
linux-kernel@vger.kernel.org, Wei Hu <weh@microsoft.com>,
Konstantin Taranov <kotaranov@microsoft.com>,
Simon Horman <horms@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Jesper Dangaard Brouer <hawk@kernel.org>,
John Fastabend <john.fastabend@gmail.com>,
Stanislav Fomichev <sdf@fomichev.me>,
Long Li <longli@microsoft.com>,
Dipayaan Roy <dipayanroy@linux.microsoft.com>,
Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>,
Aditya Garg <gargaditya@linux.microsoft.com>,
Erni Sri Satya Vennela <ernis@linux.microsoft.com>,
Muhammad Falak R Wani <falakreyaz@gmail.com>,
Jesse Brandeburg <jbrandeb@kernel.org>
Subject: [PATCH net] net: mana: fix XDP_REDIRECT of pre-allocated RX buffers
Date: Mon, 2 Nov 2026 06:43:24 +0000 [thread overview]
Message-ID: <20261102064324.806414-1-orgads@gmail.com> (raw)
mana_pre_alloc_rxbufs() fills the RX rings with plain pages from
dev_alloc_pages() (from_pool == false), but the rxq is registered with
MEM_TYPE_PAGE_POOL and mana_run_xdp() builds every xdp_buff with that
rxq info. mana_rx_skb() frees a !from_pool buffer correctly on
XDP_PASS, XDP_TX and XDP_DROP, but a redirected buffer is freed through
its memory model: __xdp_return() hands the plain page to
page_pool_put_full_netmem(). This triggers the WARN in
include/net/page_pool/helpers.h, breaks the page refcount, RX refills
fail and the queue stops receiving.
The pre-allocated buffers fill the whole ring of every rxq created by
an MTU change, by ethtool -L / -G and, since
commit 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers
instead of full pages to improve memory efficiency."), by every XDP
attach and detach. So on current kernels the first ring of redirected
packets after attaching an XDP program always hits this.
Reproduced on 7.2.11, and on 6.12.113 after ethtool -L, on an Azure
MANA VF: an XDP program that redirects UDP to an XSKMAP with an AF_XDP
socket in copy mode gives WARNINGs at __xdp_return+0x249 (stack
__xsk_map_redirect, xdp_do_redirect, mana_run_xdp, mana_poll), then
the queue stops.
Give each rxq a second xdp_rxq_info registered with
MEM_TYPE_PAGE_SHARED, the model these buffers had before the page pool
was added, and use it for buffers that are not from the pool. Those
buffers are already DMA-unmapped by mana_refill_rx_oob() before XDP
runs, and page_frag_free() frees them whatever their order. Allocating
the pre-allocated buffers from the page pool instead would need the
pools to exist before the rxqs and to outlive them, a much larger
change.
Found, fixed and tested with an AI coding assistant (Claude Code).
Fixes: b1d13f7a3b53 ("net: mana: Add page pool for RX buffers")
Signed-off-by: Orgad Shaneh <orgads@gmail.com>
---
Tested on an Azure D2s_v6 MANA VF, net at cb284914e749 with and
without this patch (same config), XDP program redirecting UDP to an
AF_XDP socket in copy mode on queue 0, 25k pps offered right after
attach:
- without: 41 WARNINGs at __xdp_return+0x252, 0 packets relayed,
hc_rx_discards_no_wqe 301470.
- with: no WARNING, 25k of 25k pps relayed, 0 loss; also over three
more attach/detach cycles, two ethtool -L combined 1/2 cycles and an
MTU 4000/1500 change before attach. MemAvailable unchanged.
W=1 build of the mana directories: no new warnings.
drivers/net/ethernet/microsoft/mana/mana_bpf.c | 9 +++++++--
drivers/net/ethernet/microsoft/mana/mana_en.c | 11 ++++++++++-
include/net/mana/mana.h | 5 ++++-
3 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
index 7c55f8724441..494267b3069a 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
@@ -78,7 +78,8 @@ int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames,
}
u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
- struct xdp_buff *xdp, void *buf_va, uint pkt_len)
+ struct xdp_buff *xdp, void *buf_va, bool from_pool,
+ uint pkt_len)
{
struct mana_stats_rx *rx_stats;
struct bpf_prog *prog;
@@ -90,7 +91,11 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
if (!prog)
goto out;
- xdp_init_buff(xdp, PAGE_SIZE, &rxq->xdp_rxq);
+ /* A redirected buffer is freed by its memory model, so a buffer not
+ * from the page pool must not claim MEM_TYPE_PAGE_POOL.
+ */
+ xdp_init_buff(xdp, PAGE_SIZE,
+ from_pool ? &rxq->xdp_rxq : &rxq->xdp_rxq_shared);
xdp_prepare_buff(xdp, buf_va, rxq->headroom, pkt_len, true);
act = bpf_prog_run_xdp(prog, xdp);
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 6b7c027e497e..7547aeb3235d 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2157,7 +2157,7 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
return;
}
- act = mana_run_xdp(ndev, rxq, &xdp, buf_va, pkt_len);
+ act = mana_run_xdp(ndev, rxq, &xdp, buf_va, from_pool, pkt_len);
if (act == XDP_REDIRECT && !rxq->xdp_rc)
return;
@@ -2947,6 +2947,9 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
xdp_rxq_info_unreg(&rxq->xdp_rxq);
+ if (xdp_rxq_info_is_reg(&rxq->xdp_rxq_shared))
+ xdp_rxq_info_unreg(&rxq->xdp_rxq_shared);
+
if (rxq->rxobj != INVALID_MANA_HANDLE)
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
@@ -3225,6 +3228,12 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL,
rxq->page_pool));
+ /* The pre-allocated buffers (mana_pre_alloc_rxbufs) are plain pages */
+ WARN_ON(xdp_rxq_info_reg(&rxq->xdp_rxq_shared, ndev, rxq_idx,
+ cq->napi.napi_id));
+ WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq_shared,
+ MEM_TYPE_PAGE_SHARED, NULL));
+
/* Initialize the DIM work before enabling NAPI, so that a poll
* cannot reach net_dim() with an uninitialized cq->dim.work.
*/
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 71d726b1f784..11ceb5946ee0 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -420,6 +420,8 @@ struct mana_rxq {
struct bpf_prog __rcu *bpf_prog;
struct xdp_rxq_info xdp_rxq;
+ /* For buffers not from the page pool (from_pool == false) */
+ struct xdp_rxq_info xdp_rxq_shared;
void *xdp_save_va; /* for reusing */
bool xdp_flush;
int xdp_rc; /* XDP redirect return code */
@@ -695,7 +697,8 @@ void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev);
int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames,
u32 flags);
u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
- struct xdp_buff *xdp, void *buf_va, uint pkt_len);
+ struct xdp_buff *xdp, void *buf_va, bool from_pool,
+ uint pkt_len);
struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
base-commit: cb284914e749388eef402938bdb3115fe1f6d337
--
2.52.0
reply other threads:[~2026-11-02 6:43 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261102064324.806414-1-orgads@gmail.com \
--to=orgads@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=decui@microsoft.com \
--cc=dipayanroy@linux.microsoft.com \
--cc=edumazet@kernel.org \
--cc=ernis@linux.microsoft.com \
--cc=falakreyaz@gmail.com \
--cc=gargaditya@linux.microsoft.com \
--cc=haiyangz@microsoft.com \
--cc=hamzamahfooz@linux.microsoft.com \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=jbrandeb@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kotaranov@microsoft.com \
--cc=kuba@kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=longli@microsoft.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=weh@microsoft.com \
--cc=wei.liu@kernel.org \
/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