On Thu, Sep 25, 2025 at 10:25 AM Xuan Zhuo <xuanz...@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 <xuanz...@linux.alibaba.com> > --- > include/linux/virtio_net.h | 19 ++++++++++++------- > 1 file changed, 12 insertions(+), 7 deletions(-) > > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h > index 20e0584db1dd..4273420a9ff9 100644 > --- a/include/linux/virtio_net.h > +++ b/include/linux/virtio_net.h > @@ -217,20 +217,25 @@ static inline int virtio_net_hdr_from_skb(const struct > sk_buff *skb, > > if (skb_is_gso(skb)) { > struct skb_shared_info *sinfo = skb_shinfo(skb); > + u16 hdr_len; > > - /* This is a hint as to how much should be linear. */ > - hdr->hdr_len = __cpu_to_virtio16(little_endian, > - skb_headlen(skb)); > + hdr_len = skb_transport_offset(skb); > hdr->gso_size = __cpu_to_virtio16(little_endian, > sinfo->gso_size); > - if (sinfo->gso_type & SKB_GSO_TCPV4) > + if (sinfo->gso_type & SKB_GSO_TCPV4) { > hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; > - else if (sinfo->gso_type & SKB_GSO_TCPV6) > + hdr_len += tcp_hdrlen(skb); > + } else if (sinfo->gso_type & SKB_GSO_TCPV6) { > hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; > - else if (sinfo->gso_type & SKB_GSO_UDP_L4) > + hdr_len += tcp_hdrlen(skb); > + } else if (sinfo->gso_type & SKB_GSO_UDP_L4) { > hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP_L4; > - else
I think we need to deal with the GSO tunnel as well? """ If the \field{gso_type} has the VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4 bit or VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6 bit set, \field{hdr_len} accounts for all the headers up to and including the inner transport. """ > + hdr_len += sizeof(struct udphdr); > + } else { > return -EINVAL; > + } > + > + hdr->hdr_len = __cpu_to_virtio16(little_endian, hdr_len); Should we at least check against the feature of VIRTIO_NET_F_GUEST_HDRLEN? > if (sinfo->gso_type & SKB_GSO_TCP_ECN) > hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; > } else > -- > 2.32.0.3.g01195cf9f >