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

net/packet: fix packet drop as of virtio gso

When we use raw socket as the vhost backend, a packet from virito with
gso offloading information, cannot be sent out in later validaton at
xmit path, as we did not set correct skb->protocol which is further used
for looking up the gso function.

To fix this, we set this field according to virito hdr information.

Fixes: e858fae2b0b8f4 ("virtio_net: use common code for virtio_net_hdr and skb GSO conversion")
Signed-off-by: Jianfeng Tan <jianfeng.tan@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jianfeng Tan and committed by
David S. Miller
9d2f67e4 ca893194

+25 -4
+18
include/linux/virtio_net.h
··· 5 5 #include <linux/if_vlan.h> 6 6 #include <uapi/linux/virtio_net.h> 7 7 8 + static inline int virtio_net_hdr_set_proto(struct sk_buff *skb, 9 + const struct virtio_net_hdr *hdr) 10 + { 11 + switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 12 + case VIRTIO_NET_HDR_GSO_TCPV4: 13 + case VIRTIO_NET_HDR_GSO_UDP: 14 + skb->protocol = cpu_to_be16(ETH_P_IP); 15 + break; 16 + case VIRTIO_NET_HDR_GSO_TCPV6: 17 + skb->protocol = cpu_to_be16(ETH_P_IPV6); 18 + break; 19 + default: 20 + return -EINVAL; 21 + } 22 + 23 + return 0; 24 + } 25 + 8 26 static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, 9 27 const struct virtio_net_hdr *hdr, 10 28 bool little_endian)
+7 -4
net/packet/af_packet.c
··· 2715 2715 } 2716 2716 } 2717 2717 2718 - if (po->has_vnet_hdr && virtio_net_hdr_to_skb(skb, vnet_hdr, 2719 - vio_le())) { 2720 - tp_len = -EINVAL; 2721 - goto tpacket_error; 2718 + if (po->has_vnet_hdr) { 2719 + if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) { 2720 + tp_len = -EINVAL; 2721 + goto tpacket_error; 2722 + } 2723 + virtio_net_hdr_set_proto(skb, vnet_hdr); 2722 2724 } 2723 2725 2724 2726 skb->destructor = tpacket_destruct_skb; ··· 2917 2915 if (err) 2918 2916 goto out_free; 2919 2917 len += sizeof(vnet_hdr); 2918 + virtio_net_hdr_set_proto(skb, &vnet_hdr); 2920 2919 } 2921 2920 2922 2921 skb_probe_transport_header(skb, reserve);