int main(void) { const struct test_case *tc; int i; for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) { const uint16_t *data16 = (const uint16_t *) tc->data; const uint32_t *data32 = (const uint32_t *) tc->data; uint32_t partial; size_t i; /* Test csum(). */ assert(ntohs(csum(tc->data, tc->size)) == tc->csum); mark('.'); /* Test csum_add16(). */ partial = 0; for (i = 0; i < tc->size / 2; i++) { partial = csum_add16(partial, data16[i]); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { partial = csum_add32(partial, data32[i]); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test alternating csum_add16() and csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i % 2) { partial = csum_add32(partial, data32[i]); } else { partial = csum_add16(partial, data16[i * 2]); partial = csum_add16(partial, data16[i * 2 + 1]); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_continue(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i) { partial = csum_continue(partial, &data32[i], 4); } else { partial = csum_continue(partial, &data16[i * 2], 2); partial = csum_continue(partial, &data16[i * 2 + 1], 2); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('#'); } test_rfc1624(); /* Test recalc_csum16(). */ for (i = 0; i < 32; i++) { uint16_t old_u16, new_u16; uint16_t old_csum; uint16_t data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u16 = data[index]; new_u16 = data[index] = random_uint32(); assert(csum(data, sizeof data) == recalc_csum16(old_csum, old_u16, new_u16)); mark('.'); } mark('#'); /* Test recalc_csum32(). */ for (i = 0; i < 32; i++) { uint32_t old_u32, new_u32; uint16_t old_csum; uint32_t data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u32 = data[index]; new_u32 = data[index] = random_uint32(); assert(csum(data, sizeof data) == recalc_csum32(old_csum, old_u32, new_u32)); mark('.'); } mark('#'); putchar('\n'); return 0; }
/* Returns the IP checksum of the 'n' bytes in 'data'. * * The return value has the same endianness as the data. That is, if 'data' * consists of a packet in network byte order, then the return value is a value * in network byte order, and if 'data' consists of a data structure in host * byte order, then the return value is in host byte order. */ ovs_be16 csum(const void *data, size_t n) { return csum_finish(csum_continue(0, data, n)); }
/* 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) } }; csum = csum_finish(packet_csum_pseudoheader(&ip)); assert(csum == htons(0xd779)); /* And also test something totally different to check for * corner cases. */ memset(&ip, 0xff, sizeof ip); csum = csum_finish(packet_csum_pseudoheader(&ip)); assert(csum == htons(0xff3c)); mark('#'); } static void test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { const struct test_case *tc;
int main(void) { const struct test_case *tc; int i; for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) { const void *data = tc->data; const ovs_be16 *data16 = (OVS_FORCE const ovs_be16 *) data; const ovs_be32 *data32 = (OVS_FORCE const ovs_be32 *) data; uint32_t partial; /* Test csum(). */ assert(ntohs(csum(tc->data, tc->size)) == tc->csum); mark('.'); /* Test csum_add16(). */ partial = 0; for (i = 0; i < tc->size / 2; i++) { partial = csum_add16(partial, get_unaligned_be16(&data16[i])); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { partial = csum_add32(partial, get_unaligned_be32(&data32[i])); } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test alternating csum_add16() and csum_add32(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i % 2) { partial = csum_add32(partial, get_unaligned_be32(&data32[i])); } else { ovs_be16 u0 = get_unaligned_be16(&data16[i * 2]); ovs_be16 u1 = get_unaligned_be16(&data16[i * 2 + 1]); partial = csum_add16(partial, u0); partial = csum_add16(partial, u1); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('.'); /* Test csum_continue(). */ partial = 0; for (i = 0; i < tc->size / 4; i++) { if (i) { partial = csum_continue(partial, &data32[i], 4); } else { partial = csum_continue(partial, &data16[i * 2], 2); partial = csum_continue(partial, &data16[i * 2 + 1], 2); } } assert(ntohs(csum_finish(partial)) == tc->csum); mark('#'); } test_rfc1624(); /* Test recalc_csum16(). */ for (i = 0; i < 32; i++) { ovs_be16 old_u16, new_u16; ovs_be16 old_csum; ovs_be16 data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = (OVS_FORCE ovs_be16) random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u16 = data[index]; new_u16 = data[index] = (OVS_FORCE ovs_be16) random_uint32(); assert(csum(data, sizeof data) == recalc_csum16(old_csum, old_u16, new_u16)); mark('.'); } mark('#'); /* Test recalc_csum32(). */ for (i = 0; i < 32; i++) { ovs_be32 old_u32, new_u32; ovs_be16 old_csum; ovs_be32 data[16]; int j, index; for (j = 0; j < ARRAY_SIZE(data); j++) { data[j] = (OVS_FORCE ovs_be32) random_uint32(); } old_csum = csum(data, sizeof data); index = random_range(ARRAY_SIZE(data)); old_u32 = data[index]; new_u32 = data[index] = (OVS_FORCE ovs_be32) random_uint32(); assert(csum(data, sizeof data) == recalc_csum32(old_csum, old_u32, new_u32)); mark('.'); } mark('#'); putchar('\n'); return 0; }
/* Returns the IP checksum of the 'n' bytes in 'data'. */ uint16_t csum(const void *data, size_t n) { return csum_finish(csum_continue(0, data, n)); }