Commit 56a06bd40fab ("virtio_net: enable gso over UDP tunnel support.") switches to check the alignment of the virtio_net_hdr_v1_hash_tunnel even when doing the transmission even if the feature is not negotiated. This will cause a series performance degradation of pktgen as the skb->data can't satisfy the alignment requirement due to the increase of the header size then virtio-net must prepare at least 2 sgs with indirect descriptors which will introduce overheads in the device.
Fixing this by calculate the header alignment during probe so when tunnel gso is not negotiated, we can less strict.
Pktgen in guest + XDP_DROP on TAP + vhost_net shows the TX PPS is recovered from 2.4Mpps to 4.45Mpps.
Note that we still need a way to recover the performance when tunnel gso is enabled, probably a new vnet header format.
Fixes: 56a06bd40fab ("virtio_net: enable gso over UDP tunnel support.") Cc: stable@vger.kernel.org Signed-off-by: Jason Wang jasowang@redhat.com --- drivers/net/virtio_net.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 31bd32bdecaf..5b851df749c0 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -441,6 +441,9 @@ struct virtnet_info { /* Packet virtio header size */ u8 hdr_len;
+ /* header alignment */ + size_t hdr_align; + /* Work struct for delayed refilling if we run low on memory. */ struct delayed_work refill;
@@ -3308,8 +3311,9 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan) pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
can_push = vi->any_header_sg && - !((unsigned long)skb->data & (__alignof__(*hdr) - 1)) && + !((unsigned long)skb->data & (vi->hdr_align - 1)) && !skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len; + /* Even if we can, don't push here yet as this would skew * csum_start offset below. */ if (can_push) @@ -6926,15 +6930,20 @@ static int virtnet_probe(struct virtio_device *vdev) }
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) || - virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO)) + virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO)) { vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash_tunnel); - else if (vi->has_rss_hash_report) + vi->hdr_align = __alignof__(struct virtio_net_hdr_v1_hash_tunnel); + } else if (vi->has_rss_hash_report) { vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash); - else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) || - virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + vi->hdr_align = __alignof__(struct virtio_net_hdr_v1_hash); + } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) || + virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); - else + vi->hdr_align = __alignof__(struct virtio_net_hdr_mrg_rxbuf); + } else { vi->hdr_len = sizeof(struct virtio_net_hdr); + vi->hdr_align = __alignof__(struct virtio_net_hdr); + }
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM)) vi->rx_tnl_csum = true;