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