Re: [PATCH net-next v8 5/5] net: stmmac: rework stmmac_rx to support XDP rx multi-buff
flat view
From: Nicolai Buchwitz <nb@tipi-net.de>
Date: 2026-10-19 11:10:38
Also in:
bpf, linux-arm-kernel
On 18.10.2026 19:07, Lorenzo Bianconi wrote:
The preceding commit dropped frames split across multiple descriptors, or using a second buffer, while XDP was enabled. This prevented the per-descriptor XDP path from re-parsing frame tails and from applying FCS handling to truncated buffers. Rework stmmac_rx() to accumulate all the descriptors that make up a frame in an xdp_buff, so the XDP program runs on the full (possibly fragmented) packet instead of just the first buffer. Frames split across descriptors or buffers are now passed to programs loaded with BPF_F_XDP_HAS_FRAGS; programs without that capability continue to drop fragmented frames. When the frame is not consumed by the program, assemble the skb from the head buffer and the collected fragments via napi_build_skb()/ xdp_update_skb_frags_info(). Note that XDP still rejects an MTU larger than ETH_DATA_LEN (stmmac_xdp_set_prog(), stmmac_change_mtu()) and disables SPH, so an ordinary frame fits in a single buffer. This path is therefore exercised by frames that do span several descriptors (for example jumbo frames the MAC admits through its jumbo-enable bit) and is groundwork for extending XDP to jumbo/SPH; it does not enable XDP jumbo support by itself. To do so, store the in-progress xdp_buff in rx_q->state instead of the partially built skb, so the accumulated head and fragments survive a NAPI poll boundary (mid-frame dma_own or dirty_rx break). The state is saved only while a frame is in progress and cleared once it completes, leaving it untouched when the poll does not process anything (e.g. netpoll invoked with a zero budget). In addition: - advertise NETDEV_XDP_ACT_RX_SG, since the RX path can now deliver non-linear buffers to XDP; - build the skb head with napi_build_skb() passing xdp->frame_sz, so skb_shinfo() lands on the same shared_info the fragments were accumulated into; - carry the XDP metadata written with bpf_xdp_adjust_meta() into the skb via skb_metadata_set(), so it is no longer dropped and TC/BPF programs can read it through data_meta; - attach fragments with xdp_buff_add_frag(), which initializes all the shared_info fields and takes care of the pfmemalloc bit; - charge fragments the whole page_pool page size (xdp->frame_sz) as truesize instead of the old dma_buf_sz; with SPH/buf2 most frames carry a fragment, so skb->truesize grows by roughly 1.5x on 4K pages and 2x on 64K pages, which reduces the effective socket receive buffer. The new value is more accurate now that a fragment is a full page_pool page, but it is a behavior change; - release the buffers collected in the xdp_buff when a frame is dropped on RX errors; the previous code relied on dev_kfree_skb() recycling the skb frags, which no longer applies now that the head and fragments live in an xdp_buff rather than a partially built skb; - drop the whole frame when it would exceed MAX_SKB_FRAGS, where the previous skb_add_rx_frag() calls were unbounded; - strip the Ethernet FCS from the accumulated xdp_buff with a driver-local tail shrink (stmmac_xdp_shrink_tail()) for both linear and fragmented frames, instead of trimming the skb or the first descriptor length. Signed-off-by: Lorenzo Bianconi <redacted>
[...]
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de> Thanks, Nicolai