Skip to content

Commit b26aa48

Browse files
Heng Qidavem330
authored andcommitted
virtio-net: build skb from multi-buffer xdp
This converts the xdp_buff directly to a skb, including multi-buffer and single buffer xdp. We'll isolate the construction of skb based on xdp from page_to_skb(). Signed-off-by: Heng Qi <hengqi@linux.alibaba.com> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 97717e8 commit b26aa48

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

drivers/net/virtio_net.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,55 @@ static struct sk_buff *receive_big(struct net_device *dev,
959959
return NULL;
960960
}
961961

962+
/* Why not use xdp_build_skb_from_frame() ?
963+
* XDP core assumes that xdp frags are PAGE_SIZE in length, while in
964+
* virtio-net there are 2 points that do not match its requirements:
965+
* 1. The size of the prefilled buffer is not fixed before xdp is set.
966+
* 2. xdp_build_skb_from_frame() does more checks that we don't need,
967+
* like eth_type_trans() (which virtio-net does in receive_buf()).
968+
*/
969+
static struct sk_buff *build_skb_from_xdp_buff(struct net_device *dev,
970+
struct virtnet_info *vi,
971+
struct xdp_buff *xdp,
972+
unsigned int xdp_frags_truesz)
973+
{
974+
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
975+
unsigned int headroom, data_len;
976+
struct sk_buff *skb;
977+
int metasize;
978+
u8 nr_frags;
979+
980+
if (unlikely(xdp->data_end > xdp_data_hard_end(xdp))) {
981+
pr_debug("Error building skb as missing reserved tailroom for xdp");
982+
return NULL;
983+
}
984+
985+
if (unlikely(xdp_buff_has_frags(xdp)))
986+
nr_frags = sinfo->nr_frags;
987+
988+
skb = build_skb(xdp->data_hard_start, xdp->frame_sz);
989+
if (unlikely(!skb))
990+
return NULL;
991+
992+
headroom = xdp->data - xdp->data_hard_start;
993+
data_len = xdp->data_end - xdp->data;
994+
skb_reserve(skb, headroom);
995+
__skb_put(skb, data_len);
996+
997+
metasize = xdp->data - xdp->data_meta;
998+
metasize = metasize > 0 ? metasize : 0;
999+
if (metasize)
1000+
skb_metadata_set(skb, metasize);
1001+
1002+
if (unlikely(xdp_buff_has_frags(xdp)))
1003+
xdp_update_skb_shared_info(skb, nr_frags,
1004+
sinfo->xdp_frags_size,
1005+
xdp_frags_truesz,
1006+
xdp_buff_is_frag_pfmemalloc(xdp));
1007+
1008+
return skb;
1009+
}
1010+
9621011
/* TODO: build xdp in big mode */
9631012
static int virtnet_build_xdp_buff_mrg(struct net_device *dev,
9641013
struct virtnet_info *vi,

0 commit comments

Comments
 (0)