Hi Eelco. Sorry for the delayed review.
On Thu, Jul 06, 2017 at 02:48:47PM +0200, Eelco Chaudron wrote: > While OVS userspace datapath (OVS-DPDK) supports GREv6, it does not > inter-operate with a native Linux ip6gretap tunnel. This is because > the Linux driver uses IPv6 optional headers for the Tunnel > Encapsulation Limit (rfc 2473, section 6.6). > > OVS userspace simply does not parse these IPv6 extension headers > inside netdev_tnl_ip_extract_tnl_md(), as such popping the tunnel > leaves extra bytes resulting in a mangled decapsulated frame. > > The change below will parse the IPv6 "next header" chain, and return > the offset to the upper layer protocol. > > Signed-off-by: Eelco Chaudron <[email protected]> > --- > lib/netdev-native-tnl.c | 91 > ++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 90 insertions(+), 1 deletion(-) > > diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c > index 7f3cf98..9a97b7f 100644 > --- a/lib/netdev-native-tnl.c > +++ b/lib/netdev-native-tnl.c > @@ -57,6 +57,80 @@ static struct vlog_rate_limit err_rl = > VLOG_RATE_LIMIT_INIT(60, 5); > uint16_t tnl_udp_port_min = 32768; > uint16_t tnl_udp_port_max = 61000; > > +static int > +netdev_tnl_ip6_get_upperlayer_offset(struct ovs_16aligned_ip6_hdr *ip6) > +{ > + uint8_t ext = ip6->ip6_nxt; > + int ext_hdr_offset = IPV6_HEADER_LEN; > + uint16_t bytes_left = ntohs(ip6->ip6_plen); > + > + while (true) { > + size_t ext_size = 0; > + struct ip6_ext *ext_hdr = (struct ip6_ext *) ((uint8_t *)ip6 + \ > + ext_hdr_offset); > + > + if (bytes_left < 8) { > + /* > + * We need at least 8 bytes of data, which is the minimal > extension > + * header length. The upper layer headers are also minimal 8 > bytes. > + */ > + break; > + } > + > + switch (ext) { > + case IPPROTO_TCP: > + case IPPROTO_UDP: > + case IPPROTO_GRE: > + /* > + * If its any of the upper layer protocols we support for tunnels > + * return the offset. > + */ > + return ext_hdr_offset; > + > + case IPPROTO_HOPOPTS: > + case IPPROTO_ROUTING: > + case IPPROTO_DSTOPTS: > + /* > + * Silently ignore these extensions, and their options. > + */ > + ext_size = (ext_hdr->ip6e_len + 1) * 8; > + if (bytes_left < ext_size) { > + return 0; > + } > + break; > + > + case IPPROTO_FRAGMENT: > + /* > + * Currently IPv6 reassembly is not supported, so do not process > + * fragmented packets. > + */ > + return 0; > + > + case IPPROTO_AH: > + /* > + * Currently authentication is not supported, so do not process > + * the packet further. > + */ > + return 0; > + > + default: > + /* > + * Drop all packets with an unsupported transport layer, > + * or unknown extension header. > + */ > + return 0; > + } > + > + ext = ext_hdr->ip6e_nxt; > + bytes_left -= ext_size; > + ext_hdr_offset += ext_size; > + } > + /* > + * If we end up here the packet is invalid, so drop it... > + */ > + return 0; > +} > + I found parse_ipv6_ext_hdrs() in lib/flow.c. It seems like we should be able to make use of that. It'd be nice if this was common between tunnels and normal IPv6. > void * > netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, > unsigned int *hlen) > @@ -115,6 +189,7 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, > struct flow_tnl *tnl, > > } else if (IP_VER(ip->ip_ihl_ver) == 6) { > ovs_be32 tc_flow = get_16aligned_be32(&ip6->ip6_flow); > + unsigned int upper_layer_offset = 0; > > memcpy(tnl->ipv6_src.s6_addr, ip6->ip6_src.be16, sizeof > ip6->ip6_src); > memcpy(tnl->ipv6_dst.s6_addr, ip6->ip6_dst.be16, sizeof > ip6->ip6_dst); > @@ -122,7 +197,21 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, > struct flow_tnl *tnl, > tnl->ip_tos = ntohl(tc_flow) >> 20; > tnl->ip_ttl = ip6->ip6_hlim; > > - *hlen += IPV6_HEADER_LEN; > + if ((l3_size - IPV6_HEADER_LEN) >= ntohs(ip6->ip6_plen)) { > + /* > + * Make sure the remaining buffer is big enough to contain > + * the entire payload. > + */ > + upper_layer_offset = netdev_tnl_ip6_get_upperlayer_offset(ip6); > + } > + > + if (upper_layer_offset <= 0) { > + VLOG_WARN_RL(&err_rl, > + "ipv6 packet has unsupported extension headers"); > + return NULL; > + } > + > + *hlen += upper_layer_offset; > > } else { > VLOG_WARN_RL(&err_rl, "ipv4 packet has invalid version (%d)", > -- > 2.7.5 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
