Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'virtio-net-fix-for-virtio_net_f_guest_hdrlen'

Xuan Zhuo says:

====================
virtio-net: fix for VIRTIO_NET_F_GUEST_HDRLEN

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 path set fixes that issue.

As discussed in [0], this version checks the VIRTIO_NET_F_GUEST_HDRLEN is
negotiated.

[0]: http://lore.kernel.org/all/20251029030913.20423-1-xuanzhuo@linux.alibaba.com

v10: fix http://lore.kernel.org/all/202603122214.8Anoxrmq-lkp@intel.com
====================

Link: https://patch.msgid.link/20260320021818.111741-1-xuanzhuo@linux.alibaba.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+55 -6
+1 -1
drivers/net/tun_vnet.h
··· 244 244 245 245 if (virtio_net_hdr_tnl_from_skb(skb, tnl_hdr, has_tnl_offload, 246 246 tun_vnet_is_little_endian(flags), 247 - vlan_hlen, true)) { 247 + vlan_hlen, true, false)) { 248 248 struct virtio_net_hdr_v1 *hdr = &tnl_hdr->hash_hdr.hdr; 249 249 struct skb_shared_info *sinfo = skb_shinfo(skb); 250 250
+5 -1
drivers/net/virtio_net.c
··· 3267 3267 struct virtio_net_hdr_v1_hash_tunnel *hdr; 3268 3268 int num_sg; 3269 3269 unsigned hdr_len = vi->hdr_len; 3270 + bool feature_hdrlen; 3270 3271 bool can_push; 3272 + 3273 + feature_hdrlen = virtio_has_feature(vi->vdev, 3274 + VIRTIO_NET_F_GUEST_HDRLEN); 3271 3275 3272 3276 pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); 3273 3277 ··· 3292 3288 3293 3289 if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl, 3294 3290 virtio_is_little_endian(vi->vdev), 0, 3295 - false)) 3291 + false, feature_hdrlen)) 3296 3292 return -EPROTO; 3297 3293 3298 3294 if (vi->mergeable_rx_bufs)
+49 -4
include/linux/virtio_net.h
··· 207 207 return __virtio_net_hdr_to_skb(skb, hdr, little_endian, hdr->gso_type); 208 208 } 209 209 210 + /* This function must be called after virtio_net_hdr_from_skb(). */ 211 + static inline void __virtio_net_set_hdrlen(const struct sk_buff *skb, 212 + struct virtio_net_hdr *hdr, 213 + bool little_endian) 214 + { 215 + u16 hdr_len; 216 + 217 + hdr_len = skb_transport_offset(skb); 218 + 219 + if (hdr->gso_type == VIRTIO_NET_HDR_GSO_UDP_L4) 220 + hdr_len += sizeof(struct udphdr); 221 + else 222 + hdr_len += tcp_hdrlen(skb); 223 + 224 + hdr->hdr_len = __cpu_to_virtio16(little_endian, hdr_len); 225 + } 226 + 227 + /* This function must be called after virtio_net_hdr_from_skb(). */ 228 + static inline void __virtio_net_set_tnl_hdrlen(const struct sk_buff *skb, 229 + struct virtio_net_hdr *hdr) 230 + { 231 + u16 hdr_len; 232 + 233 + hdr_len = skb_inner_transport_offset(skb); 234 + 235 + if (hdr->gso_type == VIRTIO_NET_HDR_GSO_UDP_L4) 236 + hdr_len += sizeof(struct udphdr); 237 + else 238 + hdr_len += inner_tcp_hdrlen(skb); 239 + 240 + hdr->hdr_len = __cpu_to_virtio16(true, hdr_len); 241 + } 242 + 210 243 static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, 211 244 struct virtio_net_hdr *hdr, 212 245 bool little_endian, ··· 418 385 bool tnl_hdr_negotiated, 419 386 bool little_endian, 420 387 int vlan_hlen, 421 - bool has_data_valid) 388 + bool has_data_valid, 389 + bool feature_hdrlen) 422 390 { 423 391 struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)vhdr; 424 392 unsigned int inner_nh, outer_th; ··· 428 394 429 395 tnl_gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | 430 396 SKB_GSO_UDP_TUNNEL_CSUM); 431 - if (!tnl_gso_type) 432 - return virtio_net_hdr_from_skb(skb, hdr, little_endian, 433 - has_data_valid, vlan_hlen); 397 + if (!tnl_gso_type) { 398 + ret = virtio_net_hdr_from_skb(skb, hdr, little_endian, 399 + has_data_valid, vlan_hlen); 400 + if (ret) 401 + return ret; 402 + 403 + if (feature_hdrlen && hdr->hdr_len) 404 + __virtio_net_set_hdrlen(skb, hdr, little_endian); 405 + 406 + return ret; 407 + } 434 408 435 409 /* Tunnel support not negotiated but skb ask for it. */ 436 410 if (!tnl_hdr_negotiated) ··· 455 413 skb_shinfo(skb)->gso_type |= tnl_gso_type; 456 414 if (ret) 457 415 return ret; 416 + 417 + if (feature_hdrlen && hdr->hdr_len) 418 + __virtio_net_set_tnl_hdrlen(skb, hdr); 458 419 459 420 if (skb->protocol == htons(ETH_P_IPV6)) 460 421 hdr->gso_type |= VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6;