1
2
3
4
5#include <rte_string_fns.h>
6#include <rte_acl.h>
7#include <getopt.h>
8#include <string.h>
9
10#include <rte_cycles.h>
11#include <rte_per_lcore.h>
12#include <rte_lcore.h>
13#include <rte_ip.h>
14
15#define PRINT_USAGE_START "%s [EAL options] --\n"
16
17#define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1
18
19#define APP_NAME "TESTACL"
20
21#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
22 unsigned long val; \
23 char *end_fld; \
24 errno = 0; \
25 val = strtoul((in), &end_fld, (base)); \
26 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
27 return -EINVAL; \
28 (fd) = (typeof(fd))val; \
29 (in) = end_fld + 1; \
30} while (0)
31
32#define OPT_RULE_FILE "rulesf"
33#define OPT_TRACE_FILE "tracef"
34#define OPT_RULE_NUM "rulenum"
35#define OPT_TRACE_NUM "tracenum"
36#define OPT_TRACE_STEP "tracestep"
37#define OPT_SEARCH_ALG "alg"
38#define OPT_BLD_CATEGORIES "bldcat"
39#define OPT_RUN_CATEGORIES "runcat"
40#define OPT_MAX_SIZE "maxsize"
41#define OPT_ITER_NUM "iter"
42#define OPT_VERBOSE "verbose"
43#define OPT_IPV6 "ipv6"
44
45#define TRACE_DEFAULT_NUM 0x10000
46#define TRACE_STEP_MAX 0x1000
47#define TRACE_STEP_DEF 0x100
48
49#define RULE_NUM 0x10000
50
51#define COMMENT_LEAD_CHAR '#'
52
53enum {
54 DUMP_NONE,
55 DUMP_SEARCH,
56 DUMP_PKT,
57 DUMP_MAX
58};
59
60enum {
61 IPV6_FRMT_NONE,
62 IPV6_FRMT_U32,
63 IPV6_FRMT_U64,
64};
65
66struct acl_alg {
67 const char *name;
68 enum rte_acl_classify_alg alg;
69};
70
71static const struct acl_alg acl_alg[] = {
72 {
73 .name = "scalar",
74 .alg = RTE_ACL_CLASSIFY_SCALAR,
75 },
76 {
77 .name = "sse",
78 .alg = RTE_ACL_CLASSIFY_SSE,
79 },
80 {
81 .name = "avx2",
82 .alg = RTE_ACL_CLASSIFY_AVX2,
83 },
84 {
85 .name = "neon",
86 .alg = RTE_ACL_CLASSIFY_NEON,
87 },
88 {
89 .name = "altivec",
90 .alg = RTE_ACL_CLASSIFY_ALTIVEC,
91 },
92 {
93 .name = "avx512x16",
94 .alg = RTE_ACL_CLASSIFY_AVX512X16,
95 },
96 {
97 .name = "avx512x32",
98 .alg = RTE_ACL_CLASSIFY_AVX512X32,
99 },
100};
101
102static struct {
103 const char *prgname;
104 const char *rule_file;
105 const char *trace_file;
106 size_t max_size;
107 uint32_t bld_categories;
108 uint32_t run_categories;
109 uint32_t nb_rules;
110 uint32_t nb_traces;
111 uint32_t trace_step;
112 uint32_t trace_sz;
113 uint32_t iter_num;
114 uint32_t verbose;
115 uint32_t ipv6;
116 struct acl_alg alg;
117 uint32_t used_traces;
118 void *traces;
119 struct rte_acl_ctx *acx;
120} config = {
121 .bld_categories = 3,
122 .run_categories = 1,
123 .nb_rules = RULE_NUM,
124 .nb_traces = TRACE_DEFAULT_NUM,
125 .trace_step = TRACE_STEP_DEF,
126 .iter_num = 1,
127 .verbose = DUMP_MAX,
128 .alg = {
129 .name = "default",
130 .alg = RTE_ACL_CLASSIFY_DEFAULT,
131 },
132 .ipv6 = IPV6_FRMT_NONE,
133};
134
135static struct rte_acl_param prm = {
136 .name = APP_NAME,
137 .socket_id = SOCKET_ID_ANY,
138};
139
140
141
142
143
144struct ipv4_5tuple {
145 uint8_t proto;
146 uint32_t ip_src;
147 uint32_t ip_dst;
148 uint16_t port_src;
149 uint16_t port_dst;
150};
151
152enum {
153 PROTO_FIELD_IPV4,
154 SRC_FIELD_IPV4,
155 DST_FIELD_IPV4,
156 SRCP_FIELD_IPV4,
157 DSTP_FIELD_IPV4,
158 NUM_FIELDS_IPV4
159};
160
161
162
163
164
165
166
167
168
169enum {
170 RTE_ACL_IPV4VLAN_PROTO,
171 RTE_ACL_IPV4VLAN_VLAN,
172 RTE_ACL_IPV4VLAN_SRC,
173 RTE_ACL_IPV4VLAN_DST,
174 RTE_ACL_IPV4VLAN_PORTS,
175 RTE_ACL_IPV4VLAN_NUM
176};
177
178struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
179 {
180 .type = RTE_ACL_FIELD_TYPE_BITMASK,
181 .size = sizeof(uint8_t),
182 .field_index = PROTO_FIELD_IPV4,
183 .input_index = RTE_ACL_IPV4VLAN_PROTO,
184 .offset = offsetof(struct ipv4_5tuple, proto),
185 },
186 {
187 .type = RTE_ACL_FIELD_TYPE_MASK,
188 .size = sizeof(uint32_t),
189 .field_index = SRC_FIELD_IPV4,
190 .input_index = RTE_ACL_IPV4VLAN_SRC,
191 .offset = offsetof(struct ipv4_5tuple, ip_src),
192 },
193 {
194 .type = RTE_ACL_FIELD_TYPE_MASK,
195 .size = sizeof(uint32_t),
196 .field_index = DST_FIELD_IPV4,
197 .input_index = RTE_ACL_IPV4VLAN_DST,
198 .offset = offsetof(struct ipv4_5tuple, ip_dst),
199 },
200 {
201 .type = RTE_ACL_FIELD_TYPE_RANGE,
202 .size = sizeof(uint16_t),
203 .field_index = SRCP_FIELD_IPV4,
204 .input_index = RTE_ACL_IPV4VLAN_PORTS,
205 .offset = offsetof(struct ipv4_5tuple, port_src),
206 },
207 {
208 .type = RTE_ACL_FIELD_TYPE_RANGE,
209 .size = sizeof(uint16_t),
210 .field_index = DSTP_FIELD_IPV4,
211 .input_index = RTE_ACL_IPV4VLAN_PORTS,
212 .offset = offsetof(struct ipv4_5tuple, port_dst),
213 },
214};
215
216#define IPV6_ADDR_LEN 16
217#define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t))
218#define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t))
219#define IPV6_ADDR_U64 (IPV6_ADDR_LEN / sizeof(uint64_t))
220
221struct ipv6_5tuple {
222 uint8_t proto;
223 uint32_t ip_src[IPV6_ADDR_U32];
224 uint32_t ip_dst[IPV6_ADDR_U32];
225 uint16_t port_src;
226 uint16_t port_dst;
227};
228
229
230enum {
231 PROTO_FIELD_IPV6,
232 SRC1_FIELD_IPV6,
233 SRC2_FIELD_IPV6,
234 SRC3_FIELD_IPV6,
235 SRC4_FIELD_IPV6,
236 DST1_FIELD_IPV6,
237 DST2_FIELD_IPV6,
238 DST3_FIELD_IPV6,
239 DST4_FIELD_IPV6,
240 SRCP_FIELD_IPV6,
241 DSTP_FIELD_IPV6,
242 NUM_FIELDS_IPV6
243};
244
245
246enum {
247 PROTO_FIELD_IPV6_U64,
248 SRC1_FIELD_IPV6_U64,
249 SRC2_FIELD_IPV6_U64,
250 DST1_FIELD_IPV6_U64,
251 DST2_FIELD_IPV6_U64,
252 SRCP_FIELD_IPV6_U64,
253 DSTP_FIELD_IPV6_U64,
254 NUM_FIELDS_IPV6_U64
255};
256
257enum {
258 PROTO_INDEX_IPV6_U64 = PROTO_FIELD_IPV6_U64,
259 SRC1_INDEX_IPV6_U64 = SRC1_FIELD_IPV6_U64,
260 SRC2_INDEX_IPV6_U64 = SRC2_FIELD_IPV6_U64 + 1,
261 DST1_INDEX_IPV6_U64 = DST1_FIELD_IPV6_U64 + 2,
262 DST2_INDEX_IPV6_U64 = DST2_FIELD_IPV6_U64 + 3,
263 PRT_INDEX_IPV6_U64 = SRCP_FIELD_IPV6 + 4,
264};
265
266struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
267 {
268 .type = RTE_ACL_FIELD_TYPE_BITMASK,
269 .size = sizeof(uint8_t),
270 .field_index = PROTO_FIELD_IPV6,
271 .input_index = PROTO_FIELD_IPV6,
272 .offset = offsetof(struct ipv6_5tuple, proto),
273 },
274 {
275 .type = RTE_ACL_FIELD_TYPE_MASK,
276 .size = sizeof(uint32_t),
277 .field_index = SRC1_FIELD_IPV6,
278 .input_index = SRC1_FIELD_IPV6,
279 .offset = offsetof(struct ipv6_5tuple, ip_src[0]),
280 },
281 {
282 .type = RTE_ACL_FIELD_TYPE_MASK,
283 .size = sizeof(uint32_t),
284 .field_index = SRC2_FIELD_IPV6,
285 .input_index = SRC2_FIELD_IPV6,
286 .offset = offsetof(struct ipv6_5tuple, ip_src[1]),
287 },
288 {
289 .type = RTE_ACL_FIELD_TYPE_MASK,
290 .size = sizeof(uint32_t),
291 .field_index = SRC3_FIELD_IPV6,
292 .input_index = SRC3_FIELD_IPV6,
293 .offset = offsetof(struct ipv6_5tuple, ip_src[2]),
294 },
295 {
296 .type = RTE_ACL_FIELD_TYPE_MASK,
297 .size = sizeof(uint32_t),
298 .field_index = SRC4_FIELD_IPV6,
299 .input_index = SRC4_FIELD_IPV6,
300 .offset = offsetof(struct ipv6_5tuple, ip_src[3]),
301 },
302 {
303 .type = RTE_ACL_FIELD_TYPE_MASK,
304 .size = sizeof(uint32_t),
305 .field_index = DST1_FIELD_IPV6,
306 .input_index = DST1_FIELD_IPV6,
307 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
308 },
309 {
310 .type = RTE_ACL_FIELD_TYPE_MASK,
311 .size = sizeof(uint32_t),
312 .field_index = DST2_FIELD_IPV6,
313 .input_index = DST2_FIELD_IPV6,
314 .offset = offsetof(struct ipv6_5tuple, ip_dst[1]),
315 },
316 {
317 .type = RTE_ACL_FIELD_TYPE_MASK,
318 .size = sizeof(uint32_t),
319 .field_index = DST3_FIELD_IPV6,
320 .input_index = DST3_FIELD_IPV6,
321 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
322 },
323 {
324 .type = RTE_ACL_FIELD_TYPE_MASK,
325 .size = sizeof(uint32_t),
326 .field_index = DST4_FIELD_IPV6,
327 .input_index = DST4_FIELD_IPV6,
328 .offset = offsetof(struct ipv6_5tuple, ip_dst[3]),
329 },
330 {
331 .type = RTE_ACL_FIELD_TYPE_RANGE,
332 .size = sizeof(uint16_t),
333 .field_index = SRCP_FIELD_IPV6,
334 .input_index = SRCP_FIELD_IPV6,
335 .offset = offsetof(struct ipv6_5tuple, port_src),
336 },
337 {
338 .type = RTE_ACL_FIELD_TYPE_RANGE,
339 .size = sizeof(uint16_t),
340 .field_index = DSTP_FIELD_IPV6,
341 .input_index = SRCP_FIELD_IPV6,
342 .offset = offsetof(struct ipv6_5tuple, port_dst),
343 },
344};
345
346struct rte_acl_field_def ipv6_u64_defs[NUM_FIELDS_IPV6_U64] = {
347 {
348 .type = RTE_ACL_FIELD_TYPE_BITMASK,
349 .size = sizeof(uint8_t),
350 .field_index = PROTO_FIELD_IPV6_U64,
351 .input_index = PROTO_FIELD_IPV6_U64,
352 .offset = offsetof(struct ipv6_5tuple, proto),
353 },
354 {
355 .type = RTE_ACL_FIELD_TYPE_MASK,
356 .size = sizeof(uint64_t),
357 .field_index = SRC1_FIELD_IPV6_U64,
358 .input_index = SRC1_INDEX_IPV6_U64,
359 .offset = offsetof(struct ipv6_5tuple, ip_src[0]),
360 },
361 {
362 .type = RTE_ACL_FIELD_TYPE_MASK,
363 .size = sizeof(uint64_t),
364 .field_index = SRC2_FIELD_IPV6_U64,
365 .input_index = SRC2_INDEX_IPV6_U64,
366 .offset = offsetof(struct ipv6_5tuple, ip_src[2]),
367 },
368 {
369 .type = RTE_ACL_FIELD_TYPE_MASK,
370 .size = sizeof(uint64_t),
371 .field_index = DST1_FIELD_IPV6_U64,
372 .input_index = DST1_INDEX_IPV6_U64,
373 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
374 },
375 {
376 .type = RTE_ACL_FIELD_TYPE_MASK,
377 .size = sizeof(uint64_t),
378 .field_index = DST2_FIELD_IPV6_U64,
379 .input_index = DST2_INDEX_IPV6_U64,
380 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
381 },
382 {
383 .type = RTE_ACL_FIELD_TYPE_RANGE,
384 .size = sizeof(uint16_t),
385 .field_index = SRCP_FIELD_IPV6_U64,
386 .input_index = PRT_INDEX_IPV6_U64,
387 .offset = offsetof(struct ipv6_5tuple, port_src),
388 },
389 {
390 .type = RTE_ACL_FIELD_TYPE_RANGE,
391 .size = sizeof(uint16_t),
392 .field_index = DSTP_FIELD_IPV6_U64,
393 .input_index = PRT_INDEX_IPV6_U64,
394 .offset = offsetof(struct ipv6_5tuple, port_dst),
395 },
396};
397
398enum {
399 CB_FLD_SRC_ADDR,
400 CB_FLD_DST_ADDR,
401 CB_FLD_SRC_PORT_LOW,
402 CB_FLD_SRC_PORT_DLM,
403 CB_FLD_SRC_PORT_HIGH,
404 CB_FLD_DST_PORT_LOW,
405 CB_FLD_DST_PORT_DLM,
406 CB_FLD_DST_PORT_HIGH,
407 CB_FLD_PROTO,
408 CB_FLD_NUM,
409};
410
411enum {
412 CB_TRC_SRC_ADDR,
413 CB_TRC_DST_ADDR,
414 CB_TRC_SRC_PORT,
415 CB_TRC_DST_PORT,
416 CB_TRC_PROTO,
417 CB_TRC_NUM,
418};
419
420RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
421
422static const char cb_port_delim[] = ":";
423
424static char line[LINE_MAX];
425
426#define dump_verbose(lvl, fh, fmt, args...) do { \
427 if ((lvl) <= (int32_t)config.verbose) \
428 fprintf(fh, fmt, ##args); \
429} while (0)
430
431
432
433
434
435
436
437
438static int
439parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v)
440{
441 int i;
442 char *s, *sp, *in[CB_TRC_NUM];
443 static const char *dlm = " \t\n";
444
445 s = str;
446 for (i = 0; i != RTE_DIM(in); i++) {
447 in[i] = strtok_r(s, dlm, &sp);
448 if (in[i] == NULL)
449 return -EINVAL;
450 s = NULL;
451 }
452
453 GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0);
454 GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0);
455 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
456 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
457 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
458
459
460 v->ip_src = rte_cpu_to_be_32(v->ip_src);
461 v->ip_dst = rte_cpu_to_be_32(v->ip_dst);
462 v->port_src = rte_cpu_to_be_16(v->port_src);
463 v->port_dst = rte_cpu_to_be_16(v->port_dst);
464
465 return 0;
466}
467
468static int
469parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
470{
471 if (inet_pton(AF_INET6, in, v) != 1)
472 return -EINVAL;
473
474 return 0;
475}
476
477
478
479
480
481
482
483static int
484parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v)
485{
486 int32_t i, rc;
487 char *s, *sp, *in[CB_TRC_NUM];
488 static const char *dlm = " \t\n";
489
490 s = str;
491 for (i = 0; i != RTE_DIM(in); i++) {
492 in[i] = strtok_r(s, dlm, &sp);
493 if (in[i] == NULL)
494 return -EINVAL;
495 s = NULL;
496 }
497
498
499 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
500 if (rc != 0)
501 return rc;
502
503
504 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst);
505 if (rc != 0)
506 return rc;
507
508 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
509 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
510 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
511
512
513 v->port_src = rte_cpu_to_be_16(v->port_src);
514 v->port_dst = rte_cpu_to_be_16(v->port_dst);
515
516 return 0;
517}
518
519
520static int
521skip_line(const char *buf)
522{
523 uint32_t i;
524
525 for (i = 0; isspace(buf[i]) != 0; i++)
526 ;
527
528 if (buf[i] == 0 || buf[i] == COMMENT_LEAD_CHAR)
529 return 1;
530
531 return 0;
532}
533
534static void
535tracef_init(void)
536{
537 static const char name[] = APP_NAME;
538 FILE *f;
539 size_t sz;
540 uint32_t i, k, n;
541 struct ipv4_5tuple *v;
542 struct ipv6_5tuple *w;
543
544 sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
545 config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
546 SOCKET_ID_ANY);
547 if (config.traces == NULL)
548 rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for "
549 "requested %u number of trace records\n",
550 sz, config.nb_traces);
551
552 f = fopen(config.trace_file, "r");
553 if (f == NULL)
554 rte_exit(-EINVAL, "failed to open file: %s\n",
555 config.trace_file);
556
557 v = config.traces;
558 w = config.traces;
559 k = 0;
560 n = 0;
561 for (i = 0; n != config.nb_traces; i++) {
562
563 if (fgets(line, sizeof(line), f) == NULL)
564 break;
565
566 if (skip_line(line) != 0) {
567 k++;
568 continue;
569 }
570
571 n = i - k;
572
573 if (config.ipv6) {
574 if (parse_cb_ipv6_trace(line, w + n) != 0)
575 rte_exit(EXIT_FAILURE,
576 "%s: failed to parse ipv6 trace "
577 "record at line %u\n",
578 config.trace_file, i + 1);
579 } else {
580 if (parse_cb_ipv4_trace(line, v + n) != 0)
581 rte_exit(EXIT_FAILURE,
582 "%s: failed to parse ipv4 trace "
583 "record at line %u\n",
584 config.trace_file, i + 1);
585 }
586 }
587
588 config.used_traces = i - k;
589 fclose(f);
590}
591
592static int
593parse_ipv6_u32_net(char *in, struct rte_acl_field field[IPV6_ADDR_U32])
594{
595 char *sa, *sm, *sv;
596 uint32_t i, m, v[IPV6_ADDR_U32];
597
598 const char *dlm = "/";
599 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
600
601
602 sv = NULL;
603 sa = strtok_r(in, dlm, &sv);
604 if (sa == NULL)
605 return -EINVAL;
606 sm = strtok_r(NULL, dlm, &sv);
607 if (sm == NULL)
608 return -EINVAL;
609
610 if (inet_pton(AF_INET6, sa, v) != 1)
611 return -EINVAL;
612
613 v[0] = rte_be_to_cpu_32(v[0]);
614 v[1] = rte_be_to_cpu_32(v[1]);
615 v[2] = rte_be_to_cpu_32(v[2]);
616 v[3] = rte_be_to_cpu_32(v[3]);
617
618
619 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
620
621
622 for (i = 0; i != RTE_DIM(v); i++) {
623 if (m >= (i + 1) * nbu32)
624 field[i].mask_range.u32 = nbu32;
625 else
626 field[i].mask_range.u32 = m > (i * nbu32) ?
627 m - (i * nbu32) : 0;
628
629 field[i].value.u32 = v[i];
630 }
631
632 return 0;
633}
634
635static int
636parse_ipv6_u64_net(char *in, struct rte_acl_field field[IPV6_ADDR_U64])
637{
638 char *sa, *sm, *sv;
639 uint32_t i, m;
640 uint64_t v[IPV6_ADDR_U64];
641
642 const char *dlm = "/";
643 const uint32_t nbu64 = sizeof(uint64_t) * CHAR_BIT;
644
645
646 sv = NULL;
647 sa = strtok_r(in, dlm, &sv);
648 if (sa == NULL)
649 return -EINVAL;
650 sm = strtok_r(NULL, dlm, &sv);
651 if (sm == NULL)
652 return -EINVAL;
653
654 if (inet_pton(AF_INET6, sa, v) != 1)
655 return -EINVAL;
656
657 v[0] = rte_be_to_cpu_64(v[0]);
658 v[1] = rte_be_to_cpu_64(v[1]);
659
660
661 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
662
663
664 for (i = 0; i != RTE_DIM(v); i++) {
665 if (m >= (i + 1) * nbu64)
666 field[i].mask_range.u32 = nbu64;
667 else
668 field[i].mask_range.u32 = m > (i * nbu64) ?
669 m - (i * nbu64) : 0;
670
671 field[i].value.u64 = v[i];
672 }
673
674 return 0;
675}
676
677static int
678parse_cb_ipv6_rule(char *str, struct acl_rule *v, int frmt)
679{
680 int i, rc;
681 uint32_t fidx;
682 const uint32_t *field_map;
683 char *s, *sp, *in[CB_FLD_NUM];
684 int (*parse_ipv6_net)(char *s, struct rte_acl_field f[]);
685
686 static const char *dlm = " \t\n";
687
688 static const uint32_t field_map_u32[CB_FLD_NUM] = {
689 [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6,
690 [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6,
691 [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6,
692 [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6,
693 [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6,
694 [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6,
695 [CB_FLD_PROTO] = PROTO_FIELD_IPV6,
696 };
697
698 static const uint32_t field_map_u64[CB_FLD_NUM] = {
699 [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6_U64,
700 [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6_U64,
701 [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6_U64,
702 [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6_U64,
703 [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6_U64,
704 [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6_U64,
705 [CB_FLD_PROTO] = PROTO_FIELD_IPV6_U64,
706 };
707
708 if (frmt == IPV6_FRMT_U32) {
709 field_map = field_map_u32;
710 parse_ipv6_net = parse_ipv6_u32_net;
711 } else if (frmt == IPV6_FRMT_U64) {
712 field_map = field_map_u64;
713 parse_ipv6_net = parse_ipv6_u64_net;
714 } else
715 return -ENOTSUP;
716
717
718
719
720 if (strchr(str, '@') != str)
721 return -EINVAL;
722
723 s = str + 1;
724
725 for (i = 0; i != RTE_DIM(in); i++) {
726 in[i] = strtok_r(s, dlm, &sp);
727 if (in[i] == NULL)
728 return -EINVAL;
729 s = NULL;
730 }
731
732 fidx = CB_FLD_SRC_ADDR;
733 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
734 if (rc != 0) {
735 RTE_LOG(ERR, TESTACL,
736 "failed to read source address/mask: %s\n", in[fidx]);
737 return rc;
738 }
739
740 fidx = CB_FLD_DST_ADDR;
741 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
742 if (rc != 0) {
743 RTE_LOG(ERR, TESTACL,
744 "failed to read destination address/mask: %s\n",
745 in[fidx]);
746 return rc;
747 }
748
749
750 fidx = CB_FLD_SRC_PORT_LOW;
751 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
752 0, UINT16_MAX, 0);
753
754 fidx = CB_FLD_SRC_PORT_HIGH;
755 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
756 0, UINT16_MAX, 0);
757
758 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
759 sizeof(cb_port_delim)) != 0)
760 return -EINVAL;
761
762
763 fidx = CB_FLD_DST_PORT_LOW;
764 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
765 0, UINT16_MAX, 0);
766
767 fidx = CB_FLD_DST_PORT_HIGH;
768 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
769 0, UINT16_MAX, 0);
770
771 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
772 sizeof(cb_port_delim)) != 0)
773 return -EINVAL;
774
775 fidx = CB_FLD_PROTO;
776 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u8,
777 0, UINT8_MAX, '/');
778 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u8,
779 0, UINT8_MAX, 0);
780
781 return 0;
782}
783
784static int
785parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v)
786{
787 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32);
788}
789
790static int
791parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v)
792{
793 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64);
794}
795
796static int
797parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
798{
799 char *sa, *sm, *sv;
800 uint32_t m, v;
801
802 const char *dlm = "/";
803
804 sv = NULL;
805 sa = strtok_r(in, dlm, &sv);
806 if (sa == NULL)
807 return -EINVAL;
808 sm = strtok_r(NULL, dlm, &sv);
809 if (sm == NULL)
810 return -EINVAL;
811
812 if (inet_pton(AF_INET, sa, &v) != 1)
813 return -EINVAL;
814
815 addr[0] = rte_be_to_cpu_32(v);
816
817 GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
818 mask_len[0] = m;
819
820 return 0;
821}
822
823
824
825
826
827
828
829
830
831static int
832parse_cb_ipv4_rule(char *str, struct acl_rule *v)
833{
834 int i, rc;
835 char *s, *sp, *in[CB_FLD_NUM];
836 static const char *dlm = " \t\n";
837
838
839
840
841 if (strchr(str, '@') != str)
842 return -EINVAL;
843
844 s = str + 1;
845
846 for (i = 0; i != RTE_DIM(in); i++) {
847 in[i] = strtok_r(s, dlm, &sp);
848 if (in[i] == NULL)
849 return -EINVAL;
850 s = NULL;
851 }
852
853 rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
854 &v->field[SRC_FIELD_IPV4].value.u32,
855 &v->field[SRC_FIELD_IPV4].mask_range.u32);
856 if (rc != 0) {
857 RTE_LOG(ERR, TESTACL,
858 "failed to read source address/mask: %s\n",
859 in[CB_FLD_SRC_ADDR]);
860 return rc;
861 }
862
863 rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
864 &v->field[DST_FIELD_IPV4].value.u32,
865 &v->field[DST_FIELD_IPV4].mask_range.u32);
866 if (rc != 0) {
867 RTE_LOG(ERR, TESTACL,
868 "failed to read destination address/mask: %s\n",
869 in[CB_FLD_DST_ADDR]);
870 return rc;
871 }
872
873
874 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
875 v->field[SRCP_FIELD_IPV4].value.u16,
876 0, UINT16_MAX, 0);
877 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
878 v->field[SRCP_FIELD_IPV4].mask_range.u16,
879 0, UINT16_MAX, 0);
880
881 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
882 sizeof(cb_port_delim)) != 0)
883 return -EINVAL;
884
885
886 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
887 v->field[DSTP_FIELD_IPV4].value.u16,
888 0, UINT16_MAX, 0);
889 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
890 v->field[DSTP_FIELD_IPV4].mask_range.u16,
891 0, UINT16_MAX, 0);
892
893 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
894 sizeof(cb_port_delim)) != 0)
895 return -EINVAL;
896
897 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8,
898 0, UINT8_MAX, '/');
899 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8,
900 0, UINT8_MAX, 0);
901
902 return 0;
903}
904
905typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
906
907static int
908add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
909{
910 int rc;
911 uint32_t i, k, n;
912 struct acl_rule v;
913 parse_5tuple parser;
914
915 static const parse_5tuple parser_func[] = {
916 [IPV6_FRMT_NONE] = parse_cb_ipv4_rule,
917 [IPV6_FRMT_U32] = parse_cb_ipv6_u32_rule,
918 [IPV6_FRMT_U64] = parse_cb_ipv6_u64_rule,
919 };
920
921 memset(&v, 0, sizeof(v));
922 parser = parser_func[config.ipv6];
923
924 k = 0;
925 for (i = 1; fgets(line, sizeof(line), f) != NULL; i++) {
926
927 if (skip_line(line) != 0) {
928 k++;
929 continue;
930 }
931
932 n = i - k;
933 rc = parser(line, &v);
934 if (rc != 0) {
935 RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
936 " failed, error code: %d (%s)\n",
937 i, rc, strerror(-rc));
938 return rc;
939 }
940
941 v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES,
942 typeof(v.data.category_mask));
943 v.data.priority = RTE_ACL_MAX_PRIORITY - n;
944 v.data.userdata = n;
945
946 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1);
947 if (rc != 0) {
948 RTE_LOG(ERR, TESTACL, "line %u: failed to add rules "
949 "into ACL context, error code: %d (%s)\n",
950 i, rc, strerror(-rc));
951 return rc;
952 }
953 }
954
955 return 0;
956}
957
958static void
959acx_init(void)
960{
961 int ret;
962 FILE *f;
963 struct rte_acl_config cfg;
964
965 memset(&cfg, 0, sizeof(cfg));
966
967
968 if (config.ipv6 == IPV6_FRMT_U32) {
969 cfg.num_fields = RTE_DIM(ipv6_defs);
970 memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs));
971 } else if (config.ipv6 == IPV6_FRMT_U64) {
972 cfg.num_fields = RTE_DIM(ipv6_u64_defs);
973 memcpy(&cfg.defs, ipv6_u64_defs, sizeof(ipv6_u64_defs));
974 } else {
975 cfg.num_fields = RTE_DIM(ipv4_defs);
976 memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
977 }
978 cfg.num_categories = config.bld_categories;
979 cfg.max_size = config.max_size;
980
981
982 prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
983 prm.max_rule_num = config.nb_rules;
984
985 config.acx = rte_acl_create(&prm);
986 if (config.acx == NULL)
987 rte_exit(rte_errno, "failed to create ACL context\n");
988
989
990 if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) {
991 ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg);
992 if (ret != 0)
993 rte_exit(ret, "failed to setup %s method "
994 "for ACL context\n", config.alg.name);
995 }
996
997
998 f = fopen(config.rule_file, "r");
999 if (f == NULL)
1000 rte_exit(-EINVAL, "failed to open file %s\n",
1001 config.rule_file);
1002
1003 ret = add_cb_rules(f, config.acx);
1004 if (ret != 0)
1005 rte_exit(ret, "failed to add rules into ACL context\n");
1006
1007 fclose(f);
1008
1009
1010 ret = rte_acl_build(config.acx, &cfg);
1011
1012 dump_verbose(DUMP_NONE, stdout,
1013 "rte_acl_build(%u) finished with %d\n",
1014 config.bld_categories, ret);
1015
1016 rte_acl_dump(config.acx);
1017
1018 if (ret != 0)
1019 rte_exit(ret, "failed to build search context\n");
1020}
1021
1022static uint32_t
1023search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
1024{
1025 int ret;
1026 uint32_t i, j, k, n, r;
1027 const uint8_t *data[step], *v;
1028 uint32_t results[step * categories];
1029
1030 v = config.traces;
1031 for (i = 0; i != config.used_traces; i += n) {
1032
1033 n = RTE_MIN(step, config.used_traces - i);
1034
1035 for (j = 0; j != n; j++) {
1036 data[j] = v;
1037 v += config.trace_sz;
1038 }
1039
1040 ret = rte_acl_classify(config.acx, data, results,
1041 n, categories);
1042
1043 if (ret != 0)
1044 rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
1045 config.ipv6 ? '6' : '4', ret);
1046
1047 for (r = 0, j = 0; j != n; j++) {
1048 for (k = 0; k != categories; k++, r++) {
1049 dump_verbose(DUMP_PKT, stdout,
1050 "ipv%c_5tuple: %u, category: %u, "
1051 "result: %u\n",
1052 config.ipv6 ? '6' : '4',
1053 i + j + 1, k, results[r] - 1);
1054 }
1055
1056 }
1057 }
1058
1059 dump_verbose(DUMP_SEARCH, stdout,
1060 "%s(%u, %u, %s) returns %u\n", __func__,
1061 categories, step, alg, i);
1062 return i;
1063}
1064
1065static int
1066search_ip5tuples(__rte_unused void *arg)
1067{
1068 uint64_t pkt, start, tm;
1069 uint32_t i, lcore;
1070 long double st;
1071
1072 lcore = rte_lcore_id();
1073 start = rte_rdtsc_precise();
1074 pkt = 0;
1075
1076 for (i = 0; i != config.iter_num; i++) {
1077 pkt += search_ip5tuples_once(config.run_categories,
1078 config.trace_step, config.alg.name);
1079 }
1080
1081 tm = rte_rdtsc_precise() - start;
1082
1083 st = (long double)tm / rte_get_timer_hz();
1084 dump_verbose(DUMP_NONE, stdout,
1085 "%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %"
1086 PRIu32 " categories, %" PRIu64 " cycles (%.2Lf sec), "
1087 "%.2Lf cycles/pkt, %.2Lf pkt/sec\n",
1088 __func__, lcore, i, pkt,
1089 config.run_categories, tm, st,
1090 (pkt == 0) ? 0 : (long double)tm / pkt, pkt / st);
1091
1092 return 0;
1093}
1094
1095static unsigned long
1096get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
1097{
1098 unsigned long val;
1099 char *end;
1100
1101 errno = 0;
1102 val = strtoul(opt, &end, 0);
1103 if (errno != 0 || end[0] != 0 || val > max || val < min)
1104 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
1105 opt, name);
1106 return val;
1107}
1108
1109static void
1110get_alg_opt(const char *opt, const char *name)
1111{
1112 uint32_t i;
1113
1114 for (i = 0; i != RTE_DIM(acl_alg); i++) {
1115 if (strcmp(opt, acl_alg[i].name) == 0) {
1116 config.alg = acl_alg[i];
1117 return;
1118 }
1119 }
1120
1121 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
1122 opt, name);
1123}
1124
1125static void
1126get_ipv6_opt(const char *opt, const char *name)
1127{
1128 uint32_t i;
1129
1130 static const struct {
1131 const char *name;
1132 uint32_t val;
1133 } ipv6_opt[] = {
1134 {
1135 .name = "4B",
1136 .val = IPV6_FRMT_U32,
1137 },
1138 {
1139 .name = "8B",
1140 .val = IPV6_FRMT_U64,
1141 },
1142 };
1143
1144 for (i = 0; i != RTE_DIM(ipv6_opt); i++) {
1145 if (strcmp(opt, ipv6_opt[i].name) == 0) {
1146 config.ipv6 = ipv6_opt[i].val;
1147 return;
1148 }
1149 }
1150
1151 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
1152 opt, name);
1153}
1154
1155
1156static void
1157print_usage(const char *prgname)
1158{
1159 uint32_t i, n, rc;
1160 char buf[PATH_MAX];
1161
1162 n = 0;
1163 buf[0] = 0;
1164
1165 for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
1166 rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
1167 acl_alg[i].name);
1168 if (rc > sizeof(buf) - n)
1169 break;
1170 n += rc;
1171 }
1172
1173 strlcpy(buf + n, acl_alg[i].name, sizeof(buf) - n);
1174
1175 fprintf(stdout,
1176 PRINT_USAGE_START
1177 "--" OPT_RULE_FILE "=<rules set file>\n"
1178 "[--" OPT_TRACE_FILE "=<input traces file>]\n"
1179 "[--" OPT_RULE_NUM
1180 "=<maximum number of rules for ACL context>]\n"
1181 "[--" OPT_TRACE_NUM
1182 "=<number of traces to read binary file in>]\n"
1183 "[--" OPT_TRACE_STEP
1184 "=<number of traces to classify per one call>]\n"
1185 "[--" OPT_BLD_CATEGORIES
1186 "=<number of categories to build with>]\n"
1187 "[--" OPT_RUN_CATEGORIES
1188 "=<number of categories to run with> "
1189 "should be either 1 or multiple of %zu, "
1190 "but not greater then %u]\n"
1191 "[--" OPT_MAX_SIZE
1192 "=<size limit (in bytes) for runtime ACL structures> "
1193 "leave 0 for default behaviour]\n"
1194 "[--" OPT_ITER_NUM "=<number of iterations to perform>]\n"
1195 "[--" OPT_VERBOSE "=<verbose level>]\n"
1196 "[--" OPT_SEARCH_ALG "=%s]\n"
1197 "[--" OPT_IPV6 "(=4B | 8B) <IPv6 rules and trace files>]\n",
1198 prgname, RTE_ACL_RESULTS_MULTIPLIER,
1199 (uint32_t)RTE_ACL_MAX_CATEGORIES,
1200 buf);
1201}
1202
1203static void
1204dump_config(FILE *f)
1205{
1206 fprintf(f, "%s:\n", __func__);
1207 fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file);
1208 fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file);
1209 fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules);
1210 fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces);
1211 fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step);
1212 fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories);
1213 fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories);
1214 fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size);
1215 fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num);
1216 fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose);
1217 fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg,
1218 config.alg.name);
1219 fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
1220}
1221
1222static void
1223check_config(void)
1224{
1225 if (config.rule_file == NULL) {
1226 print_usage(config.prgname);
1227 rte_exit(-EINVAL, "mandatory option %s is not specified\n",
1228 OPT_RULE_FILE);
1229 }
1230}
1231
1232
1233static void
1234get_input_opts(int argc, char **argv)
1235{
1236 static struct option lgopts[] = {
1237 {OPT_RULE_FILE, 1, 0, 0},
1238 {OPT_TRACE_FILE, 1, 0, 0},
1239 {OPT_TRACE_NUM, 1, 0, 0},
1240 {OPT_RULE_NUM, 1, 0, 0},
1241 {OPT_MAX_SIZE, 1, 0, 0},
1242 {OPT_TRACE_STEP, 1, 0, 0},
1243 {OPT_BLD_CATEGORIES, 1, 0, 0},
1244 {OPT_RUN_CATEGORIES, 1, 0, 0},
1245 {OPT_ITER_NUM, 1, 0, 0},
1246 {OPT_VERBOSE, 1, 0, 0},
1247 {OPT_SEARCH_ALG, 1, 0, 0},
1248 {OPT_IPV6, 2, 0, 0},
1249 {NULL, 0, 0, 0}
1250 };
1251
1252 int opt, opt_idx;
1253
1254 while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
1255
1256 if (opt != 0) {
1257 print_usage(config.prgname);
1258 rte_exit(-EINVAL, "unknown option: %c", opt);
1259 }
1260
1261 if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) {
1262 config.rule_file = optarg;
1263 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) {
1264 config.trace_file = optarg;
1265 } else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) {
1266 config.nb_rules = get_ulong_opt(optarg,
1267 lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1);
1268 } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) {
1269 config.max_size = get_ulong_opt(optarg,
1270 lgopts[opt_idx].name, 0, SIZE_MAX);
1271 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) {
1272 config.nb_traces = get_ulong_opt(optarg,
1273 lgopts[opt_idx].name, 1, UINT32_MAX);
1274 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) {
1275 config.trace_step = get_ulong_opt(optarg,
1276 lgopts[opt_idx].name, 1, TRACE_STEP_MAX);
1277 } else if (strcmp(lgopts[opt_idx].name,
1278 OPT_BLD_CATEGORIES) == 0) {
1279 config.bld_categories = get_ulong_opt(optarg,
1280 lgopts[opt_idx].name, 1,
1281 RTE_ACL_MAX_CATEGORIES);
1282 } else if (strcmp(lgopts[opt_idx].name,
1283 OPT_RUN_CATEGORIES) == 0) {
1284 config.run_categories = get_ulong_opt(optarg,
1285 lgopts[opt_idx].name, 1,
1286 RTE_ACL_MAX_CATEGORIES);
1287 } else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) {
1288 config.iter_num = get_ulong_opt(optarg,
1289 lgopts[opt_idx].name, 1, INT32_MAX);
1290 } else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) {
1291 config.verbose = get_ulong_opt(optarg,
1292 lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX);
1293 } else if (strcmp(lgopts[opt_idx].name,
1294 OPT_SEARCH_ALG) == 0) {
1295 get_alg_opt(optarg, lgopts[opt_idx].name);
1296 } else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) {
1297 config.ipv6 = IPV6_FRMT_U32;
1298 if (optarg != NULL)
1299 get_ipv6_opt(optarg, lgopts[opt_idx].name);
1300 }
1301 }
1302 config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
1303 sizeof(struct ipv4_5tuple);
1304
1305}
1306
1307int
1308main(int argc, char **argv)
1309{
1310 int ret;
1311 uint32_t lcore;
1312
1313 ret = rte_eal_init(argc, argv);
1314 if (ret < 0)
1315 rte_panic("Cannot init EAL\n");
1316
1317 argc -= ret;
1318 argv += ret;
1319
1320 config.prgname = argv[0];
1321
1322 get_input_opts(argc, argv);
1323 dump_config(stdout);
1324 check_config();
1325
1326 acx_init();
1327
1328 if (config.trace_file != NULL)
1329 tracef_init();
1330
1331 RTE_LCORE_FOREACH_WORKER(lcore)
1332 rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
1333
1334 search_ip5tuples(NULL);
1335
1336 rte_eal_mp_wait_lcore();
1337
1338 rte_acl_free(config.acx);
1339 return 0;
1340}
1341