From: "Michael S. Tsirkin" mst@redhat.com
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: 56a06bd40fab ("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 --- drivers/net/virtio_net.c | 15 +++++++++++++-- include/uapi/linux/virtio_net.h | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a757cbcab87f..5e998d88db44 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -2534,6 +2534,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, return NULL; }
+static inline u32 +virtio_net_hash_value(const struct virtio_net_hdr_v1_hash *hdr_hash) +{ + return __le16_to_cpu(hdr_hash->hash_value_lo) | + (__le16_to_cpu(hdr_hash->hash_value_hi) << 16); +} + static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash, struct sk_buff *skb) { @@ -2560,7 +2567,7 @@ static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash, default: rss_hash_type = PKT_HASH_TYPE_NONE; } - skb_set_hash(skb, __le32_to_cpu(hdr_hash->hash_value), rss_hash_type); + skb_set_hash(skb, virtio_net_hash_value(hdr_hash), rss_hash_type); }
static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *rq, @@ -3306,6 +3313,10 @@ 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);
+ /* Make sure it's safe to cast between formats */ + BUILD_BUG_ON(__alignof__(*hdr) != __alignof__(hdr->hash_hdr)); + BUILD_BUG_ON(__alignof__(*hdr) != __alignof__(hdr->hash_hdr.hdr)); + can_push = vi->any_header_sg && !((unsigned long)skb->data & (__alignof__(*hdr) - 1)) && !skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len; @@ -6745,7 +6756,7 @@ static int virtnet_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, hash_report = VIRTIO_NET_HASH_REPORT_NONE;
*rss_type = virtnet_xdp_rss_type[hash_report]; - *hash = __le32_to_cpu(hdr_hash->hash_value); + *hash = virtio_net_hash_value(hdr_hash); return 0; }
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h index 8bf27ab8bcb4..1db45b01532b 100644 --- a/include/uapi/linux/virtio_net.h +++ b/include/uapi/linux/virtio_net.h @@ -193,7 +193,8 @@ struct virtio_net_hdr_v1 {
struct virtio_net_hdr_v1_hash { struct virtio_net_hdr_v1 hdr; - __le32 hash_value; + __le16 hash_value_lo; + __le16 hash_value_hi; #define VIRTIO_NET_HASH_REPORT_NONE 0 #define VIRTIO_NET_HASH_REPORT_IPv4 1 #define VIRTIO_NET_HASH_REPORT_TCPv4 2
On 10/29/25 2:24 AM, Jason Wang wrote:
From: "Michael S. Tsirkin" mst@redhat.com
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: 56a06bd40fab ("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
Whoops, I replied to the older thread before reading this one.
Acked-by: Paolo Abeni pabeni@redhat.com
Hi Jason,
kernel test robot noticed the following build errors:
[auto build test ERROR on net/main]
url: https://github.com/intel-lab-lkp/linux/commits/Jason-Wang/virtio_net-fix-ali... base: net/main patch link: https://lore.kernel.org/r/20251029012434.75576-1-jasowang%40redhat.com patch subject: [PATCH net] virtio_net: fix alignment for virtio_net_hdr_v1_hash config: openrisc-defconfig (https://download.01.org/0day-ci/archive/20251029/202510292058.zgpkfnPq-lkp@i...) compiler: or1k-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251029/202510292058.zgpkfnPq-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202510292058.zgpkfnPq-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from net/packet/af_packet.c:86: include/linux/virtio_net.h: In function 'virtio_net_hdr_tnl_from_skb':
include/linux/virtio_net.h:404:24: error: 'struct virtio_net_hdr_v1_hash' has no member named 'hash_value'; did you mean 'hash_value_lo'?
404 | vhdr->hash_hdr.hash_value = 0; | ^~~~~~~~~~ | hash_value_lo
vim +404 include/linux/virtio_net.h
a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 376 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 377 /* a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 378 * vlan_hlen always refers to the outermost MAC header. That also a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 379 * means it refers to the only MAC header, if the packet does not carry a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 380 * any encapsulation. a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 381 */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 382 static inline int a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 383 virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 384 struct virtio_net_hdr_v1_hash_tunnel *vhdr, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 385 bool tnl_hdr_negotiated, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 386 bool little_endian, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 387 int vlan_hlen) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 388 { a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 389 struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)vhdr; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 390 unsigned int inner_nh, outer_th; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 391 int tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 392 int ret; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 393 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 394 tnl_gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 395 SKB_GSO_UDP_TUNNEL_CSUM); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 396 if (!tnl_gso_type) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 397 return virtio_net_hdr_from_skb(skb, hdr, little_endian, false, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 398 vlan_hlen); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 399 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 400 /* Tunnel support not negotiated but skb ask for it. */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 401 if (!tnl_hdr_negotiated) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 402 return -EINVAL; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 403 b2284768c6b32a Jason Wang 2025-10-22 @404 vhdr->hash_hdr.hash_value = 0; b2284768c6b32a Jason Wang 2025-10-22 405 vhdr->hash_hdr.hash_report = 0; b2284768c6b32a Jason Wang 2025-10-22 406 vhdr->hash_hdr.padding = 0; b2284768c6b32a Jason Wang 2025-10-22 407 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 408 /* Let the basic parsing deal with plain GSO features. */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 409 skb_shinfo(skb)->gso_type &= ~tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 410 ret = virtio_net_hdr_from_skb(skb, hdr, true, false, vlan_hlen); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 411 skb_shinfo(skb)->gso_type |= tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 412 if (ret) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 413 return ret; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 414 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 415 if (skb->protocol == htons(ETH_P_IPV6)) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 416 hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 417 else a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 418 hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 419 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 420 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 421 hdr->flags |= VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 422 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 423 inner_nh = skb->inner_network_header - skb_headroom(skb); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 424 outer_th = skb->transport_header - skb_headroom(skb); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 425 vhdr->inner_nh_offset = cpu_to_le16(inner_nh); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 426 vhdr->outer_th_offset = cpu_to_le16(outer_th); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 427 return 0; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 428 } a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 429
Hi Jason,
kernel test robot noticed the following build errors:
[auto build test ERROR on net/main]
url: https://github.com/intel-lab-lkp/linux/commits/Jason-Wang/virtio_net-fix-ali... base: net/main patch link: https://lore.kernel.org/r/20251029012434.75576-1-jasowang%40redhat.com patch subject: [PATCH net] virtio_net: fix alignment for virtio_net_hdr_v1_hash config: x86_64-kexec (https://download.01.org/0day-ci/archive/20251029/202510292352.dvaYVyZt-lkp@i...) compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251029/202510292352.dvaYVyZt-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202510292352.dvaYVyZt-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from net/packet/af_packet.c:86:
include/linux/virtio_net.h:404:24: error: no member named 'hash_value' in 'struct virtio_net_hdr_v1_hash'
404 | vhdr->hash_hdr.hash_value = 0; | ~~~~~~~~~~~~~~ ^ 1 error generated.
vim +404 include/linux/virtio_net.h
a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 376 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 377 /* a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 378 * vlan_hlen always refers to the outermost MAC header. That also a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 379 * means it refers to the only MAC header, if the packet does not carry a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 380 * any encapsulation. a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 381 */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 382 static inline int a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 383 virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 384 struct virtio_net_hdr_v1_hash_tunnel *vhdr, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 385 bool tnl_hdr_negotiated, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 386 bool little_endian, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 387 int vlan_hlen) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 388 { a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 389 struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)vhdr; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 390 unsigned int inner_nh, outer_th; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 391 int tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 392 int ret; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 393 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 394 tnl_gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 395 SKB_GSO_UDP_TUNNEL_CSUM); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 396 if (!tnl_gso_type) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 397 return virtio_net_hdr_from_skb(skb, hdr, little_endian, false, a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 398 vlan_hlen); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 399 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 400 /* Tunnel support not negotiated but skb ask for it. */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 401 if (!tnl_hdr_negotiated) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 402 return -EINVAL; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 403 b2284768c6b32a Jason Wang 2025-10-22 @404 vhdr->hash_hdr.hash_value = 0; b2284768c6b32a Jason Wang 2025-10-22 405 vhdr->hash_hdr.hash_report = 0; b2284768c6b32a Jason Wang 2025-10-22 406 vhdr->hash_hdr.padding = 0; b2284768c6b32a Jason Wang 2025-10-22 407 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 408 /* Let the basic parsing deal with plain GSO features. */ a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 409 skb_shinfo(skb)->gso_type &= ~tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 410 ret = virtio_net_hdr_from_skb(skb, hdr, true, false, vlan_hlen); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 411 skb_shinfo(skb)->gso_type |= tnl_gso_type; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 412 if (ret) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 413 return ret; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 414 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 415 if (skb->protocol == htons(ETH_P_IPV6)) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 416 hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 417 else a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 418 hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 419 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 420 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 421 hdr->flags |= VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 422 a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 423 inner_nh = skb->inner_network_header - skb_headroom(skb); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 424 outer_th = skb->transport_header - skb_headroom(skb); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 425 vhdr->inner_nh_offset = cpu_to_le16(inner_nh); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 426 vhdr->outer_th_offset = cpu_to_le16(outer_th); a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 427 return 0; a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 428 } a2fb4bc4e2a6a0 Paolo Abeni 2025-07-08 429
linux-stable-mirror@lists.linaro.org