1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
5 #include <rte_string_fns.h>
10 #include <rte_cycles.h>
11 #include <rte_per_lcore.h>
12 #include <rte_lcore.h>
15 #define PRINT_USAGE_START "%s [EAL options] --\n"
17 #define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1
19 #define APP_NAME "TESTACL"
21 #define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
25 val = strtoul((in), &end_fld, (base)); \
26 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
28 (fd) = (typeof(fd))val; \
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"
45 #define TRACE_DEFAULT_NUM 0x10000
46 #define TRACE_STEP_MAX 0x1000
47 #define TRACE_STEP_DEF 0x100
49 #define RULE_NUM 0x10000
51 #define COMMENT_LEAD_CHAR '#'
68 enum rte_acl_classify_alg alg;
71 static const struct acl_alg acl_alg[] = {
74 .alg = RTE_ACL_CLASSIFY_SCALAR,
78 .alg = RTE_ACL_CLASSIFY_SSE,
82 .alg = RTE_ACL_CLASSIFY_AVX2,
86 .alg = RTE_ACL_CLASSIFY_NEON,
90 .alg = RTE_ACL_CLASSIFY_ALTIVEC,
94 .alg = RTE_ACL_CLASSIFY_AVX512X16,
98 .alg = RTE_ACL_CLASSIFY_AVX512X32,
104 const char *rule_file;
105 const char *trace_file;
107 uint32_t bld_categories;
108 uint32_t run_categories;
117 uint32_t used_traces;
119 struct rte_acl_ctx *acx;
123 .nb_rules = RULE_NUM,
124 .nb_traces = TRACE_DEFAULT_NUM,
125 .trace_step = TRACE_STEP_DEF,
130 .alg = RTE_ACL_CLASSIFY_DEFAULT,
132 .ipv6 = IPV6_FRMT_NONE,
135 static struct rte_acl_param prm = {
137 .socket_id = SOCKET_ID_ANY,
141 * Rule and trace formats definitions.
162 * That effectively defines order of IPV4VLAN classifications:
164 * - VLAN (TAG and DOMAIN)
167 * - PORTS (SRC and DST)
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,
178 struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
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),
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),
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),
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),
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),
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))
223 uint32_t ip_src[IPV6_ADDR_U32];
224 uint32_t ip_dst[IPV6_ADDR_U32];
229 /* treat IPV6 address as uint32_t[4] (default mode) */
245 /* treat IPV6 address as uint64_t[2] (default mode) */
247 PROTO_FIELD_IPV6_U64,
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,
266 struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
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),
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]),
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]),
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]),
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]),
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]),
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]),
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]),
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]),
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),
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),
346 struct rte_acl_field_def ipv6_u64_defs[NUM_FIELDS_IPV6_U64] = {
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),
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]),
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]),
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]),
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]),
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),
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),
403 CB_FLD_SRC_PORT_HIGH,
406 CB_FLD_DST_PORT_HIGH,
420 RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
422 static const char cb_port_delim[] = ":";
424 static char line[LINE_MAX];
426 #define dump_verbose(lvl, fh, fmt, args...) do { \
427 if ((lvl) <= (int32_t)config.verbose) \
428 fprintf(fh, fmt, ##args); \
433 * Parse ClassBench input trace (test vectors and expected results) file.
435 * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \
436 * <src_port> <space> <dst_port> <space> <proto>
439 parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v)
442 char *s, *sp, *in[CB_TRC_NUM];
443 static const char *dlm = " \t\n";
446 for (i = 0; i != RTE_DIM(in); i++) {
447 in[i] = strtok_r(s, dlm, &sp);
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);
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);
469 parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
471 if (inet_pton(AF_INET6, in, v) != 1)
478 * Parse ClassBench input trace (test vectors and expected results) file.
480 * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \
481 * <src_port> <space> <dst_port> <space> <proto>
484 parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v)
487 char *s, *sp, *in[CB_TRC_NUM];
488 static const char *dlm = " \t\n";
491 for (i = 0; i != RTE_DIM(in); i++) {
492 in[i] = strtok_r(s, dlm, &sp);
498 /* get ip6 src address. */
499 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
503 /* get ip6 dst address. */
504 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst);
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);
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);
519 /* Bypass comment and empty lines */
521 skip_line(const char *buf)
525 for (i = 0; isspace(buf[i]) != 0; i++)
528 if (buf[i] == 0 || buf[i] == COMMENT_LEAD_CHAR)
537 static const char name[] = APP_NAME;
541 struct ipv4_5tuple *v;
542 struct ipv6_5tuple *w;
544 sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
545 config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
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);
552 f = fopen(config.trace_file, "r");
554 rte_exit(-EINVAL, "failed to open file: %s\n",
561 for (i = 0; n != config.nb_traces; i++) {
563 if (fgets(line, sizeof(line), f) == NULL)
566 if (skip_line(line) != 0) {
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);
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);
588 config.used_traces = i - k;
593 parse_ipv6_u32_net(char *in, struct rte_acl_field field[IPV6_ADDR_U32])
596 uint32_t i, m, v[IPV6_ADDR_U32];
598 const char *dlm = "/";
599 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
603 sa = strtok_r(in, dlm, &sv);
606 sm = strtok_r(NULL, dlm, &sv);
610 if (inet_pton(AF_INET6, sa, v) != 1)
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]);
619 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
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;
626 field[i].mask_range.u32 = m > (i * nbu32) ?
629 field[i].value.u32 = v[i];
636 parse_ipv6_u64_net(char *in, struct rte_acl_field field[IPV6_ADDR_U64])
640 uint64_t v[IPV6_ADDR_U64];
642 const char *dlm = "/";
643 const uint32_t nbu64 = sizeof(uint64_t) * CHAR_BIT;
647 sa = strtok_r(in, dlm, &sv);
650 sm = strtok_r(NULL, dlm, &sv);
654 if (inet_pton(AF_INET6, sa, v) != 1)
657 v[0] = rte_be_to_cpu_64(v[0]);
658 v[1] = rte_be_to_cpu_64(v[1]);
661 GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
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;
668 field[i].mask_range.u32 = m > (i * nbu64) ?
671 field[i].value.u64 = v[i];
678 parse_cb_ipv6_rule(char *str, struct acl_rule *v, int frmt)
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[]);
686 static const char *dlm = " \t\n";
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,
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,
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;
720 if (strchr(str, '@') != str)
725 for (i = 0; i != RTE_DIM(in); i++) {
726 in[i] = strtok_r(s, dlm, &sp);
732 fidx = CB_FLD_SRC_ADDR;
733 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
735 RTE_LOG(ERR, TESTACL,
736 "failed to read source address/mask: %s\n", in[fidx]);
740 fidx = CB_FLD_DST_ADDR;
741 rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
743 RTE_LOG(ERR, TESTACL,
744 "failed to read destination address/mask: %s\n",
750 fidx = CB_FLD_SRC_PORT_LOW;
751 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
754 fidx = CB_FLD_SRC_PORT_HIGH;
755 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
758 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
759 sizeof(cb_port_delim)) != 0)
762 /* destination port. */
763 fidx = CB_FLD_DST_PORT_LOW;
764 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
767 fidx = CB_FLD_DST_PORT_HIGH;
768 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
771 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
772 sizeof(cb_port_delim)) != 0)
776 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u8,
778 GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u8,
785 parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v)
787 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32);
791 parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v)
793 return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64);
797 parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
802 const char *dlm = "/";
805 sa = strtok_r(in, dlm, &sv);
808 sm = strtok_r(NULL, dlm, &sv);
812 if (inet_pton(AF_INET, sa, &v) != 1)
815 addr[0] = rte_be_to_cpu_32(v);
817 GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
823 * Parse ClassBench rules file.
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> \
832 parse_cb_ipv4_rule(char *str, struct acl_rule *v)
835 char *s, *sp, *in[CB_FLD_NUM];
836 static const char *dlm = " \t\n";
841 if (strchr(str, '@') != str)
846 for (i = 0; i != RTE_DIM(in); i++) {
847 in[i] = strtok_r(s, dlm, &sp);
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);
857 RTE_LOG(ERR, TESTACL,
858 "failed to read source address/mask: %s\n",
859 in[CB_FLD_SRC_ADDR]);
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);
867 RTE_LOG(ERR, TESTACL,
868 "failed to read destination address/mask: %s\n",
869 in[CB_FLD_DST_ADDR]);
874 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
875 v->field[SRCP_FIELD_IPV4].value.u16,
877 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
878 v->field[SRCP_FIELD_IPV4].mask_range.u16,
881 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
882 sizeof(cb_port_delim)) != 0)
885 /* destination port. */
886 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
887 v->field[DSTP_FIELD_IPV4].value.u16,
889 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
890 v->field[DSTP_FIELD_IPV4].mask_range.u16,
893 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
894 sizeof(cb_port_delim)) != 0)
897 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8,
899 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8,
905 typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
908 add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
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,
921 memset(&v, 0, sizeof(v));
922 parser = parser_func[config.ipv6];
925 for (i = 1; fgets(line, sizeof(line), f) != NULL; i++) {
927 if (skip_line(line) != 0) {
933 rc = parser(line, &v);
935 RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
936 " failed, error code: %d (%s)\n",
937 i, rc, strerror(-rc));
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;
946 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1);
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));
963 struct rte_acl_config cfg;
965 memset(&cfg, 0, sizeof(cfg));
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));
975 cfg.num_fields = RTE_DIM(ipv4_defs);
976 memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
978 cfg.num_categories = config.bld_categories;
979 cfg.max_size = config.max_size;
981 /* setup ACL creation parameters. */
982 prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
983 prm.max_rule_num = config.nb_rules;
985 config.acx = rte_acl_create(&prm);
986 if (config.acx == NULL)
987 rte_exit(rte_errno, "failed to create ACL context\n");
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);
993 rte_exit(ret, "failed to setup %s method "
994 "for ACL context\n", config.alg.name);
998 f = fopen(config.rule_file, "r");
1000 rte_exit(-EINVAL, "failed to open file %s\n",
1003 ret = add_cb_rules(f, config.acx);
1005 rte_exit(ret, "failed to add rules into ACL context\n");
1009 /* perform build. */
1010 ret = rte_acl_build(config.acx, &cfg);
1012 dump_verbose(DUMP_NONE, stdout,
1013 "rte_acl_build(%u) finished with %d\n",
1014 config.bld_categories, ret);
1016 rte_acl_dump(config.acx);
1019 rte_exit(ret, "failed to build search context\n");
1023 search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
1026 uint32_t i, j, k, n, r;
1027 const uint8_t *data[step], *v;
1028 uint32_t results[step * categories];
1031 for (i = 0; i != config.used_traces; i += n) {
1033 n = RTE_MIN(step, config.used_traces - i);
1035 for (j = 0; j != n; j++) {
1037 v += config.trace_sz;
1040 ret = rte_acl_classify(config.acx, data, results,
1044 rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
1045 config.ipv6 ? '6' : '4', ret);
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, "
1052 config.ipv6 ? '6' : '4',
1053 i + j + 1, k, results[r] - 1);
1059 dump_verbose(DUMP_SEARCH, stdout,
1060 "%s(%u, %u, %s) returns %u\n", __func__,
1061 categories, step, alg, i);
1066 search_ip5tuples(__rte_unused void *arg)
1068 uint64_t pkt, start, tm;
1072 lcore = rte_lcore_id();
1073 start = rte_rdtsc_precise();
1076 for (i = 0; i != config.iter_num; i++) {
1077 pkt += search_ip5tuples_once(config.run_categories,
1078 config.trace_step, config.alg.name);
1081 tm = rte_rdtsc_precise() - start;
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);
1095 static unsigned long
1096 get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
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",
1110 get_alg_opt(const char *opt, const char *name)
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];
1121 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
1126 get_ipv6_opt(const char *opt, const char *name)
1130 static const struct {
1136 .val = IPV6_FRMT_U32,
1140 .val = IPV6_FRMT_U64,
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;
1151 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
1157 print_usage(const char *prgname)
1165 for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
1166 rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
1168 if (rc > sizeof(buf) - n)
1173 strlcpy(buf + n, acl_alg[i].name, sizeof(buf) - n);
1177 "--" OPT_RULE_FILE "=<rules set file>\n"
1178 "[--" OPT_TRACE_FILE "=<input traces file>]\n"
1180 "=<maximum number of rules for ACL context>]\n"
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"
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,
1204 dump_config(FILE *f)
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,
1219 fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
1225 if (config.rule_file == NULL) {
1226 print_usage(config.prgname);
1227 rte_exit(-EINVAL, "mandatory option %s is not specified\n",
1234 get_input_opts(int argc, char **argv)
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},
1254 while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
1257 print_usage(config.prgname);
1258 rte_exit(-EINVAL, "unknown option: %c", opt);
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;
1299 get_ipv6_opt(optarg, lgopts[opt_idx].name);
1302 config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
1303 sizeof(struct ipv4_5tuple);
1308 main(int argc, char **argv)
1313 ret = rte_eal_init(argc, argv);
1315 rte_panic("Cannot init EAL\n");
1320 config.prgname = argv[0];
1322 get_input_opts(argc, argv);
1323 dump_config(stdout);
1328 if (config.trace_file != NULL)
1331 RTE_LCORE_FOREACH_WORKER(lcore)
1332 rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
1334 search_ip5tuples(NULL);
1336 rte_eal_mp_wait_lcore();
1338 rte_acl_free(config.acx);