From: "Daniel Zahka" <daniel.zahka@gmail.com>
To: <netdev-bot+sashiko@kernel.org>, <daniel.zahka@gmail.com>
Cc: <alexanderduyck@fb.com>, <kuba@kernel.org>,
<kernel-team@meta.com>, <andrew+netdev@lunn.ch>,
<davem@davemloft.net>, <edumazet@google.com>, <pabeni@redhat.com>,
<ast@kernel.org>, <daniel@iogearbox.net>, <hawk@kernel.org>,
<john.fastabend@gmail.com>, <sdf@fomichev.me>,
<dimitri.daskalakis1@gmail.com>, <mohsin.bashr@gmail.com>,
<linux-kernel@vger.kernel.org>, <netdev@vger.kernel.org>,
<bpf@vger.kernel.org>
Subject: Re: [PATCH net-next v2 8/8] eth: mpnic: add basic Rx handling
Date: Mon, 28 Sep 2026 11:17:42 -0400 [thread overview]
Message-ID: <DLR1SNM0T642.1TU5R4E1EQQ32@gmail.com> (raw)
In-Reply-To: <179055370821.3145.15563353156431464401@kernel.org>
On Sun Sep 27, 2026 at 8:01 PM EDT, netdev-bot+sashiko wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 4 · Low: 0
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
>
> - [Medium] Rx buffer queues can starve for good after a page allocation
> failure.
> - [Medium] mpnic_clean_rcq() never checks that a frame is in progress
> before handling a descriptor.
> - [Medium] mpnic_page_pool_get() indexes ring->rx_buf[idx] with the raw
> 18-bit MPNIC_RCD_AL_BUFF_ID from the completion descriptor (up to…
> - [Medium] The descriptor fields BUFF_OFF (16 bits) and BUFF_LEN (14
> bits) are used without range checks to build the skb head, frame_sz,…
>
> --
>
> eth: mpnic: add basic Rx handling
>
> This commit adds Rx completion processing to the mpnic driver. Each frame
> is built in an xdp_buff from three kinds of descriptor: a header
> descriptor, one payload descriptor per page and a closing metadata
> descriptor. The frame is then passed to GRO, and pages are shared between
> frames using a batched page_pool reference bias.
>
>> diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c
>> index 389a9e5476c6e..edb07b7f334bd 100644
>> --- a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c
>> +++ b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c
>> @@ -405,6 +405,34 @@ static void mpnic_fill_qt_bdqs(struct mpnic_q_triad *qt)
>
> [ ... ]
>
>> +static struct page *
>> +mpnic_page_pool_get(struct mpnic_pg_ctxt *pg_ctxt, struct mpnic_ring *ring,
>> + u32 idx)
>> +{
>> + struct page *page = pg_ctxt->page;
>> +
>> + if (unlikely(pg_ctxt->idx != idx)) {
>> + if (pg_ctxt->pagecnt_bias &&
>> + !page_pool_unref_page(page, pg_ctxt->pagecnt_bias))
>> + page_pool_put_unrefed_page(page->pp, page, -1, true);
>> +
>> + page = ring->rx_buf[idx];
>> + page_pool_fragment_page(page, MPNIC_PAGECNT_BIAS_MAX);
>
> [Severity: Medium]
> Here idx is the raw MPNIC_RCD_AL_BUFF_ID field from the completion
> descriptor. mpnic_pkt_prepare() and mpnic_add_rx_frag() pass it through
> unchanged. The field is 18 bits wide (up to 262143), but rx_buf[] only
> has hpq_size/ppq_size entries (256 by default).
>
> Could a bad buffer ID from the device read past the end of rx_buf[]?
> page_pool_fragment_page() would then write pp_ref_count through
> whatever pointer it found there.
>
> An in-range ID for a slot the device already completed seems like it
> would also reset the refcount of a page that in-flight skbs still own.
>
> mpnic_bd_prep() only posts IDs in [0, size_mask], so this needs a faulty
> or misbehaving device. Would it be worth masking idx with
> ring->size_mask, or rejecting IDs that are out of range?
>
Comment addressed in v1.
> [ ... ]
>
>> @@ -417,6 +445,87 @@ static void mpnic_flush_pg_ctxt(struct mpnic_pg_ctxt *ctxt, bool napi)
>> }
>> }
>>
>> +static unsigned int mpnic_hdr_pg_start(unsigned int pg_off)
>> +{
>
> [ ... ]
>
>> + if (ALIGN(MPNIC_RX_HROOM, 128) > MPNIC_RX_HROOM &&
>> + pg_off == ALIGN(MPNIC_RX_HROOM, 128))
>> + return 0;
>> +
>> + return pg_off - MPNIC_RX_HROOM;
>> +}
>
> [Severity: Medium]
> If the device reports a BUFF_OFF smaller than MPNIC_RX_HROOM, does this
> unsigned subtraction wrap around and produce a huge pg_start?
>
> The BUFF_OFF (16 bits) and BUFF_LEN (14 bits) fields are used without
> range checks in a few other places:
>
> - mpnic_hdr_pg_end() can return values well beyond PAGE_SIZE. These
> feed frame_sz in mpnic_pkt_prepare(), which decides where
> skb_shared_info is written.
>
> - With fin set and pg_off larger than page_size(page), frame_sz in
> mpnic_pkt_prepare() and truesz in mpnic_add_rx_frag() both underflow.
>
> - In mpnic_add_rx_frag(), a payload frag with pg_off + len past
> page_size(page) would expose adjacent memory to the stack.
>
> The same values also set the page_pool_dma_sync_for_cpu() ranges.
>
> A device that follows the configured HROOM/TROOM/MAX_HEADER_BYTES layout
> should not produce these values. Would a sanity check against
> page_size(page) still be worth adding?
>
We trust the offset field written by the device.
> [ ... ]
>
>> @@ -442,23 +551,99 @@ static void mpnic_put_pkt_buff(struct mpnic_pkt_ctxt *ctxt, bool napi)
>> page_pool_put_full_page(page->pp, page, napi);
>> }
>>
>> +static int mpnic_clean_rcq(struct mpnic_napi_vector *nv,
>> + struct mpnic_q_triad *qt, int budget)
>> +{
>
> [ ... ]
>
>> + switch (FIELD_GET(MPNIC_RCD_TYPE, rcd)) {
>> + case MPNIC_RCD_TYPE_HDR_AL:
>> + if (FIELD_GET(MPNIC_RCD_HDR_SUBTYPE, rcd) ==
>> + MPNIC_RCD_HDR_SUBTYPE_HDR)
>> + mpnic_pkt_prepare(rcd, state, qt);
>> + break;
>> + case MPNIC_RCD_TYPE_PAY_AL:
>> + mpnic_add_rx_frag(rcd, state, qt);
>> + break;
>> + case MPNIC_RCD_TYPE_META: {
>> + struct sk_buff *skb = NULL;
>> +
>> + if (likely(!(rcd &
>> + MPNIC_RCD_META_UNCORRECTABLE_ERR_MASK) &&
>> + !state->pkt.add_frag_failed))
>> + skb = xdp_build_skb_from_buff(&state->pkt.buff);
>> +
>> + if (likely(skb))
>> + napi_gro_receive(&nv->napi, skb);
>> + else
>> + mpnic_put_pkt_buff(&state->pkt, true);
>> +
>> + state->pkt.buff.data_hard_start = NULL;
>
> [Severity: Medium]
> Nothing checks that a frame is in progress before a PAY_AL or META
> descriptor is handled. state->pkt.buff.data_hard_start is zero at
> start and is set back to NULL after every META.
>
> Suppose a PAY_AL arrives without a preceding HDR descriptor.
> mpnic_add_rx_frag() then calls xdp_buff_add_frag(), which writes to
> skb_shared_info at an address based on a NULL data_hard_start and a
> stale frame_sz.
>
> A META in the same state would take the success branch:
>
> mpnic_clean_rcq()
> xdp_build_skb_from_buff()
> napi_build_skb(NULL, frame_sz)
>
> Only the error path, mpnic_put_pkt_buff(), checks data_hard_start.
>
> Can either of these cause a NULL pointer dereference in NAPI context?
>
> HDR_AL descriptors whose subtype is not MPNIC_RCD_HDR_SUBTYPE_HDR are
> skipped silently, so a frame that starts that way would hit the same
> path.
>
> The opposite case is also possible. mpnic_pkt_prepare() overwrites
> state->pkt.buff without releasing the page_pool references of an
> unfinished frame. Could that leak pages and stall page_pool_destroy()?
>
> fbnic_pkt_prepare() has a WARN_ON_ONCE(xdp->data_hard_start) at this
> point, and mpnic_pkt_prepare() drops it. Would it make sense to keep it?
>
> All of this needs the device to break the HDR, PAY_AL*, META ordering.
>
Same comment responded to in v1.
> [ ... ]
>
>> + rcq->head = head;
>> +
>> + /* Allocate buffers, force dma_wmb(), and then start writing tails */
>> + mpnic_fill_qt_bdqs(qt);
>> +
>> + return packets;
>> +}
>> +
>> static int mpnic_poll(struct napi_struct *napi, int budget)
>> {
>
> [ ... ]
>
>> - if (likely(napi_complete_done(napi, 0)))
>> + if (work_done >= budget)
>> + return budget;
>> +
>> + if (likely(napi_complete_done(napi, work_done)))
>> mpnic_nv_irq_rearm(nv);
>
> [Severity: Medium]
> mpnic_clean_rcq() is the only runtime caller of mpnic_fill_qt_bdqs().
> __mpnic_fill_bdq() simply stops when the page pool allocation fails:
>
> page = page_pool_dev_alloc_pages(bdq->page_pool);
> if (!page)
> break;
>
> The shortfall is never reported back, because mpnic_clean_rcq() only
> returns the packet count. mpnic_poll() then completes NAPI and re-arms
> the IRQ anyway.
>
> Say the allocation fails while the device has no posted buffers left,
> or fewer than the 16-descriptor HPQ/PPQ drop threshold. The device then
> drops incoming frames without writing any RCQ completions. What would
> schedule NAPI again in that case?
>
> There doesn't seem to be a timer, a service task, a forced IRQ trigger,
> or a return of the full budget to retry the refill. The only
> mpnic_nv_irq_trigger() call is in mpnic_napi_enable(). The only way out
> seems to be a Tx completion on the same vector.
>
> Could a receive-mostly queue stay stuck until the interface is brought
> down and up again?
>
> [ ... ]
Valid. We prefer to address this in a small follow up series.
next prev parent reply other threads:[~2026-09-28 15:17 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 0:35 [PATCH net-next v2 0/8] eth: mpnic: initial support for Meta Platforms NIC Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 1/8] eth: mpnic: add scaffolding " Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 12:13 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 2/8] eth: mpnic: add register init for the device Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 12:14 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 3/8] eth: mpnic: allocate MSI-X vectors Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 16:01 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 4/8] eth: mpnic: implement Tx queue allocation and cleanup Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 14:46 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 5/8] eth: mpnic: start and stop the Tx HW queues Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 15:00 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 6/8] eth: mpnic: add a netdevice and basic Tx handling Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 15:10 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 7/8] eth: mpnic: implement Rx queue allocation and cleanup Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 15:11 ` Daniel Zahka
2026-09-25 0:35 ` [PATCH net-next v2 8/8] eth: mpnic: add basic Rx handling Daniel Zahka
2026-09-28 0:01 ` netdev-bot+sashiko
2026-09-28 15:17 ` Daniel Zahka [this message]
2026-09-29 2:03 ` Jakub Kicinski
2026-09-28 18:16 ` [PATCH net-next v2 0/8] eth: mpnic: initial support for Meta Platforms NIC Daniel Zahka
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=DLR1SNM0T642.1TU5R4E1EQQ32@gmail.com \
--to=daniel.zahka@gmail.com \
--cc=alexanderduyck@fb.com \
--cc=andrew+netdev@lunn.ch \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dimitri.daskalakis1@gmail.com \
--cc=edumazet@google.com \
--cc=hawk@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mohsin.bashr@gmail.com \
--cc=netdev-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
/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®