From: Dominik Dvořák Via B4 Relay <[email protected]> Date: Thu, 05 Nov 2026 14:21:15 +0100
> From: Dominik Dvořák <[email protected]> > > Since the Rx path was converted to page pool and libeth, ice_run_xdp() > returns the buffer itself via libeth_xdp_return_buff() on XDP_DROP, > XDP_ABORTED and on a failed XDP_TX or XDP_REDIRECT. That helper also > sets xdp->data to NULL. ice_clean_rx_irq() then calls xdp_get_buff_len() > on the same buffer to update the Rx byte counter, which evaluates > xdp->data_end - NULL and adds the low 32 bits of a kernel address to > the ring's byte counter for every such frame. For multi-buffer frames > it would also read skb_shared_info from a page that has already been > returned to the page pool. [...] > Tested on an E810-XXV (7.0.14 kernel, same code as current master) with > an XDP blocklist attached to an 802.3ad bond: without the fix, each > dropped packet added about 2.5 GB to rx_queue_N_bytes; with the fix, 40 > dropped packets produced no such jumps. > > Fixes: 93f53db9f9dc ("ice: switch to Page Pool") This might need `Cc: [email protected] #` with the minimum affected version, so that it will be picked for backporting. Recently, the LTS versions got Page Pool conversion backported, so this fix is now applicable to them as well. > Link: > https://lore.kernel.org/netdev/db7pr03mb460158b90a64d025962670e0d5...@db7pr03mb4601.eurprd03.prod.outlook.com/ > Signed-off-by: Dominik Dvořák <[email protected]> > --- > Based on the stable v7.0.14 tree, which is what the affected box runs; > the changed code is identical in current master. Tested on that box > with the fixed module built against the 7.0.14-26-pve headers. > --- > drivers/net/ethernet/intel/ice/ice_txrx.c | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c > b/drivers/net/ethernet/intel/ice/ice_txrx.c > index > 4ca1a0602307d076153f77671e8c9a6ff4f8dd28..f62a1bb7bbca579b43fe2f4c8e1946e65b5cea63 > 100644 > --- a/drivers/net/ethernet/intel/ice/ice_txrx.c > +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c > @@ -968,7 +968,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, > int budget) > union ice_32b_rx_flex_desc *rx_desc; > struct libeth_fqe *rx_buf; > struct sk_buff *skb; > - unsigned int size; > + unsigned int size, len; > u16 stat_err_bits; > u16 vlan_tci; > bool rxe; > @@ -1028,13 +1028,16 @@ static int ice_clean_rx_irq(struct ice_rx_ring > *rx_ring, int budget) > if (ice_is_non_eop(rx_ring, rx_desc) || unlikely(!xdp->data)) > continue; > > + /* ice_run_xdp() may free the buffer and clear xdp->data */ > + len = xdp_get_buff_len(&xdp->base); I would simplify this further: add this to @total_rx_bytes and increment @total_rx_pkts right here and remove separate accounting for %XDP_PASS below which uses `skb->len`. Both are +/- equal and since here we need to call xdp_get_buff_len() unconditionally, we could update the stats only here. > + > xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, > rx_desc); > if (xdp_verdict == ICE_XDP_PASS) > goto construct_skb; > > if (xdp_verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) > xdp_xmit |= xdp_verdict; > - total_rx_bytes += xdp_get_buff_len(&xdp->base); > + total_rx_bytes += len; > total_rx_pkts++; > > xdp->data = NULL; Thanks, Olek
