Re: [Intel-wired-lan] [PATCH net] i40e: xsk: fix multi-buffer XDP_PASS skb construction
"Loktionov, Aleksandr" <[email protected]> Wed, 15 Jul 2026 09:37:42 +0000
| Newsgroups | org.osuosl.intel-wired-lan,org.kernel.vger.netdev |
|---|---|
| Message-ID | <IA3PR11MB8986AD34DC026A4FB3946407E5F82@IA3PR11MB8986.namprd11.prod.outlook.com> |
> -----Original Message----- > From: Intel-wired-lan <[email protected]> On Behalf > Of Chenguang Zhao > Sent: Tuesday, July 14, 2026 4:51 AM > To: Nguyen, Anthony L <[email protected]>; Kitszel, > Przemyslaw <[email protected]>; [email protected]; > [email protected]; [email protected]; [email protected]; > [email protected] > Cc: [email protected]; [email protected]; > [email protected]; Chenguang Zhao <[email protected]> > Subject: [Intel-wired-lan] [PATCH net] i40e: xsk: fix multi-buffer > XDP_PASS skb construction > > From: Chenguang Zhao <[email protected]> > > When AF_XDP ZC receives a multi-buffer frame and the XDP program > returns XDP_PASS, i40e_construct_skb_zc() copies frags into a new skb. > The copy used skb_frag_page() as the memcpy source (page metadata > instead of packet data) and passed a virtual address to > __skb_fill_page_desc_noacc(), which expects a struct page *. > > Use skb_frag_address() for the copy, attach frags with > skb_add_rx_frag() so len/data_len/truesize are updated, and on > dev_alloc_page() failure free the skb via the shared out path so > xsk_buff_free() still runs and previously attached pages are released > by kfree_skb. > > Fixes: 1c9ba9c14658 ("i40e: xsk: add RX multi-buffer support") > Signed-off-by: Chenguang Zhao <[email protected]> > --- > - Fix memcpy source: use skb_frag_address() instead of > skb_frag_page(), > which was copying page metadata rather than packet data. > > - Fix frag attachment: pass the allocated struct page * to the skb > frag > helper instead of the page virtual address. > > - Use skb_add_rx_frag() so skb->len, data_len and truesize are > updated > when attaching copied frags. > > - On mid-loop dev_alloc_page() failure, go through the shared out > path > so previously attached pages are released via kfree_skb and > xsk_buff_free() is still called. > > drivers/net/ethernet/intel/i40e/i40e_xsk.c | 13 +++++-------- > 1 file changed, 5 insertions(+), 8 deletions(-) > > diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c > b/drivers/net/ethernet/intel/i40e/i40e_xsk.c > index 9f47388eaba5..a4247710c85b 100644 > --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c > +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c > @@ -318,22 +318,19 @@ static struct sk_buff > *i40e_construct_skb_zc(struct i40e_ring *rx_ring, > goto out; > > for (int i = 0; i < nr_frags; i++) { > - struct skb_shared_info *skinfo = skb_shinfo(skb); > skb_frag_t *frag = &sinfo->frags[i]; > + unsigned int frag_size = skb_frag_size(frag); > struct page *page; > - void *addr; > > page = dev_alloc_page(); > if (!page) { > dev_kfree_skb(skb); > - return NULL; > + skb = NULL; > + goto out; > } > - addr = page_to_virt(page); > > - memcpy(addr, skb_frag_page(frag), skb_frag_size(frag)); > - > - __skb_fill_page_desc_noacc(skinfo, skinfo->nr_frags++, > - addr, 0, skb_frag_size(frag)); > + memcpy(page_to_virt(page), skb_frag_address(frag), > frag_size); > + skb_add_rx_frag(skb, i, page, 0, frag_size, PAGE_SIZE); > } > > out: > -- > 2.25.1 Reviewed-by: Aleksandr Loktionov <[email protected]>