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