xref: /dpdk/app/test/test_lpm6.c (revision 3c60274c)
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