[ovs-dev] [PATCH 2/2] packets: fix compose_nd to not crash vswitchd

Thadeu Lima de Souza Cascardo cascardo at redhat.com
Tue Feb 9 08:22:05 UTC 2016


packet_set_ipv6 and packet_set_nd assumed that valid packets were already in
place, so they were not a good fit for composing new packets. In fact,
packet_set_ipv6 didn't even set the IP version or set L4 offset, causing crashes
when compose_nd tried to access L4.

This patch introduces ipv6_compose and uses it for compose_nd, then set the ND
packets without other helpers.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo at redhat.com>
---
 lib/packets.c | 46 ++++++++++++++++++++++++++++++++++++++--------
 lib/packets.h |  3 +++
 2 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/lib/packets.c b/lib/packets.c
index 93d75bc..b794398 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -1226,6 +1226,24 @@ compose_arp(struct dp_packet *b, uint16_t arp_op,
 }
 
 void
+ipv6_compose(struct dp_packet *packet, uint8_t proto,
+             const struct in6_addr *src, const struct in6_addr *dst,
+             uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl)
+{
+    struct ovs_16aligned_ip6_hdr *ip6 = dp_packet_l3(packet);
+    ovs_be32 old_flow;
+    ip6->ip6_vfc = 0x60;
+    ip6->ip6_nxt = proto;
+    ip6->ip6_hlim = key_hl;
+    ip6->ip6_plen = 0;
+    old_flow = get_16aligned_be32(&ip6->ip6_flow) & htonl(0xF00FFFFF | ~IPV6_LABEL_MASK);
+    put_16aligned_be32(&ip6->ip6_flow, old_flow | key_fl | htonl(key_tc << 20));
+    memcpy(&ip6->ip6_src, src, sizeof(ovs_be32[4]));
+    memcpy(&ip6->ip6_dst, dst, sizeof(ovs_be32[4]));
+    dp_packet_set_l4(packet, ip6 + 1);
+}
+
+void
 compose_nd(struct dp_packet *b, const struct eth_addr eth_src,
            struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst)
 {
@@ -1233,26 +1251,38 @@ compose_nd(struct dp_packet *b, const struct eth_addr eth_src,
     struct eth_addr eth_dst;
     struct ovs_nd_msg *ns;
     struct ovs_nd_opt *nd_opt;
+    struct ovs_16aligned_ip6_hdr *ip6;
+    size_t plen = ND_MSG_LEN + ND_OPT_LEN;
+    uint32_t csum;
 
     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);
+    eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN + plen);
+    ipv6_compose(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr, 0, 0, 255);
+    ip6 = dp_packet_l3(b);
+    ip6->ip6_plen = htons(plen);
 
     ns = dp_packet_l4(b);
+    memset(ns, 0, plen);
     nd_opt = &ns->options[0];
 
     ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
     ns->icmph.icmp6_code = 0;
+    memcpy(ns->target.be32, ipv6_dst, sizeof(ovs_be32[4]));
 
     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);
+    nd_opt->nd_opt_len = 1;
+    nd_opt->nd_opt_mac = eth_src;
+
+    ns->icmph.icmp6_cksum = 0;
+    csum = packet_csum_pseudoheader6(ip6, htonl(plen));
+    csum = csum_continue(csum, &ns->icmph, plen);
+    csum = csum_finish(csum);
+    ns->icmph.icmp6_cksum = csum;
+    if (!ns->icmph.icmp6_cksum) {
+        ns->icmph.icmp6_cksum = htons(0xffff);
+    }
 }
 
 uint32_t
diff --git a/lib/packets.h b/lib/packets.h
index b8fa8db..96a3251 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -1062,6 +1062,9 @@ void packet_set_nd(struct dp_packet *, const ovs_be32 target[4],
 
 void packet_format_tcp_flags(struct ds *, uint16_t);
 const char *packet_tcp_flag_to_string(uint32_t flag);
+void ipv6_compose(struct dp_packet *, uint8_t proto, const struct in6_addr *src,
+                  const struct in6_addr *dst, uint8_t tc,
+                  ovs_be32 fl, uint8_t hlmit);
 void compose_arp(struct dp_packet *, uint16_t arp_op,
                  const struct eth_addr arp_sha,
                  const struct eth_addr arp_tha, bool broadcast,
-- 
2.5.0




More information about the dev mailing list