1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
9 #include <rte_cycles.h>
10 #include <rte_per_lcore.h>
11 #include <rte_lcore.h>
14 #define PRINT_USAGE_START "%s [EAL options]\n"
16 #define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1
18 #define APP_NAME "TESTACL"
20 #define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
24 val = strtoul((in), &end_fld, (base)); \
25 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
27 (fd) = (typeof(fd))val; \
31 #define OPT_RULE_FILE "rulesf"
32 #define OPT_TRACE_FILE "tracef"
33 #define OPT_RULE_NUM "rulenum"
34 #define OPT_TRACE_NUM "tracenum"
35 #define OPT_TRACE_STEP "tracestep"
36 #define OPT_SEARCH_ALG "alg"
37 #define OPT_BLD_CATEGORIES "bldcat"
38 #define OPT_RUN_CATEGORIES "runcat"
39 #define OPT_MAX_SIZE "maxsize"
40 #define OPT_ITER_NUM "iter"
41 #define OPT_VERBOSE "verbose"
42 #define OPT_IPV6 "ipv6"
44 #define TRACE_DEFAULT_NUM 0x10000
45 #define TRACE_STEP_MAX 0x1000
46 #define TRACE_STEP_DEF 0x100
48 #define RULE_NUM 0x10000
59 enum rte_acl_classify_alg alg;
62 static const struct acl_alg acl_alg[] = {
65 .alg = RTE_ACL_CLASSIFY_SCALAR,
69 .alg = RTE_ACL_CLASSIFY_SSE,
73 .alg = RTE_ACL_CLASSIFY_AVX2,
77 .alg = RTE_ACL_CLASSIFY_NEON,
81 .alg = RTE_ACL_CLASSIFY_ALTIVEC,
87 const char *rule_file;
88 const char *trace_file;
90 uint32_t bld_categories;
91 uint32_t run_categories;
100 uint32_t used_traces;
102 struct rte_acl_ctx *acx;
106 .nb_rules = RULE_NUM,
107 .nb_traces = TRACE_DEFAULT_NUM,
108 .trace_step = TRACE_STEP_DEF,
113 .alg = RTE_ACL_CLASSIFY_DEFAULT,
118 static struct rte_acl_param prm = {
120 .socket_id = SOCKET_ID_ANY,
124 * Rule and trace formats definitions.
145 * That effectively defines order of IPV4VLAN classifications:
147 * - VLAN (TAG and DOMAIN)
150 * - PORTS (SRC and DST)
153 RTE_ACL_IPV4VLAN_PROTO,
154 RTE_ACL_IPV4VLAN_VLAN,
155 RTE_ACL_IPV4VLAN_SRC,
156 RTE_ACL_IPV4VLAN_DST,
157 RTE_ACL_IPV4VLAN_PORTS,
161 struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
163 .type = RTE_ACL_FIELD_TYPE_BITMASK,
164 .size = sizeof(uint8_t),
165 .field_index = PROTO_FIELD_IPV4,
166 .input_index = RTE_ACL_IPV4VLAN_PROTO,
167 .offset = offsetof(struct ipv4_5tuple, proto),
170 .type = RTE_ACL_FIELD_TYPE_MASK,
171 .size = sizeof(uint32_t),
172 .field_index = SRC_FIELD_IPV4,
173 .input_index = RTE_ACL_IPV4VLAN_SRC,
174 .offset = offsetof(struct ipv4_5tuple, ip_src),
177 .type = RTE_ACL_FIELD_TYPE_MASK,
178 .size = sizeof(uint32_t),
179 .field_index = DST_FIELD_IPV4,
180 .input_index = RTE_ACL_IPV4VLAN_DST,
181 .offset = offsetof(struct ipv4_5tuple, ip_dst),
184 .type = RTE_ACL_FIELD_TYPE_RANGE,
185 .size = sizeof(uint16_t),
186 .field_index = SRCP_FIELD_IPV4,
187 .input_index = RTE_ACL_IPV4VLAN_PORTS,
188 .offset = offsetof(struct ipv4_5tuple, port_src),
191 .type = RTE_ACL_FIELD_TYPE_RANGE,
192 .size = sizeof(uint16_t),
193 .field_index = DSTP_FIELD_IPV4,
194 .input_index = RTE_ACL_IPV4VLAN_PORTS,
195 .offset = offsetof(struct ipv4_5tuple, port_dst),
199 #define IPV6_ADDR_LEN 16
200 #define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t))
201 #define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t))
205 uint32_t ip_src[IPV6_ADDR_U32];
206 uint32_t ip_dst[IPV6_ADDR_U32];
226 struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
228 .type = RTE_ACL_FIELD_TYPE_BITMASK,
229 .size = sizeof(uint8_t),
230 .field_index = PROTO_FIELD_IPV6,
231 .input_index = PROTO_FIELD_IPV6,
232 .offset = offsetof(struct ipv6_5tuple, proto),
235 .type = RTE_ACL_FIELD_TYPE_MASK,
236 .size = sizeof(uint32_t),
237 .field_index = SRC1_FIELD_IPV6,
238 .input_index = SRC1_FIELD_IPV6,
239 .offset = offsetof(struct ipv6_5tuple, ip_src[0]),
242 .type = RTE_ACL_FIELD_TYPE_MASK,
243 .size = sizeof(uint32_t),
244 .field_index = SRC2_FIELD_IPV6,
245 .input_index = SRC2_FIELD_IPV6,
246 .offset = offsetof(struct ipv6_5tuple, ip_src[1]),
249 .type = RTE_ACL_FIELD_TYPE_MASK,
250 .size = sizeof(uint32_t),
251 .field_index = SRC3_FIELD_IPV6,
252 .input_index = SRC3_FIELD_IPV6,
253 .offset = offsetof(struct ipv6_5tuple, ip_src[2]),
256 .type = RTE_ACL_FIELD_TYPE_MASK,
257 .size = sizeof(uint32_t),
258 .field_index = SRC4_FIELD_IPV6,
259 .input_index = SRC4_FIELD_IPV6,
260 .offset = offsetof(struct ipv6_5tuple, ip_src[3]),
263 .type = RTE_ACL_FIELD_TYPE_MASK,
264 .size = sizeof(uint32_t),
265 .field_index = DST1_FIELD_IPV6,
266 .input_index = DST1_FIELD_IPV6,
267 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
270 .type = RTE_ACL_FIELD_TYPE_MASK,
271 .size = sizeof(uint32_t),
272 .field_index = DST2_FIELD_IPV6,
273 .input_index = DST2_FIELD_IPV6,
274 .offset = offsetof(struct ipv6_5tuple, ip_dst[1]),
277 .type = RTE_ACL_FIELD_TYPE_MASK,
278 .size = sizeof(uint32_t),
279 .field_index = DST3_FIELD_IPV6,
280 .input_index = DST3_FIELD_IPV6,
281 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
284 .type = RTE_ACL_FIELD_TYPE_MASK,
285 .size = sizeof(uint32_t),
286 .field_index = DST4_FIELD_IPV6,
287 .input_index = DST4_FIELD_IPV6,
288 .offset = offsetof(struct ipv6_5tuple, ip_dst[3]),
291 .type = RTE_ACL_FIELD_TYPE_RANGE,
292 .size = sizeof(uint16_t),
293 .field_index = SRCP_FIELD_IPV6,
294 .input_index = SRCP_FIELD_IPV6,
295 .offset = offsetof(struct ipv6_5tuple, port_src),
298 .type = RTE_ACL_FIELD_TYPE_RANGE,
299 .size = sizeof(uint16_t),
300 .field_index = DSTP_FIELD_IPV6,
301 .input_index = SRCP_FIELD_IPV6,
302 .offset = offsetof(struct ipv6_5tuple, port_dst),
312 CB_FLD_SRC_PORT_HIGH,
315 CB_FLD_DST_PORT_HIGH,
329 RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
331 static const char cb_port_delim[] = ":";
333 static char line[LINE_MAX];
335 #define dump_verbose(lvl, fh, fmt, args...) do { \
336 if ((lvl) <= (int32_t)config.verbose) \
337 fprintf(fh, fmt, ##args); \
342 * Parse ClassBench input trace (test vectors and expected results) file.
344 * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \
345 * <src_port> <space> <dst_port> <space> <proto>
348 parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v)
351 char *s, *sp, *in[CB_TRC_NUM];
352 static const char *dlm = " \t\n";
355 for (i = 0; i != RTE_DIM(in); i++) {
356 in[i] = strtok_r(s, dlm, &sp);
362 GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0);
363 GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0);
364 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
365 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
366 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
368 /* convert to network byte order. */
369 v->ip_src = rte_cpu_to_be_32(v->ip_src);
370 v->ip_dst = rte_cpu_to_be_32(v->ip_dst);
371 v->port_src = rte_cpu_to_be_16(v->port_src);
372 v->port_dst = rte_cpu_to_be_16(v->port_dst);
378 * Parses IPV6 address, exepcts the following format:
379 * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X - is a hexedecimal digit).
382 parse_ipv6_addr(const char *in, const char **end, uint32_t v[IPV6_ADDR_U32],
385 uint32_t addr[IPV6_ADDR_U16];
387 GET_CB_FIELD(in, addr[0], 16, UINT16_MAX, ':');
388 GET_CB_FIELD(in, addr[1], 16, UINT16_MAX, ':');
389 GET_CB_FIELD(in, addr[2], 16, UINT16_MAX, ':');
390 GET_CB_FIELD(in, addr[3], 16, UINT16_MAX, ':');
391 GET_CB_FIELD(in, addr[4], 16, UINT16_MAX, ':');
392 GET_CB_FIELD(in, addr[5], 16, UINT16_MAX, ':');
393 GET_CB_FIELD(in, addr[6], 16, UINT16_MAX, ':');
394 GET_CB_FIELD(in, addr[7], 16, UINT16_MAX, dlm);
398 v[0] = (addr[0] << 16) + addr[1];
399 v[1] = (addr[2] << 16) + addr[3];
400 v[2] = (addr[4] << 16) + addr[5];
401 v[3] = (addr[6] << 16) + addr[7];
407 parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
412 rc = parse_ipv6_addr(in, &end, v, 0);
416 v[0] = rte_cpu_to_be_32(v[0]);
417 v[1] = rte_cpu_to_be_32(v[1]);
418 v[2] = rte_cpu_to_be_32(v[2]);
419 v[3] = rte_cpu_to_be_32(v[3]);
425 * Parse ClassBench input trace (test vectors and expected results) file.
427 * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \
428 * <src_port> <space> <dst_port> <space> <proto>
431 parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v)
434 char *s, *sp, *in[CB_TRC_NUM];
435 static const char *dlm = " \t\n";
438 for (i = 0; i != RTE_DIM(in); i++) {
439 in[i] = strtok_r(s, dlm, &sp);
445 /* get ip6 src address. */
446 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
450 /* get ip6 dst address. */
451 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst);
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);
459 /* convert to network byte order. */
460 v->port_src = rte_cpu_to_be_16(v->port_src);
461 v->port_dst = rte_cpu_to_be_16(v->port_dst);
469 static const char name[] = APP_NAME;
473 struct ipv4_5tuple *v;
474 struct ipv6_5tuple *w;
476 sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
477 config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
479 if (config.traces == NULL)
480 rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for "
481 "requested %u number of trace records\n",
482 sz, config.nb_traces);
484 f = fopen(config.trace_file, "r");
486 rte_exit(-EINVAL, "failed to open file: %s\n",
491 for (n = 0; n != config.nb_traces; n++) {
493 if (fgets(line, sizeof(line), f) == NULL)
497 if (parse_cb_ipv6_trace(line, w + n) != 0)
498 rte_exit(EXIT_FAILURE,
499 "%s: failed to parse ipv6 trace "
500 "record at line %u\n",
501 config.trace_file, n + 1);
503 if (parse_cb_ipv4_trace(line, v + n) != 0)
504 rte_exit(EXIT_FAILURE,
505 "%s: failed to parse ipv4 trace "
506 "record at line %u\n",
507 config.trace_file, n + 1);
511 config.used_traces = n;
516 parse_ipv6_net(const char *in, struct rte_acl_field field[4])
521 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
524 rc = parse_ipv6_addr(in, &mp, v, '/');
529 GET_CB_FIELD(mp, m, 0, CHAR_BIT * sizeof(v), 0);
531 /* put all together. */
532 for (i = 0; i != RTE_DIM(v); i++) {
533 if (m >= (i + 1) * nbu32)
534 field[i].mask_range.u32 = nbu32;
536 field[i].mask_range.u32 = m > (i * nbu32) ?
539 field[i].value.u32 = v[i];
547 parse_cb_ipv6_rule(char *str, struct acl_rule *v)
550 char *s, *sp, *in[CB_FLD_NUM];
551 static const char *dlm = " \t\n";
556 if (strchr(str, '@') != str)
561 for (i = 0; i != RTE_DIM(in); i++) {
562 in[i] = strtok_r(s, dlm, &sp);
568 rc = parse_ipv6_net(in[CB_FLD_SRC_ADDR], v->field + SRC1_FIELD_IPV6);
570 RTE_LOG(ERR, TESTACL,
571 "failed to read source address/mask: %s\n",
572 in[CB_FLD_SRC_ADDR]);
576 rc = parse_ipv6_net(in[CB_FLD_DST_ADDR], v->field + DST1_FIELD_IPV6);
578 RTE_LOG(ERR, TESTACL,
579 "failed to read destination address/mask: %s\n",
580 in[CB_FLD_DST_ADDR]);
585 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
586 v->field[SRCP_FIELD_IPV6].value.u16,
588 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
589 v->field[SRCP_FIELD_IPV6].mask_range.u16,
592 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
593 sizeof(cb_port_delim)) != 0)
596 /* destination port. */
597 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
598 v->field[DSTP_FIELD_IPV6].value.u16,
600 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
601 v->field[DSTP_FIELD_IPV6].mask_range.u16,
604 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
605 sizeof(cb_port_delim)) != 0)
608 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].value.u8,
610 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].mask_range.u8,
617 parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len)
619 uint8_t a, b, c, d, m;
621 GET_CB_FIELD(in, a, 0, UINT8_MAX, '.');
622 GET_CB_FIELD(in, b, 0, UINT8_MAX, '.');
623 GET_CB_FIELD(in, c, 0, UINT8_MAX, '.');
624 GET_CB_FIELD(in, d, 0, UINT8_MAX, '/');
625 GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
627 addr[0] = IPv4(a, b, c, d);
633 * Parse ClassBench rules file.
635 * '@'<src_ipv4_addr>'/'<masklen> <space> \
636 * <dst_ipv4_addr>'/'<masklen> <space> \
637 * <src_port_low> <space> ":" <src_port_high> <space> \
638 * <dst_port_low> <space> ":" <dst_port_high> <space> \
642 parse_cb_ipv4_rule(char *str, struct acl_rule *v)
645 char *s, *sp, *in[CB_FLD_NUM];
646 static const char *dlm = " \t\n";
651 if (strchr(str, '@') != str)
656 for (i = 0; i != RTE_DIM(in); i++) {
657 in[i] = strtok_r(s, dlm, &sp);
663 rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
664 &v->field[SRC_FIELD_IPV4].value.u32,
665 &v->field[SRC_FIELD_IPV4].mask_range.u32);
667 RTE_LOG(ERR, TESTACL,
668 "failed to read source address/mask: %s\n",
669 in[CB_FLD_SRC_ADDR]);
673 rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
674 &v->field[DST_FIELD_IPV4].value.u32,
675 &v->field[DST_FIELD_IPV4].mask_range.u32);
677 RTE_LOG(ERR, TESTACL,
678 "failed to read destination address/mask: %s\n",
679 in[CB_FLD_DST_ADDR]);
684 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
685 v->field[SRCP_FIELD_IPV4].value.u16,
687 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
688 v->field[SRCP_FIELD_IPV4].mask_range.u16,
691 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
692 sizeof(cb_port_delim)) != 0)
695 /* destination port. */
696 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
697 v->field[DSTP_FIELD_IPV4].value.u16,
699 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
700 v->field[DSTP_FIELD_IPV4].mask_range.u16,
703 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
704 sizeof(cb_port_delim)) != 0)
707 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8,
709 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8,
715 typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
718 add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
725 memset(&v, 0, sizeof(v));
726 parser = (config.ipv6 != 0) ? parse_cb_ipv6_rule : parse_cb_ipv4_rule;
728 for (n = 1; fgets(line, sizeof(line), f) != NULL; n++) {
730 rc = parser(line, &v);
732 RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
733 " failed, error code: %d (%s)\n",
734 n, rc, strerror(-rc));
738 v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES,
739 typeof(v.data.category_mask));
740 v.data.priority = RTE_ACL_MAX_PRIORITY - n;
743 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1);
745 RTE_LOG(ERR, TESTACL, "line %u: failed to add rules "
746 "into ACL context, error code: %d (%s)\n",
747 n, rc, strerror(-rc));
760 struct rte_acl_config cfg;
762 memset(&cfg, 0, sizeof(cfg));
764 /* setup ACL build config. */
766 cfg.num_fields = RTE_DIM(ipv6_defs);
767 memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs));
769 cfg.num_fields = RTE_DIM(ipv4_defs);
770 memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
772 cfg.num_categories = config.bld_categories;
773 cfg.max_size = config.max_size;
775 /* setup ACL creation parameters. */
776 prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
777 prm.max_rule_num = config.nb_rules;
779 config.acx = rte_acl_create(&prm);
780 if (config.acx == NULL)
781 rte_exit(rte_errno, "failed to create ACL context\n");
783 /* set default classify method for this context. */
784 if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) {
785 ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg);
787 rte_exit(ret, "failed to setup %s method "
788 "for ACL context\n", config.alg.name);
792 f = fopen(config.rule_file, "r");
794 rte_exit(-EINVAL, "failed to open file %s\n",
797 ret = add_cb_rules(f, config.acx);
799 rte_exit(ret, "failed to add rules into ACL context\n");
804 ret = rte_acl_build(config.acx, &cfg);
806 dump_verbose(DUMP_NONE, stdout,
807 "rte_acl_build(%u) finished with %d\n",
808 config.bld_categories, ret);
810 rte_acl_dump(config.acx);
813 rte_exit(ret, "failed to build search context\n");
817 search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
820 uint32_t i, j, k, n, r;
821 const uint8_t *data[step], *v;
822 uint32_t results[step * categories];
825 for (i = 0; i != config.used_traces; i += n) {
827 n = RTE_MIN(step, config.used_traces - i);
829 for (j = 0; j != n; j++) {
831 v += config.trace_sz;
834 ret = rte_acl_classify(config.acx, data, results,
838 rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
839 config.ipv6 ? '6' : '4', ret);
841 for (r = 0, j = 0; j != n; j++) {
842 for (k = 0; k != categories; k++, r++) {
843 dump_verbose(DUMP_PKT, stdout,
844 "ipv%c_5tuple: %u, category: %u, "
846 config.ipv6 ? '6' : '4',
847 i + j + 1, k, results[r] - 1);
853 dump_verbose(DUMP_SEARCH, stdout,
854 "%s(%u, %u, %s) returns %u\n", __func__,
855 categories, step, alg, i);
860 search_ip5tuples(__attribute__((unused)) void *arg)
862 uint64_t pkt, start, tm;
865 lcore = rte_lcore_id();
869 for (i = 0; i != config.iter_num; i++) {
870 pkt += search_ip5tuples_once(config.run_categories,
871 config.trace_step, config.alg.name);
874 tm = rte_rdtsc() - start;
875 dump_verbose(DUMP_NONE, stdout,
876 "%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %"
877 PRIu32 " categories, %" PRIu64 " cycles, %#Lf cycles/pkt\n",
878 __func__, lcore, i, pkt, config.run_categories,
879 tm, (pkt == 0) ? 0 : (long double)tm / pkt);
885 get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
891 val = strtoul(opt, &end, 0);
892 if (errno != 0 || end[0] != 0 || val > max || val < min)
893 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
899 get_alg_opt(const char *opt, const char *name)
903 for (i = 0; i != RTE_DIM(acl_alg); i++) {
904 if (strcmp(opt, acl_alg[i].name) == 0) {
905 config.alg = acl_alg[i];
910 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
915 print_usage(const char *prgname)
923 for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
924 rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
926 if (rc > sizeof(buf) - n)
931 snprintf(buf + n, sizeof(buf) - n, "%s", acl_alg[i].name);
935 "--" OPT_RULE_FILE "=<rules set file>\n"
936 "[--" OPT_TRACE_FILE "=<input traces file>]\n"
938 "=<maximum number of rules for ACL context>]\n"
940 "=<number of traces to read binary file in>]\n"
942 "=<number of traces to classify per one call>]\n"
943 "[--" OPT_BLD_CATEGORIES
944 "=<number of categories to build with>]\n"
945 "[--" OPT_RUN_CATEGORIES
946 "=<number of categories to run with> "
947 "should be either 1 or multiple of %zu, "
948 "but not greater then %u]\n"
950 "=<size limit (in bytes) for runtime ACL strucutures> "
951 "leave 0 for default behaviour]\n"
952 "[--" OPT_ITER_NUM "=<number of iterations to perform>]\n"
953 "[--" OPT_VERBOSE "=<verbose level>]\n"
954 "[--" OPT_SEARCH_ALG "=%s]\n"
955 "[--" OPT_IPV6 "=<IPv6 rules and trace files>]\n",
956 prgname, RTE_ACL_RESULTS_MULTIPLIER,
957 (uint32_t)RTE_ACL_MAX_CATEGORIES,
964 fprintf(f, "%s:\n", __func__);
965 fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file);
966 fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file);
967 fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules);
968 fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces);
969 fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step);
970 fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories);
971 fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories);
972 fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size);
973 fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num);
974 fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose);
975 fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg,
977 fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
983 if (config.rule_file == NULL) {
984 print_usage(config.prgname);
985 rte_exit(-EINVAL, "mandatory option %s is not specified\n",
992 get_input_opts(int argc, char **argv)
994 static struct option lgopts[] = {
995 {OPT_RULE_FILE, 1, 0, 0},
996 {OPT_TRACE_FILE, 1, 0, 0},
997 {OPT_TRACE_NUM, 1, 0, 0},
998 {OPT_RULE_NUM, 1, 0, 0},
999 {OPT_MAX_SIZE, 1, 0, 0},
1000 {OPT_TRACE_STEP, 1, 0, 0},
1001 {OPT_BLD_CATEGORIES, 1, 0, 0},
1002 {OPT_RUN_CATEGORIES, 1, 0, 0},
1003 {OPT_ITER_NUM, 1, 0, 0},
1004 {OPT_VERBOSE, 1, 0, 0},
1005 {OPT_SEARCH_ALG, 1, 0, 0},
1006 {OPT_IPV6, 0, 0, 0},
1012 while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
1015 print_usage(config.prgname);
1016 rte_exit(-EINVAL, "unknown option: %c", opt);
1019 if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) {
1020 config.rule_file = optarg;
1021 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) {
1022 config.trace_file = optarg;
1023 } else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) {
1024 config.nb_rules = get_ulong_opt(optarg,
1025 lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1);
1026 } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) {
1027 config.max_size = get_ulong_opt(optarg,
1028 lgopts[opt_idx].name, 0, SIZE_MAX);
1029 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) {
1030 config.nb_traces = get_ulong_opt(optarg,
1031 lgopts[opt_idx].name, 1, UINT32_MAX);
1032 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) {
1033 config.trace_step = get_ulong_opt(optarg,
1034 lgopts[opt_idx].name, 1, TRACE_STEP_MAX);
1035 } else if (strcmp(lgopts[opt_idx].name,
1036 OPT_BLD_CATEGORIES) == 0) {
1037 config.bld_categories = get_ulong_opt(optarg,
1038 lgopts[opt_idx].name, 1,
1039 RTE_ACL_MAX_CATEGORIES);
1040 } else if (strcmp(lgopts[opt_idx].name,
1041 OPT_RUN_CATEGORIES) == 0) {
1042 config.run_categories = get_ulong_opt(optarg,
1043 lgopts[opt_idx].name, 1,
1044 RTE_ACL_MAX_CATEGORIES);
1045 } else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) {
1046 config.iter_num = get_ulong_opt(optarg,
1047 lgopts[opt_idx].name, 1, INT32_MAX);
1048 } else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) {
1049 config.verbose = get_ulong_opt(optarg,
1050 lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX);
1051 } else if (strcmp(lgopts[opt_idx].name,
1052 OPT_SEARCH_ALG) == 0) {
1053 get_alg_opt(optarg, lgopts[opt_idx].name);
1054 } else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) {
1058 config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
1059 sizeof(struct ipv4_5tuple);
1064 main(int argc, char **argv)
1069 ret = rte_eal_init(argc, argv);
1071 rte_panic("Cannot init EAL\n");
1076 config.prgname = argv[0];
1078 get_input_opts(argc, argv);
1079 dump_config(stdout);
1084 if (config.trace_file != NULL)
1087 RTE_LCORE_FOREACH_SLAVE(lcore)
1088 rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
1090 search_ip5tuples(NULL);
1092 rte_eal_mp_wait_lcore();
1094 rte_acl_free(config.acx);