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