1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
3 */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_memory.h>
11 #include <rte_lpm6.h>
12
13 #include "test.h"
14 #include "test_lpm6_data.h"
15
16 #define TEST_LPM_ASSERT(cond) do { \
17 if (!(cond)) { \
18 printf("Error at line %d: \n", __LINE__); \
19 return -1; \
20 } \
21 } while(0)
22
23 typedef int32_t (* rte_lpm6_test)(void);
24
25 static int32_t test0(void);
26 static int32_t test1(void);
27 static int32_t test2(void);
28 static int32_t test3(void);
29 static int32_t test4(void);
30 static int32_t test5(void);
31 static int32_t test6(void);
32 static int32_t test7(void);
33 static int32_t test8(void);
34 static int32_t test9(void);
35 static int32_t test10(void);
36 static int32_t test11(void);
37 static int32_t test12(void);
38 static int32_t test13(void);
39 static int32_t test14(void);
40 static int32_t test15(void);
41 static int32_t test16(void);
42 static int32_t test17(void);
43 static int32_t test18(void);
44 static int32_t test19(void);
45 static int32_t test20(void);
46 static int32_t test21(void);
47 static int32_t test22(void);
48 static int32_t test23(void);
49 static int32_t test24(void);
50 static int32_t test25(void);
51 static int32_t test26(void);
52 static int32_t test27(void);
53 static int32_t test28(void);
54
55 rte_lpm6_test tests6[] = {
56 /* Test Cases */
57 test0,
58 test1,
59 test2,
60 test3,
61 test4,
62 test5,
63 test6,
64 test7,
65 test8,
66 test9,
67 test10,
68 test11,
69 test12,
70 test13,
71 test14,
72 test15,
73 test16,
74 test17,
75 test18,
76 test19,
77 test20,
78 test21,
79 test22,
80 test23,
81 test24,
82 test25,
83 test26,
84 test27,
85 test28,
86 };
87
88 #define MAX_DEPTH 128
89 #define MAX_RULES 1000000
90 #define NUMBER_TBL8S (1 << 16)
91 #define MAX_NUM_TBL8S (1 << 21)
92 #define PASS 0
93
94 static void
IPv6(uint8_t * ip,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5,uint8_t b6,uint8_t b7,uint8_t b8,uint8_t b9,uint8_t b10,uint8_t b11,uint8_t b12,uint8_t b13,uint8_t b14,uint8_t b15,uint8_t b16)95 IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
96 uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10,
97 uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15,
98 uint8_t b16)
99 {
100 ip[0] = b1;
101 ip[1] = b2;
102 ip[2] = b3;
103 ip[3] = b4;
104 ip[4] = b5;
105 ip[5] = b6;
106 ip[6] = b7;
107 ip[7] = b8;
108 ip[8] = b9;
109 ip[9] = b10;
110 ip[10] = b11;
111 ip[11] = b12;
112 ip[12] = b13;
113 ip[13] = b14;
114 ip[14] = b15;
115 ip[15] = b16;
116 }
117
118 /*
119 * Check that rte_lpm6_create fails gracefully for incorrect user input
120 * arguments
121 */
122 int32_t
test0(void)123 test0(void)
124 {
125 struct rte_lpm6 *lpm = NULL;
126 struct rte_lpm6_config config;
127
128 config.max_rules = MAX_RULES;
129 config.number_tbl8s = NUMBER_TBL8S;
130 config.flags = 0;
131
132 /* rte_lpm6_create: lpm name == NULL */
133 lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config);
134 TEST_LPM_ASSERT(lpm == NULL);
135
136 /* rte_lpm6_create: max_rules = 0 */
137 /* Note: __func__ inserts the function name, in this case "test0". */
138 config.max_rules = 0;
139 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
140 TEST_LPM_ASSERT(lpm == NULL);
141
142 /* socket_id < -1 is invalid */
143 config.max_rules = MAX_RULES;
144 lpm = rte_lpm6_create(__func__, -2, &config);
145 TEST_LPM_ASSERT(lpm == NULL);
146
147 /* rte_lpm6_create: number_tbl8s is bigger than the maximum */
148 config.number_tbl8s = MAX_NUM_TBL8S + 1;
149 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
150 TEST_LPM_ASSERT(lpm == NULL);
151
152 /* rte_lpm6_create: config = NULL */
153 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL);
154 TEST_LPM_ASSERT(lpm == NULL);
155
156 return PASS;
157 }
158
159 /*
160 * Creates two different LPM tables. Tries to create a third one with the same
161 * name as the first one and expects the create function to return the same
162 * pointer.
163 */
164 int32_t
test1(void)165 test1(void)
166 {
167 struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL;
168 struct rte_lpm6_config config;
169
170 config.max_rules = MAX_RULES;
171 config.number_tbl8s = NUMBER_TBL8S;
172 config.flags = 0;
173
174 /* rte_lpm6_create: lpm name == LPM1 */
175 lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
176 TEST_LPM_ASSERT(lpm1 != NULL);
177
178 /* rte_lpm6_create: lpm name == LPM2 */
179 lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config);
180 TEST_LPM_ASSERT(lpm2 != NULL);
181
182 /* rte_lpm6_create: lpm name == LPM2 */
183 lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
184 TEST_LPM_ASSERT(lpm3 == NULL);
185
186 rte_lpm6_free(lpm1);
187 rte_lpm6_free(lpm2);
188
189 return PASS;
190 }
191
192 /*
193 * Create lpm table then delete lpm table 20 times
194 * Use a slightly different rules size each time
195 */
196 int32_t
test2(void)197 test2(void)
198 {
199 struct rte_lpm6 *lpm = NULL;
200 struct rte_lpm6_config config;
201 int32_t i;
202
203 config.number_tbl8s = NUMBER_TBL8S;
204 config.flags = 0;
205
206 /* rte_lpm6_free: Free NULL */
207 for (i = 0; i < 20; i++) {
208 config.max_rules = MAX_RULES - i;
209 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
210 TEST_LPM_ASSERT(lpm != NULL);
211
212 rte_lpm6_free(lpm);
213 }
214
215 /* Can not test free so return success */
216 return PASS;
217 }
218
219 /*
220 * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and
221 * therefore it is impossible to check for failure but this test is added to
222 * increase function coverage metrics and to validate that freeing null does
223 * not crash.
224 */
225 int32_t
test3(void)226 test3(void)
227 {
228 struct rte_lpm6 *lpm = NULL;
229 struct rte_lpm6_config config;
230
231 config.max_rules = MAX_RULES;
232 config.number_tbl8s = NUMBER_TBL8S;
233 config.flags = 0;
234
235 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
236 TEST_LPM_ASSERT(lpm != NULL);
237
238 rte_lpm6_free(lpm);
239 rte_lpm6_free(NULL);
240 return PASS;
241 }
242
243 /*
244 * Check that rte_lpm6_add fails gracefully for incorrect user input arguments
245 */
246 int32_t
test4(void)247 test4(void)
248 {
249 struct rte_lpm6 *lpm = NULL;
250 struct rte_lpm6_config config;
251
252 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
253 uint8_t depth = 24, next_hop = 100;
254 int32_t status = 0;
255
256 config.max_rules = MAX_RULES;
257 config.number_tbl8s = NUMBER_TBL8S;
258 config.flags = 0;
259
260 /* rte_lpm6_add: lpm == NULL */
261 status = rte_lpm6_add(NULL, ip, depth, next_hop);
262 TEST_LPM_ASSERT(status < 0);
263
264 /*Create vaild lpm to use in rest of test. */
265 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
266 TEST_LPM_ASSERT(lpm != NULL);
267
268 /* rte_lpm6_add: depth < 1 */
269 status = rte_lpm6_add(lpm, ip, 0, next_hop);
270 TEST_LPM_ASSERT(status < 0);
271
272 /* rte_lpm6_add: depth > MAX_DEPTH */
273 status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
274 TEST_LPM_ASSERT(status < 0);
275
276 rte_lpm6_free(lpm);
277
278 return PASS;
279 }
280
281 /*
282 * Check that rte_lpm6_delete fails gracefully for incorrect user input
283 * arguments
284 */
285 int32_t
test5(void)286 test5(void)
287 {
288 struct rte_lpm6 *lpm = NULL;
289 struct rte_lpm6_config config;
290 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
291 uint8_t depth = 24;
292 int32_t status = 0;
293
294 config.max_rules = MAX_RULES;
295 config.number_tbl8s = NUMBER_TBL8S;
296 config.flags = 0;
297
298 /* rte_lpm_delete: lpm == NULL */
299 status = rte_lpm6_delete(NULL, ip, depth);
300 TEST_LPM_ASSERT(status < 0);
301
302 /*Create vaild lpm to use in rest of test. */
303 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
304 TEST_LPM_ASSERT(lpm != NULL);
305
306 /* rte_lpm_delete: depth < 1 */
307 status = rte_lpm6_delete(lpm, ip, 0);
308 TEST_LPM_ASSERT(status < 0);
309
310 /* rte_lpm_delete: depth > MAX_DEPTH */
311 status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1));
312 TEST_LPM_ASSERT(status < 0);
313
314 rte_lpm6_free(lpm);
315
316 return PASS;
317 }
318
319 /*
320 * Check that rte_lpm6_lookup fails gracefully for incorrect user input
321 * arguments
322 */
323 int32_t
test6(void)324 test6(void)
325 {
326 struct rte_lpm6 *lpm = NULL;
327 struct rte_lpm6_config config;
328 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
329 uint32_t next_hop_return = 0;
330 int32_t status = 0;
331
332 config.max_rules = MAX_RULES;
333 config.number_tbl8s = NUMBER_TBL8S;
334 config.flags = 0;
335
336 /* rte_lpm6_lookup: lpm == NULL */
337 status = rte_lpm6_lookup(NULL, ip, &next_hop_return);
338 TEST_LPM_ASSERT(status < 0);
339
340 /*Create vaild lpm to use in rest of test. */
341 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
342 TEST_LPM_ASSERT(lpm != NULL);
343
344 /* rte_lpm6_lookup: ip = NULL */
345 status = rte_lpm6_lookup(lpm, NULL, &next_hop_return);
346 TEST_LPM_ASSERT(status < 0);
347
348 /* rte_lpm6_lookup: next_hop = NULL */
349 status = rte_lpm6_lookup(lpm, ip, NULL);
350 TEST_LPM_ASSERT(status < 0);
351
352 rte_lpm6_free(lpm);
353
354 return PASS;
355 }
356
357 /*
358 * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user
359 * input arguments
360 */
361 int32_t
test7(void)362 test7(void)
363 {
364 struct rte_lpm6 *lpm = NULL;
365 struct rte_lpm6_config config;
366 uint8_t ip[10][16];
367 int32_t next_hop_return[10];
368 int32_t status = 0;
369
370 config.max_rules = MAX_RULES;
371 config.number_tbl8s = NUMBER_TBL8S;
372 config.flags = 0;
373
374 /* rte_lpm6_lookup: lpm == NULL */
375 status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10);
376 TEST_LPM_ASSERT(status < 0);
377
378 /*Create vaild lpm to use in rest of test. */
379 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
380 TEST_LPM_ASSERT(lpm != NULL);
381
382 /* rte_lpm6_lookup: ip = NULL */
383 status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10);
384 TEST_LPM_ASSERT(status < 0);
385
386 /* rte_lpm6_lookup: next_hop = NULL */
387 status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10);
388 TEST_LPM_ASSERT(status < 0);
389
390 rte_lpm6_free(lpm);
391
392 return PASS;
393 }
394
395 /*
396 * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user
397 * input arguments
398 */
399 int32_t
test8(void)400 test8(void)
401 {
402 struct rte_lpm6 *lpm = NULL;
403 struct rte_lpm6_config config;
404 uint8_t ip[10][16];
405 uint8_t depth[10];
406 int32_t status = 0;
407
408 config.max_rules = MAX_RULES;
409 config.number_tbl8s = NUMBER_TBL8S;
410 config.flags = 0;
411
412 /* rte_lpm6_delete: lpm == NULL */
413 status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10);
414 TEST_LPM_ASSERT(status < 0);
415
416 /*Create vaild lpm to use in rest of test. */
417 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
418 TEST_LPM_ASSERT(lpm != NULL);
419
420 /* rte_lpm6_delete: ip = NULL */
421 status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10);
422 TEST_LPM_ASSERT(status < 0);
423
424 /* rte_lpm6_delete: next_hop = NULL */
425 status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10);
426 TEST_LPM_ASSERT(status < 0);
427
428 rte_lpm6_free(lpm);
429
430 return PASS;
431 }
432
433 /*
434 * Call add, lookup and delete for a single rule with depth < 24.
435 * Check all the combinations for the first three bytes that result in a hit.
436 * Delete the rule and check that the same test returs a miss.
437 */
438 int32_t
test9(void)439 test9(void)
440 {
441 struct rte_lpm6 *lpm = NULL;
442 struct rte_lpm6_config config;
443 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
444 uint8_t depth = 16;
445 uint32_t next_hop_add = 100, next_hop_return = 0;
446 int32_t status = 0;
447 uint8_t i;
448
449 config.max_rules = MAX_RULES;
450 config.number_tbl8s = NUMBER_TBL8S;
451 config.flags = 0;
452
453 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
454 TEST_LPM_ASSERT(lpm != NULL);
455
456 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
457 TEST_LPM_ASSERT(status == 0);
458
459 for (i = 0; i < UINT8_MAX; i++) {
460 ip[2] = i;
461 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
462 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
463 }
464
465 status = rte_lpm6_delete(lpm, ip, depth);
466 TEST_LPM_ASSERT(status == 0);
467
468 for (i = 0; i < UINT8_MAX; i++) {
469 ip[2] = i;
470 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
471 TEST_LPM_ASSERT(status == -ENOENT);
472 }
473
474 rte_lpm6_free(lpm);
475
476 return PASS;
477 }
478
479 /*
480 * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
481 * another one and expects success.
482 */
483 int32_t
test10(void)484 test10(void)
485 {
486 struct rte_lpm6 *lpm = NULL;
487 struct rte_lpm6_config config;
488 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
489 uint8_t depth;
490 uint32_t next_hop_add = 100;
491 int32_t status = 0;
492 int i;
493
494 config.max_rules = 127;
495 config.number_tbl8s = NUMBER_TBL8S;
496 config.flags = 0;
497
498 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
499 TEST_LPM_ASSERT(lpm != NULL);
500
501 for (i = 1; i < 128; i++) {
502 depth = (uint8_t)i;
503 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
504 TEST_LPM_ASSERT(status == 0);
505 }
506
507 depth = 128;
508 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
509 TEST_LPM_ASSERT(status == -ENOSPC);
510
511 depth = 127;
512 status = rte_lpm6_delete(lpm, ip, depth);
513 TEST_LPM_ASSERT(status == 0);
514
515 depth = 128;
516 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
517 TEST_LPM_ASSERT(status == 0);
518
519 rte_lpm6_free(lpm);
520
521 return PASS;
522 }
523
524 /*
525 * Creates an LPM table with a small number of tbl8s and exhaust them in the
526 * middle of the process of creating a rule.
527 */
528 int32_t
test11(void)529 test11(void)
530 {
531 struct rte_lpm6 *lpm = NULL;
532 struct rte_lpm6_config config;
533 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
534 uint8_t depth;
535 uint32_t next_hop_add = 100;
536 int32_t status = 0;
537
538 config.max_rules = MAX_RULES;
539 config.number_tbl8s = 16;
540 config.flags = 0;
541
542 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
543 TEST_LPM_ASSERT(lpm != NULL);
544
545 depth = 128;
546 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
547 TEST_LPM_ASSERT(status == 0);
548
549 ip[0] = 1;
550 depth = 25;
551 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
552 TEST_LPM_ASSERT(status == 0);
553
554 status = rte_lpm6_delete(lpm, ip, depth);
555 TEST_LPM_ASSERT(status == 0);
556
557 depth = 33;
558 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
559 TEST_LPM_ASSERT(status == 0);
560
561 status = rte_lpm6_delete(lpm, ip, depth);
562 TEST_LPM_ASSERT(status == 0);
563
564 depth = 41;
565 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
566 TEST_LPM_ASSERT(status == 0);
567
568 status = rte_lpm6_delete(lpm, ip, depth);
569 TEST_LPM_ASSERT(status == 0);
570
571 depth = 49;
572 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
573 TEST_LPM_ASSERT(status == -ENOSPC);
574
575 depth = 41;
576 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
577 TEST_LPM_ASSERT(status == 0);
578
579 rte_lpm6_free(lpm);
580
581 return PASS;
582 }
583
584 /*
585 * Creates an LPM table with a small number of tbl8s and exhaust them in the
586 * middle of the process of adding a rule when there is already an existing rule
587 * in that position and needs to be extended.
588 */
589 int32_t
test12(void)590 test12(void)
591 {
592 struct rte_lpm6 *lpm = NULL;
593 struct rte_lpm6_config config;
594 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
595 uint8_t depth;
596 uint32_t next_hop_add = 100;
597 int32_t status = 0;
598
599 config.max_rules = MAX_RULES;
600 config.number_tbl8s = 16;
601 config.flags = 0;
602
603 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
604 TEST_LPM_ASSERT(lpm != NULL);
605
606 depth = 128;
607 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
608 TEST_LPM_ASSERT(status == 0);
609
610 ip[0] = 1;
611 depth = 41;
612 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
613 TEST_LPM_ASSERT(status == 0);
614
615 depth = 49;
616 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
617 TEST_LPM_ASSERT(status == -ENOSPC);
618
619 rte_lpm6_free(lpm);
620
621 return PASS;
622 }
623
624 /*
625 * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
626 * Delete one of the rules and tries to add the third one again.
627 */
628 int32_t
test13(void)629 test13(void)
630 {
631 struct rte_lpm6 *lpm = NULL;
632 struct rte_lpm6_config config;
633 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
634 uint8_t depth;
635 uint32_t next_hop_add = 100;
636 int32_t status = 0;
637
638 config.max_rules = 2;
639 config.number_tbl8s = NUMBER_TBL8S;
640 config.flags = 0;
641
642 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
643 TEST_LPM_ASSERT(lpm != NULL);
644
645 depth = 1;
646 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
647 TEST_LPM_ASSERT(status == 0);
648
649 depth = 2;
650 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
651 TEST_LPM_ASSERT(status == 0);
652
653 depth = 3;
654 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
655 TEST_LPM_ASSERT(status == -ENOSPC);
656
657 depth = 2;
658 status = rte_lpm6_delete(lpm, ip, depth);
659 TEST_LPM_ASSERT(status == 0);
660
661 depth = 3;
662 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
663 TEST_LPM_ASSERT(status == 0);
664
665 rte_lpm6_free(lpm);
666
667 return PASS;
668 }
669
670 /*
671 * Add 2^12 routes with different first 12 bits and depth 25.
672 * Add one more route with the same depth and check that results in a failure.
673 * After that delete the last rule and create the one that was attempted to be
674 * created. This checks tbl8 exhaustion.
675 */
676 int32_t
test14(void)677 test14(void)
678 {
679 struct rte_lpm6 *lpm = NULL;
680 struct rte_lpm6_config config;
681 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
682 uint8_t depth = 25;
683 uint32_t next_hop_add = 100;
684 int32_t status = 0;
685 int i;
686
687 config.max_rules = MAX_RULES;
688 config.number_tbl8s = 256;
689 config.flags = 0;
690
691 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
692 TEST_LPM_ASSERT(lpm != NULL);
693
694 for (i = 0; i < 256; i++) {
695 ip[0] = (uint8_t)i;
696 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
697 TEST_LPM_ASSERT(status == 0);
698 }
699
700 ip[0] = 255;
701 ip[1] = 1;
702 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
703 TEST_LPM_ASSERT(status == -ENOSPC);
704
705 ip[0] = 255;
706 ip[1] = 0;
707 status = rte_lpm6_delete(lpm, ip, depth);
708 TEST_LPM_ASSERT(status == 0);
709
710 ip[0] = 255;
711 ip[1] = 1;
712 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
713 TEST_LPM_ASSERT(status == 0);
714
715 rte_lpm6_free(lpm);
716
717 return PASS;
718 }
719
720 /*
721 * Call add, lookup and delete for a single rule with depth = 24
722 */
723 int32_t
test15(void)724 test15(void)
725 {
726 struct rte_lpm6 *lpm = NULL;
727 struct rte_lpm6_config config;
728 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
729 uint8_t depth = 24;
730 uint32_t next_hop_add = 100, next_hop_return = 0;
731 int32_t status = 0;
732
733 config.max_rules = MAX_RULES;
734 config.number_tbl8s = NUMBER_TBL8S;
735 config.flags = 0;
736
737 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
738 TEST_LPM_ASSERT(lpm != NULL);
739
740 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
741 TEST_LPM_ASSERT(status == 0);
742
743 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
744 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
745
746 status = rte_lpm6_delete(lpm, ip, depth);
747 TEST_LPM_ASSERT(status == 0);
748
749 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
750 TEST_LPM_ASSERT(status == -ENOENT);
751
752 rte_lpm6_free(lpm);
753
754 return PASS;
755 }
756
757 /*
758 * Call add, lookup and delete for a single rule with depth > 24
759 */
760 int32_t
test16(void)761 test16(void)
762 {
763 struct rte_lpm6 *lpm = NULL;
764 struct rte_lpm6_config config;
765 uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
766 uint8_t depth = 128;
767 uint32_t next_hop_add = 100, next_hop_return = 0;
768 int32_t status = 0;
769
770 config.max_rules = MAX_RULES;
771 config.number_tbl8s = NUMBER_TBL8S;
772 config.flags = 0;
773
774 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
775 TEST_LPM_ASSERT(lpm != NULL);
776
777 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
778 TEST_LPM_ASSERT(status == 0);
779
780 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
781 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
782
783 status = rte_lpm6_delete(lpm, ip, depth);
784 TEST_LPM_ASSERT(status == 0);
785
786 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
787 TEST_LPM_ASSERT(status == -ENOENT);
788
789 rte_lpm6_free(lpm);
790
791 return PASS;
792 }
793
794 /*
795 * Use rte_lpm6_add to add rules which effect only the second half of the lpm
796 * table. Use all possible depths ranging from 1..32. Set the next hop = to the
797 * depth. Check lookup hit for on every add and check for lookup miss on the
798 * first half of the lpm table after each add. Finally delete all rules going
799 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
800 * delete. The lookup should return the next_hop_add value related to the
801 * previous depth value (i.e. depth -1).
802 */
803 int32_t
test17(void)804 test17(void)
805 {
806 struct rte_lpm6 *lpm = NULL;
807 struct rte_lpm6_config config;
808 uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
809 255,255,255,255,255,255,255};
810 uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
811 uint8_t depth;
812 uint32_t next_hop_add, next_hop_return;
813 int32_t status = 0;
814
815 config.max_rules = MAX_RULES;
816 config.number_tbl8s = NUMBER_TBL8S;
817 config.flags = 0;
818
819 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
820 TEST_LPM_ASSERT(lpm != NULL);
821
822 /* Loop with rte_lpm6_add. */
823 for (depth = 1; depth <= 16; depth++) {
824 /* Let the next_hop_add value = depth. Just for change. */
825 next_hop_add = depth;
826
827 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
828 TEST_LPM_ASSERT(status == 0);
829
830 /* Check IP in first half of tbl24 which should be empty. */
831 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
832 TEST_LPM_ASSERT(status == -ENOENT);
833
834 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
835 TEST_LPM_ASSERT((status == 0) &&
836 (next_hop_return == next_hop_add));
837 }
838
839 /* Loop with rte_lpm6_delete. */
840 for (depth = 16; depth >= 1; depth--) {
841 next_hop_add = (depth - 1);
842
843 status = rte_lpm6_delete(lpm, ip2, depth);
844 TEST_LPM_ASSERT(status == 0);
845
846 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
847
848 if (depth != 1) {
849 TEST_LPM_ASSERT((status == 0) &&
850 (next_hop_return == next_hop_add));
851 }
852 else {
853 TEST_LPM_ASSERT(status == -ENOENT);
854 }
855
856 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
857 TEST_LPM_ASSERT(status == -ENOENT);
858 }
859
860 rte_lpm6_free(lpm);
861
862 return PASS;
863 }
864
865 /*
866 * - Add & lookup to hit invalid TBL24 entry
867 * - Add & lookup to hit valid TBL24 entry not extended
868 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
869 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
870 */
871 int32_t
test18(void)872 test18(void)
873 {
874 struct rte_lpm6 *lpm = NULL;
875 struct rte_lpm6_config config;
876 uint8_t ip[16], ip_1[16], ip_2[16];
877 uint8_t depth, depth_1, depth_2;
878 uint32_t next_hop_add, next_hop_add_1,
879 next_hop_add_2, next_hop_return;
880 int32_t status = 0;
881
882 config.max_rules = MAX_RULES;
883 config.number_tbl8s = NUMBER_TBL8S;
884 config.flags = 0;
885
886 /* Add & lookup to hit invalid TBL24 entry */
887 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
888 depth = 24;
889 next_hop_add = 100;
890
891 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
892 TEST_LPM_ASSERT(lpm != NULL);
893
894 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
895 TEST_LPM_ASSERT(status == 0);
896
897 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
898 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
899
900 status = rte_lpm6_delete(lpm, ip, depth);
901 TEST_LPM_ASSERT(status == 0);
902
903 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
904 TEST_LPM_ASSERT(status == -ENOENT);
905
906 rte_lpm6_delete_all(lpm);
907
908 /* Add & lookup to hit valid TBL24 entry not extended */
909 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
910 depth = 23;
911 next_hop_add = 100;
912
913 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
914 TEST_LPM_ASSERT(status == 0);
915
916 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
917 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
918
919 depth = 24;
920 next_hop_add = 101;
921
922 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
923 TEST_LPM_ASSERT(status == 0);
924
925 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
926 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
927
928 depth = 24;
929
930 status = rte_lpm6_delete(lpm, ip, depth);
931 TEST_LPM_ASSERT(status == 0);
932
933 depth = 23;
934
935 status = rte_lpm6_delete(lpm, ip, depth);
936 TEST_LPM_ASSERT(status == 0);
937
938 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
939 TEST_LPM_ASSERT(status == -ENOENT);
940
941 rte_lpm6_delete_all(lpm);
942
943 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
944 * entry.
945 */
946 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
947 depth = 32;
948 next_hop_add = 100;
949
950 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
951 TEST_LPM_ASSERT(status == 0);
952
953 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
954 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
955
956 IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
957 depth = 32;
958 next_hop_add = 101;
959
960 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
961 TEST_LPM_ASSERT(status == 0);
962
963 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
964 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
965
966 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
967 depth = 32;
968 next_hop_add = 100;
969
970 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
971 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
972
973 status = rte_lpm6_delete(lpm, ip, depth);
974 TEST_LPM_ASSERT(status == 0);
975
976 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
977 TEST_LPM_ASSERT(status == -ENOENT);
978
979 rte_lpm6_delete_all(lpm);
980
981 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
982 * entry
983 */
984 IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
985 depth_1 = 25;
986 next_hop_add_1 = 101;
987
988 IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
989 depth_2 = 32;
990 next_hop_add_2 = 102;
991
992 next_hop_return = 0;
993
994 status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
995 TEST_LPM_ASSERT(status == 0);
996
997 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
998 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
999
1000 status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1001 TEST_LPM_ASSERT(status == 0);
1002
1003 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1004 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1005
1006 status = rte_lpm6_delete(lpm, ip_2, depth_2);
1007 TEST_LPM_ASSERT(status == 0);
1008
1009 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1010 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1011
1012 status = rte_lpm6_delete(lpm, ip_1, depth_1);
1013 TEST_LPM_ASSERT(status == 0);
1014
1015 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1016 TEST_LPM_ASSERT(status == -ENOENT);
1017
1018 rte_lpm6_free(lpm);
1019
1020 return PASS;
1021 }
1022
1023 /*
1024 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1025 * lookup)
1026 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1027 * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1028 * delete & lookup)
1029 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1030 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1031 * - Delete a rule that is not present in the TBL24 & lookup
1032 * - Delete a rule that is not present in the TBL8 & lookup
1033 */
1034 int32_t
test19(void)1035 test19(void)
1036 {
1037 struct rte_lpm6 *lpm = NULL;
1038 struct rte_lpm6_config config;
1039 uint8_t ip[16];
1040 uint8_t depth;
1041 uint32_t next_hop_add, next_hop_return;
1042 int32_t status = 0;
1043
1044 config.max_rules = MAX_RULES;
1045 config.number_tbl8s = NUMBER_TBL8S;
1046 config.flags = 0;
1047
1048 /* Add rule that covers a TBL24 range previously invalid & lookup
1049 * (& delete & lookup)
1050 */
1051 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1052 TEST_LPM_ASSERT(lpm != NULL);
1053
1054 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1055 depth = 16;
1056 next_hop_add = 100;
1057
1058 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1059 TEST_LPM_ASSERT(status == 0);
1060
1061 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1062 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1063
1064 status = rte_lpm6_delete(lpm, ip, depth);
1065 TEST_LPM_ASSERT(status == 0);
1066
1067 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1068 TEST_LPM_ASSERT(status == -ENOENT);
1069
1070 rte_lpm6_delete_all(lpm);
1071
1072 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1073 depth = 25;
1074 next_hop_add = 100;
1075
1076 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1077 TEST_LPM_ASSERT(status == 0);
1078
1079 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1080 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1081
1082 status = rte_lpm6_delete(lpm, ip, depth);
1083 TEST_LPM_ASSERT(status == 0);
1084
1085 rte_lpm6_delete_all(lpm);
1086
1087 /*
1088 * Add rule that extends a TBL24 valid entry & lookup for both rules
1089 * (& delete & lookup)
1090 */
1091
1092 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1093 depth = 24;
1094 next_hop_add = 100;
1095
1096 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1097 TEST_LPM_ASSERT(status == 0);
1098
1099 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1100 depth = 32;
1101 next_hop_add = 101;
1102
1103 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1104 TEST_LPM_ASSERT(status == 0);
1105
1106 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1107 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1108
1109 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1110 next_hop_add = 100;
1111
1112 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1113 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1114
1115 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1116 depth = 24;
1117
1118 status = rte_lpm6_delete(lpm, ip, depth);
1119 TEST_LPM_ASSERT(status == 0);
1120
1121 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1122 TEST_LPM_ASSERT(status == -ENOENT);
1123
1124 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1125 depth = 32;
1126
1127 status = rte_lpm6_delete(lpm, ip, depth);
1128 TEST_LPM_ASSERT(status == 0);
1129
1130 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1131 TEST_LPM_ASSERT(status == -ENOENT);
1132
1133 rte_lpm6_delete_all(lpm);
1134
1135 /*
1136 * Add rule that updates the next hop in TBL24 & lookup
1137 * (& delete & lookup)
1138 */
1139
1140 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1141 depth = 24;
1142 next_hop_add = 100;
1143
1144 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1145 TEST_LPM_ASSERT(status == 0);
1146
1147 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1148 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1149
1150 next_hop_add = 101;
1151
1152 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1153 TEST_LPM_ASSERT(status == 0);
1154
1155 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1156 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1157
1158 status = rte_lpm6_delete(lpm, ip, depth);
1159 TEST_LPM_ASSERT(status == 0);
1160
1161 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1162 TEST_LPM_ASSERT(status == -ENOENT);
1163
1164 rte_lpm6_delete_all(lpm);
1165
1166 /*
1167 * Add rule that updates the next hop in TBL8 & lookup
1168 * (& delete & lookup)
1169 */
1170
1171 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1172 depth = 32;
1173 next_hop_add = 100;
1174
1175 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1176 TEST_LPM_ASSERT(status == 0);
1177
1178 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1179 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1180
1181 next_hop_add = 101;
1182
1183 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1184 TEST_LPM_ASSERT(status == 0);
1185
1186 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1187 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1188
1189 status = rte_lpm6_delete(lpm, ip, depth);
1190 TEST_LPM_ASSERT(status == 0);
1191
1192 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1193 TEST_LPM_ASSERT(status == -ENOENT);
1194
1195 rte_lpm6_delete_all(lpm);
1196
1197 /* Delete a rule that is not present in the TBL24 & lookup */
1198
1199 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1200 depth = 24;
1201 next_hop_add = 100;
1202
1203 status = rte_lpm6_delete(lpm, ip, depth);
1204 TEST_LPM_ASSERT(status < 0);
1205
1206 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1207 TEST_LPM_ASSERT(status == -ENOENT);
1208
1209 rte_lpm6_delete_all(lpm);
1210
1211 /* Delete a rule that is not present in the TBL8 & lookup */
1212
1213 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1214 depth = 32;
1215 next_hop_add = 100;
1216
1217 status = rte_lpm6_delete(lpm, ip, depth);
1218 TEST_LPM_ASSERT(status < 0);
1219
1220 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1221 TEST_LPM_ASSERT(status == -ENOENT);
1222
1223 rte_lpm6_free(lpm);
1224
1225 return PASS;
1226 }
1227
1228 /*
1229 * Add two rules, lookup to hit the more specific one, lookup to hit the less
1230 * specific one delete the less specific rule and lookup previous values again;
1231 * add a more specific rule than the existing rule, lookup again
1232 */
1233 int32_t
test20(void)1234 test20(void)
1235 {
1236 struct rte_lpm6 *lpm = NULL;
1237 struct rte_lpm6_config config;
1238 uint8_t ip[16];
1239 uint8_t depth;
1240 uint32_t next_hop_add, next_hop_return;
1241 int32_t status = 0;
1242
1243 config.max_rules = MAX_RULES;
1244 config.number_tbl8s = NUMBER_TBL8S;
1245 config.flags = 0;
1246
1247 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1248 TEST_LPM_ASSERT(lpm != NULL);
1249
1250 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1251 depth = 24;
1252 next_hop_add = 100;
1253
1254 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1255 TEST_LPM_ASSERT(status == 0);
1256
1257 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1258 depth = 128;
1259 next_hop_add = 101;
1260
1261 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1262 TEST_LPM_ASSERT(status == 0);
1263
1264 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1265 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1266
1267 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1268 next_hop_add = 100;
1269
1270 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1271 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1272
1273 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1274 depth = 24;
1275
1276 status = rte_lpm6_delete(lpm, ip, depth);
1277 TEST_LPM_ASSERT(status == 0);
1278
1279 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1280 TEST_LPM_ASSERT(status == -ENOENT);
1281
1282 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1283 depth = 128;
1284
1285 status = rte_lpm6_delete(lpm, ip, depth);
1286 TEST_LPM_ASSERT(status == 0);
1287
1288 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1289 TEST_LPM_ASSERT(status == -ENOENT);
1290
1291 rte_lpm6_free(lpm);
1292
1293 return PASS;
1294 }
1295
1296 /*
1297 * Adds 3 rules and look them up through the lookup_bulk function.
1298 * Includes in the lookup a fourth IP address that won't match
1299 * and checks that the result is as expected.
1300 */
1301 int32_t
test21(void)1302 test21(void)
1303 {
1304 struct rte_lpm6 *lpm = NULL;
1305 struct rte_lpm6_config config;
1306 uint8_t ip_batch[4][16];
1307 uint8_t depth;
1308 uint32_t next_hop_add;
1309 int32_t next_hop_return[4];
1310 int32_t status = 0;
1311
1312 config.max_rules = MAX_RULES;
1313 config.number_tbl8s = NUMBER_TBL8S;
1314 config.flags = 0;
1315
1316 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1317 TEST_LPM_ASSERT(lpm != NULL);
1318
1319 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1320 depth = 48;
1321 next_hop_add = 100;
1322
1323 status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1324 TEST_LPM_ASSERT(status == 0);
1325
1326 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1327 depth = 48;
1328 next_hop_add = 101;
1329
1330 status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1331 TEST_LPM_ASSERT(status == 0);
1332
1333 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1334 depth = 48;
1335 next_hop_add = 102;
1336
1337 status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1338 TEST_LPM_ASSERT(status == 0);
1339
1340 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1341
1342 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1343 next_hop_return, 4);
1344 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1345 && next_hop_return[1] == 101 && next_hop_return[2] == 102
1346 && next_hop_return[3] == -1);
1347
1348 rte_lpm6_free(lpm);
1349
1350 return PASS;
1351 }
1352
1353 /*
1354 * Adds 5 rules and look them up.
1355 * Use the delete_bulk function to delete two of them. Lookup again.
1356 * Use the delete_bulk function to delete one more. Lookup again.
1357 * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1358 * Use the delete_bulk function to delete the remaining one. Lookup again.
1359 */
1360 int32_t
test22(void)1361 test22(void)
1362 {
1363 struct rte_lpm6 *lpm = NULL;
1364 struct rte_lpm6_config config;
1365 uint8_t ip_batch[5][16];
1366 uint8_t depth[5];
1367 uint32_t next_hop_add;
1368 int32_t next_hop_return[5];
1369 int32_t status = 0;
1370
1371 config.max_rules = MAX_RULES;
1372 config.number_tbl8s = NUMBER_TBL8S;
1373 config.flags = 0;
1374
1375 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1376 TEST_LPM_ASSERT(lpm != NULL);
1377
1378 /* Adds 5 rules and look them up */
1379
1380 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1381 depth[0] = 48;
1382 next_hop_add = 101;
1383
1384 status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1385 TEST_LPM_ASSERT(status == 0);
1386
1387 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1388 depth[1] = 48;
1389 next_hop_add = 102;
1390
1391 status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1392 TEST_LPM_ASSERT(status == 0);
1393
1394 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1395 depth[2] = 48;
1396 next_hop_add = 103;
1397
1398 status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1399 TEST_LPM_ASSERT(status == 0);
1400
1401 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1402 depth[3] = 48;
1403 next_hop_add = 104;
1404
1405 status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1406 TEST_LPM_ASSERT(status == 0);
1407
1408 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1409 depth[4] = 48;
1410 next_hop_add = 105;
1411
1412 status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1413 TEST_LPM_ASSERT(status == 0);
1414
1415 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1416 next_hop_return, 5);
1417 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1418 && next_hop_return[1] == 102 && next_hop_return[2] == 103
1419 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1420
1421 /* Use the delete_bulk function to delete two of them. Lookup again */
1422
1423 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1424 TEST_LPM_ASSERT(status == 0);
1425
1426 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1427 next_hop_return, 5);
1428 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1429 && next_hop_return[1] == -1 && next_hop_return[2] == 103
1430 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1431
1432 /* Use the delete_bulk function to delete one more. Lookup again */
1433
1434 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1435 TEST_LPM_ASSERT(status == 0);
1436
1437 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1438 next_hop_return, 5);
1439 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1440 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1441 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1442
1443 /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1444
1445 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1446 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1447 TEST_LPM_ASSERT(status == 0);
1448
1449 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1450 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1451 next_hop_return, 5);
1452 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1453 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1454 && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1455
1456 /* Use the delete_bulk function to delete the remaining one. Lookup again */
1457
1458 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1459 TEST_LPM_ASSERT(status == 0);
1460
1461 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1462 next_hop_return, 5);
1463 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1464 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1465 && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1466
1467 rte_lpm6_free(lpm);
1468
1469 return PASS;
1470 }
1471
1472 /*
1473 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1474 * lookup (miss) in a for loop of 30 times. This will check tbl8 extension
1475 * and contraction.
1476 */
1477 int32_t
test23(void)1478 test23(void)
1479 {
1480 struct rte_lpm6 *lpm = NULL;
1481 struct rte_lpm6_config config;
1482 uint32_t i;
1483 uint8_t ip[16];
1484 uint8_t depth;
1485 uint32_t next_hop_add, next_hop_return;
1486 int32_t status = 0;
1487
1488 config.max_rules = MAX_RULES;
1489 config.number_tbl8s = NUMBER_TBL8S;
1490 config.flags = 0;
1491
1492 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1493 TEST_LPM_ASSERT(lpm != NULL);
1494
1495 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1496 depth = 128;
1497 next_hop_add = 100;
1498
1499 for (i = 0; i < 30; i++) {
1500 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1501 TEST_LPM_ASSERT(status == 0);
1502
1503 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1504 TEST_LPM_ASSERT((status == 0) &&
1505 (next_hop_return == next_hop_add));
1506
1507 status = rte_lpm6_delete(lpm, ip, depth);
1508 TEST_LPM_ASSERT(status == 0);
1509
1510 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1511 TEST_LPM_ASSERT(status == -ENOENT);
1512 }
1513
1514 rte_lpm6_free(lpm);
1515
1516 return PASS;
1517 }
1518
1519 /*
1520 * Sequence of operations for find existing lpm table
1521 *
1522 * - create table
1523 * - find existing table: hit
1524 * - find non-existing table: miss
1525 */
1526 int32_t
test24(void)1527 test24(void)
1528 {
1529 struct rte_lpm6 *lpm = NULL, *result = NULL;
1530 struct rte_lpm6_config config;
1531
1532 config.max_rules = 256 * 32;
1533 config.number_tbl8s = NUMBER_TBL8S;
1534 config.flags = 0;
1535
1536 /* Create lpm */
1537 lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1538 TEST_LPM_ASSERT(lpm != NULL);
1539
1540 /* Try to find existing lpm */
1541 result = rte_lpm6_find_existing("lpm_find_existing");
1542 TEST_LPM_ASSERT(result == lpm);
1543
1544 /* Try to find non-existing lpm */
1545 result = rte_lpm6_find_existing("lpm_find_non_existing");
1546 TEST_LPM_ASSERT(result == NULL);
1547
1548 /* Cleanup. */
1549 rte_lpm6_delete_all(lpm);
1550 rte_lpm6_free(lpm);
1551
1552 return PASS;
1553 }
1554
1555 /*
1556 * Add a set of random routes with random depths.
1557 * Lookup different IP addresses that match the routes previously added.
1558 * Checks that the next hop is the expected one.
1559 * The routes, IP addresses and expected result for every case have been
1560 * precalculated by using a python script and stored in a .h file.
1561 */
1562 int32_t
test25(void)1563 test25(void)
1564 {
1565 struct rte_lpm6 *lpm = NULL;
1566 struct rte_lpm6_config config;
1567 uint8_t ip[16];
1568 uint32_t i;
1569 uint8_t depth;
1570 uint32_t next_hop_add, next_hop_return, next_hop_expected;
1571 int32_t status = 0;
1572
1573 config.max_rules = MAX_RULES;
1574 config.number_tbl8s = NUMBER_TBL8S;
1575 config.flags = 0;
1576
1577 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1578 TEST_LPM_ASSERT(lpm != NULL);
1579
1580 for (i = 0; i < 1000; i++) {
1581 memcpy(ip, large_route_table[i].ip, 16);
1582 depth = large_route_table[i].depth;
1583 next_hop_add = large_route_table[i].next_hop;
1584 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1585 TEST_LPM_ASSERT(status == 0);
1586 }
1587
1588 /* generate large IPS table and expected next_hops */
1589 generate_large_ips_table(1);
1590
1591 for (i = 0; i < 100000; i++) {
1592 memcpy(ip, large_ips_table[i].ip, 16);
1593 next_hop_expected = large_ips_table[i].next_hop;
1594
1595 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1596 TEST_LPM_ASSERT((status == 0) &&
1597 (next_hop_return == next_hop_expected));
1598 }
1599
1600 rte_lpm6_free(lpm);
1601
1602 return PASS;
1603 }
1604
1605 /*
1606 * Test for overwriting of tbl8:
1607 * - add rule /32 and lookup
1608 * - add new rule /24 and lookup
1609 * - add third rule /25 and lookup
1610 * - lookup /32 and /24 rule to ensure the table has not been overwritten.
1611 */
1612 int32_t
test26(void)1613 test26(void)
1614 {
1615 struct rte_lpm6 *lpm = NULL;
1616 struct rte_lpm6_config config;
1617 uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1618 uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1619 uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1620 uint8_t d_ip_10_32 = 32;
1621 uint8_t d_ip_10_24 = 24;
1622 uint8_t d_ip_20_25 = 25;
1623 uint32_t next_hop_ip_10_32 = 100;
1624 uint32_t next_hop_ip_10_24 = 105;
1625 uint32_t next_hop_ip_20_25 = 111;
1626 uint32_t next_hop_return = 0;
1627 int32_t status = 0;
1628
1629 config.max_rules = MAX_RULES;
1630 config.number_tbl8s = NUMBER_TBL8S;
1631 config.flags = 0;
1632
1633 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1634 TEST_LPM_ASSERT(lpm != NULL);
1635
1636 if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1637 next_hop_ip_10_32)) < 0)
1638 return -1;
1639
1640 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1641 uint32_t test_hop_10_32 = next_hop_return;
1642 TEST_LPM_ASSERT(status == 0);
1643 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1644
1645 if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1646 next_hop_ip_10_24)) < 0)
1647 return -1;
1648
1649 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1650 uint32_t test_hop_10_24 = next_hop_return;
1651 TEST_LPM_ASSERT(status == 0);
1652 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1653
1654 if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1655 next_hop_ip_20_25)) < 0)
1656 return -1;
1657
1658 status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1659 uint32_t test_hop_20_25 = next_hop_return;
1660 TEST_LPM_ASSERT(status == 0);
1661 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1662
1663 if (test_hop_10_32 == test_hop_10_24) {
1664 printf("Next hop return equal\n");
1665 return -1;
1666 }
1667
1668 if (test_hop_10_24 == test_hop_20_25){
1669 printf("Next hop return equal\n");
1670 return -1;
1671 }
1672
1673 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1674 TEST_LPM_ASSERT(status == 0);
1675 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1676
1677 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1678 TEST_LPM_ASSERT(status == 0);
1679 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1680
1681 rte_lpm6_free(lpm);
1682
1683 return PASS;
1684 }
1685
1686 /*
1687 * Add a rule that reaches the end of the tree.
1688 * Add a rule that is more generic than the first one.
1689 * Check every possible combination that produces a match for the second rule.
1690 * This tests tbl expansion.
1691 */
1692 int32_t
test27(void)1693 test27(void)
1694 {
1695 struct rte_lpm6 *lpm = NULL;
1696 struct rte_lpm6_config config;
1697 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1698 uint8_t depth = 128;
1699 uint32_t next_hop_add = 100, next_hop_return;
1700 int32_t status = 0;
1701 int i, j;
1702
1703 config.max_rules = MAX_RULES;
1704 config.number_tbl8s = NUMBER_TBL8S;
1705 config.flags = 0;
1706
1707 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1708 TEST_LPM_ASSERT(lpm != NULL);
1709
1710 depth = 128;
1711 next_hop_add = 128;
1712 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1713 TEST_LPM_ASSERT(status == 0);
1714
1715 depth = 112;
1716 next_hop_add = 112;
1717 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1718 TEST_LPM_ASSERT(status == 0);
1719
1720 for (i = 0; i < 256; i++) {
1721 ip[14] = (uint8_t)i;
1722 for (j = 0; j < 256; j++) {
1723 ip[15] = (uint8_t)j;
1724 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1725 if (i == 0 && j == 0)
1726 TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1727 else
1728 TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1729 }
1730 }
1731
1732 rte_lpm6_free(lpm);
1733
1734 return PASS;
1735 }
1736
1737 /*
1738 * Call add, lookup and delete for a single rule with maximum 21bit next_hop
1739 * size.
1740 * Check that next_hop returned from lookup is equal to provisioned value.
1741 * Delete the rule and check that the same test returs a miss.
1742 */
1743 int32_t
test28(void)1744 test28(void)
1745 {
1746 struct rte_lpm6 *lpm = NULL;
1747 struct rte_lpm6_config config;
1748 uint8_t ip[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1749 uint8_t depth = 16;
1750 uint32_t next_hop_add = 0x001FFFFF, next_hop_return = 0;
1751 int32_t status = 0;
1752
1753 config.max_rules = MAX_RULES;
1754 config.number_tbl8s = NUMBER_TBL8S;
1755 config.flags = 0;
1756
1757 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1758 TEST_LPM_ASSERT(lpm != NULL);
1759
1760 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1761 TEST_LPM_ASSERT(status == 0);
1762
1763 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1764 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1765
1766 status = rte_lpm6_delete(lpm, ip, depth);
1767 TEST_LPM_ASSERT(status == 0);
1768 rte_lpm6_free(lpm);
1769
1770 return PASS;
1771 }
1772
1773 /*
1774 * Do all unit tests.
1775 */
1776 static int
test_lpm6(void)1777 test_lpm6(void)
1778 {
1779 unsigned i;
1780 int status = -1, global_status = 0;
1781
1782 for (i = 0; i < RTE_DIM(tests6); i++) {
1783 printf("# test %02d\n", i);
1784 status = tests6[i]();
1785
1786 if (status < 0) {
1787 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1788 global_status = status;
1789 }
1790 }
1791
1792 return global_status;
1793 }
1794
1795 REGISTER_TEST_COMMAND(lpm6_autotest, test_lpm6);
1796