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