As OVS adds userspace support for being the endpoint in protocols
like tunnels, it will need to be able to calculate pseudoheaders
as part of the checksum calculation.

Signed-off-by: Jesse Gross <je...@nicira.com>
---
 lib/packets.c     | 14 ++++++++++++++
 lib/packets.h     |  1 +
 tests/library.at  |  2 +-
 tests/test-csum.c | 31 +++++++++++++++++++++++++++++++
 4 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/lib/packets.c b/lib/packets.c
index 07cf2eb..419c6af 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -1043,3 +1043,17 @@ compose_arp(struct dp_packet *b, const uint8_t 
eth_src[ETH_ADDR_LEN],
     dp_packet_set_frame(b, eth);
     dp_packet_set_l3(b, arp);
 }
+
+uint32_t
+packet_csum_pseudoheader(const struct ip_header *ip)
+{
+    uint32_t partial = 0;
+
+    partial = csum_add32(partial, get_16aligned_be32(&ip->ip_src));
+    partial = csum_add32(partial, get_16aligned_be32(&ip->ip_dst));
+    partial = csum_add16(partial, htons(ip->ip_proto));
+    partial = csum_add16(partial, htons(ntohs(ip->ip_tot_len) -
+                                        IP_IHL(ip->ip_ihl_ver) * 4));
+
+    return partial;
+}
diff --git a/lib/packets.h b/lib/packets.h
index 2bbe6d9..29ea54f 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -806,5 +806,6 @@ void packet_format_tcp_flags(struct ds *, uint16_t);
 const char *packet_tcp_flag_to_string(uint32_t flag);
 void compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
                  ovs_be32 ip_src, ovs_be32 ip_dst);
+uint32_t packet_csum_pseudoheader(const struct ip_header *);
 
 #endif /* packets.h */
diff --git a/tests/library.at b/tests/library.at
index 2507688..426b206 100644
--- a/tests/library.at
+++ b/tests/library.at
@@ -7,7 +7,7 @@ AT_CHECK([ovstest test-flows flows pcap], [0], [checked 247 
packets, 0 errors
 AT_CLEANUP
 
 AT_SETUP([test TCP/IP checksumming])
-AT_CHECK([ovstest test-csum], [0], 
[....#....#....###................................#................................#
+AT_CHECK([ovstest test-csum], [0], 
[....#....#....####................................#................................#
 ])
 AT_CLEANUP
 
diff --git a/tests/test-csum.c b/tests/test-csum.c
index e25fb3d..2685f67 100644
--- a/tests/test-csum.c
+++ b/tests/test-csum.c
@@ -20,11 +20,13 @@
 #include <assert.h>
 #include <inttypes.h>
 #include <netinet/in.h>
+#include <netinet/ip.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "crc32c.h"
 #include "ovstest.h"
+#include "packets.h"
 #include "random.h"
 #include "unaligned.h"
 #include "util.h"
@@ -175,6 +177,34 @@ test_crc32c(void)
     mark('#');
 }
 
+/* Check the IP pseudoheader calculation. */
+static void
+test_pseudo(void)
+{
+    /* Try an IP header similar to one that the tunnel code
+     * might generate. */
+    struct ip_header ip = {
+        .ip_ihl_ver = IP_IHL_VER(5, 4),
+        .ip_tos = 0,
+        .ip_tot_len = htons(134),
+        .ip_id = 0,
+        .ip_frag_off = htons(IP_DF),
+        .ip_ttl = 64,
+        .ip_proto = IPPROTO_UDP,
+        .ip_csum = htons(0x1265),
+        .ip_src = { .hi = htons(0x1400), .lo = htons(0x0002) },
+        .ip_dst = { .hi = htons(0x1400), .lo = htons(0x0001) }
+    };
+
+    assert(packet_csum_pseudoheader(&ip) == 0x8628);
+
+    /* And also test something totally different to check for
+     * corner cases. */
+    memset(&ip, 0xff, sizeof ip);
+    assert(packet_csum_pseudoheader(&ip) == 0x5c2fb);
+
+    mark('#');
+}
 
 static void
 test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
@@ -239,6 +269,7 @@ test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
     test_rfc1624();
     test_crc32c();
+    test_pseudo();
 
     /* Test recalc_csum16(). */
     for (i = 0; i < 32; i++) {
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to