Skip to content

Commit c383826

Browse files
mstsirkinkuba-moo
authored andcommitted
virtio_net: fix alignment for virtio_net_hdr_v1_hash
Changing alignment of header would mean it's no longer safe to cast a 2 byte aligned pointer between formats. Use two 16 bit fields to make it 2 byte aligned as previously. This fixes the performance regression since commit ("virtio_net: enable gso over UDP tunnel support.") as it uses virtio_net_hdr_v1_hash_tunnel which embeds virtio_net_hdr_v1_hash. Pktgen in guest + XDP_DROP on TAP + vhost_net shows the TX PPS is recovered from 2.4Mpps to 4.45Mpps. Fixes: 56a06bd ("virtio_net: enable gso over UDP tunnel support.") Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Tested-by: Lei Yang <leiyang@redhat.com> Link: https://patch.msgid.link/20251031060551.126-1-jasowang@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent e120f46 commit c383826

File tree

3 files changed

+17
-4
lines changed

3 files changed

+17
-4
lines changed

drivers/net/virtio_net.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,6 +2539,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
25392539
return NULL;
25402540
}
25412541

2542+
static inline u32
2543+
virtio_net_hash_value(const struct virtio_net_hdr_v1_hash *hdr_hash)
2544+
{
2545+
return __le16_to_cpu(hdr_hash->hash_value_lo) |
2546+
(__le16_to_cpu(hdr_hash->hash_value_hi) << 16);
2547+
}
2548+
25422549
static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
25432550
struct sk_buff *skb)
25442551
{
@@ -2565,7 +2572,7 @@ static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
25652572
default:
25662573
rss_hash_type = PKT_HASH_TYPE_NONE;
25672574
}
2568-
skb_set_hash(skb, __le32_to_cpu(hdr_hash->hash_value), rss_hash_type);
2575+
skb_set_hash(skb, virtio_net_hash_value(hdr_hash), rss_hash_type);
25692576
}
25702577

25712578
static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *rq,
@@ -3311,6 +3318,10 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
33113318

33123319
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
33133320

3321+
/* Make sure it's safe to cast between formats */
3322+
BUILD_BUG_ON(__alignof__(*hdr) != __alignof__(hdr->hash_hdr));
3323+
BUILD_BUG_ON(__alignof__(*hdr) != __alignof__(hdr->hash_hdr.hdr));
3324+
33143325
can_push = vi->any_header_sg &&
33153326
!((unsigned long)skb->data & (__alignof__(*hdr) - 1)) &&
33163327
!skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len;
@@ -6750,7 +6761,7 @@ static int virtnet_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
67506761
hash_report = VIRTIO_NET_HASH_REPORT_NONE;
67516762

67526763
*rss_type = virtnet_xdp_rss_type[hash_report];
6753-
*hash = __le32_to_cpu(hdr_hash->hash_value);
6764+
*hash = virtio_net_hash_value(hdr_hash);
67546765
return 0;
67556766
}
67566767

include/linux/virtio_net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,8 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
401401
if (!tnl_hdr_negotiated)
402402
return -EINVAL;
403403

404-
vhdr->hash_hdr.hash_value = 0;
404+
vhdr->hash_hdr.hash_value_lo = 0;
405+
vhdr->hash_hdr.hash_value_hi = 0;
405406
vhdr->hash_hdr.hash_report = 0;
406407
vhdr->hash_hdr.padding = 0;
407408

include/uapi/linux/virtio_net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ struct virtio_net_hdr_v1 {
193193

194194
struct virtio_net_hdr_v1_hash {
195195
struct virtio_net_hdr_v1 hdr;
196-
__le32 hash_value;
196+
__le16 hash_value_lo;
197+
__le16 hash_value_hi;
197198
#define VIRTIO_NET_HASH_REPORT_NONE 0
198199
#define VIRTIO_NET_HASH_REPORT_IPv4 1
199200
#define VIRTIO_NET_HASH_REPORT_TCPv4 2

0 commit comments

Comments
 (0)