From: "Michael S. Tsirkin" <mst@redhat.com>
To: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Cc: netdev@vger.kernel.org,
"Willem de Bruijn" <willemdebruijn.kernel@gmail.com>,
"Jason Wang" <jasowang@redhat.com>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Jiri Pirko" <jiri@resnulli.us>,
"Alvaro Karsz" <alvaro.karsz@solid-run.com>,
virtualization@lists.linux.dev
Subject: Re: [PATCH net v6 1/2] virtio-net: correct hdr_len handling for VIRTIO_NET_F_GUEST_HDRLEN
Date: Wed, 19 Nov 2025 10:27:46 -0500 [thread overview]
Message-ID: <20251119102708-mutt-send-email-mst@kernel.org> (raw)
In-Reply-To: <20251119055522.617-2-xuanzhuo@linux.alibaba.com>
On Wed, Nov 19, 2025 at 01:55:21PM +0800, Xuan Zhuo wrote:
> The commit be50da3e9d4a ("net: virtio_net: implement exact header length
> guest feature") introduces support for the VIRTIO_NET_F_GUEST_HDRLEN
> feature in virtio-net.
>
> This feature requires virtio-net to set hdr_len to the actual header
> length of the packet when transmitting, the number of
> bytes from the start of the packet to the beginning of the
> transport-layer payload.
>
> However, in practice, hdr_len was being set using skb_headlen(skb),
> which is clearly incorrect. This commit fixes that issue.
>
> Fixes: be50da3e9d4a ("net: virtio_net: implement exact header length guest feature")
> Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
> ---
> drivers/net/tun_vnet.h | 2 +-
> drivers/net/virtio_net.c | 8 ++++--
> include/linux/virtio_net.h | 58 ++++++++++++++++++++++++++++++--------
> 3 files changed, 54 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
> index 81662328b2c7..b06aa6f2aade 100644
> --- a/drivers/net/tun_vnet.h
> +++ b/drivers/net/tun_vnet.h
> @@ -244,7 +244,7 @@ tun_vnet_hdr_tnl_from_skb(unsigned int flags,
>
> if (virtio_net_hdr_tnl_from_skb(skb, tnl_hdr, has_tnl_offload,
> tun_vnet_is_little_endian(flags),
> - vlan_hlen)) {
> + false, vlan_hlen)) {
> struct virtio_net_hdr_v1 *hdr = &tnl_hdr->hash_hdr.hdr;
> struct skb_shared_info *sinfo = skb_shinfo(skb);
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 0369dda5ed60..a62acfaf631b 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -3317,9 +3317,12 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
> const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
> struct virtnet_info *vi = sq->vq->vdev->priv;
> struct virtio_net_hdr_v1_hash_tunnel *hdr;
> - int num_sg;
> unsigned hdr_len = vi->hdr_len;
> + bool guest_hdrlen;
> bool can_push;
> + int num_sg;
> +
> + guest_hdrlen = virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_HDRLEN);
>
> pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
>
> @@ -3339,7 +3342,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
> hdr = &skb_vnet_common_hdr(skb)->tnl_hdr;
>
> if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl,
> - virtio_is_little_endian(vi->vdev), 0))
> + virtio_is_little_endian(vi->vdev),
> + guest_hdrlen, 0))
> return -EPROTO;
>
> if (vi->mergeable_rx_bufs)
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index b673c31569f3..ee960ec9a35e 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -207,20 +207,40 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
> return __virtio_net_hdr_to_skb(skb, hdr, little_endian, hdr->gso_type);
> }
>
> -static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> - struct virtio_net_hdr *hdr,
> - bool little_endian,
> - bool has_data_valid,
> - int vlan_hlen)
> +static inline void virtio_net_set_hdrlen(const struct sk_buff *skb,
> + struct virtio_net_hdr *hdr,
> + bool little_endian,
> + bool guest_hdrlen)
> +{
> + u16 hdr_len;
> +
> + if (guest_hdrlen) {
> + hdr_len = skb_transport_offset(skb);
> +
> + if (hdr->gso_type == VIRTIO_NET_HDR_GSO_UDP_L4)
> + hdr_len += sizeof(struct udphdr);
> + else
> + hdr_len += tcp_hdrlen(skb);
> + } else {
> + /* This is a hint as to how much should be linear. */
> + hdr_len = skb_headlen(skb);
> + }
> +
> + hdr->hdr_len = __cpu_to_virtio16(little_endian, hdr_len);
> +}
So this adds code that is broken for tunnels, then the follow up patch
fixes it up. I don't feel it's worth it, just squash the two patches
together please.
> +
> +static inline int __virtio_net_hdr_from_skb(const struct sk_buff *skb,
> + struct virtio_net_hdr *hdr,
> + bool little_endian,
> + bool has_data_valid,
> + bool guest_hdrlen,
> + int vlan_hlen)
> {
> memset(hdr, 0, sizeof(*hdr)); /* no info leak */
>
> if (skb_is_gso(skb)) {
> struct skb_shared_info *sinfo = skb_shinfo(skb);
>
> - /* This is a hint as to how much should be linear. */
> - hdr->hdr_len = __cpu_to_virtio16(little_endian,
> - skb_headlen(skb));
> hdr->gso_size = __cpu_to_virtio16(little_endian,
> sinfo->gso_size);
> if (sinfo->gso_type & SKB_GSO_TCPV4)
> @@ -231,6 +251,10 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP_L4;
> else
> return -EINVAL;
> +
> + virtio_net_set_hdrlen(skb, hdr, little_endian,
> + guest_hdrlen);
> +
> if (sinfo->gso_type & SKB_GSO_TCP_ECN)
> hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
> } else
> @@ -250,6 +274,16 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> return 0;
> }
>
> +static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> + struct virtio_net_hdr *hdr,
> + bool little_endian,
> + bool has_data_valid,
> + int vlan_hlen)
> +{
> + return __virtio_net_hdr_from_skb(skb, hdr, little_endian,
> + has_data_valid, false, vlan_hlen);
> +}
> +
> static inline unsigned int virtio_l3min(bool is_ipv6)
> {
> return is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr);
> @@ -384,6 +418,7 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
> struct virtio_net_hdr_v1_hash_tunnel *vhdr,
> bool tnl_hdr_negotiated,
> bool little_endian,
> + bool guest_hdrlen,
> int vlan_hlen)
> {
> struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)vhdr;
> @@ -394,8 +429,8 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
> tnl_gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL |
> SKB_GSO_UDP_TUNNEL_CSUM);
> if (!tnl_gso_type)
> - return virtio_net_hdr_from_skb(skb, hdr, little_endian, false,
> - vlan_hlen);
> + return __virtio_net_hdr_from_skb(skb, hdr, little_endian, false,
> + guest_hdrlen, vlan_hlen);
>
> /* Tunnel support not negotiated but skb ask for it. */
> if (!tnl_hdr_negotiated)
> @@ -408,7 +443,8 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
>
> /* Let the basic parsing deal with plain GSO features. */
> skb_shinfo(skb)->gso_type &= ~tnl_gso_type;
> - ret = virtio_net_hdr_from_skb(skb, hdr, true, false, vlan_hlen);
> + ret = __virtio_net_hdr_from_skb(skb, hdr, true, false,
> + guest_hdrlen, vlan_hlen);
> skb_shinfo(skb)->gso_type |= tnl_gso_type;
> if (ret)
> return ret;
> --
> 2.32.0.3.g01195cf9f
next prev parent reply other threads:[~2025-11-19 15:27 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-19 5:55 [PATCH net v6 0/2] virtio-net: fix for VIRTIO_NET_F_GUEST_HDRLEN Xuan Zhuo
2025-11-19 5:55 ` [PATCH net v6 1/2] virtio-net: correct hdr_len handling " Xuan Zhuo
2025-11-19 15:27 ` Michael S. Tsirkin [this message]
2025-11-19 5:55 ` [PATCH net v6 2/2] virtio-net: correct hdr_len handling for tunnel gso Xuan Zhuo
2025-11-19 15:35 ` Michael S. Tsirkin
2025-11-20 0:43 ` kernel test robot
2025-11-20 0:54 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251119102708-mutt-send-email-mst@kernel.org \
--to=mst@redhat.com \
--cc=alvaro.karsz@solid-run.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=eperezma@redhat.com \
--cc=jasowang@redhat.com \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=virtualization@lists.linux.dev \
--cc=willemdebruijn.kernel@gmail.com \
--cc=xuanzhuo@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.