net/nfp: rename set MAC function
[dpdk.git] / app / test-acl / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
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
53 enum {
54         DUMP_NONE,
55         DUMP_SEARCH,
56         DUMP_PKT,
57         DUMP_MAX
58 };
59
60 enum {
61         IPV6_FRMT_NONE,
62         IPV6_FRMT_U32,
63         IPV6_FRMT_U64,
64 };
65
66 struct acl_alg {
67         const char *name;
68         enum rte_acl_classify_alg alg;
69 };
70
71 static 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
102 static 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
135 static struct rte_acl_param prm = {
136         .name = APP_NAME,
137         .socket_id = SOCKET_ID_ANY,
138 };
139
140 /*
141  * Rule and trace formats definitions.
142  */
143
144 struct 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
152 enum {
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  * That effectively defines order of IPV4VLAN classifications:
163  *  - PROTO
164  *  - VLAN (TAG and DOMAIN)
165  *  - SRC IP ADDRESS
166  *  - DST IP ADDRESS
167  *  - PORTS (SRC and DST)
168  */
169 enum {
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
178 struct 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
221 struct 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 /* treat IPV6 address as uint32_t[4] (default mode) */
230 enum {
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 /* treat IPV6 address as uint64_t[2] (default mode) */
246 enum {
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
257 enum {
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
266 struct 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
346 struct 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
398 enum {
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
411 enum {
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
420 RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
421
422 static const char cb_port_delim[] = ":";
423
424 static 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  * Parse ClassBench input trace (test vectors and expected results) file.
434  * Expected format:
435  * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \
436  * <src_port> <space> <dst_port> <space> <proto>
437  */
438 static int
439 parse_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         /* convert to network byte order. */
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
468 static int
469 parse_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  * Parse ClassBench input trace (test vectors and expected results) file.
479  * Expected format:
480  * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \
481  * <src_port> <space> <dst_port> <space> <proto>
482  */
483 static int
484 parse_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         /* get ip6 src address. */
499         rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
500         if (rc != 0)
501                 return rc;
502
503         /* get ip6 dst address. */
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         /* convert to network byte order. */
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 /* Bypass comment and empty lines */
520 static int
521 skip_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
534 static void
535 tracef_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
592 static int
593 parse_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         /* get address. */
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         /* get mask. */
619         GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
620
621         /* put all together. */
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
635 static int
636 parse_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         /* get address. */
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         /* get mask. */
661         GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
662
663         /* put all together. */
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
677 static int
678 parse_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          * Skip leading '@'
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         /* source port. */
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         /* destination port. */
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
784 static int
785 parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v)
786 {
787         return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32);
788 }
789
790 static int
791 parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v)
792 {
793         return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64);
794 }
795
796 static int
797 parse_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  * Parse ClassBench rules file.
824  * Expected format:
825  * '@'<src_ipv4_addr>'/'<masklen> <space> \
826  * <dst_ipv4_addr>'/'<masklen> <space> \
827  * <src_port_low> <space> ":" <src_port_high> <space> \
828  * <dst_port_low> <space> ":" <dst_port_high> <space> \
829  * <proto>'/'<mask>
830  */
831 static int
832 parse_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          * Skip leading '@'
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         /* source port. */
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         /* destination port. */
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
905 typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
906
907 static int
908 add_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
958 static void
959 acx_init(void)
960 {
961         int ret;
962         FILE *f;
963         struct rte_acl_config cfg;
964
965         memset(&cfg, 0, sizeof(cfg));
966
967         /* setup ACL build config. */
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         /* setup ACL creation parameters. */
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         /* set default classify method for this context. */
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         /* add ACL rules. */
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         /* perform build. */
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
1022 static uint32_t
1023 search_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
1065 static int
1066 search_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
1095 static unsigned long
1096 get_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
1109 static void
1110 get_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
1125 static void
1126 get_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
1156 static void
1157 print_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
1203 static void
1204 dump_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
1222 static void
1223 check_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
1233 static void
1234 get_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
1307 int
1308 main(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 }