]> git.proxmox.com Git - mirror_frr.git/blame - tests/lib/test_checksum.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / lib / test_checksum.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
d62a17ae 2/*
46f4a4d2 3 * Copyright (C) 2008 Sun Microsystems, Inc.
46f4a4d2
PJ
4 */
5
5d4b8cf2
PJ
6#include <zebra.h>
7#include <stdlib.h>
8#include <time.h>
9
10#include "checksum.h"
5920b3eb 11#include "network.h"
9b6ef21e 12#include "prng.h"
5d4b8cf2
PJ
13
14struct thread_master *master;
15
16struct acc_vals {
d62a17ae 17 int c0;
18 int c1;
5d4b8cf2
PJ
19};
20
21struct csum_vals {
d62a17ae 22 struct acc_vals a;
23 int x;
24 int y;
5d4b8cf2
PJ
25};
26
27static struct csum_vals ospfd_vals, isisd_vals;
28
29typedef size_t testsz_t;
30typedef uint16_t testoff_t;
31
32/* Fletcher Checksum -- Refer to RFC1008. */
db7d7ba4 33#define MODX 4102U
6b0655a2 34
5d4b8cf2 35/* The final reduction phase.
d62a17ae 36 * This one should be the original ospfd version
5d4b8cf2 37 */
d7c0a89a
QY
38static uint16_t reduce_ospfd(struct csum_vals *vals, testsz_t len,
39 testoff_t off)
5d4b8cf2
PJ
40{
41#define x vals->x
42#define y vals->y
43#define c0 vals->a.c0
44#define c1 vals->a.c1
45
d62a17ae 46 x = ((len - off - 1) * c0 - c1) % 255;
5d4b8cf2 47
d62a17ae 48 if (x <= 0)
49 x += 255;
50 y = 510 - c0 - x;
51 if (y > 255)
52 y -= 255;
53
54 /* take care endian issue. */
55 return htons((x << 8) + y);
5d4b8cf2
PJ
56#undef x
57#undef y
58#undef c0
59#undef c1
60}
61
62/* slightly different concatenation */
d7c0a89a
QY
63static uint16_t reduce_ospfd1(struct csum_vals *vals, testsz_t len,
64 testoff_t off)
5d4b8cf2
PJ
65{
66#define x vals->x
67#define y vals->y
68#define c0 vals->a.c0
69#define c1 vals->a.c1
70
d62a17ae 71 x = ((len - off - 1) * c0 - c1) % 255;
72 if (x <= 0)
73 x += 255;
74 y = 510 - c0 - x;
75 if (y > 255)
76 y -= 255;
5d4b8cf2 77
d62a17ae 78 /* take care endian issue. */
79 return htons((x << 8) | (y & 0xff));
5d4b8cf2
PJ
80#undef x
81#undef y
82#undef c0
83#undef c1
84}
85
86/* original isisd version */
d7c0a89a
QY
87static uint16_t reduce_isisd(struct csum_vals *vals, testsz_t len,
88 testoff_t off)
5d4b8cf2
PJ
89{
90#define x vals->x
91#define y vals->y
92#define c0 vals->a.c0
93#define c1 vals->a.c1
d7c0a89a 94 uint32_t mul;
d62a17ae 95
96 mul = (len - off) * (c0);
97 x = mul - c0 - c1;
98 y = c1 - mul - 1;
5d4b8cf2 99
d62a17ae 100 if (y > 0)
101 y++;
102 if (x < 0)
103 x--;
5d4b8cf2 104
d62a17ae 105 x %= 255;
106 y %= 255;
5d4b8cf2 107
d62a17ae 108 if (x == 0)
109 x = 255;
110 if (y == 0)
111 y = 1;
5d4b8cf2 112
d62a17ae 113 return htons((x << 8) | (y & 0xff));
5d4b8cf2
PJ
114
115#undef x
116#undef y
117#undef c0
118#undef c1
119}
120
121/* Is the -1 in y wrong perhaps? */
d7c0a89a
QY
122static uint16_t reduce_isisd_yfix(struct csum_vals *vals, testsz_t len,
123 testoff_t off)
5d4b8cf2
PJ
124{
125#define x vals->x
126#define y vals->y
127#define c0 vals->a.c0
128#define c1 vals->a.c1
d7c0a89a 129 uint32_t mul;
d62a17ae 130
131 mul = (len - off) * (c0);
132 x = mul - c0 - c1;
133 y = c1 - mul;
5d4b8cf2 134
d62a17ae 135 if (y > 0)
136 y++;
137 if (x < 0)
138 x--;
5d4b8cf2 139
d62a17ae 140 x %= 255;
141 y %= 255;
5d4b8cf2 142
d62a17ae 143 if (x == 0)
144 x = 255;
145 if (y == 0)
146 y = 1;
5d4b8cf2 147
d62a17ae 148 return htons((x << 8) | (y & 0xff));
5d4b8cf2
PJ
149
150#undef x
151#undef y
152#undef c0
153#undef c1
154}
155
156/* Move the mods yp */
d7c0a89a
QY
157static uint16_t reduce_isisd_mod(struct csum_vals *vals, testsz_t len,
158 testoff_t off)
5d4b8cf2
PJ
159{
160#define x vals->x
161#define y vals->y
162#define c0 vals->a.c0
163#define c1 vals->a.c1
d7c0a89a 164 uint32_t mul;
5d4b8cf2 165
d62a17ae 166 mul = (len - off) * (c0);
167 x = mul - c1 - c0;
168 y = c1 - mul - 1;
5d4b8cf2 169
d62a17ae 170 x %= 255;
171 y %= 255;
5d4b8cf2 172
d62a17ae 173 if (y > 0)
174 y++;
175 if (x < 0)
176 x--;
5d4b8cf2 177
d62a17ae 178 if (x == 0)
179 x = 255;
180 if (y == 0)
181 y = 1;
182
183 return htons((x << 8) | (y & 0xff));
5d4b8cf2
PJ
184
185#undef x
186#undef y
187#undef c0
188#undef c1
189}
190
191/* Move the mods up + fix y */
d7c0a89a
QY
192static uint16_t reduce_isisd_mody(struct csum_vals *vals, testsz_t len,
193 testoff_t off)
5d4b8cf2
PJ
194{
195#define x vals->x
196#define y vals->y
197#define c0 vals->a.c0
198#define c1 vals->a.c1
d7c0a89a 199 uint32_t mul;
d62a17ae 200
201 mul = (len - off) * (c0);
202 x = mul - c0 - c1;
203 y = c1 - mul;
5d4b8cf2 204
d62a17ae 205 x %= 255;
206 y %= 255;
5d4b8cf2 207
d62a17ae 208 if (y > 0)
209 y++;
210 if (x < 0)
211 x--;
5d4b8cf2 212
d62a17ae 213 if (x == 0)
214 x = 255;
215 if (y == 0)
216 y = 1;
5d4b8cf2 217
d62a17ae 218 return htons((x << 8) | (y & 0xff));
5d4b8cf2
PJ
219
220#undef x
221#undef y
222#undef c0
223#undef c1
224}
225
226struct reductions_t {
d62a17ae 227 const char *name;
d7c0a89a 228 uint16_t (*f)(struct csum_vals *, testsz_t, testoff_t);
5d4b8cf2 229} reducts[] = {
d62a17ae 230 {.name = "ospfd", .f = reduce_ospfd},
231 {.name = "ospfd-1", .f = reduce_ospfd1},
232 {.name = "isisd", .f = reduce_isisd},
233 {.name = "isisd-yfix", .f = reduce_isisd_yfix},
234 {.name = "isisd-mod", .f = reduce_isisd_mod},
235 {.name = "isisd-mody", .f = reduce_isisd_mody},
236 {NULL, NULL},
5d4b8cf2 237};
6b0655a2 238
5d4b8cf2 239/* The original ospfd checksum */
d7c0a89a 240static uint16_t ospfd_checksum(uint8_t *buffer, testsz_t len, testoff_t off)
5d4b8cf2 241{
d7c0a89a 242 uint8_t *sp, *ep, *p, *q;
d62a17ae 243 int c0 = 0, c1 = 0;
244 int x, y;
d7c0a89a 245 uint16_t checksum, *csum;
d62a17ae 246
d7c0a89a 247 csum = (uint16_t *)(buffer + off);
d62a17ae 248 *(csum) = 0;
249
250 sp = buffer;
251
252 for (ep = sp + len; sp < ep; sp = q) {
253 q = sp + MODX;
254 if (q > ep)
255 q = ep;
256 for (p = sp; p < q; p++) {
257 c0 += *p;
258 c1 += c0;
259 }
260 c0 %= 255;
261 c1 %= 255;
262 }
263
264 ospfd_vals.a.c0 = c0;
265 ospfd_vals.a.c1 = c1;
266
267 // printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
268 // __func__, len, off, c0, c1);
269
270 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
271
272 if (x <= 0)
273 x += 255;
274 y = 510 - c0 - x;
275 if (y > 255)
276 y -= 255;
277
278 ospfd_vals.x = x;
279 ospfd_vals.y = y;
280
281 buffer[off] = x;
282 buffer[off + 1] = y;
283
284 /* take care endian issue. */
285 checksum = htons((x << 8) | (y & 0xff));
286
287 return (checksum);
5d4b8cf2
PJ
288}
289
290/* the original, broken isisd checksum */
d7c0a89a 291static uint16_t iso_csum_create(uint8_t *buffer, testsz_t len, testoff_t off)
5d4b8cf2
PJ
292{
293
d7c0a89a 294 uint8_t *p;
d62a17ae 295 int x;
296 int y;
d7c0a89a
QY
297 uint32_t mul;
298 uint32_t c0;
299 uint32_t c1;
300 uint16_t checksum, *csum;
d62a17ae 301 int i, init_len, partial_len;
302
303 checksum = 0;
304
d7c0a89a 305 csum = (uint16_t *)(buffer + off);
d62a17ae 306 *(csum) = checksum;
307
308 p = buffer;
309 c0 = 0;
310 c1 = 0;
311 init_len = len;
312
313 while (len != 0) {
314 partial_len = MIN(len, MODX);
315
316 for (i = 0; i < partial_len; i++) {
317 c0 = c0 + *(p++);
318 c1 += c0;
319 }
320
321 c0 = c0 % 255;
322 c1 = c1 % 255;
323
324 len -= partial_len;
5d4b8cf2
PJ
325 }
326
d62a17ae 327 isisd_vals.a.c0 = c0;
328 isisd_vals.a.c1 = c1;
329
330 mul = (init_len - off) * c0;
331
332 x = mul - c1 - c0;
333 y = c1 - mul - 1;
334
335 if (y > 0)
336 y++;
337 if (x < 0)
338 x--;
339
340 x %= 255;
341 y %= 255;
342
343 if (x == 0)
344 x = 255;
345 if (y == 0)
346 y = 1;
347
348 isisd_vals.x = x;
349 isisd_vals.y = y;
350
351 checksum = htons((x << 8) | (y & 0xFF));
352
353 *(csum) = checksum;
354
355 /* return the checksum for user usage */
356 return checksum;
5d4b8cf2
PJ
357}
358
d7c0a89a 359static int verify(uint8_t *buffer, testsz_t len)
5d4b8cf2 360{
d7c0a89a
QY
361 uint8_t *p;
362 uint32_t c0;
363 uint32_t c1;
d62a17ae 364 int i, partial_len;
365
366 p = buffer;
367
368 c0 = 0;
369 c1 = 0;
370
371 while (len) {
372 partial_len = MIN(len, 5803U);
373
374 for (i = 0; i < partial_len; i++) {
375 c0 = c0 + *(p++);
376 c1 += c0;
377 }
378 c0 = c0 % 255;
379 c1 = c1 % 255;
380
381 len -= partial_len;
382 }
383
384 if (c0 == 0 && c1 == 0)
385 return 0;
386
387 return 1;
5d4b8cf2
PJ
388}
389
d62a17ae 390static int /* return checksum in low-order 16 bits */
9d303b37 391 in_cksum_optimized(void *parg, int nbytes)
439c52f1 392{
d7c0a89a 393 unsigned short *ptr = parg;
d62a17ae 394 register long sum; /* assumes long == 32 bits */
d7c0a89a 395 register unsigned short answer; /* assumes unsigned short == 16 bits */
439c52f1
JT
396 register int count;
397 /*
398 * Our algorithm is simple, using a 32-bit accumulator (sum),
399 * we add sequential 16-bit words to it, and at the end, fold back
400 * all the carry bits from the top 16 bits into the lower 16 bits.
401 */
402
403 sum = 0;
404 count = nbytes >> 1; /* div by 2 */
d62a17ae 405 for (ptr--; count; --count)
406 sum += *++ptr;
439c52f1 407
d62a17ae 408 if (nbytes & 1) /* Odd */
d7c0a89a 409 sum += *(uint8_t *)(++ptr); /* one byte only */
439c52f1
JT
410
411 /*
412 * Add back carry outs from top 16 bits to low 16 bits.
413 */
414
d62a17ae 415 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
416 sum += (sum >> 16); /* add carry */
417 answer = ~sum; /* ones-complement, then truncate to 16 bits */
418 return (answer);
439c52f1
JT
419}
420
421
1dba254e 422static int /* return checksum in low-order 16 bits */
9d303b37 423 in_cksum_rfc(void *parg, int count)
439c52f1
JT
424/* from RFC 1071 */
425{
d7c0a89a 426 unsigned short *addr = parg;
439c52f1
JT
427 /* Compute Internet Checksum for "count" bytes
428 * beginning at location "addr".
429 */
d62a17ae 430 register long sum = 0;
439c52f1 431
d62a17ae 432 while (count > 1) {
433 /* This is the inner loop */
434 sum += *addr++;
435 count -= 2;
439c52f1
JT
436 }
437 /* Add left-over byte, if any */
438 if (count > 0) {
d7c0a89a 439 sum += *(uint8_t *)addr;
439c52f1
JT
440 }
441
442 /* Fold 32-bit sum to 16 bits */
d62a17ae 443 while (sum >> 16)
444 sum = (sum & 0xffff) + (sum >> 16);
439c52f1
JT
445 return ~sum;
446}
447
448
d62a17ae 449int main(int argc, char **argv)
5d4b8cf2
PJ
450{
451/* 60017 65629 702179 */
452#define MAXDATALEN 60017
d7c0a89a
QY
453#define BUFSIZE MAXDATALEN + sizeof(uint16_t)
454 uint8_t buffer[BUFSIZE];
d62a17ae 455 int exercise = 0;
5d4b8cf2 456#define EXERCISESTEP 257
9b6ef21e 457 struct prng *prng = prng_new(0);
d62a17ae 458
459 while (1) {
d7c0a89a 460 uint16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
9b6ef21e 461 int i;
d62a17ae 462
463 exercise += EXERCISESTEP;
464 exercise %= MAXDATALEN;
465
89087f23
DL
466 printf("\rexercising length %d\033[K", exercise);
467
9b6ef21e
DL
468 for (i = 0; i < exercise; i++)
469 buffer[i] = prng_rand(prng);
d62a17ae 470
471 in_csum = in_cksum(buffer, exercise);
472 in_csum_res = in_cksum_optimized(buffer, exercise);
473 in_csum_rfc = in_cksum_rfc(buffer, exercise);
474 if (in_csum_res != in_csum || in_csum != in_csum_rfc)
89087f23 475 printf("\nverify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n",
d62a17ae 476 in_csum, in_csum_res, in_csum_rfc, exercise);
477
89087f23
DL
478 struct iovec iov[3];
479 uint16_t in_csum_iov;
480
481 iov[0].iov_base = buffer;
482 iov[0].iov_len = exercise / 2;
483 iov[1].iov_base = buffer + iov[0].iov_len;
484 iov[1].iov_len = exercise - iov[0].iov_len;
485
486 in_csum_iov = in_cksumv(iov, 2);
487 if (in_csum_iov != in_csum)
488 printf("\nverify: in_cksumv failed, lens: %zu+%zu\n",
489 iov[0].iov_len, iov[1].iov_len);
490
491 if (exercise >= 6) {
492 /* force split with byte leftover */
493 iov[0].iov_base = buffer;
494 iov[0].iov_len = (exercise / 2) | 1;
495 iov[1].iov_base = buffer + iov[0].iov_len;
496 iov[1].iov_len = 2;
497 iov[2].iov_base = buffer + iov[0].iov_len + 2;
498 iov[2].iov_len = exercise - iov[0].iov_len - 2;
499
500 in_csum_iov = in_cksumv(iov, 3);
501 if (in_csum_iov != in_csum)
502 printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
503 iov[0].iov_len, iov[1].iov_len,
504 iov[2].iov_len, in_csum_iov, in_csum);
505
506 /* force split without byte leftover */
507 iov[0].iov_base = buffer;
508 iov[0].iov_len = (exercise / 2) & ~1UL;
509 iov[1].iov_base = buffer + iov[0].iov_len;
510 iov[1].iov_len = 2;
511 iov[2].iov_base = buffer + iov[0].iov_len + 2;
512 iov[2].iov_len = exercise - iov[0].iov_len - 2;
513
514 in_csum_iov = in_cksumv(iov, 3);
515 if (in_csum_iov != in_csum)
516 printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
517 iov[0].iov_len, iov[1].iov_len,
518 iov[2].iov_len, in_csum_iov, in_csum);
519 }
520
9b6ef21e
DL
521 if (exercise >= FLETCHER_CHECKSUM_VALIDATE)
522 continue;
523
d7c0a89a 524 ospfd = ospfd_checksum(buffer, exercise + sizeof(uint16_t),
d62a17ae 525 exercise);
d7c0a89a 526 if (verify(buffer, exercise + sizeof(uint16_t)))
89087f23 527 printf("\nverify: ospfd failed\n");
d7c0a89a 528 isisd = iso_csum_create(buffer, exercise + sizeof(uint16_t),
d62a17ae 529 exercise);
d7c0a89a 530 if (verify(buffer, exercise + sizeof(uint16_t)))
89087f23 531 printf("\nverify: isisd failed\n");
d7c0a89a 532 lib = fletcher_checksum(buffer, exercise + sizeof(uint16_t),
d62a17ae 533 exercise);
d7c0a89a 534 if (verify(buffer, exercise + sizeof(uint16_t)))
89087f23 535 printf("\nverify: lib failed\n");
d62a17ae 536
537 if (ospfd != lib) {
89087f23 538 printf("\nMismatch in values at size %d\n"
d62a17ae 539 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
540 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
541 "lib: 0x%04x\n",
542 exercise, ospfd, ospfd_vals.a.c0,
543 ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
544 isisd, isisd_vals.a.c0, isisd_vals.a.c1,
545 isisd_vals.x, isisd_vals.y, lib);
546
547 /* Investigate reduction phase discrepencies */
548 if (ospfd_vals.a.c0 == isisd_vals.a.c0
549 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
550 printf("\n");
551 for (i = 0; reducts[i].name != NULL; i++) {
552 ospfd = reducts[i].f(
553 &ospfd_vals,
d7c0a89a 554 exercise + sizeof(uint16_t),
d62a17ae 555 exercise);
556 printf("%20s: x: %02x, y %02x, checksum 0x%04x\n",
557 reducts[i].name,
558 ospfd_vals.x & 0xff,
559 ospfd_vals.y & 0xff, ospfd);
560 }
561 }
562
d7c0a89a 563 printf("\n uint8_t testdata [] = {\n ");
d62a17ae 564 for (i = 0; i < exercise; i++) {
565 printf("0x%02x,%s", buffer[i],
566 (i + 1) % 8 ? " " : "\n ");
567 }
568 printf("\n}\n");
569 exit(1);
570 }
571 }
5d4b8cf2 572}