ecd420116a0bcfdfbbee995c8e055f868fb1cb31
[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 comarison 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 loookup 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                         break;
715                 case 'd':
716                         distrib_string = optarg;
717                         break;
718                 case 'l':
719                         errno = 0;
720                         config.nb_lookup_ips = strtoul(optarg, &endptr, 10);
721                         if ((errno != 0) || (config.nb_lookup_ips == 0)) {
722                                 print_usage();
723                                 rte_exit(-EINVAL, "Invalid option -l\n");
724                         }
725                         break;
726                 case 'r':
727                         errno = 0;
728                         config.rnd_lookup_ips_ratio =
729                                 strtoul(optarg, &endptr, 10);
730                         if ((errno != 0) ||
731                                         (config.rnd_lookup_ips_ratio == 0) ||
732                                         (config.rnd_lookup_ips_ratio >= 100)) {
733                                 print_usage();
734                                 rte_exit(-EINVAL, "Invalid option -r\n");
735                         }
736                         break;
737                 case 's':
738                         config.flags |= SHUFFLE_FLAG;
739                         break;
740                 case 'c':
741                         config.flags |= CMP_FLAG;
742                         break;
743                 case '6':
744                         config.flags |= IPV6_FLAG;
745                         break;
746                 case 'a':
747                         config.flags |= CMP_ALL_FLAG;
748                         break;
749                 case 'b':
750                         if (strcmp(optarg, "rib") == 0) {
751                                 config.flags &= ~FIB_TYPE_MASK;
752                                 config.flags |= FIB_RIB_TYPE;
753                         } else if (strcmp(optarg, "dir") == 0) {
754                                 config.flags &= ~FIB_TYPE_MASK;
755                                 config.flags |= FIB_V4_DIR_TYPE;
756                         } else if (strcmp(optarg, "trie") == 0) {
757                                 config.flags &= ~FIB_TYPE_MASK;
758                                 config.flags |= FIB_V6_TRIE_TYPE;
759                         } else
760                                 rte_exit(-EINVAL, "Invalid option -b\n");
761                         break;
762                 case 'e':
763                         errno = 0;
764                         config.ent_sz = strtoul(optarg, &endptr, 10);
765                         if (errno != 0) {
766                                 print_usage();
767                                 rte_exit(-EINVAL, "Invalid option -e\n");
768                         }
769                         break;
770                 case 'g':
771                         errno = 0;
772                         config.tbl8 = strtoul(optarg, &endptr, 10);
773                         if ((errno != 0) || (config.tbl8 == 0)) {
774                                 print_usage();
775                                 rte_exit(-EINVAL, "Invalid option -g\n");
776                         }
777                         break;
778                 case 'v':
779                         if ((strcmp(optarg, "s1") == 0) ||
780                                         (strcmp(optarg, "s") == 0)) {
781                                 config.lookup_fn = 1;
782                                 break;
783                         } else if (strcmp(optarg, "v") == 0) {
784                                 config.lookup_fn = 2;
785                                 break;
786                         } else if (strcmp(optarg, "s2") == 0) {
787                                 config.lookup_fn = 3;
788                                 break;
789                         } else if (strcmp(optarg, "s3") == 0) {
790                                 config.lookup_fn = 4;
791                                 break;
792                         }
793                         print_usage();
794                         rte_exit(-EINVAL, "Invalid option -v %s\n", optarg);
795                 default:
796                         print_usage();
797                         rte_exit(-EINVAL, "Invalid options\n");
798                 }
799         }
800 }
801
802 static int
803 dump_rt_4(struct rt_rule_4 *rt)
804 {
805         FILE *f;
806         uint32_t i;
807
808         f = fopen(config.routes_file_s, "w");
809         if (f == NULL) {
810                 printf("Can not open file %s\n", config.routes_file_s);
811                 return -1;
812         }
813
814         for (i = 0; i < config.nb_routes; i++)
815                 fprintf(f, NIPQUAD_FMT"/%d %"PRIu64"\n", NIPQUAD(rt[i].addr),
816                         rt[i].depth, rt[i].nh);
817
818         fclose(f);
819         return 0;
820 }
821
822 static inline void
823 print_depth_err(void)
824 {
825         printf("LPM does not support /0 prefix length (default route), use "
826                 "-d 0:0 option or remove /0 prefix from routes file\n");
827 }
828
829 static int
830 run_v4(void)
831 {
832         uint64_t start, acc;
833         uint64_t def_nh = 0;
834         struct rte_fib *fib;
835         struct rte_fib_conf conf = {0};
836         struct rt_rule_4 *rt;
837         uint32_t i, j, k;
838         int ret = 0;
839         struct rte_lpm  *lpm = NULL;
840         struct rte_lpm_config lpm_conf;
841         uint32_t *tbl4 = config.lookup_tbl;
842         uint64_t fib_nh[BURST_SZ];
843         uint32_t lpm_nh[BURST_SZ];
844
845         rt = (struct rt_rule_4 *)config.rt;
846
847         if (config.flags & DRY_RUN_FLAG) {
848                 if (config.routes_file_s != NULL)
849                         ret = dump_rt_4(rt);
850                 if (ret != 0)
851                         return ret;
852                 if (config.lookup_ips_file_s != NULL)
853                         ret = dump_lookup(AF_INET);
854                 return ret;
855         }
856
857         conf.type = get_fib_type();
858         conf.default_nh = def_nh;
859         conf.max_routes = config.nb_routes * 2;
860         conf.rib_ext_sz = 0;
861         if (conf.type == RTE_FIB_DIR24_8) {
862                 conf.dir24_8.nh_sz = __builtin_ctz(config.ent_sz);
863                 conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
864                         get_max_nh(conf.dir24_8.nh_sz));
865         }
866
867         fib = rte_fib_create("test", -1, &conf);
868         if (fib == NULL) {
869                 printf("Can not alloc FIB, err %d\n", rte_errno);
870                 return -rte_errno;
871         }
872
873         if (config.lookup_fn != 0) {
874                 if (config.lookup_fn == 1)
875                         ret = rte_fib_select_lookup(fib,
876                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO);
877                 else if (config.lookup_fn == 2)
878                         ret = rte_fib_select_lookup(fib,
879                                 RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512);
880                 else if (config.lookup_fn == 3)
881                         ret = rte_fib_select_lookup(fib,
882                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE);
883                 else if (config.lookup_fn == 4)
884                         ret = rte_fib_select_lookup(fib,
885                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI);
886                 else
887                         ret = -EINVAL;
888                 if (ret != 0) {
889                         printf("Can not init lookup function\n");
890                         return ret;
891                 }
892         }
893
894         for (k = config.print_fract, i = 0; k > 0; k--) {
895                 start = rte_rdtsc_precise();
896                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
897                         ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
898                                 rt[i + j].nh);
899                         if (unlikely(ret != 0)) {
900                                 printf("Can not add a route to FIB, err %d\n",
901                                         ret);
902                                 return -ret;
903                         }
904                 }
905                 printf("AVG FIB add %"PRIu64"\n",
906                         (rte_rdtsc_precise() - start) / j);
907                 i += j;
908         }
909
910         if (config.flags & CMP_FLAG) {
911                 lpm_conf.max_rules = config.nb_routes * 2;
912                 lpm_conf.number_tbl8s = RTE_MAX(conf.dir24_8.num_tbl8,
913                         config.tbl8);
914
915                 lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
916                 if (lpm == NULL) {
917                         printf("Can not alloc LPM, err %d\n", rte_errno);
918                         return -rte_errno;
919                 }
920                 for (k = config.print_fract, i = 0; k > 0; k--) {
921                         start = rte_rdtsc_precise();
922                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
923                                 ret = rte_lpm_add(lpm, rt[i + j].addr,
924                                         rt[i + j].depth, rt[i + j].nh);
925                                 if (ret != 0) {
926                                         if (rt[i + j].depth == 0)
927                                                 print_depth_err();
928                                         printf("Can not add a route to LPM, "
929                                                 "err %d\n", ret);
930                                         return -ret;
931                                 }
932                         }
933                         printf("AVG LPM add %"PRIu64"\n",
934                                 (rte_rdtsc_precise() - start) / j);
935                         i += j;
936                 }
937         }
938
939         acc = 0;
940         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
941                 start = rte_rdtsc_precise();
942                 ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
943                 acc += rte_rdtsc_precise() - start;
944                 if (ret != 0) {
945                         printf("FIB lookup fails, err %d\n", ret);
946                         return -ret;
947                 }
948         }
949         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
950
951         if (config.flags & CMP_FLAG) {
952                 acc = 0;
953                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
954                         start = rte_rdtsc_precise();
955                         ret = rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh,
956                                 BURST_SZ);
957                         acc += rte_rdtsc_precise() - start;
958                         if (ret != 0) {
959                                 printf("LPM lookup fails, err %d\n", ret);
960                                 return -ret;
961                         }
962                 }
963                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
964
965                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
966                         rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
967                         rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh, BURST_SZ);
968                         for (j = 0; j < BURST_SZ; j++) {
969                                 struct rte_lpm_tbl_entry *tbl;
970                                 tbl = (struct rte_lpm_tbl_entry *)&lpm_nh[j];
971                                 if ((fib_nh[j] != tbl->next_hop) &&
972                                                 !((tbl->valid == 0) &&
973                                                 (fib_nh[j] == def_nh))) {
974                                         printf("FAIL\n");
975                                         return -1;
976                                 }
977                         }
978                 }
979                 printf("FIB and LPM lookup returns same values\n");
980         }
981
982         for (k = config.print_fract, i = 0; k > 0; k--) {
983                 start = rte_rdtsc_precise();
984                 for (j = 0; j < (config.nb_routes - i) / k; j++)
985                         rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
986
987                 printf("AVG FIB delete %"PRIu64"\n",
988                         (rte_rdtsc_precise() - start) / j);
989                 i += j;
990         }
991
992         if (config.flags & CMP_FLAG) {
993                 for (k = config.print_fract, i = 0; k > 0; k--) {
994                         start = rte_rdtsc_precise();
995                         for (j = 0; j < (config.nb_routes - i) / k; j++)
996                                 rte_lpm_delete(lpm, rt[i + j].addr,
997                                         rt[i + j].depth);
998
999                         printf("AVG LPM delete %"PRIu64"\n",
1000                                 (rte_rdtsc_precise() - start) / j);
1001                         i += j;
1002                 }
1003         }
1004
1005         return 0;
1006 }
1007
1008 static int
1009 dump_rt_6(struct rt_rule_6 *rt)
1010 {
1011         FILE *f;
1012         uint32_t i;
1013
1014         f = fopen(config.routes_file_s, "w");
1015         if (f == NULL) {
1016                 printf("Can not open file %s\n", config.routes_file_s);
1017                 return -1;
1018         }
1019
1020         for (i = 0; i < config.nb_routes; i++) {
1021                 fprintf(f, NIPQUAD6_FMT"/%d %"PRIu64"\n", NIPQUAD6(rt[i].addr),
1022                         rt[i].depth, rt[i].nh);
1023
1024         }
1025         fclose(f);
1026         return 0;
1027 }
1028
1029 static int
1030 run_v6(void)
1031 {
1032         uint64_t start, acc;
1033         uint64_t def_nh = 0;
1034         struct rte_fib6 *fib;
1035         struct rte_fib6_conf conf = {0};
1036         struct rt_rule_6 *rt;
1037         uint32_t i, j, k;
1038         int ret = 0;
1039         struct rte_lpm6 *lpm = NULL;
1040         struct rte_lpm6_config lpm_conf;
1041         uint8_t *tbl6;
1042         uint64_t fib_nh[BURST_SZ];
1043         int32_t lpm_nh[BURST_SZ];
1044
1045         rt = (struct rt_rule_6 *)config.rt;
1046         tbl6 = config.lookup_tbl;
1047
1048         if (config.flags & DRY_RUN_FLAG) {
1049                 if (config.routes_file_s != NULL)
1050                         ret =  dump_rt_6(rt);
1051                 if (ret != 0)
1052                         return ret;
1053                 if (config.lookup_ips_file_s != NULL)
1054                         ret = dump_lookup(AF_INET6);
1055                 return ret;
1056         }
1057
1058         conf.type = get_fib_type();
1059         conf.default_nh = def_nh;
1060         conf.max_routes = config.nb_routes * 2;
1061         conf.rib_ext_sz = 0;
1062         if (conf.type == RTE_FIB6_TRIE) {
1063                 conf.trie.nh_sz = __builtin_ctz(config.ent_sz);
1064                 conf.trie.num_tbl8 = RTE_MIN(config.tbl8,
1065                         get_max_nh(conf.trie.nh_sz));
1066         }
1067
1068         fib = rte_fib6_create("test", -1, &conf);
1069         if (fib == NULL) {
1070                 printf("Can not alloc FIB, err %d\n", rte_errno);
1071                 return -rte_errno;
1072         }
1073
1074         if (config.lookup_fn != 0) {
1075                 if (config.lookup_fn == 1)
1076                         ret = rte_fib6_select_lookup(fib,
1077                                 RTE_FIB6_LOOKUP_TRIE_SCALAR);
1078                 else if (config.lookup_fn == 2)
1079                         ret = rte_fib6_select_lookup(fib,
1080                                 RTE_FIB6_LOOKUP_TRIE_VECTOR_AVX512);
1081                 else
1082                         ret = -EINVAL;
1083                 if (ret != 0) {
1084                         printf("Can not init lookup function\n");
1085                         return ret;
1086                 }
1087         }
1088
1089         for (k = config.print_fract, i = 0; k > 0; k--) {
1090                 start = rte_rdtsc_precise();
1091                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
1092                         ret = rte_fib6_add(fib, rt[i + j].addr,
1093                                 rt[i + j].depth, rt[i + j].nh);
1094                         if (unlikely(ret != 0)) {
1095                                 printf("Can not add a route to FIB, err %d\n",
1096                                         ret);
1097                                 return -ret;
1098                         }
1099                 }
1100                 printf("AVG FIB add %"PRIu64"\n",
1101                         (rte_rdtsc_precise() - start) / j);
1102                 i += j;
1103         }
1104
1105         if (config.flags & CMP_FLAG) {
1106                 lpm_conf.max_rules = config.nb_routes * 2;
1107                 lpm_conf.number_tbl8s = RTE_MAX(conf.trie.num_tbl8,
1108                         config.tbl8);
1109
1110                 lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1111                 if (lpm == NULL) {
1112                         printf("Can not alloc LPM, err %d\n", rte_errno);
1113                         return -rte_errno;
1114                 }
1115                 for (k = config.print_fract, i = 0; k > 0; k--) {
1116                         start = rte_rdtsc_precise();
1117                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
1118                                 ret = rte_lpm6_add(lpm, rt[i + j].addr,
1119                                         rt[i + j].depth, rt[i + j].nh);
1120                                 if (ret != 0) {
1121                                         if (rt[i + j].depth == 0)
1122                                                 print_depth_err();
1123                                         printf("Can not add a route to LPM, "
1124                                                 "err %d\n", ret);
1125                                         return -ret;
1126                                 }
1127                         }
1128                         printf("AVG LPM add %"PRIu64"\n",
1129                                 (rte_rdtsc_precise() - start) / j);
1130                         i += j;
1131                 }
1132         }
1133
1134         acc = 0;
1135         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1136                 start = rte_rdtsc_precise();
1137                 ret = rte_fib6_lookup_bulk(fib, (uint8_t (*)[16])(tbl6 + i*16),
1138                         fib_nh, BURST_SZ);
1139                 acc += rte_rdtsc_precise() - start;
1140                 if (ret != 0) {
1141                         printf("FIB lookup fails, err %d\n", ret);
1142                         return -ret;
1143                 }
1144         }
1145         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1146
1147         if (config.flags & CMP_FLAG) {
1148                 acc = 0;
1149                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1150                         start = rte_rdtsc_precise();
1151                         ret = rte_lpm6_lookup_bulk_func(lpm,
1152                                 (uint8_t (*)[16])(tbl6 + i*16),
1153                                 lpm_nh, BURST_SZ);
1154                         acc += rte_rdtsc_precise() - start;
1155                         if (ret != 0) {
1156                                 printf("LPM lookup fails, err %d\n", ret);
1157                                 return -ret;
1158                         }
1159                 }
1160                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
1161
1162                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1163                         rte_fib6_lookup_bulk(fib,
1164                                 (uint8_t (*)[16])(tbl6 + i*16),
1165                                 fib_nh, BURST_SZ);
1166                         rte_lpm6_lookup_bulk_func(lpm,
1167                                 (uint8_t (*)[16])(tbl6 + i*16),
1168                                 lpm_nh, BURST_SZ);
1169                         for (j = 0; j < BURST_SZ; j++) {
1170                                 if ((fib_nh[j] != (uint32_t)lpm_nh[j]) &&
1171                                                 !((lpm_nh[j] == -1) &&
1172                                                 (fib_nh[j] == def_nh))) {
1173                                         printf("FAIL\n");
1174                                         return -1;
1175                                 }
1176                         }
1177                 }
1178                 printf("FIB and LPM lookup returns same values\n");
1179         }
1180
1181         for (k = config.print_fract, i = 0; k > 0; k--) {
1182                 start = rte_rdtsc_precise();
1183                 for (j = 0; j < (config.nb_routes - i) / k; j++)
1184                         rte_fib6_delete(fib, rt[i + j].addr, rt[i + j].depth);
1185
1186                 printf("AVG FIB delete %"PRIu64"\n",
1187                         (rte_rdtsc_precise() - start) / j);
1188                 i += j;
1189         }
1190
1191         if (config.flags & CMP_FLAG) {
1192                 for (k = config.print_fract, i = 0; k > 0; k--) {
1193                         start = rte_rdtsc_precise();
1194                         for (j = 0; j < (config.nb_routes - i) / k; j++)
1195                                 rte_lpm6_delete(lpm, rt[i + j].addr,
1196                                         rt[i + j].depth);
1197
1198                         printf("AVG LPM delete %"PRIu64"\n",
1199                                 (rte_rdtsc_precise() - start) / j);
1200                         i += j;
1201                 }
1202         }
1203         return 0;
1204 }
1205
1206 int
1207 main(int argc, char **argv)
1208 {
1209         int ret, af, rt_ent_sz, lookup_ent_sz;
1210         FILE *fr = NULL;
1211         FILE *fl = NULL;
1212         uint8_t depth_lim;
1213
1214         ret = rte_eal_init(argc, argv);
1215         if (ret < 0)
1216                 rte_panic("Cannot init EAL\n");
1217
1218         argc -= ret;
1219         argv += ret;
1220
1221         config.prgname = argv[0];
1222
1223         parse_opts(argc, argv);
1224
1225         ret = check_config();
1226         if (ret != 0)
1227                 rte_exit(-ret, "Bad configuration\n");
1228
1229         af = ((config.flags & IPV6_FLAG) == 0) ? AF_INET : AF_INET6;
1230         depth_lim = (af == AF_INET) ? 32 : 128;
1231         rt_ent_sz = (af == AF_INET) ? sizeof(struct rt_rule_4) :
1232                 sizeof(struct rt_rule_6);
1233         lookup_ent_sz = (af == AF_INET) ? 4 : 16;
1234
1235         /* Count number of rules in file*/
1236         if (config.routes_file != NULL) {
1237                 fr = fopen(config.routes_file, "r");
1238                 if (fr == NULL)
1239                         rte_exit(-errno, "Can not open file with routes %s\n",
1240                                 config.routes_file);
1241
1242                 config.nb_routes = 0;
1243                 while (fgets(line, sizeof(line), fr) != NULL)
1244                         config.nb_routes++;
1245                 rewind(fr);
1246         }
1247
1248         /* Count number of ip's in file*/
1249         if (config.lookup_ips_file != NULL) {
1250                 fl = fopen(config.lookup_ips_file, "r");
1251                 if (fl == NULL)
1252                         rte_exit(-errno, "Can not open file with ip's %s\n",
1253                                 config.lookup_ips_file);
1254
1255                 config.nb_lookup_ips = 0;
1256                 while (fgets(line, sizeof(line), fl) != NULL)
1257                         config.nb_lookup_ips++;
1258                 rewind(fl);
1259         }
1260
1261         /* Alloc routes table*/
1262         config.rt  = rte_malloc(NULL, rt_ent_sz * config.nb_routes, 0);
1263         if (config.rt == NULL)
1264                 rte_exit(-ENOMEM, "Can not alloc rt\n");
1265
1266         /* Alloc table with ip's for lookup*/
1267         config.lookup_tbl  = rte_malloc(NULL, lookup_ent_sz *
1268                 config.nb_lookup_ips, 0);
1269         if (config.lookup_tbl == NULL)
1270                 rte_exit(-ENOMEM, "Can not alloc lookup table\n");
1271
1272         /* Fill routes table */
1273         if (fr == NULL) {
1274                 if (distrib_string != NULL)
1275                         ret = parse_distrib(depth_lim, config.nb_routes);
1276                 else {
1277                         uint8_t rpd[129] = {0};
1278                         uint32_t nrpd[129] = {0};
1279                         ret = complete_distrib(depth_lim, config.nb_routes,
1280                                 rpd, nrpd);
1281                 }
1282                 if (ret != 0)
1283                         rte_exit(-ret,
1284                                 "Bad routes distribution configuration\n");
1285                 if (af == AF_INET) {
1286                         gen_random_rt_4(config.rt,
1287                                 __builtin_ctz(config.ent_sz));
1288                         if (config.flags & SHUFFLE_FLAG)
1289                                 shuffle_rt_4(config.rt, config.nb_routes);
1290                 } else {
1291                         gen_random_rt_6(config.rt,
1292                                 __builtin_ctz(config.ent_sz));
1293                         if (config.flags & SHUFFLE_FLAG)
1294                                 shuffle_rt_6(config.rt, config.nb_routes);
1295                 }
1296         } else {
1297                 if (af == AF_INET)
1298                         ret = parse_rt_4(fr);
1299                 else
1300                         ret = parse_rt_6(fr);
1301
1302                 if (ret != 0) {
1303                         rte_exit(-ret, "failed to parse routes file %s\n",
1304                                 config.routes_file);
1305                 }
1306         }
1307
1308         /* Fill lookup table with ip's*/
1309         if (fl == NULL)
1310                 gen_rnd_lookup_tbl(af);
1311         else {
1312                 ret = parse_lookup(fl, af);
1313                 if (ret != 0)
1314                         rte_exit(-ret, "failed to parse lookup file\n");
1315         }
1316
1317         print_config();
1318
1319         if (af == AF_INET)
1320                 ret = run_v4();
1321         else
1322                 ret = run_v6();
1323
1324         return ret;
1325 }