From: Nicolai Buchwitz <nb@tipi-net.de>
To: "Théo Lebrun" <theo.lebrun@bootlin.com>
Cc: Conor Dooley <conor.dooley@microchip.com>,
Claudiu Beznea <claudiu.beznea@tuxon.dev>,
Jonathan Bell <jonathan@raspberrypi.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Richard Cochran <richardcochran@gmail.com>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net 1/2] net: macb: exclude software FCS from TX byte statistics
Date: Tue, 25 Aug 2026 17:04:14 +0200 [thread overview]
Message-ID: <d1f02ab923c0464fa73cafa75a21943d@tipi-net.de> (raw)
In-Reply-To: <20260824134703.766708-2-nb@tipi-net.de>
Replying to netdev's sashiko
https://netdev-ai.bots.linux.dev/sashiko/#/message/20260824134703.766708-2-nb%40tipi-net.de:
> --- Patch [1]: [PATCH net 1/2] net: macb: exclude software FCS from TX
> byte statistics ---
> commit 24acee751440b1a44c9e16688554df0848ab621a
> Author: Nicolai Buchwitz <nb@tipi-net.de>
>
> net: macb: exclude software FCS from TX byte statistics
>
> Frames going through macb_pad_and_fcs() get padded and four FCS
> bytes appended, and TX completion then accounts the grown skb->len.
> tx_bytes is supposed to exclude the FCS, and frames padded by the
> hardware are counted without the padding anyway, so these frames
> show up too large in the statistics.
>
> > diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> > index 76ee4f5060335..623d072a271d0 100644
> > --- a/drivers/net/ethernet/cadence/macb_main.c
> > +++ b/drivers/net/ethernet/cadence/macb_main.c
> > @@ -1322,8 +1322,8 @@ static void macb_tx_error_task(struct work_struct *work)
> > bp->netdev->stats.tx_packets++;
> > queue->stats.tx_packets++;
> > packets++;
> > - bp->netdev->stats.tx_bytes += skb->len;
> > - queue->stats.tx_bytes += skb->len;
> > + bp->netdev->stats.tx_bytes += tx_skb->skb_len;
> > + queue->stats.tx_bytes += tx_skb->skb_len;
> > bytes += skb->len;
> > }
> > } else {
>
> This is a pre-existing issue, but does macb_tx_error_task() leak BQL
> bytes for
> dropped pending packets?
>
> When recovering from a TX error, macb_tx_error_task() iterates through
> the TX
> ring. For pending descriptors that did not successfully transmit, the
> code calls
> macb_tx_unmap(bp, tx_skb, 0) which frees the SKB.
>
> However, it appears to fail to accumulate the freed SKB's length into
> the bytes
> accumulator. When netdev_tx_completed_queue() is subsequently called,
> these
> leaked bytes are never reported to BQL, which could permanently retain
> these
> charged bytes and stall the TX queue.
Looks like it. The dropped frames never get a completion credit, and DQL
only gets reset on close. This is independent of the statistics change,
so I would address it in a follow-up fix. Objections?
> This is another pre-existing issue, but does macb_tx_error_task()
> modify the TX
> ring pointers without holding the appropriate lock?
>
> macb_tx_error_task() acquires bp->lock and issues a non-blocking stop
> to the
> queues via netif_tx_stop_all_queues(). It then manipulates the ring
> pointers
> queue->tx_head and queue->tx_tail.
>
> However, the fast-path macb_start_xmit() protects these identical
> pointers
> using queue->tx_ptr_lock.
>
> Since netif_tx_stop_all_queues() does not wait for an already-running
> macb_start_xmit() to complete, could macb_tx_error_task() zero out the
> ring
> pointers while macb_start_xmit() is concurrently populating descriptors
> on
> another CPU?
AFAIU yes, stopping the queues doesn't wait for a start_xmit that's
already running. Taking tx_ptr_lock there before bp->lock, in the same
order as start_xmit, should fix that. I would handle this together with
the
BQL issue in a follow-up series.
> [ ... ]
> > @@ -2485,6 +2487,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
> > return ret;
> > }
> >
> > + skb_len = skb->len;
> > if (macb_pad_and_fcs(&skb, netdev)) {
>
> This isn't a bug introduced by this patch, but does macb_pad_and_fcs()
> append
> an FCS before verifying TX ring space, which could corrupt the SKB upon
> retry?
>
> [ ... ]
>
> Because the network stack will subsequently retry transmitting this
> identical
> SKB, and its length is now larger, will macb_pad_and_fcs() compute a
> new CRC
> over the old FCS and append a second, duplicate FCS, eventually
> corrupting the
> payload once tailroom is exhausted?
Yes, and the copy path looks worse: the stack can requeue an skb the
driver already
consumed. I'll do the ring space check before touching the skb at all.
After that
point the driver never returns NETDEV_TX_BUSY, so swapping the skb
should be fine.
> This is also a pre-existing issue, but does macb_pad_and_fcs() modify
> shared SKB
> data for cloned packets and break nonlinear SKB layouts?
>
> If an SKB is cloned (e.g., multicast, TCP retransmissions) or nonlinear
> (paged
> fragments), and its length is already >= ETH_ZLEN (60 bytes) so padlen
> <= 0,
> and it has at least 4 bytes of tailroom, the code skips the
> reallocation check:
>
> if (padlen <= 0) {
> /* FCS could be appeded to tailroom. */
> if (tailroom >= ETH_FCS_LEN)
> goto add_fcs;
>
> It then directly appends 4 bytes of FCS via skb_put_u8(). For cloned
> SKBs, this
> modifies shared memory data. For nonlinear SKBs, skb_put() illegally
> extends the
> linear part, which could trigger a panic in skb_panic().
The cloned part looks right. The nonlinear case IMHO can't trigger
today:
skb_tailroom() is 0 for nonlinear skbs, so they go down
skb_copy_expand(),
which linearizes them anyway.
I'll order the cloned check before the in-place FCS path.
next prev parent reply other threads:[~2026-08-25 15:04 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 13:47 [PATCH net 0/2] net: macb: fix zero UDPv4 checksum on transmit Nicolai Buchwitz
2026-08-24 13:47 ` [PATCH net 1/2] net: macb: exclude software FCS from TX byte statistics Nicolai Buchwitz
2026-08-25 15:04 ` Nicolai Buchwitz [this message]
2026-08-24 13:47 ` [PATCH net 2/2] net: macb: fix zero UDPv4 checksum on transmit Nicolai Buchwitz
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=d1f02ab923c0464fa73cafa75a21943d@tipi-net.de \
--to=nb@tipi-net.de \
--cc=andrew+netdev@lunn.ch \
--cc=claudiu.beznea@tuxon.dev \
--cc=conor.dooley@microchip.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=jonathan@raspberrypi.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=theo.lebrun@bootlin.com \
/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