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