tile: fix build
[dpdk.git] / app / test / test_lpm.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37
38 #include <rte_ip.h>
39 #include <rte_lpm.h>
40
41 #include "test.h"
42 #include "test_xmmt_ops.h"
43
44 #define TEST_LPM_ASSERT(cond) do {                                            \
45         if (!(cond)) {                                                        \
46                 printf("Error at line %d: \n", __LINE__);                     \
47                 return -1;                                                    \
48         }                                                                     \
49 } while(0)
50
51 typedef int32_t (*rte_lpm_test)(void);
52
53 static int32_t test0(void);
54 static int32_t test1(void);
55 static int32_t test2(void);
56 static int32_t test3(void);
57 static int32_t test4(void);
58 static int32_t test5(void);
59 static int32_t test6(void);
60 static int32_t test7(void);
61 static int32_t test8(void);
62 static int32_t test9(void);
63 static int32_t test10(void);
64 static int32_t test11(void);
65 static int32_t test12(void);
66 static int32_t test13(void);
67 static int32_t test14(void);
68 static int32_t test15(void);
69 static int32_t test16(void);
70 static int32_t test17(void);
71 static int32_t test18(void);
72
73 rte_lpm_test tests[] = {
74 /* Test Cases */
75         test0,
76         test1,
77         test2,
78         test3,
79         test4,
80         test5,
81         test6,
82         test7,
83         test8,
84         test9,
85         test10,
86         test11,
87         test12,
88         test13,
89         test14,
90         test15,
91         test16,
92         test17,
93         test18
94 };
95
96 #define NUM_LPM_TESTS (sizeof(tests)/sizeof(tests[0]))
97 #define MAX_DEPTH 32
98 #define MAX_RULES 256
99 #define NUMBER_TBL8S 256
100 #define PASS 0
101
102 /*
103  * Check that rte_lpm_create fails gracefully for incorrect user input
104  * arguments
105  */
106 int32_t
107 test0(void)
108 {
109         struct rte_lpm *lpm = NULL;
110         struct rte_lpm_config config;
111
112         config.max_rules = MAX_RULES;
113         config.number_tbl8s = NUMBER_TBL8S;
114         config.flags = 0;
115
116         /* rte_lpm_create: lpm name == NULL */
117         lpm = rte_lpm_create(NULL, SOCKET_ID_ANY, &config);
118         TEST_LPM_ASSERT(lpm == NULL);
119
120         /* rte_lpm_create: max_rules = 0 */
121         /* Note: __func__ inserts the function name, in this case "test0". */
122         config.max_rules = 0;
123         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
124         TEST_LPM_ASSERT(lpm == NULL);
125
126         /* socket_id < -1 is invalid */
127         config.max_rules = MAX_RULES;
128         lpm = rte_lpm_create(__func__, -2, &config);
129         TEST_LPM_ASSERT(lpm == NULL);
130
131         return PASS;
132 }
133
134 /*
135  * Create lpm table then delete lpm table 100 times
136  * Use a slightly different rules size each time
137  * */
138 int32_t
139 test1(void)
140 {
141         struct rte_lpm *lpm = NULL;
142         struct rte_lpm_config config;
143
144         config.number_tbl8s = NUMBER_TBL8S;
145         config.flags = 0;
146         int32_t i;
147
148         /* rte_lpm_free: Free NULL */
149         for (i = 0; i < 100; i++) {
150                 config.max_rules = MAX_RULES - i;
151                 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
152                 TEST_LPM_ASSERT(lpm != NULL);
153
154                 rte_lpm_free(lpm);
155         }
156
157         /* Can not test free so return success */
158         return PASS;
159 }
160
161 /*
162  * Call rte_lpm_free for NULL pointer user input. Note: free has no return and
163  * therefore it is impossible to check for failure but this test is added to
164  * increase function coverage metrics and to validate that freeing null does
165  * not crash.
166  */
167 int32_t
168 test2(void)
169 {
170         struct rte_lpm *lpm = NULL;
171         struct rte_lpm_config config;
172
173         config.max_rules = MAX_RULES;
174         config.number_tbl8s = NUMBER_TBL8S;
175         config.flags = 0;
176
177         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
178         TEST_LPM_ASSERT(lpm != NULL);
179
180         rte_lpm_free(lpm);
181         rte_lpm_free(NULL);
182         return PASS;
183 }
184
185 /*
186  * Check that rte_lpm_add fails gracefully for incorrect user input arguments
187  */
188 int32_t
189 test3(void)
190 {
191         struct rte_lpm *lpm = NULL;
192         struct rte_lpm_config config;
193
194         config.max_rules = MAX_RULES;
195         config.number_tbl8s = NUMBER_TBL8S;
196         config.flags = 0;
197         uint32_t ip = IPv4(0, 0, 0, 0), next_hop = 100;
198         uint8_t depth = 24;
199         int32_t status = 0;
200
201         /* rte_lpm_add: lpm == NULL */
202         status = rte_lpm_add(NULL, ip, depth, next_hop);
203         TEST_LPM_ASSERT(status < 0);
204
205         /*Create vaild lpm to use in rest of test. */
206         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
207         TEST_LPM_ASSERT(lpm != NULL);
208
209         /* rte_lpm_add: depth < 1 */
210         status = rte_lpm_add(lpm, ip, 0, next_hop);
211         TEST_LPM_ASSERT(status < 0);
212
213         /* rte_lpm_add: depth > MAX_DEPTH */
214         status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
215         TEST_LPM_ASSERT(status < 0);
216
217         rte_lpm_free(lpm);
218
219         return PASS;
220 }
221
222 /*
223  * Check that rte_lpm_delete fails gracefully for incorrect user input
224  * arguments
225  */
226 int32_t
227 test4(void)
228 {
229         struct rte_lpm *lpm = NULL;
230         struct rte_lpm_config config;
231
232         config.max_rules = MAX_RULES;
233         config.number_tbl8s = NUMBER_TBL8S;
234         config.flags = 0;
235         uint32_t ip = IPv4(0, 0, 0, 0);
236         uint8_t depth = 24;
237         int32_t status = 0;
238
239         /* rte_lpm_delete: lpm == NULL */
240         status = rte_lpm_delete(NULL, ip, depth);
241         TEST_LPM_ASSERT(status < 0);
242
243         /*Create vaild lpm to use in rest of test. */
244         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
245         TEST_LPM_ASSERT(lpm != NULL);
246
247         /* rte_lpm_delete: depth < 1 */
248         status = rte_lpm_delete(lpm, ip, 0);
249         TEST_LPM_ASSERT(status < 0);
250
251         /* rte_lpm_delete: depth > MAX_DEPTH */
252         status = rte_lpm_delete(lpm, ip, (MAX_DEPTH + 1));
253         TEST_LPM_ASSERT(status < 0);
254
255         rte_lpm_free(lpm);
256
257         return PASS;
258 }
259
260 /*
261  * Check that rte_lpm_lookup fails gracefully for incorrect user input
262  * arguments
263  */
264 int32_t
265 test5(void)
266 {
267 #if defined(RTE_LIBRTE_LPM_DEBUG)
268         struct rte_lpm *lpm = NULL;
269         struct rte_lpm_config config;
270
271         config.max_rules = MAX_RULES;
272         config.number_tbl8s = NUMBER_TBL8S;
273         config.flags = 0;
274         uint32_t ip = IPv4(0, 0, 0, 0), next_hop_return = 0;
275         int32_t status = 0;
276
277         /* rte_lpm_lookup: lpm == NULL */
278         status = rte_lpm_lookup(NULL, ip, &next_hop_return);
279         TEST_LPM_ASSERT(status < 0);
280
281         /*Create vaild lpm to use in rest of test. */
282         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
283         TEST_LPM_ASSERT(lpm != NULL);
284
285         /* rte_lpm_lookup: depth < 1 */
286         status = rte_lpm_lookup(lpm, ip, NULL);
287         TEST_LPM_ASSERT(status < 0);
288
289         rte_lpm_free(lpm);
290 #endif
291         return PASS;
292 }
293
294
295
296 /*
297  * Call add, lookup and delete for a single rule with depth <= 24
298  */
299 int32_t
300 test6(void)
301 {
302         struct rte_lpm *lpm = NULL;
303         struct rte_lpm_config config;
304
305         config.max_rules = MAX_RULES;
306         config.number_tbl8s = NUMBER_TBL8S;
307         config.flags = 0;
308         uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0;
309         uint8_t depth = 24;
310         int32_t status = 0;
311
312         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
313         TEST_LPM_ASSERT(lpm != NULL);
314
315         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
316         TEST_LPM_ASSERT(status == 0);
317
318         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
319         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
320
321         status = rte_lpm_delete(lpm, ip, depth);
322         TEST_LPM_ASSERT(status == 0);
323
324         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
325         TEST_LPM_ASSERT(status == -ENOENT);
326
327         rte_lpm_free(lpm);
328
329         return PASS;
330 }
331
332 /*
333  * Call add, lookup and delete for a single rule with depth > 24
334  */
335
336 int32_t
337 test7(void)
338 {
339         xmm_t ipx4;
340         uint32_t hop[4];
341         struct rte_lpm *lpm = NULL;
342         struct rte_lpm_config config;
343
344         config.max_rules = MAX_RULES;
345         config.number_tbl8s = NUMBER_TBL8S;
346         config.flags = 0;
347         uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0;
348         uint8_t depth = 32;
349         int32_t status = 0;
350
351         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
352         TEST_LPM_ASSERT(lpm != NULL);
353
354         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
355         TEST_LPM_ASSERT(status == 0);
356
357         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
358         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
359
360         ipx4 = vect_set_epi32(ip, ip + 0x100, ip - 0x100, ip);
361         rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
362         TEST_LPM_ASSERT(hop[0] == next_hop_add);
363         TEST_LPM_ASSERT(hop[1] == UINT32_MAX);
364         TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
365         TEST_LPM_ASSERT(hop[3] == next_hop_add);
366
367         status = rte_lpm_delete(lpm, ip, depth);
368         TEST_LPM_ASSERT(status == 0);
369
370         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
371         TEST_LPM_ASSERT(status == -ENOENT);
372
373         rte_lpm_free(lpm);
374
375         return PASS;
376 }
377
378 /*
379  * Use rte_lpm_add to add rules which effect only the second half of the lpm
380  * table. Use all possible depths ranging from 1..32. Set the next hop = to the
381  * depth. Check lookup hit for on every add and check for lookup miss on the
382  * first half of the lpm table after each add. Finally delete all rules going
383  * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
384  * delete. The lookup should return the next_hop_add value related to the
385  * previous depth value (i.e. depth -1).
386  */
387 int32_t
388 test8(void)
389 {
390         xmm_t ipx4;
391         uint32_t hop[4];
392         struct rte_lpm *lpm = NULL;
393         struct rte_lpm_config config;
394
395         config.max_rules = MAX_RULES;
396         config.number_tbl8s = NUMBER_TBL8S;
397         config.flags = 0;
398         uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0);
399         uint32_t next_hop_add, next_hop_return;
400         uint8_t depth;
401         int32_t status = 0;
402
403         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
404         TEST_LPM_ASSERT(lpm != NULL);
405
406         /* Loop with rte_lpm_add. */
407         for (depth = 1; depth <= 32; depth++) {
408                 /* Let the next_hop_add value = depth. Just for change. */
409                 next_hop_add = depth;
410
411                 status = rte_lpm_add(lpm, ip2, depth, next_hop_add);
412                 TEST_LPM_ASSERT(status == 0);
413
414                 /* Check IP in first half of tbl24 which should be empty. */
415                 status = rte_lpm_lookup(lpm, ip1, &next_hop_return);
416                 TEST_LPM_ASSERT(status == -ENOENT);
417
418                 status = rte_lpm_lookup(lpm, ip2, &next_hop_return);
419                 TEST_LPM_ASSERT((status == 0) &&
420                         (next_hop_return == next_hop_add));
421
422                 ipx4 = vect_set_epi32(ip2, ip1, ip2, ip1);
423                 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
424                 TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
425                 TEST_LPM_ASSERT(hop[1] == next_hop_add);
426                 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
427                 TEST_LPM_ASSERT(hop[3] == next_hop_add);
428         }
429
430         /* Loop with rte_lpm_delete. */
431         for (depth = 32; depth >= 1; depth--) {
432                 next_hop_add = (uint8_t) (depth - 1);
433
434                 status = rte_lpm_delete(lpm, ip2, depth);
435                 TEST_LPM_ASSERT(status == 0);
436
437                 status = rte_lpm_lookup(lpm, ip2, &next_hop_return);
438
439                 if (depth != 1) {
440                         TEST_LPM_ASSERT((status == 0) &&
441                                 (next_hop_return == next_hop_add));
442                 } else {
443                         TEST_LPM_ASSERT(status == -ENOENT);
444                 }
445
446                 status = rte_lpm_lookup(lpm, ip1, &next_hop_return);
447                 TEST_LPM_ASSERT(status == -ENOENT);
448
449                 ipx4 = vect_set_epi32(ip1, ip1, ip2, ip2);
450                 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
451                 if (depth != 1) {
452                         TEST_LPM_ASSERT(hop[0] == next_hop_add);
453                         TEST_LPM_ASSERT(hop[1] == next_hop_add);
454                 } else {
455                         TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
456                         TEST_LPM_ASSERT(hop[1] == UINT32_MAX);
457                 }
458                 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
459                 TEST_LPM_ASSERT(hop[3] == UINT32_MAX);
460         }
461
462         rte_lpm_free(lpm);
463
464         return PASS;
465 }
466
467 /*
468  * - Add & lookup to hit invalid TBL24 entry
469  * - Add & lookup to hit valid TBL24 entry not extended
470  * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
471  * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
472  *
473  */
474 int32_t
475 test9(void)
476 {
477         struct rte_lpm *lpm = NULL;
478         struct rte_lpm_config config;
479
480         config.max_rules = MAX_RULES;
481         config.number_tbl8s = NUMBER_TBL8S;
482         config.flags = 0;
483         uint32_t ip, ip_1, ip_2;
484         uint8_t depth, depth_1, depth_2;
485         uint32_t next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return;
486         int32_t status = 0;
487
488         /* Add & lookup to hit invalid TBL24 entry */
489         ip = IPv4(128, 0, 0, 0);
490         depth = 24;
491         next_hop_add = 100;
492
493         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
494         TEST_LPM_ASSERT(lpm != NULL);
495
496         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
497         TEST_LPM_ASSERT(status == 0);
498
499         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
500         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
501
502         status = rte_lpm_delete(lpm, ip, depth);
503         TEST_LPM_ASSERT(status == 0);
504
505         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
506         TEST_LPM_ASSERT(status == -ENOENT);
507
508         rte_lpm_delete_all(lpm);
509
510         /* Add & lookup to hit valid TBL24 entry not extended */
511         ip = IPv4(128, 0, 0, 0);
512         depth = 23;
513         next_hop_add = 100;
514
515         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
516         TEST_LPM_ASSERT(status == 0);
517
518         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
519         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
520
521         depth = 24;
522         next_hop_add = 101;
523
524         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
525         TEST_LPM_ASSERT(status == 0);
526
527         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
528         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
529
530         depth = 24;
531
532         status = rte_lpm_delete(lpm, ip, depth);
533         TEST_LPM_ASSERT(status == 0);
534
535         depth = 23;
536
537         status = rte_lpm_delete(lpm, ip, depth);
538         TEST_LPM_ASSERT(status == 0);
539
540         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
541         TEST_LPM_ASSERT(status == -ENOENT);
542
543         rte_lpm_delete_all(lpm);
544
545         /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
546          * entry */
547         ip = IPv4(128, 0, 0, 0);
548         depth = 32;
549         next_hop_add = 100;
550
551         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
552         TEST_LPM_ASSERT(status == 0);
553
554         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
555         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
556
557         ip = IPv4(128, 0, 0, 5);
558         depth = 32;
559         next_hop_add = 101;
560
561         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
562         TEST_LPM_ASSERT(status == 0);
563
564         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
565         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
566
567         status = rte_lpm_delete(lpm, ip, depth);
568         TEST_LPM_ASSERT(status == 0);
569
570         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
571         TEST_LPM_ASSERT(status == -ENOENT);
572
573         ip = IPv4(128, 0, 0, 0);
574         depth = 32;
575         next_hop_add = 100;
576
577         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
578         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
579
580         status = rte_lpm_delete(lpm, ip, depth);
581         TEST_LPM_ASSERT(status == 0);
582
583         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
584         TEST_LPM_ASSERT(status == -ENOENT);
585
586         rte_lpm_delete_all(lpm);
587
588         /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
589          * entry */
590         ip_1 = IPv4(128, 0, 0, 0);
591         depth_1 = 25;
592         next_hop_add_1 = 101;
593
594         ip_2 = IPv4(128, 0, 0, 5);
595         depth_2 = 32;
596         next_hop_add_2 = 102;
597
598         next_hop_return = 0;
599
600         status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1);
601         TEST_LPM_ASSERT(status == 0);
602
603         status = rte_lpm_lookup(lpm, ip_1, &next_hop_return);
604         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
605
606         status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2);
607         TEST_LPM_ASSERT(status == 0);
608
609         status = rte_lpm_lookup(lpm, ip_2, &next_hop_return);
610         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
611
612         status = rte_lpm_delete(lpm, ip_2, depth_2);
613         TEST_LPM_ASSERT(status == 0);
614
615         status = rte_lpm_lookup(lpm, ip_2, &next_hop_return);
616         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
617
618         status = rte_lpm_delete(lpm, ip_1, depth_1);
619         TEST_LPM_ASSERT(status == 0);
620
621         status = rte_lpm_lookup(lpm, ip_1, &next_hop_return);
622         TEST_LPM_ASSERT(status == -ENOENT);
623
624         rte_lpm_free(lpm);
625
626         return PASS;
627 }
628
629
630 /*
631  * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
632  *   lookup)
633  * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
634  * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
635  *   delete & lookup)
636  * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
637  * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
638  * - Delete a rule that is not present in the TBL24 & lookup
639  * - Delete a rule that is not present in the TBL8 & lookup
640  *
641  */
642 int32_t
643 test10(void)
644 {
645
646         struct rte_lpm *lpm = NULL;
647         struct rte_lpm_config config;
648
649         config.max_rules = MAX_RULES;
650         config.number_tbl8s = NUMBER_TBL8S;
651         config.flags = 0;
652         uint32_t ip, next_hop_add, next_hop_return;
653         uint8_t depth;
654         int32_t status = 0;
655
656         /* Add rule that covers a TBL24 range previously invalid & lookup
657          * (& delete & lookup) */
658         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
659         TEST_LPM_ASSERT(lpm != NULL);
660
661         ip = IPv4(128, 0, 0, 0);
662         depth = 16;
663         next_hop_add = 100;
664
665         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
666         TEST_LPM_ASSERT(status == 0);
667
668         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
669         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
670
671         status = rte_lpm_delete(lpm, ip, depth);
672         TEST_LPM_ASSERT(status == 0);
673
674         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
675         TEST_LPM_ASSERT(status == -ENOENT);
676
677         rte_lpm_delete_all(lpm);
678
679         ip = IPv4(128, 0, 0, 0);
680         depth = 25;
681         next_hop_add = 100;
682
683         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
684         TEST_LPM_ASSERT(status == 0);
685
686         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
687         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
688
689         status = rte_lpm_delete(lpm, ip, depth);
690         TEST_LPM_ASSERT(status == 0);
691
692         rte_lpm_delete_all(lpm);
693
694         /* Add rule that extends a TBL24 valid entry & lookup for both rules
695          * (& delete & lookup) */
696
697         ip = IPv4(128, 0, 0, 0);
698         depth = 24;
699         next_hop_add = 100;
700
701         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
702         TEST_LPM_ASSERT(status == 0);
703
704         ip = IPv4(128, 0, 0, 10);
705         depth = 32;
706         next_hop_add = 101;
707
708         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
709         TEST_LPM_ASSERT(status == 0);
710
711         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
712         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
713
714         ip = IPv4(128, 0, 0, 0);
715         next_hop_add = 100;
716
717         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
718         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
719
720         ip = IPv4(128, 0, 0, 0);
721         depth = 24;
722
723         status = rte_lpm_delete(lpm, ip, depth);
724         TEST_LPM_ASSERT(status == 0);
725
726         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
727         TEST_LPM_ASSERT(status == -ENOENT);
728
729         ip = IPv4(128, 0, 0, 10);
730         depth = 32;
731
732         status = rte_lpm_delete(lpm, ip, depth);
733         TEST_LPM_ASSERT(status == 0);
734
735         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
736         TEST_LPM_ASSERT(status == -ENOENT);
737
738         rte_lpm_delete_all(lpm);
739
740         /* Add rule that updates the next hop in TBL24 & lookup
741          * (& delete & lookup) */
742
743         ip = IPv4(128, 0, 0, 0);
744         depth = 24;
745         next_hop_add = 100;
746
747         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
748         TEST_LPM_ASSERT(status == 0);
749
750         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
751         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
752
753         next_hop_add = 101;
754
755         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
756         TEST_LPM_ASSERT(status == 0);
757
758         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
759         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
760
761         status = rte_lpm_delete(lpm, ip, depth);
762         TEST_LPM_ASSERT(status == 0);
763
764         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
765         TEST_LPM_ASSERT(status == -ENOENT);
766
767         rte_lpm_delete_all(lpm);
768
769         /* Add rule that updates the next hop in TBL8 & lookup
770          * (& delete & lookup) */
771
772         ip = IPv4(128, 0, 0, 0);
773         depth = 32;
774         next_hop_add = 100;
775
776         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
777         TEST_LPM_ASSERT(status == 0);
778
779         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
780         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
781
782         next_hop_add = 101;
783
784         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
785         TEST_LPM_ASSERT(status == 0);
786
787         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
788         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
789
790         status = rte_lpm_delete(lpm, ip, depth);
791         TEST_LPM_ASSERT(status == 0);
792
793         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
794         TEST_LPM_ASSERT(status == -ENOENT);
795
796         rte_lpm_delete_all(lpm);
797
798         /* Delete a rule that is not present in the TBL24 & lookup */
799
800         ip = IPv4(128, 0, 0, 0);
801         depth = 24;
802
803         status = rte_lpm_delete(lpm, ip, depth);
804         TEST_LPM_ASSERT(status < 0);
805
806         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
807         TEST_LPM_ASSERT(status == -ENOENT);
808
809         rte_lpm_delete_all(lpm);
810
811         /* Delete a rule that is not present in the TBL8 & lookup */
812
813         ip = IPv4(128, 0, 0, 0);
814         depth = 32;
815
816         status = rte_lpm_delete(lpm, ip, depth);
817         TEST_LPM_ASSERT(status < 0);
818
819         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
820         TEST_LPM_ASSERT(status == -ENOENT);
821
822         rte_lpm_free(lpm);
823
824         return PASS;
825 }
826
827 /*
828  * Add two rules, lookup to hit the more specific one, lookup to hit the less
829  * specific one delete the less specific rule and lookup previous values again;
830  * add a more specific rule than the existing rule, lookup again
831  *
832  * */
833 int32_t
834 test11(void)
835 {
836
837         struct rte_lpm *lpm = NULL;
838         struct rte_lpm_config config;
839
840         config.max_rules = MAX_RULES;
841         config.number_tbl8s = NUMBER_TBL8S;
842         config.flags = 0;
843         uint32_t ip, next_hop_add, next_hop_return;
844         uint8_t depth;
845         int32_t status = 0;
846
847         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
848         TEST_LPM_ASSERT(lpm != NULL);
849
850         ip = IPv4(128, 0, 0, 0);
851         depth = 24;
852         next_hop_add = 100;
853
854         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
855         TEST_LPM_ASSERT(status == 0);
856
857         ip = IPv4(128, 0, 0, 10);
858         depth = 32;
859         next_hop_add = 101;
860
861         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
862         TEST_LPM_ASSERT(status == 0);
863
864         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
865         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
866
867         ip = IPv4(128, 0, 0, 0);
868         next_hop_add = 100;
869
870         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
871         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
872
873         ip = IPv4(128, 0, 0, 0);
874         depth = 24;
875
876         status = rte_lpm_delete(lpm, ip, depth);
877         TEST_LPM_ASSERT(status == 0);
878
879         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
880         TEST_LPM_ASSERT(status == -ENOENT);
881
882         ip = IPv4(128, 0, 0, 10);
883         depth = 32;
884
885         status = rte_lpm_delete(lpm, ip, depth);
886         TEST_LPM_ASSERT(status == 0);
887
888         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
889         TEST_LPM_ASSERT(status == -ENOENT);
890
891         rte_lpm_free(lpm);
892
893         return PASS;
894 }
895
896 /*
897  * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
898  * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
899  * and contraction.
900  *
901  * */
902
903 int32_t
904 test12(void)
905 {
906         xmm_t ipx4;
907         uint32_t hop[4];
908         struct rte_lpm *lpm = NULL;
909         struct rte_lpm_config config;
910
911         config.max_rules = MAX_RULES;
912         config.number_tbl8s = NUMBER_TBL8S;
913         config.flags = 0;
914         uint32_t ip, i, next_hop_add, next_hop_return;
915         uint8_t depth;
916         int32_t status = 0;
917
918         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
919         TEST_LPM_ASSERT(lpm != NULL);
920
921         ip = IPv4(128, 0, 0, 0);
922         depth = 32;
923         next_hop_add = 100;
924
925         for (i = 0; i < 1000; i++) {
926                 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
927                 TEST_LPM_ASSERT(status == 0);
928
929                 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
930                 TEST_LPM_ASSERT((status == 0) &&
931                                 (next_hop_return == next_hop_add));
932
933                 ipx4 = vect_set_epi32(ip, ip + 1, ip, ip - 1);
934                 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
935                 TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
936                 TEST_LPM_ASSERT(hop[1] == next_hop_add);
937                 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
938                 TEST_LPM_ASSERT(hop[3] == next_hop_add);
939
940                 status = rte_lpm_delete(lpm, ip, depth);
941                 TEST_LPM_ASSERT(status == 0);
942
943                 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
944                 TEST_LPM_ASSERT(status == -ENOENT);
945         }
946
947         rte_lpm_free(lpm);
948
949         return PASS;
950 }
951
952 /*
953  * Add a rule to tbl24, lookup (hit), then add a rule that will extend this
954  * tbl24 entry, lookup (hit). delete the rule that caused the tbl24 extension,
955  * lookup (miss) and repeat for loop of 1000 times. This will check tbl8
956  * extension and contraction.
957  *
958  * */
959
960 int32_t
961 test13(void)
962 {
963         struct rte_lpm *lpm = NULL;
964         struct rte_lpm_config config;
965
966         config.max_rules = MAX_RULES;
967         config.number_tbl8s = NUMBER_TBL8S;
968         config.flags = 0;
969         uint32_t ip, i, next_hop_add_1, next_hop_add_2, next_hop_return;
970         uint8_t depth;
971         int32_t status = 0;
972
973         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
974         TEST_LPM_ASSERT(lpm != NULL);
975
976         ip = IPv4(128, 0, 0, 0);
977         depth = 24;
978         next_hop_add_1 = 100;
979
980         status = rte_lpm_add(lpm, ip, depth, next_hop_add_1);
981         TEST_LPM_ASSERT(status == 0);
982
983         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
984         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
985
986         depth = 32;
987         next_hop_add_2 = 101;
988
989         for (i = 0; i < 1000; i++) {
990                 status = rte_lpm_add(lpm, ip, depth, next_hop_add_2);
991                 TEST_LPM_ASSERT(status == 0);
992
993                 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
994                 TEST_LPM_ASSERT((status == 0) &&
995                                 (next_hop_return == next_hop_add_2));
996
997                 status = rte_lpm_delete(lpm, ip, depth);
998                 TEST_LPM_ASSERT(status == 0);
999
1000                 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1001                 TEST_LPM_ASSERT((status == 0) &&
1002                                 (next_hop_return == next_hop_add_1));
1003         }
1004
1005         depth = 24;
1006
1007         status = rte_lpm_delete(lpm, ip, depth);
1008         TEST_LPM_ASSERT(status == 0);
1009
1010         status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1011         TEST_LPM_ASSERT(status == -ENOENT);
1012
1013         rte_lpm_free(lpm);
1014
1015         return PASS;
1016 }
1017
1018 /*
1019  * Fore TBL8 extension exhaustion. Add 256 rules that require a tbl8 extension.
1020  * No more tbl8 extensions will be allowed. Now add one more rule that required
1021  * a tbl8 extension and get fail.
1022  * */
1023 int32_t
1024 test14(void)
1025 {
1026
1027         /* We only use depth = 32 in the loop below so we must make sure
1028          * that we have enough storage for all rules at that depth*/
1029
1030         struct rte_lpm *lpm = NULL;
1031         struct rte_lpm_config config;
1032
1033         config.max_rules = 256 * 32;
1034         config.number_tbl8s = NUMBER_TBL8S;
1035         config.flags = 0;
1036         uint32_t ip, next_hop_add, next_hop_return;
1037         uint8_t depth;
1038         int32_t status = 0;
1039
1040         /* Add enough space for 256 rules for every depth */
1041         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1042         TEST_LPM_ASSERT(lpm != NULL);
1043
1044         depth = 32;
1045         next_hop_add = 100;
1046         ip = IPv4(0, 0, 0, 0);
1047
1048         /* Add 256 rules that require a tbl8 extension */
1049         for (; ip <= IPv4(0, 0, 255, 0); ip += 256) {
1050                 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
1051                 TEST_LPM_ASSERT(status == 0);
1052
1053                 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1054                 TEST_LPM_ASSERT((status == 0) &&
1055                                 (next_hop_return == next_hop_add));
1056         }
1057
1058         /* All tbl8 extensions have been used above. Try to add one more and
1059          * we get a fail */
1060         ip = IPv4(1, 0, 0, 0);
1061         depth = 32;
1062
1063         status = rte_lpm_add(lpm, ip, depth, next_hop_add);
1064         TEST_LPM_ASSERT(status < 0);
1065
1066         rte_lpm_free(lpm);
1067
1068         return PASS;
1069 }
1070
1071 /*
1072  * Sequence of operations for find existing lpm table
1073  *
1074  *  - create table
1075  *  - find existing table: hit
1076  *  - find non-existing table: miss
1077  *
1078  */
1079 int32_t
1080 test15(void)
1081 {
1082         struct rte_lpm *lpm = NULL, *result = NULL;
1083         struct rte_lpm_config config;
1084
1085         config.max_rules = 256 * 32;
1086         config.number_tbl8s = NUMBER_TBL8S;
1087         config.flags = 0;
1088
1089         /* Create lpm  */
1090         lpm = rte_lpm_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1091         TEST_LPM_ASSERT(lpm != NULL);
1092
1093         /* Try to find existing lpm */
1094         result = rte_lpm_find_existing("lpm_find_existing");
1095         TEST_LPM_ASSERT(result == lpm);
1096
1097         /* Try to find non-existing lpm */
1098         result = rte_lpm_find_existing("lpm_find_non_existing");
1099         TEST_LPM_ASSERT(result == NULL);
1100
1101         /* Cleanup. */
1102         rte_lpm_delete_all(lpm);
1103         rte_lpm_free(lpm);
1104
1105         return PASS;
1106 }
1107
1108 /*
1109  * test failure condition of overloading the tbl8 so no more will fit
1110  * Check we get an error return value in that case
1111  */
1112 int32_t
1113 test16(void)
1114 {
1115         uint32_t ip;
1116         struct rte_lpm_config config;
1117
1118         config.max_rules = 256 * 32;
1119         config.number_tbl8s = NUMBER_TBL8S;
1120         config.flags = 0;
1121         struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1122
1123         /* ip loops through all possibilities for top 24 bits of address */
1124         for (ip = 0; ip < 0xFFFFFF; ip++) {
1125                 /* add an entry within a different tbl8 each time, since
1126                  * depth >24 and the top 24 bits are different */
1127                 if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0)
1128                         break;
1129         }
1130
1131         if (ip != NUMBER_TBL8S) {
1132                 printf("Error, unexpected failure with filling tbl8 groups\n");
1133                 printf("Failed after %u additions, expected after %u\n",
1134                                 (unsigned)ip, (unsigned)NUMBER_TBL8S);
1135         }
1136
1137         rte_lpm_free(lpm);
1138         return 0;
1139 }
1140
1141 /*
1142  * Test for overwriting of tbl8:
1143  *  - add rule /32 and lookup
1144  *  - add new rule /24 and lookup
1145  *      - add third rule /25 and lookup
1146  *      - lookup /32 and /24 rule to ensure the table has not been overwritten.
1147  */
1148 int32_t
1149 test17(void)
1150 {
1151         struct rte_lpm *lpm = NULL;
1152         struct rte_lpm_config config;
1153
1154         config.max_rules = MAX_RULES;
1155         config.number_tbl8s = NUMBER_TBL8S;
1156         config.flags = 0;
1157         const uint32_t ip_10_32 = IPv4(10, 10, 10, 2);
1158         const uint32_t ip_10_24 = IPv4(10, 10, 10, 0);
1159         const uint32_t ip_20_25 = IPv4(10, 10, 20, 2);
1160         const uint8_t d_ip_10_32 = 32,
1161                         d_ip_10_24 = 24,
1162                         d_ip_20_25 = 25;
1163         const uint32_t next_hop_ip_10_32 = 100,
1164                         next_hop_ip_10_24 = 105,
1165                         next_hop_ip_20_25 = 111;
1166         uint32_t next_hop_return = 0;
1167         int32_t status = 0;
1168
1169         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1170         TEST_LPM_ASSERT(lpm != NULL);
1171
1172         if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32,
1173                         next_hop_ip_10_32)) < 0)
1174                 return -1;
1175
1176         status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return);
1177         uint32_t test_hop_10_32 = next_hop_return;
1178         TEST_LPM_ASSERT(status == 0);
1179         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1180
1181         if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24,
1182                         next_hop_ip_10_24)) < 0)
1183                         return -1;
1184
1185         status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return);
1186         uint32_t test_hop_10_24 = next_hop_return;
1187         TEST_LPM_ASSERT(status == 0);
1188         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1189
1190         if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25,
1191                         next_hop_ip_20_25)) < 0)
1192                 return -1;
1193
1194         status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return);
1195         uint32_t test_hop_20_25 = next_hop_return;
1196         TEST_LPM_ASSERT(status == 0);
1197         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1198
1199         if (test_hop_10_32 == test_hop_10_24) {
1200                 printf("Next hop return equal\n");
1201                 return -1;
1202         }
1203
1204         if (test_hop_10_24 == test_hop_20_25) {
1205                 printf("Next hop return equal\n");
1206                 return -1;
1207         }
1208
1209         status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return);
1210         TEST_LPM_ASSERT(status == 0);
1211         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1212
1213         status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return);
1214         TEST_LPM_ASSERT(status == 0);
1215         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1216
1217         rte_lpm_free(lpm);
1218
1219         return PASS;
1220 }
1221
1222 /*
1223  * Test for recycle of tbl8
1224  *  - step 1: add a rule with depth=28 (> 24)
1225  *  - step 2: add a rule with same 24-bit prefix and depth=23 (< 24)
1226  *  - step 3: delete the first rule
1227  *  - step 4: check tbl8 is freed
1228  *  - step 5: add a rule same as the first one (depth=28)
1229  *  - step 6: check same tbl8 is allocated
1230  *  - step 7: add a rule with same 24-bit prefix and depth=24
1231  *  - step 8: delete the rule (depth=28) added in step 5
1232  *  - step 9: check tbl8 is freed
1233  *  - step 10: add a rule with same 24-bit prefix and depth = 28
1234  *  - setp 11: check same tbl8 is allocated again
1235  */
1236 int32_t
1237 test18(void)
1238 {
1239 #define group_idx next_hop
1240         struct rte_lpm *lpm = NULL;
1241         struct rte_lpm_config config;
1242         uint32_t ip, next_hop;
1243         uint8_t depth;
1244         uint32_t tbl8_group_index;
1245
1246         config.max_rules = MAX_RULES;
1247         config.number_tbl8s = NUMBER_TBL8S;
1248         config.flags = 0;
1249
1250         lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1251         TEST_LPM_ASSERT(lpm != NULL);
1252
1253         ip = IPv4(192, 168, 100, 100);
1254         depth = 28;
1255         next_hop = 1;
1256         rte_lpm_add(lpm, ip, depth, next_hop);
1257
1258         TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1259         tbl8_group_index = lpm->tbl24[ip>>8].group_idx;
1260
1261         depth = 23;
1262         next_hop = 2;
1263         rte_lpm_add(lpm, ip, depth, next_hop);
1264         TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1265
1266         depth = 28;
1267         rte_lpm_delete(lpm, ip, depth);
1268
1269         TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group);
1270
1271         next_hop = 3;
1272         rte_lpm_add(lpm, ip, depth, next_hop);
1273
1274         TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1275         TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx);
1276
1277         depth = 24;
1278         next_hop = 4;
1279         rte_lpm_add(lpm, ip, depth, next_hop);
1280         TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1281
1282         depth = 28;
1283         rte_lpm_delete(lpm, ip, depth);
1284
1285         TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group);
1286
1287         next_hop = 5;
1288         rte_lpm_add(lpm, ip, depth, next_hop);
1289
1290         TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1291         TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx);
1292
1293         rte_lpm_free(lpm);
1294 #undef group_idx
1295         return PASS;
1296 }
1297
1298 /*
1299  * Do all unit tests.
1300  */
1301
1302 static int
1303 test_lpm(void)
1304 {
1305         unsigned i;
1306         int status, global_status = 0;
1307
1308         for (i = 0; i < NUM_LPM_TESTS; i++) {
1309                 status = tests[i]();
1310                 if (status < 0) {
1311                         printf("ERROR: LPM Test %u: FAIL\n", i);
1312                         global_status = status;
1313                 }
1314         }
1315
1316         return global_status;
1317 }
1318
1319 REGISTER_TEST_COMMAND(lpm_autotest, test_lpm);