ofproto-dpif-xlate: Support IPv6 when sending to tunnel
[cascardo/ovs.git] / lib / packets.c
index fe06ac8..0ad5073 100644 (file)
@@ -39,23 +39,13 @@ const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
 struct in6_addr
 flow_tnl_dst(const struct flow_tnl *tnl)
 {
-    struct in6_addr addr;
-    if (tnl->ip_dst) {
-        in6_addr_set_mapped_ipv4(&addr, tnl->ip_dst);
-        return addr;
-    }
-    return tnl->ipv6_dst;
+    return tnl->ip_dst ? in6_addr_mapped_ipv4(tnl->ip_dst) : tnl->ipv6_dst;
 }
 
 struct in6_addr
 flow_tnl_src(const struct flow_tnl *tnl)
 {
-    struct in6_addr addr;
-    if (tnl->ip_src) {
-        in6_addr_set_mapped_ipv4(&addr, tnl->ip_src);
-        return addr;
-    }
-    return tnl->ipv6_src;
+    return tnl->ip_src ? in6_addr_mapped_ipv4(tnl->ip_src) : tnl->ipv6_src;
 }
 
 /* Parses 's' as a 16-digit hexadecimal number representing a datapath ID.  On
@@ -1177,6 +1167,36 @@ compose_arp(struct dp_packet *b, uint16_t arp_op,
     dp_packet_set_l3(b, arp);
 }
 
+void
+compose_nd(struct dp_packet *b, const struct eth_addr eth_src,
+           struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst)
+{
+    struct in6_addr sn_addr;
+    struct eth_addr eth_dst;
+    struct ovs_nd_msg *ns;
+    struct ovs_nd_opt *nd_opt;
+
+    in6_addr_solicited_node(&sn_addr, ipv6_dst);
+    ipv6_multicast_to_ethernet(&eth_dst, &sn_addr);
+
+    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6,
+                IPV6_HEADER_LEN + ICMP6_HEADER_LEN + ND_OPT_LEN);
+    packet_set_ipv6(b, IPPROTO_ICMPV6,
+                    ALIGNED_CAST(ovs_be32 *, ipv6_src->s6_addr),
+                    ALIGNED_CAST(ovs_be32 *, sn_addr.s6_addr),
+                    0, 0, 255);
+
+    ns = dp_packet_l4(b);
+    nd_opt = &ns->options[0];
+
+    ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
+    ns->icmph.icmp6_code = 0;
+
+    nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+    packet_set_nd(b, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr),
+                  eth_src, eth_addr_zero);
+}
+
 uint32_t
 packet_csum_pseudoheader(const struct ip_header *ip)
 {
@@ -1191,3 +1211,26 @@ packet_csum_pseudoheader(const struct ip_header *ip)
     return partial;
 }
 
+#ifndef __CHECKER__
+uint32_t
+packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6)
+{
+    uint32_t partial = 0;
+
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_src.be32[0])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_src.be32[1])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_src.be32[2])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_src.be32[3])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[0])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[1])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[2])));
+    partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[3])));
+
+    partial = csum_add16(partial, 0);
+    partial = csum_add16(partial, ip6->ip6_plen);
+    partial = csum_add16(partial, 0);
+    partial = csum_add16(partial, ip6->ip6_nxt);
+
+    return partial;
+}
+#endif