[ovs-dev] [PATCH 1/2] packets: Fix UDP over IPv6 checksum

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


Fix the IPv6 pseudoheader checksum. Requires that the payload length is given to
the function.

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

diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 88f5022..a2d5093 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -1000,15 +1000,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
 
     if (udp->udp_csum) {
         uint32_t csum;
+        size_t udp_len;
+        udp_len = dp_packet_size(packet) -
+		  ((const unsigned char *) udp -
+                   (const unsigned char *) dp_packet_l2(packet));
         if (is_header_ipv6(dp_packet_data(packet))) {
-            csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
+            csum = packet_csum_pseudoheader6(dp_packet_l3(packet),
+                                             htonl(udp_len));
         } else {
             csum = packet_csum_pseudoheader(dp_packet_l3(packet));
         }
 
-        csum = csum_continue(csum, udp, dp_packet_size(packet) -
-                             ((const unsigned char *)udp -
-                              (const unsigned char *)dp_packet_l2(packet)));
+        csum = csum_continue(csum, udp, udp_len);
         if (csum_finish(csum)) {
             return NULL;
         }
@@ -1048,7 +1051,8 @@ push_udp_header(struct dp_packet *packet,
     if (udp->udp_csum) {
         uint32_t csum;
         if (is_header_ipv6(dp_packet_data(packet))) {
-            csum = packet_csum_pseudoheader6(ipv6_hdr(dp_packet_data(packet)));
+            csum = packet_csum_pseudoheader6(ipv6_hdr(dp_packet_data(packet)),
+                                             htonl(ip_tot_size));
         } else {
             csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
         }
diff --git a/lib/packets.c b/lib/packets.c
index d82341d..93d75bc 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -1271,7 +1271,8 @@ packet_csum_pseudoheader(const struct ip_header *ip)
 
 #ifndef __CHECKER__
 uint32_t
-packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6)
+packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6,
+                          ovs_be32 plen)
 {
     uint32_t partial = 0;
 
@@ -1284,10 +1285,9 @@ packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6)
     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_add32(partial, plen);
     partial = csum_add16(partial, 0);
-    partial = csum_add16(partial, ip6->ip6_plen);
-    partial = csum_add16(partial, 0);
-    partial = csum_add16(partial, ip6->ip6_nxt);
+    partial = csum_add16(partial, htons(ip6->ip6_nxt));
 
     return partial;
 }
diff --git a/lib/packets.h b/lib/packets.h
index f1445de..b8fa8db 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -838,7 +838,7 @@ struct icmp6_header {
 };
 BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
 
-uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *);
+uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *, ovs_be32);
 
 /* Neighbor Discovery option field.
  * ND options are always a multiple of 8 bytes in size. */
-- 
2.5.0




More information about the dev mailing list