On Tue, 3 Mar 2026 11:15:16 +0800, Jason Wang <[email protected]> wrote: > On Mon, Mar 2, 2026 at 5:04 PM Xuan Zhuo <[email protected]> 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 <[email protected]> > > --- > > 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 > > >
