bpf: allow self-xor operation
[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         if (conf.type == RTE_FIB_DIR24_8) {
861                 conf.dir24_8.nh_sz = __builtin_ctz(config.ent_sz);
862                 conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
863                         get_max_nh(conf.dir24_8.nh_sz));
864         }
865
866         fib = rte_fib_create("test", -1, &conf);
867         if (fib == NULL) {
868                 printf("Can not alloc FIB, err %d\n", rte_errno);
869                 return -rte_errno;
870         }
871
872         if (config.lookup_fn != 0) {
873                 if (config.lookup_fn == 1)
874                         ret = rte_fib_select_lookup(fib,
875                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO);
876                 else if (config.lookup_fn == 2)
877                         ret = rte_fib_select_lookup(fib,
878                                 RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512);
879                 else if (config.lookup_fn == 3)
880                         ret = rte_fib_select_lookup(fib,
881                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE);
882                 else if (config.lookup_fn == 4)
883                         ret = rte_fib_select_lookup(fib,
884                                 RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI);
885                 else
886                         ret = -EINVAL;
887                 if (ret != 0) {
888                         printf("Can not init lookup function\n");
889                         return ret;
890                 }
891         }
892
893         for (k = config.print_fract, i = 0; k > 0; k--) {
894                 start = rte_rdtsc_precise();
895                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
896                         ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
897                                 rt[i + j].nh);
898                         if (unlikely(ret != 0)) {
899                                 printf("Can not add a route to FIB, err %d\n",
900                                         ret);
901                                 return -ret;
902                         }
903                 }
904                 printf("AVG FIB add %"PRIu64"\n",
905                         (rte_rdtsc_precise() - start) / j);
906                 i += j;
907         }
908
909         if (config.flags & CMP_FLAG) {
910                 lpm_conf.max_rules = config.nb_routes * 2;
911                 lpm_conf.number_tbl8s = RTE_MAX(conf.dir24_8.num_tbl8,
912                         config.tbl8);
913
914                 lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
915                 if (lpm == NULL) {
916                         printf("Can not alloc LPM, err %d\n", rte_errno);
917                         return -rte_errno;
918                 }
919                 for (k = config.print_fract, i = 0; k > 0; k--) {
920                         start = rte_rdtsc_precise();
921                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
922                                 ret = rte_lpm_add(lpm, rt[i + j].addr,
923                                         rt[i + j].depth, rt[i + j].nh);
924                                 if (ret != 0) {
925                                         if (rt[i + j].depth == 0)
926                                                 print_depth_err();
927                                         printf("Can not add a route to LPM, "
928                                                 "err %d\n", ret);
929                                         return -ret;
930                                 }
931                         }
932                         printf("AVG LPM add %"PRIu64"\n",
933                                 (rte_rdtsc_precise() - start) / j);
934                         i += j;
935                 }
936         }
937
938         acc = 0;
939         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
940                 start = rte_rdtsc_precise();
941                 ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
942                 acc += rte_rdtsc_precise() - start;
943                 if (ret != 0) {
944                         printf("FIB lookup fails, err %d\n", ret);
945                         return -ret;
946                 }
947         }
948         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
949
950         if (config.flags & CMP_FLAG) {
951                 acc = 0;
952                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
953                         start = rte_rdtsc_precise();
954                         ret = rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh,
955                                 BURST_SZ);
956                         acc += rte_rdtsc_precise() - start;
957                         if (ret != 0) {
958                                 printf("LPM lookup fails, err %d\n", ret);
959                                 return -ret;
960                         }
961                 }
962                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
963
964                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
965                         rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
966                         rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh, BURST_SZ);
967                         for (j = 0; j < BURST_SZ; j++) {
968                                 struct rte_lpm_tbl_entry *tbl;
969                                 tbl = (struct rte_lpm_tbl_entry *)&lpm_nh[j];
970                                 if ((fib_nh[j] != tbl->next_hop) &&
971                                                 !((tbl->valid == 0) &&
972                                                 (fib_nh[j] == def_nh))) {
973                                         printf("FAIL\n");
974                                         return -1;
975                                 }
976                         }
977                 }
978                 printf("FIB and LPM lookup returns same values\n");
979         }
980
981         for (k = config.print_fract, i = 0; k > 0; k--) {
982                 start = rte_rdtsc_precise();
983                 for (j = 0; j < (config.nb_routes - i) / k; j++)
984                         rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
985
986                 printf("AVG FIB delete %"PRIu64"\n",
987                         (rte_rdtsc_precise() - start) / j);
988                 i += j;
989         }
990
991         if (config.flags & CMP_FLAG) {
992                 for (k = config.print_fract, i = 0; k > 0; k--) {
993                         start = rte_rdtsc_precise();
994                         for (j = 0; j < (config.nb_routes - i) / k; j++)
995                                 rte_lpm_delete(lpm, rt[i + j].addr,
996                                         rt[i + j].depth);
997
998                         printf("AVG LPM delete %"PRIu64"\n",
999                                 (rte_rdtsc_precise() - start) / j);
1000                         i += j;
1001                 }
1002         }
1003
1004         return 0;
1005 }
1006
1007 static int
1008 dump_rt_6(struct rt_rule_6 *rt)
1009 {
1010         FILE *f;
1011         uint32_t i;
1012
1013         f = fopen(config.routes_file_s, "w");
1014         if (f == NULL) {
1015                 printf("Can not open file %s\n", config.routes_file_s);
1016                 return -1;
1017         }
1018
1019         for (i = 0; i < config.nb_routes; i++) {
1020                 fprintf(f, NIPQUAD6_FMT"/%d %"PRIu64"\n", NIPQUAD6(rt[i].addr),
1021                         rt[i].depth, rt[i].nh);
1022
1023         }
1024         fclose(f);
1025         return 0;
1026 }
1027
1028 static int
1029 run_v6(void)
1030 {
1031         uint64_t start, acc;
1032         uint64_t def_nh = 0;
1033         struct rte_fib6 *fib;
1034         struct rte_fib6_conf conf = {0};
1035         struct rt_rule_6 *rt;
1036         uint32_t i, j, k;
1037         int ret = 0;
1038         struct rte_lpm6 *lpm = NULL;
1039         struct rte_lpm6_config lpm_conf;
1040         uint8_t *tbl6;
1041         uint64_t fib_nh[BURST_SZ];
1042         int32_t lpm_nh[BURST_SZ];
1043
1044         rt = (struct rt_rule_6 *)config.rt;
1045         tbl6 = config.lookup_tbl;
1046
1047         if (config.flags & DRY_RUN_FLAG) {
1048                 if (config.routes_file_s != NULL)
1049                         ret =  dump_rt_6(rt);
1050                 if (ret != 0)
1051                         return ret;
1052                 if (config.lookup_ips_file_s != NULL)
1053                         ret = dump_lookup(AF_INET6);
1054                 return ret;
1055         }
1056
1057         conf.type = get_fib_type();
1058         conf.default_nh = def_nh;
1059         conf.max_routes = config.nb_routes * 2;
1060         if (conf.type == RTE_FIB6_TRIE) {
1061                 conf.trie.nh_sz = __builtin_ctz(config.ent_sz);
1062                 conf.trie.num_tbl8 = RTE_MIN(config.tbl8,
1063                         get_max_nh(conf.trie.nh_sz));
1064         }
1065
1066         fib = rte_fib6_create("test", -1, &conf);
1067         if (fib == NULL) {
1068                 printf("Can not alloc FIB, err %d\n", rte_errno);
1069                 return -rte_errno;
1070         }
1071
1072         if (config.lookup_fn != 0) {
1073                 if (config.lookup_fn == 1)
1074                         ret = rte_fib6_select_lookup(fib,
1075                                 RTE_FIB6_LOOKUP_TRIE_SCALAR);
1076                 else if (config.lookup_fn == 2)
1077                         ret = rte_fib6_select_lookup(fib,
1078                                 RTE_FIB6_LOOKUP_TRIE_VECTOR_AVX512);
1079                 else
1080                         ret = -EINVAL;
1081                 if (ret != 0) {
1082                         printf("Can not init lookup function\n");
1083                         return ret;
1084                 }
1085         }
1086
1087         for (k = config.print_fract, i = 0; k > 0; k--) {
1088                 start = rte_rdtsc_precise();
1089                 for (j = 0; j < (config.nb_routes - i) / k; j++) {
1090                         ret = rte_fib6_add(fib, rt[i + j].addr,
1091                                 rt[i + j].depth, rt[i + j].nh);
1092                         if (unlikely(ret != 0)) {
1093                                 printf("Can not add a route to FIB, err %d\n",
1094                                         ret);
1095                                 return -ret;
1096                         }
1097                 }
1098                 printf("AVG FIB add %"PRIu64"\n",
1099                         (rte_rdtsc_precise() - start) / j);
1100                 i += j;
1101         }
1102
1103         if (config.flags & CMP_FLAG) {
1104                 lpm_conf.max_rules = config.nb_routes * 2;
1105                 lpm_conf.number_tbl8s = RTE_MAX(conf.trie.num_tbl8,
1106                         config.tbl8);
1107
1108                 lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1109                 if (lpm == NULL) {
1110                         printf("Can not alloc LPM, err %d\n", rte_errno);
1111                         return -rte_errno;
1112                 }
1113                 for (k = config.print_fract, i = 0; k > 0; k--) {
1114                         start = rte_rdtsc_precise();
1115                         for (j = 0; j < (config.nb_routes - i) / k; j++) {
1116                                 ret = rte_lpm6_add(lpm, rt[i + j].addr,
1117                                         rt[i + j].depth, rt[i + j].nh);
1118                                 if (ret != 0) {
1119                                         if (rt[i + j].depth == 0)
1120                                                 print_depth_err();
1121                                         printf("Can not add a route to LPM, "
1122                                                 "err %d\n", ret);
1123                                         return -ret;
1124                                 }
1125                         }
1126                         printf("AVG LPM add %"PRIu64"\n",
1127                                 (rte_rdtsc_precise() - start) / j);
1128                         i += j;
1129                 }
1130         }
1131
1132         acc = 0;
1133         for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1134                 start = rte_rdtsc_precise();
1135                 ret = rte_fib6_lookup_bulk(fib, (uint8_t (*)[16])(tbl6 + i*16),
1136                         fib_nh, BURST_SZ);
1137                 acc += rte_rdtsc_precise() - start;
1138                 if (ret != 0) {
1139                         printf("FIB lookup fails, err %d\n", ret);
1140                         return -ret;
1141                 }
1142         }
1143         printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1144
1145         if (config.flags & CMP_FLAG) {
1146                 acc = 0;
1147                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1148                         start = rte_rdtsc_precise();
1149                         ret = rte_lpm6_lookup_bulk_func(lpm,
1150                                 (uint8_t (*)[16])(tbl6 + i*16),
1151                                 lpm_nh, BURST_SZ);
1152                         acc += rte_rdtsc_precise() - start;
1153                         if (ret != 0) {
1154                                 printf("LPM lookup fails, err %d\n", ret);
1155                                 return -ret;
1156                         }
1157                 }
1158                 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
1159
1160                 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1161                         rte_fib6_lookup_bulk(fib,
1162                                 (uint8_t (*)[16])(tbl6 + i*16),
1163                                 fib_nh, BURST_SZ);
1164                         rte_lpm6_lookup_bulk_func(lpm,
1165                                 (uint8_t (*)[16])(tbl6 + i*16),
1166                                 lpm_nh, BURST_SZ);
1167                         for (j = 0; j < BURST_SZ; j++) {
1168                                 if ((fib_nh[j] != (uint32_t)lpm_nh[j]) &&
1169                                                 !((lpm_nh[j] == -1) &&
1170                                                 (fib_nh[j] == def_nh))) {
1171                                         printf("FAIL\n");
1172                                         return -1;
1173                                 }
1174                         }
1175                 }
1176                 printf("FIB and LPM lookup returns same values\n");
1177         }
1178
1179         for (k = config.print_fract, i = 0; k > 0; k--) {
1180                 start = rte_rdtsc_precise();
1181                 for (j = 0; j < (config.nb_routes - i) / k; j++)
1182                         rte_fib6_delete(fib, rt[i + j].addr, rt[i + j].depth);
1183
1184                 printf("AVG FIB delete %"PRIu64"\n",
1185                         (rte_rdtsc_precise() - start) / j);
1186                 i += j;
1187         }
1188
1189         if (config.flags & CMP_FLAG) {
1190                 for (k = config.print_fract, i = 0; k > 0; k--) {
1191                         start = rte_rdtsc_precise();
1192                         for (j = 0; j < (config.nb_routes - i) / k; j++)
1193                                 rte_lpm6_delete(lpm, rt[i + j].addr,
1194                                         rt[i + j].depth);
1195
1196                         printf("AVG LPM delete %"PRIu64"\n",
1197                                 (rte_rdtsc_precise() - start) / j);
1198                         i += j;
1199                 }
1200         }
1201         return 0;
1202 }
1203
1204 int
1205 main(int argc, char **argv)
1206 {
1207         int ret, af, rt_ent_sz, lookup_ent_sz;
1208         FILE *fr = NULL;
1209         FILE *fl = NULL;
1210         uint8_t depth_lim;
1211
1212         ret = rte_eal_init(argc, argv);
1213         if (ret < 0)
1214                 rte_panic("Cannot init EAL\n");
1215
1216         argc -= ret;
1217         argv += ret;
1218
1219         config.prgname = argv[0];
1220
1221         parse_opts(argc, argv);
1222
1223         ret = check_config();
1224         if (ret != 0)
1225                 rte_exit(-ret, "Bad configuration\n");
1226
1227         af = ((config.flags & IPV6_FLAG) == 0) ? AF_INET : AF_INET6;
1228         depth_lim = (af == AF_INET) ? 32 : 128;
1229         rt_ent_sz = (af == AF_INET) ? sizeof(struct rt_rule_4) :
1230                 sizeof(struct rt_rule_6);
1231         lookup_ent_sz = (af == AF_INET) ? 4 : 16;
1232
1233         /* Count number of rules in file*/
1234         if (config.routes_file != NULL) {
1235                 fr = fopen(config.routes_file, "r");
1236                 if (fr == NULL)
1237                         rte_exit(-errno, "Can not open file with routes %s\n",
1238                                 config.routes_file);
1239
1240                 config.nb_routes = 0;
1241                 while (fgets(line, sizeof(line), fr) != NULL)
1242                         config.nb_routes++;
1243                 rewind(fr);
1244         }
1245
1246         /* Count number of ip's in file*/
1247         if (config.lookup_ips_file != NULL) {
1248                 fl = fopen(config.lookup_ips_file, "r");
1249                 if (fl == NULL)
1250                         rte_exit(-errno, "Can not open file with ip's %s\n",
1251                                 config.lookup_ips_file);
1252
1253                 config.nb_lookup_ips = 0;
1254                 while (fgets(line, sizeof(line), fl) != NULL)
1255                         config.nb_lookup_ips++;
1256                 rewind(fl);
1257         }
1258
1259         /* Alloc routes table*/
1260         config.rt  = rte_malloc(NULL, rt_ent_sz * config.nb_routes, 0);
1261         if (config.rt == NULL)
1262                 rte_exit(-ENOMEM, "Can not alloc rt\n");
1263
1264         /* Alloc table with ip's for lookup*/
1265         config.lookup_tbl  = rte_malloc(NULL, lookup_ent_sz *
1266                 config.nb_lookup_ips, 0);
1267         if (config.lookup_tbl == NULL)
1268                 rte_exit(-ENOMEM, "Can not alloc lookup table\n");
1269
1270         /* Fill routes table */
1271         if (fr == NULL) {
1272                 if (distrib_string != NULL)
1273                         ret = parse_distrib(depth_lim, config.nb_routes);
1274                 else {
1275                         uint8_t rpd[129] = {0};
1276                         uint32_t nrpd[129] = {0};
1277                         ret = complete_distrib(depth_lim, config.nb_routes,
1278                                 rpd, nrpd);
1279                 }
1280                 if (ret != 0)
1281                         rte_exit(-ret,
1282                                 "Bad routes distribution configuration\n");
1283                 if (af == AF_INET) {
1284                         gen_random_rt_4(config.rt,
1285                                 __builtin_ctz(config.ent_sz));
1286                         if (config.flags & SHUFFLE_FLAG)
1287                                 shuffle_rt_4(config.rt, config.nb_routes);
1288                 } else {
1289                         gen_random_rt_6(config.rt,
1290                                 __builtin_ctz(config.ent_sz));
1291                         if (config.flags & SHUFFLE_FLAG)
1292                                 shuffle_rt_6(config.rt, config.nb_routes);
1293                 }
1294         } else {
1295                 if (af == AF_INET)
1296                         ret = parse_rt_4(fr);
1297                 else
1298                         ret = parse_rt_6(fr);
1299
1300                 if (ret != 0) {
1301                         rte_exit(-ret, "failed to parse routes file %s\n",
1302                                 config.routes_file);
1303                 }
1304         }
1305
1306         /* Fill lookup table with ip's*/
1307         if (fl == NULL)
1308                 gen_rnd_lookup_tbl(af);
1309         else {
1310                 ret = parse_lookup(fl, af);
1311                 if (ret != 0)
1312                         rte_exit(-ret, "failed to parse lookup file\n");
1313         }
1314
1315         print_config();
1316
1317         if (af == AF_INET)
1318                 ret = run_v4();
1319         else
1320                 ret = run_v6();
1321
1322         return ret;
1323 }