1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019 Intel Corporation
8 #include <sys/socket.h>
10 #include <rte_cycles.h>
11 #include <rte_errno.h>
13 #include <rte_random.h>
14 #include <rte_malloc.h>
20 #define PRINT_USAGE_START "%s [EAL options] --\n"
22 #define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
26 val = strtoul((in), &end_fld, (base)); \
27 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
29 (fd) = (typeof(fd))val; \
33 #define DEF_ROUTES_NUM 0x10000
34 #define DEF_LOOKUP_IPS_NUM 0x100000
36 #define DEFAULT_LPM_TBL8 100000U
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)
48 static char *distrib_string;
49 static char line[LINE_MAX];
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]
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 | \
87 const char *routes_file;
88 const char *lookup_ips_file;
89 const char *routes_file_s;
90 const char *lookup_ips_file_s;
94 uint32_t nb_lookup_ips;
95 uint32_t nb_lookup_ips_rnd;
96 uint32_t nb_routes_per_depth[128 + 1];
100 uint8_t rnd_lookup_ips_ratio;
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,
113 .rnd_lookup_ips_ratio = 0,
131 get_rnd_rng(uint64_t l, uint64_t u)
136 return (rte_rand() % (u - l) + l);
139 static __rte_always_inline __attribute__((pure)) uint8_t
140 bits_in_nh(uint8_t nh_sz)
142 return 8 * (1 << nh_sz);
145 static __rte_always_inline __attribute__((pure)) uint64_t
146 get_max_nh(uint8_t nh_sz)
148 /* min between fib and lpm6 which is 21 bits */
149 return RTE_MIN(((1ULL << (bits_in_nh(nh_sz) - 1)) - 1),
156 if (config.flags & IPV6_FLAG) {
157 if ((config.flags & FIB_TYPE_MASK) == FIB_V6_TRIE_TYPE)
158 return RTE_FIB6_TRIE;
160 return RTE_FIB6_DUMMY;
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;
171 complete_distrib(uint8_t depth_lim, const uint32_t n, uint8_t rpd[],
179 * complete number of routes for every depth
180 * that was configured with ratio
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] =
188 config.nb_routes_per_depth[depth] =
189 (n * rpd[depth]) / 100;
191 nr += config.nb_routes_per_depth[depth];
197 printf("Too much configured routes\n");
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];
219 parse_distrib(uint8_t depth_lim, const uint32_t n)
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 */
224 uint8_t depth, ratio, ratio_acc = 0;
227 in = strtok(distrib_string, ",");
229 /*parse configures routes percentage ratios*/
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",
242 printf("Ratio for depth /%d is bigger "
243 "than 100%%\n", depth);
246 if ((depth < 64) && ((n * ratio) / 100) >
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));
255 /*configured zero routes for a given depth*/
257 rpd[depth] = UINT8_MAX;
258 /*sum of all percentage ratios*/
261 GET_CB_FIELD(in, n_routes, 0, UINT32_MAX, '\0');
262 rpd[depth] = UINT8_MAX;
263 nrpd[depth] = n_routes;
266 /*number of configured depths in*/
267 in = strtok(NULL, ",");
270 if (ratio_acc > 100) {
271 printf("Total ratio's sum is bigger than 100%%\n");
275 return complete_distrib(depth_lim, n, rpd, nrpd);
279 shuffle_rt_4(struct rt_rule_4 *rt, int n)
281 struct rt_rule_4 tmp;
284 for (i = 0; i < n; i++) {
286 tmp.addr = rt[i].addr;
287 tmp.depth = rt[i].depth;
290 rt[i].addr = rt[j].addr;
291 rt[i].depth = rt[j].depth;
294 rt[j].addr = tmp.addr;
295 rt[j].depth = tmp.depth;
301 shuffle_rt_6(struct rt_rule_6 *rt, int n)
303 struct rt_rule_6 tmp;
306 for (i = 0; i < n; i++) {
308 memcpy(tmp.addr, rt[i].addr, 16);
309 tmp.depth = rt[i].depth;
312 memcpy(rt[i].addr, rt[j].addr, 16);
313 rt[i].depth = rt[j].depth;
316 memcpy(rt[j].addr, tmp.addr, 16);
317 rt[j].depth = tmp.depth;
323 gen_random_rt_4(struct rt_rule_4 *rt, int nh_sz)
325 uint32_t i, j, k = 0;
327 if (config.nb_routes_per_depth[0] != 0) {
330 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
333 for (i = 1; i <= 32; i++) {
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);
343 rt[k].nh = rte_rand() & get_max_nh(nh_sz);
349 complete_v6_addr(uint32_t *addr, uint32_t rnd, int n)
353 for (i = 0; i < n; i++)
354 addr[i] = rte_rand();
361 gen_random_rt_6(struct rt_rule_6 *rt, int nh_sz)
363 uint32_t a, i, j, k = 0;
365 if (config.nb_routes_per_depth[0] != 0) {
366 memset(rt[k].addr, 0, 16);
368 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
371 for (a = 0; a < 4; a++) {
372 for (i = 1; i <= 32; i++) {
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,
384 rt[k].depth = (a * 32) + i;
385 rt[k].nh = rte_rand() & get_max_nh(nh_sz);
392 set_rnd_ipv6(uint8_t *addr, uint8_t *route, int depth)
396 for (i = 0; i < 16; i++)
397 addr[i] = rte_rand();
399 for (i = 0; i < 16; i++) {
402 else if (depth > 0) {
403 addr[i] &= (uint16_t)UINT8_MAX >> depth;
404 addr[i] |= route[i] & UINT8_MAX << (8 - depth);
412 gen_rnd_lookup_tbl(int af)
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;
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++;
427 tbl4[i] = rt4[j].addr | (rte_rand() &
428 ((1ULL << (32 - rt4[j].depth)) - 1));
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++;
437 set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr,
445 _inet_net_pton(int af, char *prefix, void *addr)
447 const char *dlm = "/";
450 unsigned int max_depth;
452 if ((prefix == NULL) || (addr == NULL))
455 s = strtok_r(prefix, dlm, &sp);
459 ret = inet_pton(af, s, addr);
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);
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;
479 rt = (struct rt_rule_4 *)config.rt;
481 while (fgets(line, sizeof(line), f) != NULL) {
483 for (i = 0; i != string_tok_nb; i++) {
484 in[i] = strtok_r(s, dlm, &sp);
490 ret = _inet_net_pton(AF_INET, in[RT_PREFIX], &rt[j].addr);
494 rt[j].addr = rte_be_to_cpu_32(rt[j].addr);
496 config.nb_routes_per_depth[ret]++;
497 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 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;
513 rt = (struct rt_rule_6 *)config.rt;
515 while (fgets(line, sizeof(line), f) != NULL) {
517 for (i = 0; i != string_tok_nb; i++) {
518 in[i] = strtok_r(s, dlm, &sp);
524 ret = _inet_net_pton(AF_INET6, in[RT_PREFIX], rt[j].addr);
529 config.nb_routes_per_depth[ret]++;
530 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
539 parse_lookup(FILE *f, int af)
542 uint8_t *tbl = (uint8_t *)config.lookup_tbl;
543 int step = (af == AF_INET) ? 4 : 16;
546 while (fgets(line, sizeof(line), f) != NULL) {
547 s = strtok(line, " \t\n");
550 ret = inet_pton(af, s, &tbl[i]);
562 uint32_t *tbl4 = config.lookup_tbl;
563 uint8_t *tbl6 = config.lookup_tbl;
566 f = fopen(config.lookup_ips_file_s, "w");
568 printf("Can not open file %s\n", config.lookup_ips_file_s);
573 for (i = 0; i < config.nb_lookup_ips; i++)
574 fprintf(f, NIPQUAD_FMT"\n", NIPQUAD(tbl4[i]));
576 for (i = 0; i < config.nb_lookup_ips; i++)
577 fprintf(f, NIPQUAD6_FMT"\n", NIPQUAD6(&tbl6[i * 16]));
590 depth_lim = ((config.flags & IPV6_FLAG) == IPV6_FLAG) ? 128 : 32;
594 "Routes distribution:\n", config.nb_routes);
596 for (i = 1; i <= depth_lim; i++) {
598 "depth /%d:%u", i, config.nb_routes_per_depth[i]);
603 fprintf(stdout, "%c", dlm);
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);
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",
654 if ((config.routes_file == NULL) && (config.lookup_ips_file != NULL)) {
655 printf("-t option only valid with -f option\n");
659 if ((config.flags & CMP_ALL_FLAG) && (config.flags & IPV6_FLAG)) {
660 printf("-a flag is only valid for ipv4\n");
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");
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",
677 if ((config.ent_sz == 1) && (config.flags & IPV6_FLAG)) {
678 printf("-e 1 is valid only for ipv4\n");
685 parse_opts(int argc, char **argv)
690 while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:sv:")) !=
694 config.routes_file = optarg;
697 config.lookup_ips_file = optarg;
700 config.routes_file_s = optarg;
701 config.flags |= DRY_RUN_FLAG;
704 config.lookup_ips_file_s = optarg;
705 config.flags |= DRY_RUN_FLAG;
709 config.nb_routes = strtoul(optarg, &endptr, 10);
710 if ((errno != 0) || (config.nb_routes == 0)) {
712 rte_exit(-EINVAL, "Invalid option -n\n");
715 if (config.nb_routes < config.print_fract)
716 config.print_fract = config.nb_routes;
720 distrib_string = optarg;
724 config.nb_lookup_ips = strtoul(optarg, &endptr, 10);
725 if ((errno != 0) || (config.nb_lookup_ips == 0)) {
727 rte_exit(-EINVAL, "Invalid option -l\n");
732 config.rnd_lookup_ips_ratio =
733 strtoul(optarg, &endptr, 10);
735 (config.rnd_lookup_ips_ratio == 0) ||
736 (config.rnd_lookup_ips_ratio >= 100)) {
738 rte_exit(-EINVAL, "Invalid option -r\n");
742 config.flags |= SHUFFLE_FLAG;
745 config.flags |= CMP_FLAG;
748 config.flags |= IPV6_FLAG;
751 config.flags |= CMP_ALL_FLAG;
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;
764 rte_exit(-EINVAL, "Invalid option -b\n");
768 config.ent_sz = strtoul(optarg, &endptr, 10);
771 rte_exit(-EINVAL, "Invalid option -e\n");
776 config.tbl8 = strtoul(optarg, &endptr, 10);
777 if ((errno != 0) || (config.tbl8 == 0)) {
779 rte_exit(-EINVAL, "Invalid option -g\n");
783 if ((strcmp(optarg, "s1") == 0) ||
784 (strcmp(optarg, "s") == 0)) {
785 config.lookup_fn = 1;
787 } else if (strcmp(optarg, "v") == 0) {
788 config.lookup_fn = 2;
790 } else if (strcmp(optarg, "s2") == 0) {
791 config.lookup_fn = 3;
793 } else if (strcmp(optarg, "s3") == 0) {
794 config.lookup_fn = 4;
798 rte_exit(-EINVAL, "Invalid option -v %s\n", optarg);
801 rte_exit(-EINVAL, "Invalid options\n");
807 dump_rt_4(struct rt_rule_4 *rt)
812 f = fopen(config.routes_file_s, "w");
814 printf("Can not open file %s\n", config.routes_file_s);
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);
827 print_depth_err(void)
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");
839 struct rte_fib_conf conf = {0};
840 struct rt_rule_4 *rt;
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];
849 rt = (struct rt_rule_4 *)config.rt;
851 if (config.flags & DRY_RUN_FLAG) {
852 if (config.routes_file_s != NULL)
856 if (config.lookup_ips_file_s != NULL)
857 ret = dump_lookup(AF_INET);
861 conf.type = get_fib_type();
862 conf.default_nh = def_nh;
863 conf.max_routes = config.nb_routes * 2;
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));
871 fib = rte_fib_create("test", -1, &conf);
873 printf("Can not alloc FIB, err %d\n", rte_errno);
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);
893 printf("Can not init lookup function\n");
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,
903 if (unlikely(ret != 0)) {
904 printf("Can not add a route to FIB, err %d\n",
909 printf("AVG FIB add %"PRIu64"\n",
910 (rte_rdtsc_precise() - start) / j);
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,
919 lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
921 printf("Can not alloc LPM, err %d\n", rte_errno);
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);
930 if (rt[i + j].depth == 0)
932 printf("Can not add a route to LPM, "
937 printf("AVG LPM add %"PRIu64"\n",
938 (rte_rdtsc_precise() - start) / j);
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;
949 printf("FIB lookup fails, err %d\n", ret);
953 printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
955 if (config.flags & CMP_FLAG) {
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,
961 acc += rte_rdtsc_precise() - start;
963 printf("LPM lookup fails, err %d\n", ret);
967 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
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))) {
983 printf("FIB and LPM lookup returns same values\n");
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);
991 printf("AVG FIB delete %"PRIu64"\n",
992 (rte_rdtsc_precise() - start) / j);
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,
1003 printf("AVG LPM delete %"PRIu64"\n",
1004 (rte_rdtsc_precise() - start) / j);
1013 dump_rt_6(struct rt_rule_6 *rt)
1018 f = fopen(config.routes_file_s, "w");
1020 printf("Can not open file %s\n", config.routes_file_s);
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);
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;
1043 struct rte_lpm6 *lpm = NULL;
1044 struct rte_lpm6_config lpm_conf;
1046 uint64_t fib_nh[BURST_SZ];
1047 int32_t lpm_nh[BURST_SZ];
1049 rt = (struct rt_rule_6 *)config.rt;
1050 tbl6 = config.lookup_tbl;
1052 if (config.flags & DRY_RUN_FLAG) {
1053 if (config.routes_file_s != NULL)
1054 ret = dump_rt_6(rt);
1057 if (config.lookup_ips_file_s != NULL)
1058 ret = dump_lookup(AF_INET6);
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));
1072 fib = rte_fib6_create("test", -1, &conf);
1074 printf("Can not alloc FIB, err %d\n", rte_errno);
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);
1088 printf("Can not init lookup function\n");
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",
1104 printf("AVG FIB add %"PRIu64"\n",
1105 (rte_rdtsc_precise() - start) / j);
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,
1114 lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1116 printf("Can not alloc LPM, err %d\n", rte_errno);
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);
1125 if (rt[i + j].depth == 0)
1127 printf("Can not add a route to LPM, "
1132 printf("AVG LPM add %"PRIu64"\n",
1133 (rte_rdtsc_precise() - start) / j);
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),
1143 acc += rte_rdtsc_precise() - start;
1145 printf("FIB lookup fails, err %d\n", ret);
1149 printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1151 if (config.flags & CMP_FLAG) {
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),
1158 acc += rte_rdtsc_precise() - start;
1160 printf("LPM lookup fails, err %d\n", ret);
1164 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
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),
1170 rte_lpm6_lookup_bulk_func(lpm,
1171 (uint8_t (*)[16])(tbl6 + i*16),
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))) {
1182 printf("FIB and LPM lookup returns same values\n");
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);
1190 printf("AVG FIB delete %"PRIu64"\n",
1191 (rte_rdtsc_precise() - start) / j);
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,
1202 printf("AVG LPM delete %"PRIu64"\n",
1203 (rte_rdtsc_precise() - start) / j);
1211 main(int argc, char **argv)
1213 int ret, af, rt_ent_sz, lookup_ent_sz;
1218 ret = rte_eal_init(argc, argv);
1220 rte_panic("Cannot init EAL\n");
1225 config.prgname = argv[0];
1227 parse_opts(argc, argv);
1229 ret = check_config();
1231 rte_exit(-ret, "Bad configuration\n");
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;
1239 /* Count number of rules in file*/
1240 if (config.routes_file != NULL) {
1241 fr = fopen(config.routes_file, "r");
1243 rte_exit(-errno, "Can not open file with routes %s\n",
1244 config.routes_file);
1246 config.nb_routes = 0;
1247 while (fgets(line, sizeof(line), fr) != NULL)
1250 if (config.nb_routes < config.print_fract)
1251 config.print_fract = config.nb_routes;
1256 /* Count number of ip's in file*/
1257 if (config.lookup_ips_file != NULL) {
1258 fl = fopen(config.lookup_ips_file, "r");
1260 rte_exit(-errno, "Can not open file with ip's %s\n",
1261 config.lookup_ips_file);
1263 config.nb_lookup_ips = 0;
1264 while (fgets(line, sizeof(line), fl) != NULL)
1265 config.nb_lookup_ips++;
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");
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");
1280 /* Fill routes table */
1282 if (distrib_string != NULL)
1283 ret = parse_distrib(depth_lim, config.nb_routes);
1285 uint8_t rpd[129] = {0};
1286 uint32_t nrpd[129] = {0};
1287 ret = complete_distrib(depth_lim, config.nb_routes,
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);
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);
1306 ret = parse_rt_4(fr);
1308 ret = parse_rt_6(fr);
1311 rte_exit(-ret, "failed to parse routes file %s\n",
1312 config.routes_file);
1316 /* Fill lookup table with ip's*/
1318 gen_rnd_lookup_tbl(af);
1320 ret = parse_lookup(fl, af);
1322 rte_exit(-ret, "failed to parse lookup file\n");