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