packet: Add IP pseudoheader checksum calculation.
authorJesse Gross <jesse@nicira.com>
Mon, 30 Mar 2015 19:17:05 +0000 (12:17 -0700)
committerJesse Gross <jesse@nicira.com>
Tue, 7 Apr 2015 23:51:57 +0000 (16:51 -0700)
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 <jesse@nicira.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
lib/packets.c
lib/packets.h
tests/library.at
tests/test-csum.c

index 07cf2eb..419c6af 100644 (file)
@@ -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;
+}
index 2bbe6d9..29ea54f 100644 (file)
@@ -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 */
index dfc5ad9..9bd6d81 100644 (file)
@@ -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
 
index e25fb3d..2685f67 100644 (file)
 #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++) {