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