Skb with skb->protocol 0 at the time of virtio_net_hdr_to_skb may have a protocol inferred from virtio_net_hdr with virtio_net_hdr_set_proto. Unlike TCP, UDP does not have separate types for IPv4 and IPv6. Type VIRTIO_NET_HDR_GSO_UDP is guessed to be IPv4/UDP. As of the below commit, UFOv6 packets are dropped due to not matching the protocol as obtained from dev_parse_header_protocol. Invert the test to take that L2 protocol field as starting point and pass both UFOv4 and UFOv6 for VIRTIO_NET_HDR_GSO_UDP.
Unified · Split
| @@ -7,6 +7,21 @@ · 6 unmodified lines | |||
| 7 | #include <uapi/linux/udp.h> | 7 | #include <uapi/linux/udp.h> |
| 8 | #include <uapi/linux/virtio_net.h> | 8 | #include <uapi/linux/virtio_net.h> |
| 9 | 9 | ||
| 10 | static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type) | ||
| 11 | { | ||
| 12 | switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { | ||
| 13 | case VIRTIO_NET_HDR_GSO_TCPV4: | ||
| 14 | return protocol == cpu_to_be16(ETH_P_IP); | ||
| 15 | case VIRTIO_NET_HDR_GSO_TCPV6: | ||
| 16 | return protocol == cpu_to_be16(ETH_P_IPV6); | ||
| 17 | case VIRTIO_NET_HDR_GSO_UDP: | ||
| 18 | return protocol == cpu_to_be16(ETH_P_IP) || | ||
| 19 | protocol == cpu_to_be16(ETH_P_IPV6); | ||
| 20 | default: | ||
| 21 | return false; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 10 | static inline int virtio_net_hdr_set_proto(struct sk_buff *skb, | 25 | static inline int virtio_net_hdr_set_proto(struct sk_buff *skb, |
| 11 | const struct virtio_net_hdr *hdr) | 26 | const struct virtio_net_hdr *hdr) |
| 12 | { | 27 | { |
| @@ -88,9 +103,12 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, · 75 unmodified lines | |||
| 88 | if (!skb->protocol) { | 103 | if (!skb->protocol) { |
| 89 | __be16 protocol = dev_parse_header_protocol(skb); | 104 | __be16 protocol = dev_parse_header_protocol(skb); |
| 90 | 105 | ||
| 91 | virtio_net_hdr_set_proto(skb, hdr); | 106 | if (!protocol) |
| 92 | if (protocol && protocol != skb->protocol) | 107 | virtio_net_hdr_set_proto(skb, hdr); |
| 108 | else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type)) | ||
| 93 | return -EINVAL; | 109 | return -EINVAL; |
| 110 | else | ||
| 111 | skb->protocol = protocol; | ||
| 94 | } | 112 | } |
| 95 | retry: | 113 | retry: |
| 96 | if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, | 114 | if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, |