1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019 Intel Corporation
5 #include <rte_string_fns.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
14 #include <rte_cycles.h>
15 #include <rte_errno.h>
17 #include <rte_random.h>
18 #include <rte_malloc.h>
24 #define PRINT_USAGE_START "%s [EAL options] --\n"
26 #define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
30 val = strtoul((in), &end_fld, (base)); \
31 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
33 (fd) = (typeof(fd))val; \
37 #define DEF_ROUTES_NUM 0x10000
38 #define DEF_LOOKUP_IPS_NUM 0x100000
40 #define DEFAULT_LPM_TBL8 100000U
42 #define CMP_FLAG (1 << 0)
43 #define CMP_ALL_FLAG (1 << 1)
44 #define IPV6_FLAG (1 << 2)
45 #define FIB_RIB_TYPE (1 << 3)
46 #define FIB_V4_DIR_TYPE (1 << 4)
47 #define FIB_V6_TRIE_TYPE (1 << 4)
48 #define FIB_TYPE_MASK (FIB_RIB_TYPE|FIB_V4_DIR_TYPE|FIB_V6_TRIE_TYPE)
49 #define SHUFFLE_FLAG (1 << 7)
50 #define DRY_RUN_FLAG (1 << 8)
52 static char *distrib_string;
53 static char line[LINE_MAX];
62 #define NIPQUAD_FMT "%u.%u.%u.%u"
63 #define NIPQUAD(addr) \
64 (unsigned)((unsigned char *)&addr)[3], \
65 (unsigned)((unsigned char *)&addr)[2], \
66 (unsigned)((unsigned char *)&addr)[1], \
67 (unsigned)((unsigned char *)&addr)[0]
69 #define NIPQUAD6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
70 #define NIPQUAD6(addr) \
71 ((uint8_t *)addr)[0] << 8 | \
72 ((uint8_t *)addr)[1], \
73 ((uint8_t *)addr)[2] << 8 | \
74 ((uint8_t *)addr)[3], \
75 ((uint8_t *)addr)[4] << 8 | \
76 ((uint8_t *)addr)[5], \
77 ((uint8_t *)addr)[6] << 8 | \
78 ((uint8_t *)addr)[7], \
79 ((uint8_t *)addr)[8] << 8 | \
80 ((uint8_t *)addr)[9], \
81 ((uint8_t *)addr)[10] << 8 | \
82 ((uint8_t *)addr)[11], \
83 ((uint8_t *)addr)[12] << 8 | \
84 ((uint8_t *)addr)[13], \
85 ((uint8_t *)addr)[14] << 8 | \
91 const char *routes_file;
92 const char *lookup_ips_file;
93 const char *routes_file_s;
94 const char *lookup_ips_file_s;
98 uint32_t nb_lookup_ips;
99 uint32_t nb_lookup_ips_rnd;
100 uint32_t nb_routes_per_depth[128 + 1];
104 uint8_t rnd_lookup_ips_ratio;
108 .lookup_ips_file = NULL,
109 .nb_routes = DEF_ROUTES_NUM,
110 .nb_lookup_ips = DEF_LOOKUP_IPS_NUM,
111 .nb_lookup_ips_rnd = 0,
112 .nb_routes_per_depth = {0},
113 .flags = FIB_V4_DIR_TYPE,
114 .tbl8 = DEFAULT_LPM_TBL8,
116 .rnd_lookup_ips_ratio = 0,
133 get_rnd_rng(uint64_t l, uint64_t u)
138 return (rte_rand() % (u - l) + l);
141 static __rte_always_inline __attribute__((pure)) uint8_t
142 bits_in_nh(uint8_t nh_sz)
144 return 8 * (1 << nh_sz);
147 static __rte_always_inline __attribute__((pure)) uint64_t
148 get_max_nh(uint8_t nh_sz)
150 /* min between fib and lpm6 which is 21 bits */
151 return RTE_MIN(((1ULL << (bits_in_nh(nh_sz) - 1)) - 1),
158 if (config.flags & IPV6_FLAG) {
159 if ((config.flags & FIB_TYPE_MASK) == FIB_V6_TRIE_TYPE)
160 return RTE_FIB6_TRIE;
162 return RTE_FIB6_DUMMY;
164 if ((config.flags & FIB_TYPE_MASK) == FIB_V4_DIR_TYPE)
165 return RTE_FIB_DIR24_8;
166 if ((config.flags & FIB_TYPE_MASK) == FIB_RIB_TYPE)
167 return RTE_FIB_DUMMY;
173 complete_distrib(uint8_t depth_lim, const uint32_t n, uint8_t rpd[],
181 * complete number of routes for every depth
182 * that was configured with ratio
184 for (depth = 0; depth <= depth_lim; depth++) {
185 if (rpd[depth] != 0) {
186 if (rpd[depth] == UINT8_MAX)
187 config.nb_routes_per_depth[depth] =
190 config.nb_routes_per_depth[depth] =
191 (n * rpd[depth]) / 100;
193 nr += config.nb_routes_per_depth[depth];
199 printf("Too much configured routes\n");
203 /*complete number of routes for every unspecified depths*/
204 for (depth = 0; depth <= depth_lim; depth++) {
205 if (rpd[depth] == 0) {
206 /*we don't need more than two /1 routes*/
207 uint64_t max_routes_per_depth =
208 1ULL << RTE_MIN(depth, 63);
209 uint32_t avg_routes_left = (n - nr) /
210 (depth_lim + 1 - m++);
211 config.nb_routes_per_depth[depth] =
212 RTE_MIN(max_routes_per_depth, avg_routes_left);
213 nr += config.nb_routes_per_depth[depth];
221 parse_distrib(uint8_t depth_lim, const uint32_t n)
223 uint8_t rpd[128 + 1] = {0}; /*routes ratios per depth including /0 */
224 uint32_t nrpd[128 + 1] = {0}; /* number of routes per depth */
226 uint8_t depth, ratio, ratio_acc = 0;
229 in = strtok(distrib_string, ",");
231 /*parse configures routes percentage ratios*/
233 GET_CB_FIELD(in, depth, 0, UINT8_MAX, ':');
234 if (in[strlen(in) - 1] == '%') {
235 in[strlen(in) - 1] = 0;
236 GET_CB_FIELD(in, ratio, 0, UINT8_MAX, '\0');
237 if (depth > depth_lim) {
238 printf("Depth /%d is bigger than maximum "
239 "allowed depth /%d for this AF\n",
244 printf("Ratio for depth /%d is bigger "
245 "than 100%%\n", depth);
248 if ((depth < 64) && ((n * ratio) / 100) >
250 printf("Configured ratio %d%% for depth /%d "
251 "has %d different routes, but maximum "
252 "is %lu\n", ratio, depth,
253 ((n * ratio) / 100), (1UL << depth));
257 /*configured zero routes for a given depth*/
259 rpd[depth] = UINT8_MAX;
260 /*sum of all percentage ratios*/
263 GET_CB_FIELD(in, n_routes, 0, UINT32_MAX, '\0');
264 rpd[depth] = UINT8_MAX;
265 nrpd[depth] = n_routes;
268 /*number of configured depths in*/
269 in = strtok(NULL, ",");
272 if (ratio_acc > 100) {
273 printf("Total ratio's sum is bigger than 100%%\n");
277 return complete_distrib(depth_lim, n, rpd, nrpd);
281 shuffle_rt_4(struct rt_rule_4 *rt, int n)
283 struct rt_rule_4 tmp;
286 for (i = 0; i < n; i++) {
288 tmp.addr = rt[i].addr;
289 tmp.depth = rt[i].depth;
292 rt[i].addr = rt[j].addr;
293 rt[i].depth = rt[j].depth;
296 rt[j].addr = tmp.addr;
297 rt[j].depth = tmp.depth;
303 shuffle_rt_6(struct rt_rule_6 *rt, int n)
305 struct rt_rule_6 tmp;
308 for (i = 0; i < n; i++) {
310 memcpy(tmp.addr, rt[i].addr, 16);
311 tmp.depth = rt[i].depth;
314 memcpy(rt[i].addr, rt[j].addr, 16);
315 rt[i].depth = rt[j].depth;
318 memcpy(rt[j].addr, tmp.addr, 16);
319 rt[j].depth = tmp.depth;
325 gen_random_rt_4(struct rt_rule_4 *rt, int nh_sz)
327 uint32_t i, j, k = 0;
329 if (config.nb_routes_per_depth[0] != 0) {
332 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
335 for (i = 1; i <= 32; i++) {
338 step = (double)(1ULL << i) / config.nb_routes_per_depth[i];
339 for (j = 0; j < config.nb_routes_per_depth[i];
340 j++, k++, edge += step) {
341 uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
342 (uint64_t)(edge + step));
343 rt[k].addr = rnd_val << (32 - i);
345 rt[k].nh = rte_rand() & get_max_nh(nh_sz);
351 complete_v6_addr(uint32_t *addr, uint32_t rnd, int n)
355 for (i = 0; i < n; i++)
356 addr[i] = rte_rand();
363 gen_random_rt_6(struct rt_rule_6 *rt, int nh_sz)
365 uint32_t i, j, k = 0;
367 if (config.nb_routes_per_depth[0] != 0) {
368 memset(rt[k].addr, 0, 16);
370 rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
373 for (int a = 0; a < 4; a++) {
374 for (i = 1; i <= 32; i++) {
377 double step = (double)(1ULL << i) /
378 config.nb_routes_per_depth[(a * 32) + i];
379 for (j = 0; j < config.nb_routes_per_depth[a * 32 + i];
380 j++, k++, edge += step) {
381 uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
382 (uint64_t)(edge + step));
383 rnd = rte_cpu_to_be_32(rnd_val << (32 - i));
384 complete_v6_addr((uint32_t *)rt[k].addr,
386 rt[k].depth = (a * 32) + i;
387 rt[k].nh = rte_rand() & get_max_nh(nh_sz);
394 set_rnd_ipv6(uint8_t *addr, uint8_t *route, int depth)
398 for (i = 0; i < 16; i++)
399 addr[i] = rte_rand();
401 for (i = 0; i < 16; i++) {
404 else if (depth > 0) {
405 addr[i] &= (uint16_t)UINT8_MAX >> depth;
406 addr[i] |= route[i] & UINT8_MAX << (8 - depth);
414 gen_rnd_lookup_tbl(int af)
416 uint32_t *tbl4 = config.lookup_tbl;
417 uint8_t *tbl6 = config.lookup_tbl;
418 struct rt_rule_4 *rt4 = (struct rt_rule_4 *)config.rt;
419 struct rt_rule_6 *rt6 = (struct rt_rule_6 *)config.rt;
423 for (i = 0, j = 0; i < config.nb_lookup_ips;
424 i++, j = (j + 1) % config.nb_routes) {
425 if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
426 tbl4[i] = rte_rand();
427 config.nb_lookup_ips_rnd++;
429 tbl4[i] = rt4[j].addr | (rte_rand() &
430 ((1ULL << (32 - rt4[j].depth)) - 1));
433 for (i = 0, j = 0; i < config.nb_lookup_ips;
434 i++, j = (j + 1) % config.nb_routes) {
435 if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
436 set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr, 0);
437 config.nb_lookup_ips_rnd++;
439 set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr,
450 char *s, *sp, *in[RT_NUM];
451 static const char *dlm = " \t\n";
452 int string_tok_nb = RTE_DIM(in);
453 struct rt_rule_4 *rt;
455 rt = (struct rt_rule_4 *)config.rt;
457 while (fgets(line, sizeof(line), f) != NULL) {
459 for (i = 0; i != string_tok_nb; i++) {
460 in[i] = strtok_r(s, dlm, &sp);
466 ret = inet_net_pton(AF_INET, in[RT_PREFIX], &rt[j].addr,
471 rt[j].addr = rte_be_to_cpu_32(rt[j].addr);
473 config.nb_routes_per_depth[ret]++;
474 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
482 __inet_net_pton6(char *prefix, uint8_t *addr)
484 const char *dlm = "/";
488 if ((prefix == NULL) || (addr == NULL))
491 s = strtok_r(prefix, dlm, &sp);
495 ret = inet_pton(AF_INET6, s, addr);
499 s = strtok_r(NULL, dlm, &sp);
500 GET_CB_FIELD(s, depth, 0, 128, 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;
514 rt = (struct rt_rule_6 *)config.rt;
516 while (fgets(line, sizeof(line), f) != NULL) {
518 for (i = 0; i != string_tok_nb; i++) {
519 in[i] = strtok_r(s, dlm, &sp);
525 ret = __inet_net_pton6(in[RT_PREFIX], rt[j].addr);
530 config.nb_routes_per_depth[ret]++;
531 GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
540 parse_lookup(FILE *f, int af)
543 uint8_t *tbl = (uint8_t *)config.lookup_tbl;
544 int step = (af == AF_INET) ? 4 : 16;
547 while (fgets(line, sizeof(line), f) != NULL) {
548 s = strtok(line, " \t\n");
549 ret = inet_pton(af, s, &tbl[i]);
561 uint32_t *tbl4 = config.lookup_tbl;
562 uint8_t *tbl6 = config.lookup_tbl;
565 f = fopen(config.lookup_ips_file_s, "w");
567 printf("Can not open file %s\n", config.lookup_ips_file_s);
572 for (i = 0; i < config.nb_lookup_ips; i++)
573 fprintf(f, NIPQUAD_FMT"\n", NIPQUAD(tbl4[i]));
575 for (i = 0; i < config.nb_lookup_ips; i++)
576 fprintf(f, NIPQUAD6_FMT"\n", NIPQUAD6(&tbl6[i * 16]));
589 depth_lim = ((config.flags & IPV6_FLAG) == IPV6_FLAG) ? 128 : 32;
593 "Routes distribution:\n", config.nb_routes);
595 for (i = 1; i <= depth_lim; i++) {
597 "depth /%d:%u", i, config.nb_routes_per_depth[i]);
602 fprintf(stdout, "%c", dlm);
606 "Lookup tuples: %u\n"
607 "Configured ratios of random ips for lookup: %u\n"
608 "Random lookup ips: %u\n",
609 config.nb_lookup_ips, config.rnd_lookup_ips_ratio,
610 config.nb_lookup_ips_rnd);
618 "[-f <routes file>]\n"
619 "[-t <ip's file for lookup>]\n"
620 "[-n <number of routes (if -f is not specified)>]\n"
621 "[-l <number of ip's for lookup (if -t is not specified)>]\n"
622 "[-d <\",\" separated \"depth:n%%\"routes depth distribution"
623 "(if -f is not specified)>]\n"
624 "[-r <percentage ratio of random ip's to lookup"
625 "(if -t is not specified)>]\n"
626 "[-c <do comarison with LPM library>]\n"
627 "[-6 <do tests with ipv6 (default ipv4)>]\n"
628 "[-s <shuffle randomly generated routes>]\n"
629 "[-a <check nexthops for all ipv4 address space"
630 "(only valid with -c)>]\n"
631 "[-b <fib algorithm>]\n\tavailible options for ipv4\n"
632 "\t\trib - RIB based FIB\n"
633 "\t\tdir - DIR24_8 based FIB\n"
634 "\tavailible options for ipv6:\n"
635 "\t\trib - RIB based FIB\n"
636 "\t\ttrie - TRIE based FIB\n"
637 "defaults are: dir for ipv4 and trie for ipv6\n"
638 "[-e <entry size (valid only for dir and trie fib types): "
639 "1/2/4/8 (default 4)>]\n"
640 "[-g <number of tbl8's for dir24_8 or trie FIBs>]\n"
641 "[-w <path to the file to dump routing table>]\n"
642 "[-u <path to the file to dump ip's for lookup>]\n",
649 if ((config.routes_file == NULL) && (config.lookup_ips_file != NULL)) {
650 printf("-t option only valid with -f option\n");
654 if ((config.flags & CMP_ALL_FLAG) && (config.flags & IPV6_FLAG)) {
655 printf("-a flag is only valid for ipv4\n");
659 if ((config.flags & CMP_ALL_FLAG) &&
660 ((config.flags & CMP_FLAG) != CMP_FLAG)) {
661 printf("-a flag is valid only with -c flag\n");
665 if (!((config.ent_sz == 1) || (config.ent_sz == 2) ||
666 (config.ent_sz == 4) || (config.ent_sz == 8))) {
667 printf("wrong -e option %d, can be 1 or 2 or 4 or 8\n",
672 if ((config.ent_sz == 1) && (config.flags & IPV6_FLAG)) {
673 printf("-e 1 is valid only for ipv4\n");
680 parse_opts(int argc, char **argv)
685 while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:s")) !=
689 config.routes_file = optarg;
692 config.lookup_ips_file = optarg;
695 config.routes_file_s = optarg;
696 config.flags |= DRY_RUN_FLAG;
699 config.lookup_ips_file_s = optarg;
700 config.flags |= DRY_RUN_FLAG;
704 config.nb_routes = strtoul(optarg, &endptr, 10);
705 if ((errno != 0) || (config.nb_routes == 0)) {
707 rte_exit(-EINVAL, "Invalid option -n\n");
711 distrib_string = optarg;
715 config.nb_lookup_ips = strtoul(optarg, &endptr, 10);
716 if ((errno != 0) || (config.nb_lookup_ips == 0)) {
718 rte_exit(-EINVAL, "Invalid option -l\n");
723 config.rnd_lookup_ips_ratio =
724 strtoul(optarg, &endptr, 10);
726 (config.rnd_lookup_ips_ratio == 0) ||
727 (config.rnd_lookup_ips_ratio >= 100)) {
729 rte_exit(-EINVAL, "Invalid option -r\n");
733 config.flags |= SHUFFLE_FLAG;
736 config.flags |= CMP_FLAG;
739 config.flags |= IPV6_FLAG;
742 config.flags |= CMP_ALL_FLAG;
745 if (strcmp(optarg, "rib") == 0) {
746 config.flags &= ~FIB_TYPE_MASK;
747 config.flags |= FIB_RIB_TYPE;
748 } else if (strcmp(optarg, "dir") == 0) {
749 config.flags &= ~FIB_TYPE_MASK;
750 config.flags |= FIB_V4_DIR_TYPE;
751 } else if (strcmp(optarg, "trie") == 0) {
752 config.flags &= ~FIB_TYPE_MASK;
753 config.flags |= FIB_V6_TRIE_TYPE;
755 rte_exit(-EINVAL, "Invalid option -b\n");
759 config.ent_sz = strtoul(optarg, &endptr, 10);
762 rte_exit(-EINVAL, "Invalid option -e\n");
767 config.tbl8 = strtoul(optarg, &endptr, 10);
768 if ((errno != 0) || (config.tbl8 == 0)) {
770 rte_exit(-EINVAL, "Invalid option -g\n");
775 rte_exit(-EINVAL, "Invalid options\n");
781 dump_rt_4(struct rt_rule_4 *rt)
786 f = fopen(config.routes_file_s, "w");
788 printf("Can not open file %s\n", config.routes_file_s);
792 for (i = 0; i < config.nb_routes; i++)
793 fprintf(f, NIPQUAD_FMT"/%d %lu\n", NIPQUAD(rt[i].addr),
794 rt[i].depth, rt[i].nh);
801 print_depth_err(void)
803 printf("LPM does not support /0 prefix length (default route), use "
804 "-d 0:0 option or remove /0 prefix from routes file\n");
813 struct rte_fib_conf conf = {0};
814 struct rt_rule_4 *rt;
817 struct rte_lpm *lpm = NULL;
818 struct rte_lpm_config lpm_conf;
819 uint32_t *tbl4 = config.lookup_tbl;
820 uint64_t fib_nh[BURST_SZ];
821 uint32_t lpm_nh[BURST_SZ];
823 rt = (struct rt_rule_4 *)config.rt;
825 if (config.flags & DRY_RUN_FLAG) {
826 if (config.routes_file_s != NULL)
830 if (config.lookup_ips_file_s != NULL)
831 ret = dump_lookup(AF_INET);
835 conf.type = get_fib_type();
836 conf.default_nh = def_nh;
837 conf.max_routes = config.nb_routes * 2;
838 if (conf.type == RTE_FIB_DIR24_8) {
839 conf.dir24_8.nh_sz = __builtin_ctz(config.ent_sz);
840 conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
841 get_max_nh(conf.dir24_8.nh_sz));
844 fib = rte_fib_create("test", -1, &conf);
846 printf("Can not alloc FIB, err %d\n", rte_errno);
850 for (k = config.print_fract, i = 0; k > 0; k--) {
851 start = rte_rdtsc_precise();
852 for (j = 0; j < (config.nb_routes - i) / k; j++) {
853 ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
855 if (unlikely(ret != 0)) {
856 printf("Can not add a route to FIB, err %d\n",
861 printf("AVG FIB add %lu\n", (rte_rdtsc_precise() - start) / j);
865 if (config.flags & CMP_FLAG) {
866 lpm_conf.max_rules = config.nb_routes * 2;
867 lpm_conf.number_tbl8s = RTE_MAX(conf.dir24_8.num_tbl8,
870 lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
872 printf("Can not alloc LPM, err %d\n", rte_errno);
875 for (k = config.print_fract, i = 0; k > 0; k--) {
876 start = rte_rdtsc_precise();
877 for (j = 0; j < (config.nb_routes - i) / k; j++) {
878 ret = rte_lpm_add(lpm, rt[i + j].addr,
879 rt[i + j].depth, rt[i + j].nh);
881 if (rt[i + j].depth == 0)
883 printf("Can not add a route to LPM, "
888 printf("AVG LPM add %lu\n",
889 (rte_rdtsc_precise() - start) / j);
895 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
896 start = rte_rdtsc_precise();
897 ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
898 acc += rte_rdtsc_precise() - start;
900 printf("FIB lookup fails, err %d\n", ret);
904 printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
906 if (config.flags & CMP_FLAG) {
908 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
909 start = rte_rdtsc_precise();
910 ret = rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh,
912 acc += rte_rdtsc_precise() - start;
914 printf("LPM lookup fails, err %d\n", ret);
918 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
920 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
921 rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
922 rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh, BURST_SZ);
923 for (j = 0; j < BURST_SZ; j++) {
924 struct rte_lpm_tbl_entry *tbl;
925 tbl = (struct rte_lpm_tbl_entry *)&lpm_nh[j];
926 if ((fib_nh[j] != tbl->next_hop) &&
927 !((tbl->valid == 0) &&
928 (fib_nh[j] == def_nh))) {
934 printf("FIB and LPM lookup returns same values\n");
937 for (k = config.print_fract, i = 0; k > 0; k--) {
938 start = rte_rdtsc_precise();
939 for (j = 0; j < (config.nb_routes - i) / k; j++)
940 rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
942 printf("AVG FIB delete %lu\n",
943 (rte_rdtsc_precise() - start) / j);
947 if (config.flags & CMP_FLAG) {
948 for (k = config.print_fract, i = 0; k > 0; k--) {
949 start = rte_rdtsc_precise();
950 for (j = 0; j < (config.nb_routes - i) / k; j++)
951 rte_lpm_delete(lpm, rt[i + j].addr,
954 printf("AVG LPM delete %lu\n",
955 (rte_rdtsc_precise() - start) / j);
964 dump_rt_6(struct rt_rule_6 *rt)
969 f = fopen(config.routes_file_s, "w");
971 printf("Can not open file %s\n", config.routes_file_s);
975 for (i = 0; i < config.nb_routes; i++) {
976 fprintf(f, NIPQUAD6_FMT"/%d %lu\n", NIPQUAD6(rt[i].addr),
977 rt[i].depth, rt[i].nh);
989 struct rte_fib6 *fib;
990 struct rte_fib6_conf conf = {0};
991 struct rt_rule_6 *rt;
994 struct rte_lpm6 *lpm = NULL;
995 struct rte_lpm6_config lpm_conf;
997 uint64_t fib_nh[BURST_SZ];
998 int32_t lpm_nh[BURST_SZ];
1000 rt = (struct rt_rule_6 *)config.rt;
1001 tbl6 = config.lookup_tbl;
1003 if (config.flags & DRY_RUN_FLAG) {
1004 if (config.routes_file_s != NULL)
1005 ret = dump_rt_6(rt);
1008 if (config.lookup_ips_file_s != NULL)
1009 ret = dump_lookup(AF_INET6);
1013 conf.type = get_fib_type();
1014 conf.default_nh = def_nh;
1015 conf.max_routes = config.nb_routes * 2;
1016 if (conf.type == RTE_FIB6_TRIE) {
1017 conf.trie.nh_sz = __builtin_ctz(config.ent_sz);
1018 conf.trie.num_tbl8 = RTE_MIN(config.tbl8,
1019 get_max_nh(conf.trie.nh_sz));
1022 fib = rte_fib6_create("test", -1, &conf);
1024 printf("Can not alloc FIB, err %d\n", rte_errno);
1028 for (k = config.print_fract, i = 0; k > 0; k--) {
1029 start = rte_rdtsc_precise();
1030 for (j = 0; j < (config.nb_routes - i) / k; j++) {
1031 ret = rte_fib6_add(fib, rt[i + j].addr,
1032 rt[i + j].depth, rt[i + j].nh);
1033 if (unlikely(ret != 0)) {
1034 printf("Can not add a route to FIB, err %d\n",
1039 printf("AVG FIB add %lu\n", (rte_rdtsc_precise() - start) / j);
1043 if (config.flags & CMP_FLAG) {
1044 lpm_conf.max_rules = config.nb_routes * 2;
1045 lpm_conf.number_tbl8s = RTE_MAX(conf.trie.num_tbl8,
1048 lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1050 printf("Can not alloc LPM, err %d\n", rte_errno);
1053 for (k = config.print_fract, i = 0; k > 0; k--) {
1054 start = rte_rdtsc_precise();
1055 for (j = 0; j < (config.nb_routes - i) / k; j++) {
1056 ret = rte_lpm6_add(lpm, rt[i + j].addr,
1057 rt[i + j].depth, rt[i + j].nh);
1059 if (rt[i + j].depth == 0)
1061 printf("Can not add a route to LPM, "
1066 printf("AVG LPM add %lu\n",
1067 (rte_rdtsc_precise() - start) / j);
1073 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1074 start = rte_rdtsc_precise();
1075 ret = rte_fib6_lookup_bulk(fib, (uint8_t (*)[16])(tbl6 + i*16),
1077 acc += rte_rdtsc_precise() - start;
1079 printf("FIB lookup fails, err %d\n", ret);
1083 printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1085 if (config.flags & CMP_FLAG) {
1087 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1088 start = rte_rdtsc_precise();
1089 ret = rte_lpm6_lookup_bulk_func(lpm,
1090 (uint8_t (*)[16])(tbl6 + i*16),
1092 acc += rte_rdtsc_precise() - start;
1094 printf("LPM lookup fails, err %d\n", ret);
1098 printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
1100 for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1101 rte_fib6_lookup_bulk(fib,
1102 (uint8_t (*)[16])(tbl6 + i*16),
1104 rte_lpm6_lookup_bulk_func(lpm,
1105 (uint8_t (*)[16])(tbl6 + i*16),
1107 for (j = 0; j < BURST_SZ; j++) {
1108 if ((fib_nh[j] != (uint32_t)lpm_nh[j]) &&
1109 !((lpm_nh[j] == -1) &&
1110 (fib_nh[j] == def_nh))) {
1116 printf("FIB and LPM lookup returns same values\n");
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 rte_fib6_delete(fib, rt[i + j].addr, rt[i + j].depth);
1124 printf("AVG FIB delete %lu\n",
1125 (rte_rdtsc_precise() - start) / j);
1129 if (config.flags & CMP_FLAG) {
1130 for (k = config.print_fract, i = 0; k > 0; k--) {
1131 start = rte_rdtsc_precise();
1132 for (j = 0; j < (config.nb_routes - i) / k; j++)
1133 rte_lpm6_delete(lpm, rt[i + j].addr,
1136 printf("AVG LPM delete %lu\n",
1137 (rte_rdtsc_precise() - start) / j);
1145 main(int argc, char **argv)
1147 int ret, af, rt_ent_sz, lookup_ent_sz;
1151 ret = rte_eal_init(argc, argv);
1153 rte_panic("Cannot init EAL\n");
1158 config.prgname = argv[0];
1160 parse_opts(argc, argv);
1162 ret = check_config();
1164 rte_exit(-ret, "Bad configuration\n");
1166 af = ((config.flags & IPV6_FLAG) == 0) ? AF_INET : AF_INET6;
1167 depth_lim = (af == AF_INET) ? 32 : 128;
1168 rt_ent_sz = (af == AF_INET) ? sizeof(struct rt_rule_4) :
1169 sizeof(struct rt_rule_6);
1170 lookup_ent_sz = (af == AF_INET) ? 4 : 16;
1172 /* Count number of rules in file*/
1173 if (config.routes_file != NULL) {
1174 fr = fopen(config.routes_file, "r");
1176 rte_exit(-errno, "Can not open file with routes %s\n",
1177 config.routes_file);
1179 config.nb_routes = 0;
1180 while (fgets(line, sizeof(line), fr) != NULL)
1185 /* Count number of ip's in file*/
1186 if (config.lookup_ips_file != NULL) {
1187 fl = fopen(config.lookup_ips_file, "r");
1189 rte_exit(-errno, "Can not open file with ip's %s\n",
1190 config.lookup_ips_file);
1192 config.nb_lookup_ips = 0;
1193 while (fgets(line, sizeof(line), fl) != NULL)
1194 config.nb_lookup_ips++;
1198 /* Alloc routes table*/
1199 config.rt = rte_malloc(NULL, rt_ent_sz * config.nb_routes, 0);
1200 if (config.rt == NULL)
1201 rte_exit(-ENOMEM, "Can not alloc rt\n");
1203 /* Alloc table with ip's for lookup*/
1204 config.lookup_tbl = rte_malloc(NULL, lookup_ent_sz *
1205 config.nb_lookup_ips, 0);
1206 if (config.lookup_tbl == NULL)
1207 rte_exit(-ENOMEM, "Can not alloc lookup table\n");
1209 /* Fill routes table */
1210 if (config.routes_file == NULL) {
1211 if (distrib_string != NULL)
1212 ret = parse_distrib(depth_lim, config.nb_routes);
1214 uint8_t rpd[129] = {0};
1215 uint32_t nrpd[129] = {0};
1216 ret = complete_distrib(depth_lim, config.nb_routes,
1221 "Bad routes distribution configuration\n");
1222 if (af == AF_INET) {
1223 gen_random_rt_4(config.rt,
1224 __builtin_ctz(config.ent_sz));
1225 if (config.flags & SHUFFLE_FLAG)
1226 shuffle_rt_4(config.rt, config.nb_routes);
1228 gen_random_rt_6(config.rt,
1229 __builtin_ctz(config.ent_sz));
1230 if (config.flags & SHUFFLE_FLAG)
1231 shuffle_rt_6(config.rt, config.nb_routes);
1235 ret = parse_rt_4(fr);
1237 ret = parse_rt_6(fr);
1240 rte_exit(-ret, "failed to parse routes file %s\n",
1241 config.routes_file);
1245 /* Fill lookup table with ip's*/
1246 if (config.lookup_ips_file == NULL)
1247 gen_rnd_lookup_tbl(af);
1249 ret = parse_lookup(fl, af);
1251 rte_exit(-ret, "failed to parse lookup file\n");