From: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
To: Jason Wang <jasowang@redhat.com>
Cc: netdev@vger.kernel.org,
"Willem de Bruijn" <willemdebruijn.kernel@gmail.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>,
"Michael S. Tsirkin" <mst@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 v7 1/2] virtio-net: correct hdr_len handling for VIRTIO_NET_F_GUEST_HDRLEN
Date: Tue, 3 Mar 2026 17:09:13 +0800 [thread overview]
Message-ID: <1772528953.3431165-1-xuanzhuo@linux.alibaba.com> (raw)
In-Reply-To: <CACGkMEtnOKxJVY2qrbFsTwR9c=e34HU7z6Mdhyj3kPGf867F-g@mail.gmail.com>
On Tue, 3 Mar 2026 11:15:16 +0800, Jason Wang <jasowang@redhat.com> wrote:
> On Mon, Mar 2, 2026 at 5:04 PM Xuan Zhuo <xuanzhuo@linux.alibaba.com> 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 | 61 ++++++++++++++++++++++++++++++--------
> > 3 files changed, 56 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
> > index a5f93b6c4482..fa5cab9d3e55 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, true)) {
> > + vlan_hlen, true, false)) {
> > 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 72d6a9c6a5a2..1800058c8072 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -3265,9 +3265,13 @@ 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 feature_hdrlen;
> > bool can_push;
> > + int num_sg;
>
> nit: the change to num_sg seems to be unnecessary.
>
> > +
> > + feature_hdrlen = virtio_has_feature(vi->vdev,
> > + VIRTIO_NET_F_GUEST_HDRLEN);
> >
> > pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
> >
> > @@ -3288,7 +3292,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
> >
> > if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl,
> > virtio_is_little_endian(vi->vdev), 0,
> > - false))
> > + false, feature_hdrlen))
> > return -EPROTO;
> >
> > if (vi->mergeable_rx_bufs)
> > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> > index 75dabb763c65..d31c9af1f3d6 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 feature_hdrlen)
> > +{
> > + u16 hdr_len;
> > +
> > + if (feature_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);
> > +}
> > +
> > +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 feature_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,
> > + feature_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);
> > @@ -385,7 +419,8 @@ virtio_net_hdr_tnl_from_skb(const struct sk_buff *skb,
> > bool tnl_hdr_negotiated,
> > bool little_endian,
> > int vlan_hlen,
> > - bool has_data_valid)
> > + bool has_data_valid,
> > + bool feature_hdrlen)
> > {
> > struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)vhdr;
> > unsigned int inner_nh, outer_th;
> > @@ -395,8 +430,9 @@ 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,
> > - has_data_valid, vlan_hlen);
> > + return __virtio_net_hdr_from_skb(skb, hdr, little_endian,
> > + has_data_valid,
> > + feature_hdrlen, vlan_hlen);
> >
> > /* Tunnel support not negotiated but skb ask for it. */
> > if (!tnl_hdr_negotiated)
> > @@ -409,7 +445,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,
> > + feature_hdrlen, vlan_hlen);
>
> This seems to be incorrect as tnl_gso_type is masked so
> __virtio_net_hdr_from_skb() can only see UDP packet for tunnel gso
> packet?
Yes, moving to next patch maybe more suitable.
>
> (And it seems to be fixed in next patch, could we simply squash them)
As the issues fixed originate from different commits.
This separation makes it easier to selectively revert to
previous versions.
Thanks.
>
> Thanks
>
>
> > skb_shinfo(skb)->gso_type |= tnl_gso_type;
> > if (ret)
> > return ret;
> > --
> > 2.32.0.3.g01195cf9f
> >
>
next prev parent reply other threads:[~2026-03-03 9:11 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-02 9:04 [PATCH net v7 0/2] virtio-net: fix for VIRTIO_NET_F_GUEST_HDRLEN Xuan Zhuo
2026-03-02 9:04 ` [PATCH net v7 1/2] virtio-net: correct hdr_len handling " Xuan Zhuo
2026-03-03 3:15 ` Jason Wang
2026-03-03 9:09 ` Xuan Zhuo [this message]
2026-03-02 9:04 ` [PATCH net v7 2/2] virtio-net: correct hdr_len handling for tunnel gso Xuan Zhuo
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=1772528953.3431165-1-xuanzhuo@linux.alibaba.com \
--to=xuanzhuo@linux.alibaba.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=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=virtualization@lists.linux.dev \
--cc=willemdebruijn.kernel@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox