在 2021/4/2 下午7:00, Xuan Zhuo 写道:
On Fri, 2 Apr 2021 10:52:12 +0800, Jason Wang <[email protected]> wrote:
So I wonder something like the following like this help. We know the
frag size, that means, if we know there's sufficient tailroom we can use
build_skb() without reserving dedicated room for skb_shared_info.
Thanks
Do you mean so?
I have also considered this scenario, although build_skb is not always used, but
it is also very good for the right situation.
Something like this. Would you mind to post a formal patch to net-next
with some perf numbers?
Thanks
Thanks.
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bb4ea9dbc16b..3db207c67422 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -383,17 +383,12 @@ static struct sk_buff *page_to_skb(struct virtnet_info
*vi,
{
struct sk_buff *skb;
struct virtio_net_hdr_mrg_rxbuf *hdr;
- unsigned int copy, hdr_len, hdr_padded_len;
- char *p;
+ unsigned int copy, hdr_len, hdr_padded_len, shinfo_size;
+ char *p, *hdr_p;
p = page_address(page) + offset;
+ hdr_p = p;
- /* copy small packet so we can reuse these pages for small data */
- skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN);
- if (unlikely(!skb))
- return NULL;
-
- hdr = skb_vnet_hdr(skb);
hdr_len = vi->hdr_len;
if (vi->mergeable_rx_bufs)
@@ -401,27 +396,57 @@ static struct sk_buff *page_to_skb(struct virtnet_info
*vi,
else
hdr_padded_len = sizeof(struct padded_vnet_hdr);
- /* hdr_valid means no XDP, so we can copy the vnet header */
- if (hdr_valid)
- memcpy(hdr, p, hdr_len);
-
len -= hdr_len;
offset += hdr_padded_len;
p += hdr_padded_len;
- copy = len;
- if (copy > skb_tailroom(skb))
- copy = skb_tailroom(skb);
- skb_put_data(skb, p, copy);
+ shinfo_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ if (truesize - len - hdr_len >= shinfo_size && len > GOOD_COPY_LEN) {
+ skb = build_skb(p, truesize);
+ if (unlikely(!skb))
+ return NULL;
+
+ skb_put(skb, len);
+
+ /* hdr_valid means no XDP, so we can copy the vnet header */
+ if (hdr_valid) {
+ hdr = skb_vnet_hdr(skb);
+ memcpy(hdr, hdr_p, hdr_len);
+ }
+
+ if (metasize) {
+ __skb_pull(skb, metasize);
+ skb_metadata_set(skb, metasize);
+ }
+
+ return skb;
+ } else {
+ /* copy small packet so we can reuse these pages for small data
*/
+ skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN);
+ if (unlikely(!skb))
+ return NULL;
+
+ copy = len;
+ if (copy > skb_tailroom(skb))
+ copy = skb_tailroom(skb);
+ skb_put_data(skb, p, copy);
+
+ len -= copy;
+ offset += copy;
+ }
+
+ hdr = skb_vnet_hdr(skb);
+
+ /* hdr_valid means no XDP, so we can copy the vnet header */
+ if (hdr_valid)
+ memcpy(hdr, hdr_p, hdr_len);
if (metasize) {
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}
- len -= copy;
- offset += copy;
-
if (vi->mergeable_rx_bufs) {
if (len)
skb_add_rx_frag(skb, 0, page, offset, len, truesize);