]> git.proxmox.com Git - ovs.git/blob - tests/test-csum.c
dpif-netdev: Incremental addition/deletion of PMD threads.
[ovs.git] / tests / test-csum.c
1 /*
2 * Copyright (c) 2009, 2010, 2011, 2014 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #undef NDEBUG
19 #include "csum.h"
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <netinet/in.h>
23 #include <netinet/ip.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "crc32c.h"
28 #include "ovstest.h"
29 #include "packets.h"
30 #include "random.h"
31 #include "unaligned.h"
32 #include "util.h"
33
34 struct test_case {
35 char *data;
36 size_t size; /* Test requires a multiple of 4. */
37 uint16_t csum;
38 };
39
40 #define TEST_CASE(DATA, CSUM) { DATA, (sizeof DATA) - 1, CSUM }
41
42 static const struct test_case test_cases[] = {
43 /* RFC 1071 section 3. */
44 TEST_CASE("\x00\x01\xf2\x03"
45 "\xf4\xf5\xf6\xf7",
46 0xffff - 0xddf2 /* ~0xddf2 */),
47
48 /* http://www.sbprojects.com/projects/tcpip/theory/theory14.htm */
49 TEST_CASE("\x45\x00\x00\x28"
50 "\x1F\xFD\x40\x00"
51 "\x80\x06\x00\x00"
52 "\xC0\xA8\x3B\x0A"
53 "\xC0\xA8\x3B\x32",
54 0xe345),
55
56 /* http://mathforum.org/library/drmath/view/54379.html */
57 TEST_CASE("\x86\x5e\xac\x60"
58 "\x71\x2a\x81\xb5",
59 0xda60),
60 };
61
62 static void
63 mark(char c)
64 {
65 putchar(c);
66 fflush(stdout);
67 }
68
69 #if 0
70 /* This code is useful for generating new test cases for RFC 1624 section 4. */
71 static void
72 generate_rfc1624_test_case(void)
73 {
74 int i;
75
76 for (i = 0; i < 10000000; i++) {
77 uint32_t data[8];
78 int j;
79
80 for (j = 0; j < 8; j++) {
81 data[j] = random_uint32();
82 }
83 data[7] &= 0x0000ffff;
84 data[7] |= 0x55550000;
85 if (ntohs(~csum(data, sizeof data - 2)) == 0xcd7a) {
86 ovs_hex_dump(stdout, data, sizeof data, 0, false);
87 exit(0);
88 }
89 }
90 }
91 #endif
92
93
94
95 /* Make sure we get the calculation in RFC 1624 section 4 correct. */
96 static void
97 test_rfc1624(void)
98 {
99 /* "...an IP packet header in which a 16-bit field m = 0x5555..." */
100 uint8_t data[32] = {
101 0xfe, 0x8f, 0xc1, 0x14, 0x4b, 0x6f, 0x70, 0x2a,
102 0x80, 0x29, 0x78, 0xc0, 0x58, 0x81, 0x77, 0xaa,
103 0x66, 0x64, 0xfc, 0x96, 0x63, 0x97, 0x64, 0xee,
104 0x12, 0x53, 0x1d, 0xa9, 0x2d, 0xa9, 0x55, 0x55
105 };
106
107 /* "...the one's complement sum of all other header octets is 0xCD7A." */
108 assert(ntohs(csum(data, sizeof data - 2)) == 0xffff - 0xcd7a);
109
110 /* "...the header checksum would be:
111
112 HC = ~(0xCD7A + 0x5555)
113 = ~0x22D0
114 = 0xDD2F"
115 */
116 assert(ntohs(csum(data, sizeof data)) == 0xdd2f);
117
118 /* "a 16-bit field m = 0x5555 changes to m' = 0x3285..." */
119 data[30] = 0x32;
120 data[31] = 0x85;
121
122 /* "The new checksum via recomputation is:
123
124 HC' = ~(0xCD7A + 0x3285)
125 = ~0xFFFF
126 = 0x0000"
127 */
128 assert(ntohs(csum(data, sizeof data)) == 0x0000);
129
130 /* "Applying [Eqn. 3] to the example above, we get the correct result:
131
132 HC' = ~(C + (-m) + m')
133 = ~(0x22D0 + ~0x5555 + 0x3285)
134 = ~0xFFFF
135 = 0x0000" */
136 assert(recalc_csum16(htons(0xdd2f), htons(0x5555), htons(0x3285))
137 == htons(0x0000));
138
139 mark('#');
140 }
141
142 /* CRC32C checksum tests, based on Intel IPPs, Chapter 13,
143 * ippsCRC32C_8u() example, found at the following location:
144 * http://software.intel.com/sites/products/documentation/hpc/ipp/ipps/ */
145 static void
146 test_crc32c(void)
147 {
148 int i;
149 uint8_t data[48] = {
150 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
153 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18,
154 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
156 };
157
158 /* iSCSI Read PDU */
159 assert(ntohl(crc32c(data, 48)) == 0x563a96d9L);
160
161 /* 32 bytes of all zeroes */
162 for (i = 0; i < 32; i++) data[i] = 0x00;
163 assert(ntohl(crc32c(data, 32)) == 0xaa36918aL);
164
165 /* 32 bytes of all ones */
166 for (i = 0; i < 32; i++) data[i] = 0xff;
167 assert(ntohl(crc32c(data, 32)) == 0x43aba862L);
168
169 /* 32 bytes of incrementing 00..1f */
170 for (i = 0; i < 32; i++) data[i] = i;
171 assert(ntohl(crc32c(data, 32)) == 0x4e79dd46L);
172
173 /* 32 bytes of decrementing 1f..00 */
174 for (i = 0; i < 32; i++) data[i] = 31 - i;
175 assert(ntohl(crc32c(data, 32)) == 0x5cdb3f11L);
176
177 mark('#');
178 }
179
180 /* Check the IP pseudoheader calculation. */
181 static void
182 test_pseudo(void)
183 {
184 ovs_be16 csum;
185 /* Try an IP header similar to one that the tunnel code
186 * might generate. */
187 struct ip_header ip = {
188 .ip_ihl_ver = IP_IHL_VER(5, 4),
189 .ip_tos = 0,
190 .ip_tot_len = htons(134),
191 .ip_id = 0,
192 .ip_frag_off = htons(IP_DF),
193 .ip_ttl = 64,
194 .ip_proto = IPPROTO_UDP,
195 .ip_csum = htons(0x1265),
196 .ip_src = { .hi = htons(0x1400), .lo = htons(0x0002) },
197 .ip_dst = { .hi = htons(0x1400), .lo = htons(0x0001) }
198 };
199
200 csum = csum_finish(packet_csum_pseudoheader(&ip));
201 assert(csum == htons(0xd779));
202
203 /* And also test something totally different to check for
204 * corner cases. */
205 memset(&ip, 0xff, sizeof ip);
206 csum = csum_finish(packet_csum_pseudoheader(&ip));
207 assert(csum == htons(0xff3c));
208
209 mark('#');
210 }
211
212 static void
213 test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
214 {
215 const struct test_case *tc;
216 int i;
217
218 for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) {
219 const void *data = tc->data;
220 const ovs_be16 *data16 = (OVS_FORCE const ovs_be16 *) data;
221 const ovs_be32 *data32 = (OVS_FORCE const ovs_be32 *) data;
222 uint32_t partial;
223
224 /* Test csum(). */
225 assert(ntohs(csum(tc->data, tc->size)) == tc->csum);
226 mark('.');
227
228 /* Test csum_add16(). */
229 partial = 0;
230 for (i = 0; i < tc->size / 2; i++) {
231 partial = csum_add16(partial, get_unaligned_be16(&data16[i]));
232 }
233 assert(ntohs(csum_finish(partial)) == tc->csum);
234 mark('.');
235
236 /* Test csum_add32(). */
237 partial = 0;
238 for (i = 0; i < tc->size / 4; i++) {
239 partial = csum_add32(partial, get_unaligned_be32(&data32[i]));
240 }
241 assert(ntohs(csum_finish(partial)) == tc->csum);
242 mark('.');
243
244 /* Test alternating csum_add16() and csum_add32(). */
245 partial = 0;
246 for (i = 0; i < tc->size / 4; i++) {
247 if (i % 2) {
248 partial = csum_add32(partial, get_unaligned_be32(&data32[i]));
249 } else {
250 ovs_be16 u0 = get_unaligned_be16(&data16[i * 2]);
251 ovs_be16 u1 = get_unaligned_be16(&data16[i * 2 + 1]);
252 partial = csum_add16(partial, u0);
253 partial = csum_add16(partial, u1);
254 }
255 }
256 assert(ntohs(csum_finish(partial)) == tc->csum);
257 mark('.');
258
259 /* Test csum_continue(). */
260 partial = 0;
261 for (i = 0; i < tc->size / 4; i++) {
262 if (i) {
263 partial = csum_continue(partial, &data32[i], 4);
264 } else {
265 partial = csum_continue(partial, &data16[i * 2], 2);
266 partial = csum_continue(partial, &data16[i * 2 + 1], 2);
267 }
268 }
269 assert(ntohs(csum_finish(partial)) == tc->csum);
270 mark('#');
271 }
272
273 test_rfc1624();
274 test_crc32c();
275 test_pseudo();
276
277 /* Test recalc_csum16(). */
278 for (i = 0; i < 32; i++) {
279 ovs_be16 old_u16, new_u16;
280 ovs_be16 old_csum;
281 ovs_be16 data[16];
282 int j, index;
283
284 for (j = 0; j < ARRAY_SIZE(data); j++) {
285 data[j] = (OVS_FORCE ovs_be16) random_uint32();
286 }
287 old_csum = csum(data, sizeof data);
288 index = random_range(ARRAY_SIZE(data));
289 old_u16 = data[index];
290 new_u16 = data[index] = (OVS_FORCE ovs_be16) random_uint32();
291 assert(csum(data, sizeof data)
292 == recalc_csum16(old_csum, old_u16, new_u16));
293 mark('.');
294 }
295 mark('#');
296
297 /* Test recalc_csum32(). */
298 for (i = 0; i < 32; i++) {
299 ovs_be32 old_u32, new_u32;
300 ovs_be16 old_csum;
301 ovs_be32 data[16];
302 int j, index;
303
304 for (j = 0; j < ARRAY_SIZE(data); j++) {
305 data[j] = (OVS_FORCE ovs_be32) random_uint32();
306 }
307 old_csum = csum(data, sizeof data);
308 index = random_range(ARRAY_SIZE(data));
309 old_u32 = data[index];
310 new_u32 = data[index] = (OVS_FORCE ovs_be32) random_uint32();
311 assert(csum(data, sizeof data)
312 == recalc_csum32(old_csum, old_u32, new_u32));
313 mark('.');
314 }
315 mark('#');
316
317 putchar('\n');
318 }
319
320 OVSTEST_REGISTER("test-csum", test_csum_main);