Message ID | 20221220141449.115918-8-hengqi@linux.alibaba.com (mailing list archive) |
---|---|
State | Deferred |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | virtio_net: support multi buffer xdp | expand |
在 2022/12/20 22:14, Heng Qi 写道: > 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> > --- > drivers/net/virtio_net.c | 50 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 50 insertions(+) > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c > index 9f31bfa7f9a6..4e12196fcfd4 100644 > --- a/drivers/net/virtio_net.c > +++ b/drivers/net/virtio_net.c > @@ -948,6 +948,56 @@ static struct sk_buff *receive_big(struct net_device *dev, > return NULL; > } > > +/* Why not use xdp_build_skb_from_frame() ? > + * XDP core assumes that xdp frags are PAGE_SIZE in length, while in > + * virtio-net there are 2 points that do not match its requirements: > + * 1. The size of the prefilled buffer is not fixed before xdp is set. > + * 2. When xdp is loaded, virtio-net has a hole mechanism (refer to > + * add_recvbuf_mergeable()), which will make the size of a buffer > + * exceed PAGE_SIZE. Is point 2 still valid after patch 1? Other than this: Acked-by: Jason Wang <jasowang@redhat.com> Thanks > + */ > +static struct sk_buff *build_skb_from_xdp_buff(struct net_device *dev, > + struct virtnet_info *vi, > + struct xdp_buff *xdp, > + unsigned int xdp_frags_truesz) > +{ > + struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); > + unsigned int headroom, data_len; > + struct sk_buff *skb; > + int metasize; > + u8 nr_frags; > + > + if (unlikely(xdp->data_end > xdp_data_hard_end(xdp))) { > + pr_debug("Error building skb as missing reserved tailroom for xdp"); > + return NULL; > + } > + > + if (unlikely(xdp_buff_has_frags(xdp))) > + nr_frags = sinfo->nr_frags; > + > + skb = build_skb(xdp->data_hard_start, xdp->frame_sz); > + if (unlikely(!skb)) > + return NULL; > + > + headroom = xdp->data - xdp->data_hard_start; > + data_len = xdp->data_end - xdp->data; > + skb_reserve(skb, headroom); > + __skb_put(skb, data_len); > + > + metasize = xdp->data - xdp->data_meta; > + metasize = metasize > 0 ? metasize : 0; > + if (metasize) > + skb_metadata_set(skb, metasize); > + > + if (unlikely(xdp_buff_has_frags(xdp))) > + xdp_update_skb_shared_info(skb, nr_frags, > + sinfo->xdp_frags_size, > + xdp_frags_truesz, > + xdp_buff_is_frag_pfmemalloc(xdp)); > + > + return skb; > +} > + > /* TODO: build xdp in big mode */ > static int virtnet_build_xdp_buff_mrg(struct net_device *dev, > struct virtnet_info *vi,
在 2022/12/27 下午3:31, Jason Wang 写道: > > 在 2022/12/20 22:14, Heng Qi 写道: >> 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> >> --- >> drivers/net/virtio_net.c | 50 ++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 50 insertions(+) >> >> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c >> index 9f31bfa7f9a6..4e12196fcfd4 100644 >> --- a/drivers/net/virtio_net.c >> +++ b/drivers/net/virtio_net.c >> @@ -948,6 +948,56 @@ static struct sk_buff *receive_big(struct >> net_device *dev, >> return NULL; >> } >> +/* Why not use xdp_build_skb_from_frame() ? >> + * XDP core assumes that xdp frags are PAGE_SIZE in length, while in >> + * virtio-net there are 2 points that do not match its requirements: >> + * 1. The size of the prefilled buffer is not fixed before xdp is set. >> + * 2. When xdp is loaded, virtio-net has a hole mechanism (refer to >> + * add_recvbuf_mergeable()), which will make the size of a buffer >> + * exceed PAGE_SIZE. > > > Is point 2 still valid after patch 1? Yes, it is invalid anymore, I'll correct that, and there's a little more reason that xdp_build_skb_from_frame() does more checks that we don't need, like eth_type_trans() (which virtio-net does in receive_buf()). > > Other than this: > > Acked-by: Jason Wang <jasowang@redhat.com> Thanks for your energy. > > Thanks > > >> + */ >> +static struct sk_buff *build_skb_from_xdp_buff(struct net_device *dev, >> + struct virtnet_info *vi, >> + struct xdp_buff *xdp, >> + unsigned int xdp_frags_truesz) >> +{ >> + struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); >> + unsigned int headroom, data_len; >> + struct sk_buff *skb; >> + int metasize; >> + u8 nr_frags; >> + >> + if (unlikely(xdp->data_end > xdp_data_hard_end(xdp))) { >> + pr_debug("Error building skb as missing reserved tailroom >> for xdp"); >> + return NULL; >> + } >> + >> + if (unlikely(xdp_buff_has_frags(xdp))) >> + nr_frags = sinfo->nr_frags; >> + >> + skb = build_skb(xdp->data_hard_start, xdp->frame_sz); >> + if (unlikely(!skb)) >> + return NULL; >> + >> + headroom = xdp->data - xdp->data_hard_start; >> + data_len = xdp->data_end - xdp->data; >> + skb_reserve(skb, headroom); >> + __skb_put(skb, data_len); >> + >> + metasize = xdp->data - xdp->data_meta; >> + metasize = metasize > 0 ? metasize : 0; >> + if (metasize) >> + skb_metadata_set(skb, metasize); >> + >> + if (unlikely(xdp_buff_has_frags(xdp))) >> + xdp_update_skb_shared_info(skb, nr_frags, >> + sinfo->xdp_frags_size, >> + xdp_frags_truesz, >> + xdp_buff_is_frag_pfmemalloc(xdp)); >> + >> + return skb; >> +} >> + >> /* TODO: build xdp in big mode */ >> static int virtnet_build_xdp_buff_mrg(struct net_device *dev, >> struct virtnet_info *vi,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9f31bfa7f9a6..4e12196fcfd4 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -948,6 +948,56 @@ static struct sk_buff *receive_big(struct net_device *dev, return NULL; } +/* Why not use xdp_build_skb_from_frame() ? + * XDP core assumes that xdp frags are PAGE_SIZE in length, while in + * virtio-net there are 2 points that do not match its requirements: + * 1. The size of the prefilled buffer is not fixed before xdp is set. + * 2. When xdp is loaded, virtio-net has a hole mechanism (refer to + * add_recvbuf_mergeable()), which will make the size of a buffer + * exceed PAGE_SIZE. + */ +static struct sk_buff *build_skb_from_xdp_buff(struct net_device *dev, + struct virtnet_info *vi, + struct xdp_buff *xdp, + unsigned int xdp_frags_truesz) +{ + struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); + unsigned int headroom, data_len; + struct sk_buff *skb; + int metasize; + u8 nr_frags; + + if (unlikely(xdp->data_end > xdp_data_hard_end(xdp))) { + pr_debug("Error building skb as missing reserved tailroom for xdp"); + return NULL; + } + + if (unlikely(xdp_buff_has_frags(xdp))) + nr_frags = sinfo->nr_frags; + + skb = build_skb(xdp->data_hard_start, xdp->frame_sz); + if (unlikely(!skb)) + return NULL; + + headroom = xdp->data - xdp->data_hard_start; + data_len = xdp->data_end - xdp->data; + skb_reserve(skb, headroom); + __skb_put(skb, data_len); + + metasize = xdp->data - xdp->data_meta; + metasize = metasize > 0 ? metasize : 0; + if (metasize) + skb_metadata_set(skb, metasize); + + if (unlikely(xdp_buff_has_frags(xdp))) + xdp_update_skb_shared_info(skb, nr_frags, + sinfo->xdp_frags_size, + xdp_frags_truesz, + xdp_buff_is_frag_pfmemalloc(xdp)); + + return skb; +} + /* TODO: build xdp in big mode */ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, struct virtnet_info *vi,