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