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