event/cnxk: support setting queue attributes at runtime
[dpdk.git] / app / test-fib / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4
5 #include <getopt.h>
6 #include <string.h>
7 #include <arpa/inet.h>
8 #include <sys/socket.h>
9
10 #include <rte_cycles.h>
11 #include <rte_errno.h>
12 #include <rte_ip.h>
13 #include <rte_random.h>
14 #include <rte_malloc.h>
15 #include <rte_lpm.h>
16 #include <rte_lpm6.h>
17 #include <rte_fib.h>
18 #include <rte_fib6.h>
19
20 #define PRINT_USAGE_START       "%s [EAL options] --\n"
21
22 #define GET_CB_FIELD(in, fd, base, lim, dlm)    do {            \
23         unsigned long val;                                      \
24         char *end_fld;                                          \
25         errno = 0;                                              \
26         val = strtoul((in), &end_fld, (base));                  \
27         if (errno != 0 || end_fld[0] != (dlm) || val > (lim))   \
28                 return -EINVAL;                                 \
29         (fd) = (typeof(fd))val;                                 \
30         (in) = end_fld + 1;                                     \
31 } while (0)
32
33 #define DEF_ROUTES_NUM          0x10000
34 #define DEF_LOOKUP_IPS_NUM      0x100000
35 #define BURST_SZ                64
36 #define DEFAULT_LPM_TBL8        100000U
37
38 #define CMP_FLAG                (1 << 0)
39 #define CMP_ALL_FLAG            (1 << 1)
40 #define IPV6_FLAG               (1 << 2)
41 #define FIB_RIB_TYPE            (1 << 3)
42 #define FIB_V4_DIR_TYPE         (1 << 4)
43 #define FIB_V6_TRIE_TYPE        (1 << 4)
44 #define FIB_TYPE_MASK           (FIB_RIB_TYPE|FIB_V4_DIR_TYPE|FIB_V6_TRIE_TYPE)
45 #define SHUFFLE_FLAG            (1 << 7)
46 #define DRY_RUN_FLAG            (1 << 8)
47
48 static char *distrib_string;
49 static char line[LINE_MAX];
50
51 enum {
52         RT_PREFIX,
53         RT_NEXTHOP,
54         RT_NUM
55 };
56
57 #ifndef NIPQUAD
58 #define NIPQUAD_FMT "%u.%u.%u.%u"
59 #define NIPQUAD(addr)                           \
60         (unsigned)((unsigned char *)&addr)[3],  \
61         (unsigned)((unsigned char *)&addr)[2],  \
62         (unsigned)((unsigned char *)&addr)[1],  \
63         (unsigned)((unsigned char *)&addr)[0]
64
65 #define NIPQUAD6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
66 #define NIPQUAD6(addr)                          \
67         ((uint8_t *)addr)[0] << 8 |     \
68         ((uint8_t *)addr)[1],           \
69         ((uint8_t *)addr)[2] << 8 |     \
70         ((uint8_t *)addr)[3],           \
71         ((uint8_t *)addr)[4] << 8 |     \
72         ((uint8_t *)addr)[5],           \
73         ((uint8_t *)addr)[6] << 8 |     \
74         ((uint8_t *)addr)[7],           \
75         ((uint8_t *)addr)[8] << 8 |     \
76         ((uint8_t *)addr)[9],           \
77         ((uint8_t *)addr)[10] << 8 |    \
78         ((uint8_t *)addr)[11],          \
79         ((uint8_t *)addr)[12] << 8 |    \
80         ((uint8_t *)addr)[13],          \
81         ((uint8_t *)addr)[14] << 8 |    \
82         ((uint8_t *)addr)[15]
83 #endif
84
85 static struct {
86         const char      *prgname;
87         const char      *routes_file;
88         const char      *lookup_ips_file;
89         const char      *routes_file_s;
90         const char      *lookup_ips_file_s;
91         void            *rt;
92         void            *lookup_tbl;
93         uint32_t        nb_routes;
94         uint32_t        nb_lookup_ips;
95         uint32_t        nb_lookup_ips_rnd;
96         uint32_t        nb_routes_per_depth[128 + 1];
97         uint32_t        flags;
98         uint32_t        tbl8;
99         uint8_t         ent_sz;
100         uint8_t         rnd_lookup_ips_ratio;
101         uint8_t         print_fract;
102         uint8_t         lookup_fn;
103 } config = {
104         .routes_file = NULL,
105         .lookup_ips_file = NULL,
106         .nb_routes = DEF_ROUTES_NUM,
107         .nb_lookup_ips = DEF_LOOKUP_IPS_NUM,
108         .nb_lookup_ips_rnd = 0,
109         .nb_routes_per_depth = {0},
110         .flags = FIB_V4_DIR_TYPE,
111         .tbl8 = DEFAULT_LPM_TBL8,
112         .ent_sz = 4,
113         .rnd_lookup_ips_ratio = 0,
114         .print_fract = 10,
115         .lookup_fn = 0
116 };
117
118 struct rt_rule_4 {
119         uint32_t        addr;
120         uint8_t         depth;
121         uint64_t        nh;
122 };
123
124 struct rt_rule_6 {
125         uint8_t         addr[16];
126         uint8_t         depth;
127         uint64_t        nh;
128 };
129
130 static uint64_t
131 get_rnd_rng(uint64_t l, uint64_t u)
132 {
133         if (l == u)
134                 return l;
135         else
136                 return (rte_rand() % (u - l) + l);
137 }
138
139 static __rte_always_inline __attribute__((pure)) uint8_t
140 bits_in_nh(uint8_t nh_sz)
141 {
142         return 8 * (1 << nh_sz);
143 }
144
145 static  __rte_always_inline __attribute__((pure)) uint64_t
146 get_max_nh(uint8_t nh_sz)
147 {
148         /* min between fib and lpm6 which is 21 bits */
149         return RTE_MIN(((1ULL << (bits_in_nh(nh_sz) - 1)) - 1),
150                         (1ULL << 21) - 1);
151 }
152
153 static int
154 get_fib_type(void)
155 {
156         if (config.flags & IPV6_FLAG) {
157                 if ((config.flags & FIB_TYPE_MASK) == FIB_V6_TRIE_TYPE)
158                         return RTE_FIB6_TRIE;
159                 else
160                         return RTE_FIB6_DUMMY;
161         } else {
162                 if ((config.flags & FIB_TYPE_MASK) == FIB_V4_DIR_TYPE)
163                         return RTE_FIB_DIR24_8;
164                 if ((config.flags & FIB_TYPE_MASK) == FIB_RIB_TYPE)
165                         return RTE_FIB_DUMMY;
166         }
167         return -1;
168 }
169
170 static int
171 complete_distrib(uint8_t depth_lim, const uint32_t n, uint8_t rpd[],
172         uint32_t nrpd[])
173 {
174         uint8_t depth;
175         uint32_t nr = 0;
176         uint8_t m = 0;
177
178         /*
179          * complete number of routes for every depth
180          * that was configured with ratio
181          */
182         for (depth = 0; depth <= depth_lim; depth++) {
183                 if (rpd[depth] != 0) {
184                         if (rpd[depth] == UINT8_MAX)
185                                 config.nb_routes_per_depth[depth] =
186                                         nrpd[depth];
187                         else
188                                 config.nb_routes_per_depth[depth] =
189                                         (n * rpd[depth]) / 100;
190
191                         nr += config.nb_routes_per_depth[depth];
192                         m++;
193                 }
194         }
195
196         if (nr > n) {
197                 printf("Too much configured routes\n");
198                 return -1;
199         }
200
201         /*complete number of routes for every unspecified depths*/
202         for (depth = 0; depth <= depth_lim; depth++) {
203                 if (rpd[depth] == 0) {
204                         /*we don't need more than two /1 routes*/
205                         uint64_t max_routes_per_depth =
206                                 1ULL << RTE_MIN(depth, 63);
207                         uint32_t avg_routes_left = (n - nr) /
208                                 (depth_lim + 1 - m++);
209                         config.nb_routes_per_depth[depth] =
210                                 RTE_MIN(max_routes_per_depth, avg_routes_left);
211                         nr += config.nb_routes_per_depth[depth];
212                 }
213         }
214
215         return 0;
216 }
217
218 static int
219 parse_distrib(uint8_t depth_lim, const uint32_t n)
220 {
221         uint8_t rpd[128 + 1] = {0}; /*routes ratios per depth including /0 */
222         uint32_t nrpd[128 + 1] = {0}; /* number of routes per depth */
223         uint32_t n_routes;
224         uint8_t depth, ratio, ratio_acc = 0;
225         char *in;
226
227         in = strtok(distrib_string, ",");
228
229         /*parse configures routes percentage ratios*/
230         while (in != NULL) {
231                 GET_CB_FIELD(in, depth, 0, UINT8_MAX, ':');
232                 if (in[strlen(in) - 1] == '%') {
233                         in[strlen(in) - 1] = 0;
234                         GET_CB_FIELD(in, ratio, 0, UINT8_MAX, '\0');
235                         if (depth > depth_lim) {
236                                 printf("Depth /%d is bigger than maximum "
237                                         "allowed depth /%d for this AF\n",
238                                         depth, depth_lim);
239                                 return -EINVAL;
240                         }
241                         if (ratio > 100) {
242                                 printf("Ratio for depth /%d is bigger "
243                                         "than 100%%\n", depth);
244                                 return -EINVAL;
245                         }
246                         if ((depth < 64) && ((n * ratio) / 100) >
247                                         (1ULL << depth)) {
248                                 printf("Configured ratio %d%% for depth /%d "
249                                         "has %d different routes, but maximum "
250                                         "is %lu\n", ratio, depth,
251                                         ((n * ratio) / 100), (1UL << depth));
252                                 return -EINVAL;
253                         }
254                         rpd[depth] = ratio;
255                         /*configured zero routes for a given depth*/
256                         if (ratio == 0)
257                                 rpd[depth] = UINT8_MAX;
258                         /*sum of all percentage ratios*/
259                         ratio_acc += ratio;
260                 } else {
261                         GET_CB_FIELD(in, n_routes, 0, UINT32_MAX, '\0');
262                         rpd[depth] = UINT8_MAX;
263                         nrpd[depth] = n_routes;
264                 }
265
266                 /*number of configured depths in*/
267                 in = strtok(NULL, ",");
268         }
269
270         if (ratio_acc > 100) {
271                 printf("Total ratio's sum is bigger than 100%%\n");
272                 return -EINVAL;
273         }
274
275         return complete_distrib(depth_lim, n, rpd, nrpd);
276 }
277
278 static void
279 shuffle_rt_4(struct rt_rule_4 *rt, int n)
280 {
281         struct rt_rule_4 tmp;
282         int i, j;
283
284         for (i = 0; i < n; i++) {
285                 j = rte_rand() % n;
286                 tmp.addr = rt[i].addr;
287                 tmp.depth = rt[i].depth;
288                 tmp.nh = rt[i].nh;
289
290                 rt[i].addr = rt[j].addr;
291                 rt[i].depth = rt[j].depth;
292                 rt[i].nh = rt[j].nh;
293
294                 rt[j].addr = tmp.addr;
295                 rt[j].depth = tmp.depth;
296                 rt[j].nh = tmp.nh;
297         }
298 }
299
300 static void
301 shuffle_rt_6(struct rt_rule_6 *rt, int n)
302 {
303         struct rt_rule_6 tmp;
304         int i, j;
305
306         for (i = 0; i < n; i++) {
307                 j = rte_rand() % n;
308                 memcpy(tmp.addr, rt[i].addr, 16);
309                 tmp.depth = rt[i].depth;
310                 tmp.nh = rt[i].nh;
311
312                 memcpy(rt[i].addr, rt[j].addr, 16);
313                 rt[i].depth = rt[j].depth;
314                 rt[i].nh = rt[j].nh;
315
316                 memcpy(rt[j].addr, tmp.addr, 16);
317                 rt[j].depth = tmp.depth;
318                 rt[j].nh = tmp.nh;
319         }
320 }
321
322 static void
323 gen_random_rt_4(struct rt_rule_4 *rt, int nh_sz)
324 {
325         uint32_t i, j, k = 0;
326
327         if (config.nb_routes_per_depth[0] != 0) {
328                 rt[k].addr = 0;
329                 rt[k].depth = 0;
330                 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
331         }
332
333         for (i = 1; i <= 32; i++) {
334                 double edge = 0;
335                 double step;
336                 step = (double)(1ULL << i) / config.nb_routes_per_depth[i];
337                 for (j = 0; j < config.nb_routes_per_depth[i];
338                                 j++, k++, edge += step) {
339                         uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
340                                 (uint64_t)(edge + step));
341                         rt[k].addr = rnd_val << (32 - i);
342                         rt[k].depth = i;
343                         rt[k].nh = rte_rand() & get_max_nh(nh_sz);
344                 }
345         }
346 }
347
348 static void
349 complete_v6_addr(uint32_t *addr, uint32_t rnd, int n)
350 {
351         int i;
352
353         for (i = 0; i < n; i++)
354                 addr[i] = rte_rand();
355         addr[i++] = rnd;
356         for (; i < 4; i++)
357                 addr[i] = 0;
358 }
359
360 static void
361 gen_random_rt_6(struct rt_rule_6 *rt, int nh_sz)
362 {
363         uint32_t a, i, j, k = 0;
364
365         if (config.nb_routes_per_depth[0] != 0) {
366                 memset(rt[k].addr, 0, 16);
367                 rt[k].depth = 0;
368                 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
369         }
370
371         for (a = 0; a < 4; a++) {
372                 for (i = 1; i <= 32; i++) {
373                         uint32_t rnd;
374                         double edge = 0;
375                         double step = (double)(1ULL << i) /
376                                 config.nb_routes_per_depth[(a * 32) + i];
377                         for (j = 0; j < config.nb_routes_per_depth[a * 32 + i];
378                                         j++, k++, edge += step) {
379                                 uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
380                                         (uint64_t)(edge + step));
381                                 rnd = rte_cpu_to_be_32(rnd_val << (32 - i));
382                                 complete_v6_addr((uint32_t *)rt[k].addr,
383                                         rnd, a);
384                                 rt[k].depth = (a * 32) + i;
385                                 rt[k].nh = rte_rand() & get_max_nh(nh_sz);
386                         }
387                 }
388         }
389 }
390
391 static inline void
392 set_rnd_ipv6(uint8_t *addr, uint8_t *route, int depth)
393 {
394         int i;
395
396         for (i = 0; i < 16; i++)
397                 addr[i] = rte_rand();
398
399         for (i = 0; i < 16; i++) {
400                 if (depth >= 8)
401                         addr[i] = route[i];
402                 else if (depth > 0) {
403                         addr[i] &= (uint16_t)UINT8_MAX >> depth;
404                         addr[i] |= route[i] & UINT8_MAX << (8 - depth);
405                 } else
406                         return;
407                 depth -= 8;
408         }
409 }
410
411 static void
412 gen_rnd_lookup_tbl(int af)
413 {
414         uint32_t *tbl4 = config.lookup_tbl;
415         uint8_t *tbl6 = config.lookup_tbl;
416         struct rt_rule_4 *rt4 = (struct rt_rule_4 *)config.rt;
417         struct rt_rule_6 *rt6 = (struct rt_rule_6 *)config.rt;
418         uint32_t i, j;
419
420         if (af == AF_INET) {
421                 for (i = 0, j = 0; i < config.nb_lookup_ips;
422                                 i++, j = (j + 1) % config.nb_routes) {
423                         if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
424                                 tbl4[i] = rte_rand();
425                                 config.nb_lookup_ips_rnd++;
426                         } else
427                                 tbl4[i] = rt4[j].addr | (rte_rand() &
428                                         ((1ULL << (32 - rt4[j].depth)) - 1));
429                 }
430         } else {
431                 for (i = 0, j = 0; i < config.nb_lookup_ips;
432                                 i++, j = (j + 1) % config.nb_routes) {
433                         if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
434                                 set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr, 0);
435                                 config.nb_lookup_ips_rnd++;
436                         } else {
437                                 set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr,
438                                         rt6[j].depth);
439                         }
440                 }
441         }
442 }
443
444 static int
445 _inet_net_pton(int af, char *prefix, void *addr)
446 {
447         const char *dlm = "/";
448         char *s, *sp;
449         int ret, depth;
450         unsigned int max_depth;
451
452         if ((prefix == NULL) || (addr == NULL))
453                 return -EINVAL;
454
455         s = strtok_r(prefix, dlm, &sp);
456         if (s == NULL)
457                 return -EINVAL;
458
459         ret = inet_pton(af, s, addr);
460         if (ret != 1)
461                 return -errno;
462
463         s = strtok_r(NULL, dlm, &sp);
464         max_depth = (af == AF_INET) ? 32 : 128;
465         GET_CB_FIELD(s, depth, 0, max_depth, 0);
466
467         return depth;
468 }
469
470 static int
471 parse_rt_4(FILE *f)
472 {
473         int ret, i, j = 0;
474         char *s, *sp, *in[RT_NUM];
475         static const char *dlm = " \t\n";
476         int string_tok_nb = RTE_DIM(in);
477         struct rt_rule_4 *rt;
478
479         rt = (struct rt_rule_4 *)config.rt;
480
481         while (fgets(line, sizeof(line), f) != NULL) {
482                 s = line;
483                 for (i = 0; i != string_tok_nb; i++) {
484                         in[i] = strtok_r(s, dlm, &sp);
485                         if (in[i] == NULL)
486                                 return -EINVAL;
487                         s = NULL;
488                 }
489
490                 ret = _inet_net_pton(AF_INET, in[RT_PREFIX], &rt[j].addr);
491                 if (ret == -1)
492                         return -errno;
493
494                 rt[j].addr = rte_be_to_cpu_32(rt[j].addr);
495                 rt[j].depth = ret;
496                 config.nb_routes_per_depth[ret]++;
497                 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
498                                 UINT32_MAX, 0);
499                 j++;
500         }
501         return 0;
502 }
503
504 static int
505 parse_rt_6(FILE *f)
506 {
507         int ret, i, j = 0;
508         char *s, *sp, *in[RT_NUM];
509         static const char *dlm = " \t\n";
510         int string_tok_nb = RTE_DIM(in);
511         struct rt_rule_6 *rt;
512
513         rt = (struct rt_rule_6 *)config.rt;
514
515         while (fgets(line, sizeof(line), f) != NULL) {
516                 s = line;
517                 for (i = 0; i != string_tok_nb; i++) {
518                         in[i] = strtok_r(s, dlm, &sp);
519                         if (in[i] == NULL)
520                                 return -EINVAL;
521                         s = NULL;
522                 }
523
524                 ret = _inet_net_pton(AF_INET6, in[RT_PREFIX], rt[j].addr);
525                 if (ret < 0)
526                         return ret;
527
528                 rt[j].depth = ret;
529                 config.nb_routes_per_depth[ret]++;
530                 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
531                                 UINT32_MAX, 0);
532                 j++;
533         }
534
535         return 0;
536 }
537
538 static int
539 parse_lookup(FILE *f, int af)
540 {
541         int ret, i = 0;
542         uint8_t *tbl = (uint8_t *)config.lookup_tbl;
543         int step = (af == AF_INET) ? 4 : 16;
544         char *s;
545
546         while (fgets(line, sizeof(line), f) != NULL) {
547                 s = strtok(line, " \t\n");
548                 if (s == NULL)
549                         return -EINVAL;
550                 ret = inet_pton(af, s, &tbl[i]);
551                 if (ret != 1)
552                         return -EINVAL;
553                 i += step;
554         }
555         return 0;
556 }
557
558 static int
559 dump_lookup(int af)
560 {
561         FILE *f;
562         uint32_t *tbl4 = config.lookup_tbl;
563         uint8_t *tbl6 = config.lookup_tbl;
564         uint32_t i;
565
566         f = fopen(config.lookup_ips_file_s, "w");
567         if (f == NULL) {
568                 printf("Can not open file %s\n", config.lookup_ips_file_s);
569                 return -1;
570         }
571
572         if (af == AF_INET) {
573                 for (i = 0; i < config.nb_lookup_ips; i++)
574                         fprintf(f, NIPQUAD_FMT"\n", NIPQUAD(tbl4[i]));
575         } else {
576                 for (i = 0; i < config.nb_lookup_ips; i++)
577                         fprintf(f, NIPQUAD6_FMT"\n", NIPQUAD6(&tbl6[i * 16]));
578         }
579         fclose(f);
580         return 0;
581 }
582
583 static void
584 print_config(void)
585 {
586         uint8_t depth_lim;
587         char dlm;
588         int i;
589
590         depth_lim = ((config.flags & IPV6_FLAG) == IPV6_FLAG) ? 128 : 32;
591
592         fprintf(stdout,
593                 "Routes total: %u\n"
594                 "Routes distribution:\n", config.nb_routes);
595
596         for (i = 1; i <= depth_lim; i++) {
597                 fprintf(stdout,
598                         "depth /%d:%u", i, config.nb_routes_per_depth[i]);
599                 if (i % 4 == 0)
600                         dlm = '\n';
601                 else
602                         dlm = '\t';
603                 fprintf(stdout, "%c", dlm);
604         }
605
606         fprintf(stdout,
607                 "Lookup tuples: %u\n"
608                 "Configured ratios of random ips for lookup: %u\n"
609                 "Random lookup ips: %u\n",
610                 config.nb_lookup_ips, config.rnd_lookup_ips_ratio,
611                 config.nb_lookup_ips_rnd);
612 }
613
614 static void
615 print_usage(void)
616 {
617         fprintf(stdout,
618                 PRINT_USAGE_START
619                 "[-f <routes file>]\n"
620                 "[-t <ip's file for lookup>]\n"
621                 "[-n <number of routes (if -f is not specified)>]\n"
622                 "[-l <number of ip's for lookup (if -t is not specified)>]\n"
623                 "[-d <\",\" separated \"depth:n%%\"routes depth distribution"
624                 "(if -f is not specified)>]\n"
625                 "[-r <percentage ratio of random ip's to lookup"
626                 "(if -t is not specified)>]\n"
627                 "[-c <do comparison with LPM library>]\n"
628                 "[-6 <do tests with ipv6 (default ipv4)>]\n"
629                 "[-s <shuffle randomly generated routes>]\n"
630                 "[-a <check nexthops for all ipv4 address space"
631                 "(only valid with -c)>]\n"
632                 "[-b <fib algorithm>]\n\tavailable options for ipv4\n"
633                 "\t\trib - RIB based FIB\n"
634                 "\t\tdir - DIR24_8 based FIB\n"
635                 "\tavailable options for ipv6:\n"
636                 "\t\trib - RIB based FIB\n"
637                 "\t\ttrie - TRIE based FIB\n"
638                 "defaults are: dir for ipv4 and trie for ipv6\n"
639                 "[-e <entry size (valid only for dir and trie fib types): "
640                 "1/2/4/8 (default 4)>]\n"
641                 "[-g <number of tbl8's for dir24_8 or trie FIBs>]\n"
642                 "[-w <path to the file to dump routing table>]\n"
643                 "[-u <path to the file to dump ip's for lookup>]\n"
644                 "[-v <type of lookup function:"
645                 "\ts1, s2, s3 (3 types of scalar), v (vector) -"
646                 " for DIR24_8 based FIB\n"
647                 "\ts, v - for TRIE based ipv6 FIB>]\n",
648                 config.prgname);
649 }
650
651 static int
652 check_config(void)
653 {
654         if ((config.routes_file == NULL) && (config.lookup_ips_file != NULL)) {
655                 printf("-t option only valid with -f option\n");
656                 return -1;
657         }
658
659         if ((config.flags & CMP_ALL_FLAG) && (config.flags & IPV6_FLAG)) {
660                 printf("-a flag is only valid for ipv4\n");
661                 return -1;
662         }
663
664         if ((config.flags & CMP_ALL_FLAG) &&
665                         ((config.flags & CMP_FLAG) != CMP_FLAG)) {
666                 printf("-a flag is valid only with -c flag\n");
667                 return -1;
668         }
669
670         if (!((config.ent_sz == 1) || (config.ent_sz == 2) ||
671                         (config.ent_sz == 4) || (config.ent_sz == 8))) {
672                 printf("wrong -e option %d, can be 1 or 2 or 4 or 8\n",
673                         config.ent_sz);
674                 return -1;
675         }
676
677         if ((config.ent_sz == 1) && (config.flags & IPV6_FLAG)) {
678                 printf("-e 1 is valid only for ipv4\n");
679                 return -1;
680         }
681         return 0;
682 }
683
684 static void
685 parse_opts(int argc, char **argv)
686 {
687         int opt;
688         char *endptr;
689
690         while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:sv:")) !=
691                         -1) {
692                 switch (opt) {
693                 case 'f':
694                         config.routes_file = optarg;
695                         break;
696                 case 't':
697                         config.lookup_ips_file = optarg;
698                         break;
699                 case 'w':
700                         config.routes_file_s = optarg;
701                         config.flags |= DRY_RUN_FLAG;
702                         break;
703                 case 'u':
704                         config.lookup_ips_file_s = optarg;
705                         config.flags |= DRY_RUN_FLAG;
706                         break;
707                 case 'n':
708                         errno = 0;
709                         config.nb_routes = strtoul(optarg, &endptr, 10);
710                         if ((errno != 0) || (config.nb_routes == 0)) {
711                                 print_usage();
712                                 rte_exit(-EINVAL, "Invalid option -n\n");
713                         }
714
715                         if (config.nb_routes < config.print_fract)
716                                 config.print_fract = config.nb_routes;
717
718                         break;
719                 case 'd':
720                         distrib_string = optarg;
721                         break;
722                 case 'l':
723                         errno = 0;
724                         config.nb_lookup_ips = strtoul(optarg, &endptr, 10);
725                         if ((errno != 0) || (config.nb_lookup_ips == 0)) {
726                                 print_usage();
727                                 rte_exit(-EINVAL, "Invalid option -l\n");
728                         }
729                         break;
730                 case 'r':
731                         errno = 0;
732                         config.rnd_lookup_ips_ratio =
733                                 strtoul(optarg, &endptr, 10);
734                         if ((errno != 0) ||
735                                         (config.rnd_lookup_ips_ratio == 0) ||
736                                         (config.rnd_lookup_ips_ratio >= 100)) {
737                                 print_usage();
738                                 rte_exit(-EINVAL, "Invalid option -r\n");
739                         }
740                         break;
741                 case 's':
742                         config.flags |= SHUFFLE_FLAG;
743                         break;
744                 case 'c':
745                         config.flags |= CMP_FLAG;
746                         break;
747                 case '6':
748                         config.flags |= IPV6_FLAG;
749                         break;
750                 case 'a':
751                         config.flags |= CMP_ALL_FLAG;
752                         break;
753                 case 'b':
754                         if (strcmp(optarg, "rib") == 0) {
755                                 config.flags &= ~FIB_TYPE_MASK;
756                                 config.flags |= FIB_RIB_TYPE;
757                         } else if (strcmp(optarg, "dir") == 0) {
758                                 config.flags &= ~FIB_TYPE_MASK;
759                                 config.flags |= FIB_V4_DIR_TYPE;
760                         } else if (strcmp(optarg, "trie") == 0) {
761                                 config.flags &= ~FIB_TYPE_MASK;
762                                 config.flags |= FIB_V6_TRIE_TYPE;
763                         } else
764                                 rte_exit(-EINVAL, "Invalid option -b\n");
765                         break;
766                 case 'e':
767                         errno = 0;
768                         config.ent_sz = strtoul(optarg, &endptr, 10);
769                         if (errno != 0) {
770                                 print_usage();
771                                 rte_exit(-EINVAL, "Invalid option -e\n");
772                         }
773                         break;
774                 case 'g':
775                         errno = 0;
776                         config.tbl8 = strtoul(optarg, &endptr, 10);
777                         if ((errno != 0) || (config.tbl8 == 0)) {
778                                 print_usage();
779                                 rte_exit(-EINVAL, "Invalid option -g\n");
780                         }
781                         break;
782                 case 'v':
783                         if ((strcmp(optarg, "s1") == 0) ||
784                                         (strcmp(optarg, "s") == 0)) {
785                                 config.lookup_fn = 1;
786                                 break;
787                         } else if (strcmp(optarg, "v") == 0) {
788                                 config.lookup_fn = 2;
789                                 break;
790                         } else if (strcmp(optarg, "s2") == 0) {
791                                 config.lookup_fn = 3;
792                                 break;
793                         } else if (strcmp(optarg, "s3") == 0) {
794                                 config.lookup_fn = 4;
795                                 break;
796                         }
797                         print_usage();
798                         rte_exit(-EINVAL, "Invalid option -v %s\n", optarg);
799                 default:
800                         print_usage();
801                         rte_exit(-EINVAL, "Invalid options\n");
802                 }
803         }
804 }
805
806 static int
807 dump_rt_4(struct rt_rule_4 *rt)
808 {
809         FILE *f;
810         uint32_t i;
811
812         f = fopen(config.routes_file_s, "w");
813         if (f == NULL) {
814                 printf("Can not open file %s\n", config.routes_file_s);
815                 return -1;
816         }
817
818         for (i = 0; i < config.nb_routes; i++)
819                 fprintf(f, NIPQUAD_FMT"/%d %"PRIu64"\n", NIPQUAD(rt[i].addr),
820                         rt[i].depth, rt[i].nh);
821
822         fclose(f);
823         return 0;
824 }
825
826 static inline void
827 print_depth_err(void)
828 {
829         printf("LPM does not support /0 prefix length (default route), use "
830                 "-d 0:0 option or remove /0 prefix from routes file\n");
831 }
832
833 static int
834 run_v4(void)
835 {
836         uint64_t start, acc;
837         uint64_t def_nh = 0;
838         struct rte_fib *fib;
839         struct rte_fib_conf conf = {0};
840         struct rt_rule_4 *rt;
841         uint32_t i, j, k;
842         int ret = 0;
843         struct rte_lpm  *lpm = NULL;
844         struct rte_lpm_config lpm_conf;
845         uint32_t *tbl4 = config.lookup_tbl;
846         uint64_t fib_nh[BURST_SZ];
847         uint32_t lpm_nh[BURST_SZ];
848
849         rt = (struct rt_rule_4 *)config.rt;
850
851         if (config.flags & DRY_RUN_FLAG) {
852                 if (config.routes_file_s != NULL)
853                         ret = dump_rt_4(rt);
854                 if (ret != 0)
855                         return ret;
856                 if (config.lookup_ips_file_s != NULL)
857                         ret = dump_lookup(AF_INET);
858                 return ret;
859         }
860
861         conf.type = get_fib_type();
862         conf.default_nh = def_nh;
863         conf.max_routes = config.nb_routes * 2;
864         conf.rib_ext_sz = 0;
865         if (conf.type == RTE_FIB_DIR24_8) {
866                 conf.dir24_8.nh_sz = __builtin_ctz(config.ent_sz);
867                 conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
868                         get_max_nh(conf.dir24_8.nh_sz));
869         }
870
871         fib = rte_fib_create("test", -1, &conf);
872         if (fib == NULL) {
873                 printf("Can not alloc FIB, err %d\n", rte_errno);
874                 return -rte_errno;
875         }
876
877         if (config.lookup_fn != 0) {
878                 if (config.lookup_fn == 1)
879                         ret = rte_fib_select_lookup(fib,
880                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO);
881                 else if (config.lookup_fn == 2)
882                         ret = rte_fib_select_lookup(fib,
883                                 RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512);
884                 else if (config.lookup_fn == 3)
885                         ret = rte_fib_select_lookup(fib,
886                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE);
887                 else if (config.lookup_fn == 4)
888                         ret = rte_fib_select_lookup(fib,
889                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI);
890                 else
891                         ret = -EINVAL;
892                 if (ret != 0) {
893                         printf("Can not init lookup function\n");
894                         return ret;
895                 }
896         }
897
898         for (k = config.print_fract, i = 0; k > 0; k--) {
899                 start = rte_rdtsc_precise();
900                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
901                         ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
902                                 rt[i + j].nh);
903                         if (unlikely(ret != 0)) {
904                                 printf("Can not add a route to FIB, err %d\n",
905                                         ret);
906                                 return -ret;
907                         }
908                 }
909                 printf("AVG FIB add %"PRIu64"\n",
910                         (rte_rdtsc_precise() - start) / j);
911                 i += j;
912         }
913
914         if (config.flags & CMP_FLAG) {
915                 lpm_conf.max_rules = config.nb_routes * 2;
916                 lpm_conf.number_tbl8s = RTE_MAX(conf.dir24_8.num_tbl8,
917                         config.tbl8);
918
919                 lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
920                 if (lpm == NULL) {
921                         printf("Can not alloc LPM, err %d\n", rte_errno);
922                         return -rte_errno;
923                 }
924                 for (k = config.print_fract, i = 0; k > 0; k--) {
925                         start = rte_rdtsc_precise();
926                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
927                                 ret = rte_lpm_add(lpm, rt[i + j].addr,
928                                         rt[i + j].depth, rt[i + j].nh);
929                                 if (ret != 0) {
930                                         if (rt[i + j].depth == 0)
931                                                 print_depth_err();
932                                         printf("Can not add a route to LPM, "
933                                                 "err %d\n", ret);
934                                         return -ret;
935                                 }
936                         }
937                         printf("AVG LPM add %"PRIu64"\n",
938                                 (rte_rdtsc_precise() - start) / j);
939                         i += j;
940                 }
941         }
942
943         acc = 0;
944         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
945                 start = rte_rdtsc_precise();
946                 ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
947                 acc += rte_rdtsc_precise() - start;
948                 if (ret != 0) {
949                         printf("FIB lookup fails, err %d\n", ret);
950                         return -ret;
951                 }
952         }
953         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
954
955         if (config.flags & CMP_FLAG) {
956                 acc = 0;
957                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
958                         start = rte_rdtsc_precise();
959                         ret = rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh,
960                                 BURST_SZ);
961                         acc += rte_rdtsc_precise() - start;
962                         if (ret != 0) {
963                                 printf("LPM lookup fails, err %d\n", ret);
964                                 return -ret;
965                         }
966                 }
967                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
968
969                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
970                         rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
971                         rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh, BURST_SZ);
972                         for (j = 0; j < BURST_SZ; j++) {
973                                 struct rte_lpm_tbl_entry *tbl;
974                                 tbl = (struct rte_lpm_tbl_entry *)&lpm_nh[j];
975                                 if ((fib_nh[j] != tbl->next_hop) &&
976                                                 !((tbl->valid == 0) &&
977                                                 (fib_nh[j] == def_nh))) {
978                                         printf("FAIL\n");
979                                         return -1;
980                                 }
981                         }
982                 }
983                 printf("FIB and LPM lookup returns same values\n");
984         }
985
986         for (k = config.print_fract, i = 0; k > 0; k--) {
987                 start = rte_rdtsc_precise();
988                 for (j = 0; j < (config.nb_routes - i) / k; j++)
989                         rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
990
991                 printf("AVG FIB delete %"PRIu64"\n",
992                         (rte_rdtsc_precise() - start) / j);
993                 i += j;
994         }
995
996         if (config.flags & CMP_FLAG) {
997                 for (k = config.print_fract, i = 0; k > 0; k--) {
998                         start = rte_rdtsc_precise();
999                         for (j = 0; j < (config.nb_routes - i) / k; j++)
1000                                 rte_lpm_delete(lpm, rt[i + j].addr,
1001                                         rt[i + j].depth);
1002
1003                         printf("AVG LPM delete %"PRIu64"\n",
1004                                 (rte_rdtsc_precise() - start) / j);
1005                         i += j;
1006                 }
1007         }
1008
1009         return 0;
1010 }
1011
1012 static int
1013 dump_rt_6(struct rt_rule_6 *rt)
1014 {
1015         FILE *f;
1016         uint32_t i;
1017
1018         f = fopen(config.routes_file_s, "w");
1019         if (f == NULL) {
1020                 printf("Can not open file %s\n", config.routes_file_s);
1021                 return -1;
1022         }
1023
1024         for (i = 0; i < config.nb_routes; i++) {
1025                 fprintf(f, NIPQUAD6_FMT"/%d %"PRIu64"\n", NIPQUAD6(rt[i].addr),
1026                         rt[i].depth, rt[i].nh);
1027
1028         }
1029         fclose(f);
1030         return 0;
1031 }
1032
1033 static int
1034 run_v6(void)
1035 {
1036         uint64_t start, acc;
1037         uint64_t def_nh = 0;
1038         struct rte_fib6 *fib;
1039         struct rte_fib6_conf conf = {0};
1040         struct rt_rule_6 *rt;
1041         uint32_t i, j, k;
1042         int ret = 0;
1043         struct rte_lpm6 *lpm = NULL;
1044         struct rte_lpm6_config lpm_conf;
1045         uint8_t *tbl6;
1046         uint64_t fib_nh[BURST_SZ];
1047         int32_t lpm_nh[BURST_SZ];
1048
1049         rt = (struct rt_rule_6 *)config.rt;
1050         tbl6 = config.lookup_tbl;
1051
1052         if (config.flags & DRY_RUN_FLAG) {
1053                 if (config.routes_file_s != NULL)
1054                         ret =  dump_rt_6(rt);
1055                 if (ret != 0)
1056                         return ret;
1057                 if (config.lookup_ips_file_s != NULL)
1058                         ret = dump_lookup(AF_INET6);
1059                 return ret;
1060         }
1061
1062         conf.type = get_fib_type();
1063         conf.default_nh = def_nh;
1064         conf.max_routes = config.nb_routes * 2;
1065         conf.rib_ext_sz = 0;
1066         if (conf.type == RTE_FIB6_TRIE) {
1067                 conf.trie.nh_sz = __builtin_ctz(config.ent_sz);
1068                 conf.trie.num_tbl8 = RTE_MIN(config.tbl8,
1069                         get_max_nh(conf.trie.nh_sz));
1070         }
1071
1072         fib = rte_fib6_create("test", -1, &conf);
1073         if (fib == NULL) {
1074                 printf("Can not alloc FIB, err %d\n", rte_errno);
1075                 return -rte_errno;
1076         }
1077
1078         if (config.lookup_fn != 0) {
1079                 if (config.lookup_fn == 1)
1080                         ret = rte_fib6_select_lookup(fib,
1081                                 RTE_FIB6_LOOKUP_TRIE_SCALAR);
1082                 else if (config.lookup_fn == 2)
1083                         ret = rte_fib6_select_lookup(fib,
1084                                 RTE_FIB6_LOOKUP_TRIE_VECTOR_AVX512);
1085                 else
1086                         ret = -EINVAL;
1087                 if (ret != 0) {
1088                         printf("Can not init lookup function\n");
1089                         return ret;
1090                 }
1091         }
1092
1093         for (k = config.print_fract, i = 0; k > 0; k--) {
1094                 start = rte_rdtsc_precise();
1095                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
1096                         ret = rte_fib6_add(fib, rt[i + j].addr,
1097                                 rt[i + j].depth, rt[i + j].nh);
1098                         if (unlikely(ret != 0)) {
1099                                 printf("Can not add a route to FIB, err %d\n",
1100                                         ret);
1101                                 return -ret;
1102                         }
1103                 }
1104                 printf("AVG FIB add %"PRIu64"\n",
1105                         (rte_rdtsc_precise() - start) / j);
1106                 i += j;
1107         }
1108
1109         if (config.flags & CMP_FLAG) {
1110                 lpm_conf.max_rules = config.nb_routes * 2;
1111                 lpm_conf.number_tbl8s = RTE_MAX(conf.trie.num_tbl8,
1112                         config.tbl8);
1113
1114                 lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1115                 if (lpm == NULL) {
1116                         printf("Can not alloc LPM, err %d\n", rte_errno);
1117                         return -rte_errno;
1118                 }
1119                 for (k = config.print_fract, i = 0; k > 0; k--) {
1120                         start = rte_rdtsc_precise();
1121                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
1122                                 ret = rte_lpm6_add(lpm, rt[i + j].addr,
1123                                         rt[i + j].depth, rt[i + j].nh);
1124                                 if (ret != 0) {
1125                                         if (rt[i + j].depth == 0)
1126                                                 print_depth_err();
1127                                         printf("Can not add a route to LPM, "
1128                                                 "err %d\n", ret);
1129                                         return -ret;
1130                                 }
1131                         }
1132                         printf("AVG LPM add %"PRIu64"\n",
1133                                 (rte_rdtsc_precise() - start) / j);
1134                         i += j;
1135                 }
1136         }
1137
1138         acc = 0;
1139         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1140                 start = rte_rdtsc_precise();
1141                 ret = rte_fib6_lookup_bulk(fib, (uint8_t (*)[16])(tbl6 + i*16),
1142                         fib_nh, BURST_SZ);
1143                 acc += rte_rdtsc_precise() - start;
1144                 if (ret != 0) {
1145                         printf("FIB lookup fails, err %d\n", ret);
1146                         return -ret;
1147                 }
1148         }
1149         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1150
1151         if (config.flags & CMP_FLAG) {
1152                 acc = 0;
1153                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1154                         start = rte_rdtsc_precise();
1155                         ret = rte_lpm6_lookup_bulk_func(lpm,
1156                                 (uint8_t (*)[16])(tbl6 + i*16),
1157                                 lpm_nh, BURST_SZ);
1158                         acc += rte_rdtsc_precise() - start;
1159                         if (ret != 0) {
1160                                 printf("LPM lookup fails, err %d\n", ret);
1161                                 return -ret;
1162                         }
1163                 }
1164                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
1165
1166                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1167                         rte_fib6_lookup_bulk(fib,
1168                                 (uint8_t (*)[16])(tbl6 + i*16),
1169                                 fib_nh, BURST_SZ);
1170                         rte_lpm6_lookup_bulk_func(lpm,
1171                                 (uint8_t (*)[16])(tbl6 + i*16),
1172                                 lpm_nh, BURST_SZ);
1173                         for (j = 0; j < BURST_SZ; j++) {
1174                                 if ((fib_nh[j] != (uint32_t)lpm_nh[j]) &&
1175                                                 !((lpm_nh[j] == -1) &&
1176                                                 (fib_nh[j] == def_nh))) {
1177                                         printf("FAIL\n");
1178                                         return -1;
1179                                 }
1180                         }
1181                 }
1182                 printf("FIB and LPM lookup returns same values\n");
1183         }
1184
1185         for (k = config.print_fract, i = 0; k > 0; k--) {
1186                 start = rte_rdtsc_precise();
1187                 for (j = 0; j < (config.nb_routes - i) / k; j++)
1188                         rte_fib6_delete(fib, rt[i + j].addr, rt[i + j].depth);
1189
1190                 printf("AVG FIB delete %"PRIu64"\n",
1191                         (rte_rdtsc_precise() - start) / j);
1192                 i += j;
1193         }
1194
1195         if (config.flags & CMP_FLAG) {
1196                 for (k = config.print_fract, i = 0; k > 0; k--) {
1197                         start = rte_rdtsc_precise();
1198                         for (j = 0; j < (config.nb_routes - i) / k; j++)
1199                                 rte_lpm6_delete(lpm, rt[i + j].addr,
1200                                         rt[i + j].depth);
1201
1202                         printf("AVG LPM delete %"PRIu64"\n",
1203                                 (rte_rdtsc_precise() - start) / j);
1204                         i += j;
1205                 }
1206         }
1207         return 0;
1208 }
1209
1210 int
1211 main(int argc, char **argv)
1212 {
1213         int ret, af, rt_ent_sz, lookup_ent_sz;
1214         FILE *fr = NULL;
1215         FILE *fl = NULL;
1216         uint8_t depth_lim;
1217
1218         ret = rte_eal_init(argc, argv);
1219         if (ret < 0)
1220                 rte_panic("Cannot init EAL\n");
1221
1222         argc -= ret;
1223         argv += ret;
1224
1225         config.prgname = argv[0];
1226
1227         parse_opts(argc, argv);
1228
1229         ret = check_config();
1230         if (ret != 0)
1231                 rte_exit(-ret, "Bad configuration\n");
1232
1233         af = ((config.flags & IPV6_FLAG) == 0) ? AF_INET : AF_INET6;
1234         depth_lim = (af == AF_INET) ? 32 : 128;
1235         rt_ent_sz = (af == AF_INET) ? sizeof(struct rt_rule_4) :
1236                 sizeof(struct rt_rule_6);
1237         lookup_ent_sz = (af == AF_INET) ? 4 : 16;
1238
1239         /* Count number of rules in file*/
1240         if (config.routes_file != NULL) {
1241                 fr = fopen(config.routes_file, "r");
1242                 if (fr == NULL)
1243                         rte_exit(-errno, "Can not open file with routes %s\n",
1244                                 config.routes_file);
1245
1246                 config.nb_routes = 0;
1247                 while (fgets(line, sizeof(line), fr) != NULL)
1248                         config.nb_routes++;
1249
1250                 if (config.nb_routes < config.print_fract)
1251                         config.print_fract = config.nb_routes;
1252
1253                 rewind(fr);
1254         }
1255
1256         /* Count number of ip's in file*/
1257         if (config.lookup_ips_file != NULL) {
1258                 fl = fopen(config.lookup_ips_file, "r");
1259                 if (fl == NULL)
1260                         rte_exit(-errno, "Can not open file with ip's %s\n",
1261                                 config.lookup_ips_file);
1262
1263                 config.nb_lookup_ips = 0;
1264                 while (fgets(line, sizeof(line), fl) != NULL)
1265                         config.nb_lookup_ips++;
1266                 rewind(fl);
1267         }
1268
1269         /* Alloc routes table*/
1270         config.rt  = rte_malloc(NULL, rt_ent_sz * config.nb_routes, 0);
1271         if (config.rt == NULL)
1272                 rte_exit(-ENOMEM, "Can not alloc rt\n");
1273
1274         /* Alloc table with ip's for lookup*/
1275         config.lookup_tbl  = rte_malloc(NULL, lookup_ent_sz *
1276                 config.nb_lookup_ips, 0);
1277         if (config.lookup_tbl == NULL)
1278                 rte_exit(-ENOMEM, "Can not alloc lookup table\n");
1279
1280         /* Fill routes table */
1281         if (fr == NULL) {
1282                 if (distrib_string != NULL)
1283                         ret = parse_distrib(depth_lim, config.nb_routes);
1284                 else {
1285                         uint8_t rpd[129] = {0};
1286                         uint32_t nrpd[129] = {0};
1287                         ret = complete_distrib(depth_lim, config.nb_routes,
1288                                 rpd, nrpd);
1289                 }
1290                 if (ret != 0)
1291                         rte_exit(-ret,
1292                                 "Bad routes distribution configuration\n");
1293                 if (af == AF_INET) {
1294                         gen_random_rt_4(config.rt,
1295                                 __builtin_ctz(config.ent_sz));
1296                         if (config.flags & SHUFFLE_FLAG)
1297                                 shuffle_rt_4(config.rt, config.nb_routes);
1298                 } else {
1299                         gen_random_rt_6(config.rt,
1300                                 __builtin_ctz(config.ent_sz));
1301                         if (config.flags & SHUFFLE_FLAG)
1302                                 shuffle_rt_6(config.rt, config.nb_routes);
1303                 }
1304         } else {
1305                 if (af == AF_INET)
1306                         ret = parse_rt_4(fr);
1307                 else
1308                         ret = parse_rt_6(fr);
1309
1310                 if (ret != 0) {
1311                         rte_exit(-ret, "failed to parse routes file %s\n",
1312                                 config.routes_file);
1313                 }
1314         }
1315
1316         /* Fill lookup table with ip's*/
1317         if (fl == NULL)
1318                 gen_rnd_lookup_tbl(af);
1319         else {
1320                 ret = parse_lookup(fl, af);
1321                 if (ret != 0)
1322                         rte_exit(-ret, "failed to parse lookup file\n");
1323         }
1324
1325         print_config();
1326
1327         if (af == AF_INET)
1328                 ret = run_v4();
1329         else
1330                 ret = run_v6();
1331
1332         return ret;
1333 }