History

net: accept UFOv6 packages in virtio_net_hdr_to_skb

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.

Willem de Bruijn committed 4 years ago

Commit 7e5cced1 parent a9725e11 file · +20 −2Browse files

Showing the changes to include/linux (1 of 1 file). Show all

Unified · Split

include/linux/virtio_net.h+20−2
@@ -7,6 +7,21 @@ · 6 unmodified lines
77 #include <uapi/linux/udp.h>
88 #include <uapi/linux/virtio_net.h>
99
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+
1025 static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
1126 const struct virtio_net_hdr *hdr)
1227 {
@@ -88,9 +103,12 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, · 75 unmodified lines
88103 if (!skb->protocol) {
89104 __be16 protocol = dev_parse_header_protocol(skb);
90105
91− virtio_net_hdr_set_proto(skb, hdr);
92− if (protocol && protocol != skb->protocol)
106+ if (!protocol)
107+ virtio_net_hdr_set_proto(skb, hdr);
108+ else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type))
93109 return -EINVAL;
110+ else
111+ skb->protocol = protocol;
94112 }
95113 retry:
96114 if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,