Introduce xdp_update_skb_shared_info routine to update frags array metadata from a given xdp_buffer/xdp_frame. We do not need to reset frags array since it is already initialized by the driver. Rely on xdp_update_skb_shared_info in mvneta driver. Suggested-by: Alexander Duyck <alexander.duyck@xxxxxxxxx> Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> --- drivers/net/ethernet/marvell/mvneta.c | 29 +++++++++++++++------------ include/net/xdp.h | 3 +++ net/core/xdp.c | 27 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 361bc4fbe20b..abf2e50880e0 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2294,18 +2294,29 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, rx_desc->buf_phys_addr = 0; if (data_len > 0 && xdp_sinfo->nr_frags < MAX_SKB_FRAGS) { - skb_frag_t *frag = &xdp_sinfo->frags[xdp_sinfo->nr_frags++]; + skb_frag_t *frag = &xdp_sinfo->frags[xdp_sinfo->nr_frags]; skb_frag_off_set(frag, pp->rx_offset_correction); skb_frag_size_set(frag, data_len); __skb_frag_set_page(frag, page); + /* We don't need to reset pp_recycle here. It's already set, so + * just mark fragments for recycling. + */ + page_pool_store_mem_info(page, rxq->page_pool); + + /* first fragment */ + if (!xdp_sinfo->nr_frags) + xdp_sinfo->gso_type = *size; + xdp_sinfo->nr_frags++; /* last fragment */ if (len == *size) { struct skb_shared_info *sinfo; sinfo = xdp_get_shared_info_from_buff(xdp); + sinfo->xdp_frags_tsize = xdp_sinfo->nr_frags * PAGE_SIZE; sinfo->nr_frags = xdp_sinfo->nr_frags; + sinfo->gso_type = xdp_sinfo->gso_type; memcpy(sinfo->frags, xdp_sinfo->frags, sinfo->nr_frags * sizeof(skb_frag_t)); } @@ -2320,7 +2331,7 @@ mvneta_swbm_build_skb(struct mvneta_port *pp, struct page_pool *pool, struct xdp_buff *xdp, u32 desc_status) { struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); - int i, num_frags = sinfo->nr_frags; + int num_frags = sinfo->nr_frags, size = sinfo->gso_type; struct sk_buff *skb; skb = build_skb(xdp->data_hard_start, PAGE_SIZE); @@ -2333,17 +2344,9 @@ mvneta_swbm_build_skb(struct mvneta_port *pp, struct page_pool *pool, skb_put(skb, xdp->data_end - xdp->data); skb->ip_summed = mvneta_rx_csum(pp, desc_status); - for (i = 0; i < num_frags; i++) { - skb_frag_t *frag = &sinfo->frags[i]; - - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - skb_frag_page(frag), skb_frag_off(frag), - skb_frag_size(frag), PAGE_SIZE); - /* We don't need to reset pp_recycle here. It's already set, so - * just mark fragments for recycling. - */ - page_pool_store_mem_info(skb_frag_page(frag), pool); - } + if (num_frags) + xdp_update_skb_shared_info(skb, num_frags, size, + sinfo->xdp_frags_tsize, sinfo); return skb; } diff --git a/include/net/xdp.h b/include/net/xdp.h index ad5b02dcb6f4..08d151ea8400 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -164,6 +164,9 @@ void xdp_warn(const char *msg, const char *func, const int line); #define XDP_WARN(msg) xdp_warn(msg, __func__, __LINE__) struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp); +void xdp_update_skb_shared_info(struct sk_buff *skb, int nr_frags, + int size, int truesize, + struct skb_shared_info *sinfo); struct sk_buff *__xdp_build_skb_from_frame(struct xdp_frame *xdpf, struct sk_buff *skb, struct net_device *dev); diff --git a/net/core/xdp.c b/net/core/xdp.c index cc92ccb38432..3f44c69e1f56 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -527,6 +527,33 @@ int xdp_alloc_skb_bulk(void **skbs, int n_skb, gfp_t gfp) } EXPORT_SYMBOL_GPL(xdp_alloc_skb_bulk); +void xdp_update_skb_shared_info(struct sk_buff *skb, int nr_frags, + int size, int truesize, + struct skb_shared_info *sinfo) +{ + int i; + + skb_shinfo(skb)->nr_frags = nr_frags; + + skb->len += size; + skb->data_len += size; + skb->truesize += truesize; + + if (skb->pfmemalloc) + return; + + for (i = 0; i < nr_frags; i++) { + struct page *page = skb_frag_page(&sinfo->frags[i]); + + page = compound_head(page); + if (page_is_pfmemalloc(page)) { + skb->pfmemalloc = true; + break; + } + } +} +EXPORT_SYMBOL_GPL(xdp_update_skb_shared_info); + struct sk_buff *__xdp_build_skb_from_frame(struct xdp_frame *xdpf, struct sk_buff *skb, struct net_device *dev) -- 2.31.1