forked from mirrors/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: e858fae2b0 ("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>
			
			
This commit is contained in:
		
							parent
							
								
									ca89319483
								
							
						
					
					
						commit
						9d2f67e43b
					
				
					 2 changed files with 25 additions and 4 deletions
				
			
		| 
						 | 
					@ -5,6 +5,24 @@
 | 
				
			||||||
#include <linux/if_vlan.h>
 | 
					#include <linux/if_vlan.h>
 | 
				
			||||||
#include <uapi/linux/virtio_net.h>
 | 
					#include <uapi/linux/virtio_net.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
 | 
				
			||||||
 | 
										   const struct virtio_net_hdr *hdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
 | 
				
			||||||
 | 
						case VIRTIO_NET_HDR_GSO_TCPV4:
 | 
				
			||||||
 | 
						case VIRTIO_NET_HDR_GSO_UDP:
 | 
				
			||||||
 | 
							skb->protocol = cpu_to_be16(ETH_P_IP);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case VIRTIO_NET_HDR_GSO_TCPV6:
 | 
				
			||||||
 | 
							skb->protocol = cpu_to_be16(ETH_P_IPV6);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 | 
					static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 | 
				
			||||||
					const struct virtio_net_hdr *hdr,
 | 
										const struct virtio_net_hdr *hdr,
 | 
				
			||||||
					bool little_endian)
 | 
										bool little_endian)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2715,10 +2715,12 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (po->has_vnet_hdr && virtio_net_hdr_to_skb(skb, vnet_hdr,
 | 
							if (po->has_vnet_hdr) {
 | 
				
			||||||
							      vio_le())) {
 | 
								if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) {
 | 
				
			||||||
			tp_len = -EINVAL;
 | 
									tp_len = -EINVAL;
 | 
				
			||||||
			goto tpacket_error;
 | 
									goto tpacket_error;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								virtio_net_hdr_set_proto(skb, vnet_hdr);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		skb->destructor = tpacket_destruct_skb;
 | 
							skb->destructor = tpacket_destruct_skb;
 | 
				
			||||||
| 
						 | 
					@ -2915,6 +2917,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out_free;
 | 
								goto out_free;
 | 
				
			||||||
		len += sizeof(vnet_hdr);
 | 
							len += sizeof(vnet_hdr);
 | 
				
			||||||
 | 
							virtio_net_hdr_set_proto(skb, &vnet_hdr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_probe_transport_header(skb, reserve);
 | 
						skb_probe_transport_header(skb, reserve);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue