[ovs-dev] [PATCH] datapath: Fix checksum calculation when modifying ICMPv6 packets.

Jesse Gross jesse at nicira.com
Fri Aug 15 18:18:20 UTC 2014


The checksum of ICMPv6 packets uses the IP pseudoheader as part of
the calculation, unlike ICMP in IPv4. This was not implemented,
which means that modifying the IP addresses of an ICMPv6 packet
would cause the checksum to no longer be correct as the psuedoheader
did not match.

Reported-by: Neal Shrader <icosahedral at gmail.com>
Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/actions.c | 8 ++++++--
 lib/packets.c      | 5 +++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index b16e0b2..713a45d 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -383,11 +383,11 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
 {
 	int transport_len = skb->len - skb_transport_offset(skb);
 
-	if (l4_proto == IPPROTO_TCP) {
+	if (l4_proto == NEXTHDR_TCP) {
 		if (likely(transport_len >= sizeof(struct tcphdr)))
 			inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
 						  addr, new_addr, 1);
-	} else if (l4_proto == IPPROTO_UDP) {
+	} else if (l4_proto == NEXTHDR_UDP) {
 		if (likely(transport_len >= sizeof(struct udphdr))) {
 			struct udphdr *uh = udp_hdr(skb);
 
@@ -398,6 +398,10 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
 					uh->check = CSUM_MANGLED_0;
 			}
 		}
+	} else if (l4_proto == NEXTHDR_ICMP) {
+		if (likely(transport_len >= sizeof(struct icmp6hdr)))
+			inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
+						  skb, addr, new_addr, 1);
 	}
 }
 
diff --git a/lib/packets.c b/lib/packets.c
index 6244c3f..ace7d8e 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -20,6 +20,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <stdlib.h>
 #include "byte-order.h"
 #include "csum.h"
@@ -714,6 +715,10 @@ packet_update_csum128(struct ofpbuf *packet, uint8_t proto,
                 uh->udp_csum = htons(0xffff);
             }
         }
+    } else if (proto == IPPROTO_ICMPV6 && l4_size >= sizeof(struct icmp6_hdr)) {
+        struct icmp6_hdr *icmp = ofpbuf_l4(packet);
+
+        icmp->icmp6_cksum = recalc_csum128(icmp->icmp6_cksum, addr, new_addr);
     }
 }
 
-- 
1.9.1




More information about the dev mailing list