xref: /dpdk/app/test-acl/main.c (revision f7c9651c830e4a54c81b0357fca768787d3d6402)
175795fabSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
275795fabSBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
375795fabSBruce Richardson  */
475795fabSBruce Richardson 
56723c0fcSBruce Richardson #include <rte_string_fns.h>
675795fabSBruce Richardson #include <rte_acl.h>
775795fabSBruce Richardson #include <getopt.h>
875795fabSBruce Richardson #include <string.h>
975795fabSBruce Richardson 
1075795fabSBruce Richardson #include <rte_cycles.h>
1175795fabSBruce Richardson #include <rte_per_lcore.h>
1275795fabSBruce Richardson #include <rte_lcore.h>
1375795fabSBruce Richardson #include <rte_ip.h>
1475795fabSBruce Richardson 
15a658775cSThomas Monjalon #define	PRINT_USAGE_START	"%s [EAL options] --\n"
1675795fabSBruce Richardson 
1775795fabSBruce Richardson #define	RTE_LOGTYPE_TESTACL	RTE_LOGTYPE_USER1
1875795fabSBruce Richardson 
1975795fabSBruce Richardson #define	APP_NAME	"TESTACL"
2075795fabSBruce Richardson 
2175795fabSBruce Richardson #define GET_CB_FIELD(in, fd, base, lim, dlm)	do {            \
2275795fabSBruce Richardson 	unsigned long val;                                      \
2375795fabSBruce Richardson 	char *end_fld;                                          \
2475795fabSBruce Richardson 	errno = 0;                                              \
2575795fabSBruce Richardson 	val = strtoul((in), &end_fld, (base));                  \
2675795fabSBruce Richardson 	if (errno != 0 || end_fld[0] != (dlm) || val > (lim))   \
2775795fabSBruce Richardson 		return -EINVAL;                               \
2875795fabSBruce Richardson 	(fd) = (typeof(fd))val;                                 \
2975795fabSBruce Richardson 	(in) = end_fld + 1;                                     \
3075795fabSBruce Richardson } while (0)
3175795fabSBruce Richardson 
3275795fabSBruce Richardson #define	OPT_RULE_FILE		"rulesf"
3375795fabSBruce Richardson #define	OPT_TRACE_FILE		"tracef"
3475795fabSBruce Richardson #define	OPT_RULE_NUM		"rulenum"
3575795fabSBruce Richardson #define	OPT_TRACE_NUM		"tracenum"
3675795fabSBruce Richardson #define	OPT_TRACE_STEP		"tracestep"
3775795fabSBruce Richardson #define	OPT_SEARCH_ALG		"alg"
3875795fabSBruce Richardson #define	OPT_BLD_CATEGORIES	"bldcat"
3975795fabSBruce Richardson #define	OPT_RUN_CATEGORIES	"runcat"
4075795fabSBruce Richardson #define	OPT_MAX_SIZE		"maxsize"
4175795fabSBruce Richardson #define	OPT_ITER_NUM		"iter"
4275795fabSBruce Richardson #define	OPT_VERBOSE		"verbose"
4375795fabSBruce Richardson #define	OPT_IPV6		"ipv6"
4475795fabSBruce Richardson 
4575795fabSBruce Richardson #define	TRACE_DEFAULT_NUM	0x10000
4675795fabSBruce Richardson #define	TRACE_STEP_MAX		0x1000
4775795fabSBruce Richardson #define	TRACE_STEP_DEF		0x100
4875795fabSBruce Richardson 
4975795fabSBruce Richardson #define	RULE_NUM		0x10000
5075795fabSBruce Richardson 
51ca2183d3SKonstantin Ananyev #define COMMENT_LEAD_CHAR	'#'
52ca2183d3SKonstantin Ananyev 
5375795fabSBruce Richardson enum {
5475795fabSBruce Richardson 	DUMP_NONE,
5575795fabSBruce Richardson 	DUMP_SEARCH,
5675795fabSBruce Richardson 	DUMP_PKT,
5775795fabSBruce Richardson 	DUMP_MAX
5875795fabSBruce Richardson };
5975795fabSBruce Richardson 
6060018ef4SKonstantin Ananyev enum {
6160018ef4SKonstantin Ananyev 	IPV6_FRMT_NONE,
6260018ef4SKonstantin Ananyev 	IPV6_FRMT_U32,
6360018ef4SKonstantin Ananyev 	IPV6_FRMT_U64,
6460018ef4SKonstantin Ananyev };
6560018ef4SKonstantin Ananyev 
6675795fabSBruce Richardson struct acl_alg {
6775795fabSBruce Richardson 	const char *name;
6875795fabSBruce Richardson 	enum rte_acl_classify_alg alg;
6975795fabSBruce Richardson };
7075795fabSBruce Richardson 
7175795fabSBruce Richardson static const struct acl_alg acl_alg[] = {
7275795fabSBruce Richardson 	{
7375795fabSBruce Richardson 		.name = "scalar",
7475795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_SCALAR,
7575795fabSBruce Richardson 	},
7675795fabSBruce Richardson 	{
7775795fabSBruce Richardson 		.name = "sse",
7875795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_SSE,
7975795fabSBruce Richardson 	},
8075795fabSBruce Richardson 	{
8175795fabSBruce Richardson 		.name = "avx2",
8275795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_AVX2,
8375795fabSBruce Richardson 	},
8475795fabSBruce Richardson 	{
8575795fabSBruce Richardson 		.name = "neon",
8675795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_NEON,
8775795fabSBruce Richardson 	},
8875795fabSBruce Richardson 	{
8975795fabSBruce Richardson 		.name = "altivec",
9075795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_ALTIVEC,
9175795fabSBruce Richardson 	},
92b64c2295SKonstantin Ananyev 	{
93b64c2295SKonstantin Ananyev 		.name = "avx512x16",
94b64c2295SKonstantin Ananyev 		.alg = RTE_ACL_CLASSIFY_AVX512X16,
95b64c2295SKonstantin Ananyev 	},
9645da22e4SKonstantin Ananyev 	{
9745da22e4SKonstantin Ananyev 		.name = "avx512x32",
9845da22e4SKonstantin Ananyev 		.alg = RTE_ACL_CLASSIFY_AVX512X32,
9945da22e4SKonstantin Ananyev 	},
10075795fabSBruce Richardson };
10175795fabSBruce Richardson 
10275795fabSBruce Richardson static struct {
10375795fabSBruce Richardson 	const char         *prgname;
10475795fabSBruce Richardson 	const char         *rule_file;
10575795fabSBruce Richardson 	const char         *trace_file;
10675795fabSBruce Richardson 	size_t              max_size;
10775795fabSBruce Richardson 	uint32_t            bld_categories;
10875795fabSBruce Richardson 	uint32_t            run_categories;
10975795fabSBruce Richardson 	uint32_t            nb_rules;
11075795fabSBruce Richardson 	uint32_t            nb_traces;
11175795fabSBruce Richardson 	uint32_t            trace_step;
11275795fabSBruce Richardson 	uint32_t            trace_sz;
11375795fabSBruce Richardson 	uint32_t            iter_num;
11475795fabSBruce Richardson 	uint32_t            verbose;
11575795fabSBruce Richardson 	uint32_t            ipv6;
11675795fabSBruce Richardson 	struct acl_alg      alg;
11775795fabSBruce Richardson 	uint32_t            used_traces;
11875795fabSBruce Richardson 	void               *traces;
11975795fabSBruce Richardson 	struct rte_acl_ctx *acx;
12075795fabSBruce Richardson } config = {
12175795fabSBruce Richardson 	.bld_categories = 3,
12275795fabSBruce Richardson 	.run_categories = 1,
12375795fabSBruce Richardson 	.nb_rules = RULE_NUM,
12475795fabSBruce Richardson 	.nb_traces = TRACE_DEFAULT_NUM,
12575795fabSBruce Richardson 	.trace_step = TRACE_STEP_DEF,
12675795fabSBruce Richardson 	.iter_num = 1,
12775795fabSBruce Richardson 	.verbose = DUMP_MAX,
12875795fabSBruce Richardson 	.alg = {
12975795fabSBruce Richardson 		.name = "default",
13075795fabSBruce Richardson 		.alg = RTE_ACL_CLASSIFY_DEFAULT,
13175795fabSBruce Richardson 	},
13260018ef4SKonstantin Ananyev 	.ipv6 = IPV6_FRMT_NONE,
13375795fabSBruce Richardson };
13475795fabSBruce Richardson 
13575795fabSBruce Richardson static struct rte_acl_param prm = {
13675795fabSBruce Richardson 	.name = APP_NAME,
13775795fabSBruce Richardson 	.socket_id = SOCKET_ID_ANY,
13875795fabSBruce Richardson };
13975795fabSBruce Richardson 
14075795fabSBruce Richardson /*
14175795fabSBruce Richardson  * Rule and trace formats definitions.
14275795fabSBruce Richardson  */
14375795fabSBruce Richardson 
14475795fabSBruce Richardson struct ipv4_5tuple {
14575795fabSBruce Richardson 	uint8_t  proto;
14675795fabSBruce Richardson 	uint32_t ip_src;
14775795fabSBruce Richardson 	uint32_t ip_dst;
14875795fabSBruce Richardson 	uint16_t port_src;
14975795fabSBruce Richardson 	uint16_t port_dst;
15075795fabSBruce Richardson };
15175795fabSBruce Richardson 
15275795fabSBruce Richardson enum {
15375795fabSBruce Richardson 	PROTO_FIELD_IPV4,
15475795fabSBruce Richardson 	SRC_FIELD_IPV4,
15575795fabSBruce Richardson 	DST_FIELD_IPV4,
15675795fabSBruce Richardson 	SRCP_FIELD_IPV4,
15775795fabSBruce Richardson 	DSTP_FIELD_IPV4,
15875795fabSBruce Richardson 	NUM_FIELDS_IPV4
15975795fabSBruce Richardson };
16075795fabSBruce Richardson 
16175795fabSBruce Richardson /*
16275795fabSBruce Richardson  * That effectively defines order of IPV4VLAN classifications:
16375795fabSBruce Richardson  *  - PROTO
16475795fabSBruce Richardson  *  - VLAN (TAG and DOMAIN)
16575795fabSBruce Richardson  *  - SRC IP ADDRESS
16675795fabSBruce Richardson  *  - DST IP ADDRESS
16775795fabSBruce Richardson  *  - PORTS (SRC and DST)
16875795fabSBruce Richardson  */
16975795fabSBruce Richardson enum {
17075795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_PROTO,
17175795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_VLAN,
17275795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_SRC,
17375795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_DST,
17475795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_PORTS,
17575795fabSBruce Richardson 	RTE_ACL_IPV4VLAN_NUM
17675795fabSBruce Richardson };
17775795fabSBruce Richardson 
17875795fabSBruce Richardson struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
17975795fabSBruce Richardson 	{
18075795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
18175795fabSBruce Richardson 		.size = sizeof(uint8_t),
18275795fabSBruce Richardson 		.field_index = PROTO_FIELD_IPV4,
18375795fabSBruce Richardson 		.input_index = RTE_ACL_IPV4VLAN_PROTO,
18475795fabSBruce Richardson 		.offset = offsetof(struct ipv4_5tuple, proto),
18575795fabSBruce Richardson 	},
18675795fabSBruce Richardson 	{
18775795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
18875795fabSBruce Richardson 		.size = sizeof(uint32_t),
18975795fabSBruce Richardson 		.field_index = SRC_FIELD_IPV4,
19075795fabSBruce Richardson 		.input_index = RTE_ACL_IPV4VLAN_SRC,
19175795fabSBruce Richardson 		.offset = offsetof(struct ipv4_5tuple, ip_src),
19275795fabSBruce Richardson 	},
19375795fabSBruce Richardson 	{
19475795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
19575795fabSBruce Richardson 		.size = sizeof(uint32_t),
19675795fabSBruce Richardson 		.field_index = DST_FIELD_IPV4,
19775795fabSBruce Richardson 		.input_index = RTE_ACL_IPV4VLAN_DST,
19875795fabSBruce Richardson 		.offset = offsetof(struct ipv4_5tuple, ip_dst),
19975795fabSBruce Richardson 	},
20075795fabSBruce Richardson 	{
20175795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_RANGE,
20275795fabSBruce Richardson 		.size = sizeof(uint16_t),
20375795fabSBruce Richardson 		.field_index = SRCP_FIELD_IPV4,
20475795fabSBruce Richardson 		.input_index = RTE_ACL_IPV4VLAN_PORTS,
20575795fabSBruce Richardson 		.offset = offsetof(struct ipv4_5tuple, port_src),
20675795fabSBruce Richardson 	},
20775795fabSBruce Richardson 	{
20875795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_RANGE,
20975795fabSBruce Richardson 		.size = sizeof(uint16_t),
21075795fabSBruce Richardson 		.field_index = DSTP_FIELD_IPV4,
21175795fabSBruce Richardson 		.input_index = RTE_ACL_IPV4VLAN_PORTS,
21275795fabSBruce Richardson 		.offset = offsetof(struct ipv4_5tuple, port_dst),
21375795fabSBruce Richardson 	},
21475795fabSBruce Richardson };
21575795fabSBruce Richardson 
21675795fabSBruce Richardson #define	IPV6_ADDR_LEN	16
21775795fabSBruce Richardson #define	IPV6_ADDR_U16	(IPV6_ADDR_LEN / sizeof(uint16_t))
21875795fabSBruce Richardson #define	IPV6_ADDR_U32	(IPV6_ADDR_LEN / sizeof(uint32_t))
21960018ef4SKonstantin Ananyev #define	IPV6_ADDR_U64	(IPV6_ADDR_LEN / sizeof(uint64_t))
22075795fabSBruce Richardson 
22175795fabSBruce Richardson struct ipv6_5tuple {
22275795fabSBruce Richardson 	uint8_t  proto;
22375795fabSBruce Richardson 	uint32_t ip_src[IPV6_ADDR_U32];
22475795fabSBruce Richardson 	uint32_t ip_dst[IPV6_ADDR_U32];
22575795fabSBruce Richardson 	uint16_t port_src;
22675795fabSBruce Richardson 	uint16_t port_dst;
22775795fabSBruce Richardson };
22875795fabSBruce Richardson 
22960018ef4SKonstantin Ananyev /* treat IPV6 address as uint32_t[4] (default mode) */
23075795fabSBruce Richardson enum {
23175795fabSBruce Richardson 	PROTO_FIELD_IPV6,
23275795fabSBruce Richardson 	SRC1_FIELD_IPV6,
23375795fabSBruce Richardson 	SRC2_FIELD_IPV6,
23475795fabSBruce Richardson 	SRC3_FIELD_IPV6,
23575795fabSBruce Richardson 	SRC4_FIELD_IPV6,
23675795fabSBruce Richardson 	DST1_FIELD_IPV6,
23775795fabSBruce Richardson 	DST2_FIELD_IPV6,
23875795fabSBruce Richardson 	DST3_FIELD_IPV6,
23975795fabSBruce Richardson 	DST4_FIELD_IPV6,
24075795fabSBruce Richardson 	SRCP_FIELD_IPV6,
24175795fabSBruce Richardson 	DSTP_FIELD_IPV6,
24275795fabSBruce Richardson 	NUM_FIELDS_IPV6
24375795fabSBruce Richardson };
24475795fabSBruce Richardson 
24560018ef4SKonstantin Ananyev /* treat IPV6 address as uint64_t[2] (default mode) */
24660018ef4SKonstantin Ananyev enum {
24760018ef4SKonstantin Ananyev 	PROTO_FIELD_IPV6_U64,
24860018ef4SKonstantin Ananyev 	SRC1_FIELD_IPV6_U64,
24960018ef4SKonstantin Ananyev 	SRC2_FIELD_IPV6_U64,
25060018ef4SKonstantin Ananyev 	DST1_FIELD_IPV6_U64,
25160018ef4SKonstantin Ananyev 	DST2_FIELD_IPV6_U64,
25260018ef4SKonstantin Ananyev 	SRCP_FIELD_IPV6_U64,
25360018ef4SKonstantin Ananyev 	DSTP_FIELD_IPV6_U64,
25460018ef4SKonstantin Ananyev 	NUM_FIELDS_IPV6_U64
25560018ef4SKonstantin Ananyev };
25660018ef4SKonstantin Ananyev 
25760018ef4SKonstantin Ananyev enum {
25860018ef4SKonstantin Ananyev 	PROTO_INDEX_IPV6_U64 = PROTO_FIELD_IPV6_U64,
25960018ef4SKonstantin Ananyev 	SRC1_INDEX_IPV6_U64 = SRC1_FIELD_IPV6_U64,
26060018ef4SKonstantin Ananyev 	SRC2_INDEX_IPV6_U64 = SRC2_FIELD_IPV6_U64 + 1,
26160018ef4SKonstantin Ananyev 	DST1_INDEX_IPV6_U64 = DST1_FIELD_IPV6_U64 + 2,
26260018ef4SKonstantin Ananyev 	DST2_INDEX_IPV6_U64 = DST2_FIELD_IPV6_U64 + 3,
26360018ef4SKonstantin Ananyev 	PRT_INDEX_IPV6_U64 = SRCP_FIELD_IPV6 + 4,
26460018ef4SKonstantin Ananyev };
26560018ef4SKonstantin Ananyev 
26675795fabSBruce Richardson struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
26775795fabSBruce Richardson 	{
26875795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
26975795fabSBruce Richardson 		.size = sizeof(uint8_t),
27075795fabSBruce Richardson 		.field_index = PROTO_FIELD_IPV6,
27175795fabSBruce Richardson 		.input_index = PROTO_FIELD_IPV6,
27275795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, proto),
27375795fabSBruce Richardson 	},
27475795fabSBruce Richardson 	{
27575795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
27675795fabSBruce Richardson 		.size = sizeof(uint32_t),
27775795fabSBruce Richardson 		.field_index = SRC1_FIELD_IPV6,
27875795fabSBruce Richardson 		.input_index = SRC1_FIELD_IPV6,
27975795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_src[0]),
28075795fabSBruce Richardson 	},
28175795fabSBruce Richardson 	{
28275795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
28375795fabSBruce Richardson 		.size = sizeof(uint32_t),
28475795fabSBruce Richardson 		.field_index = SRC2_FIELD_IPV6,
28575795fabSBruce Richardson 		.input_index = SRC2_FIELD_IPV6,
28675795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_src[1]),
28775795fabSBruce Richardson 	},
28875795fabSBruce Richardson 	{
28975795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
29075795fabSBruce Richardson 		.size = sizeof(uint32_t),
29175795fabSBruce Richardson 		.field_index = SRC3_FIELD_IPV6,
29275795fabSBruce Richardson 		.input_index = SRC3_FIELD_IPV6,
29375795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_src[2]),
29475795fabSBruce Richardson 	},
29575795fabSBruce Richardson 	{
29675795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
29775795fabSBruce Richardson 		.size = sizeof(uint32_t),
29875795fabSBruce Richardson 		.field_index = SRC4_FIELD_IPV6,
29975795fabSBruce Richardson 		.input_index = SRC4_FIELD_IPV6,
30075795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_src[3]),
30175795fabSBruce Richardson 	},
30275795fabSBruce Richardson 	{
30375795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
30475795fabSBruce Richardson 		.size = sizeof(uint32_t),
30575795fabSBruce Richardson 		.field_index = DST1_FIELD_IPV6,
30675795fabSBruce Richardson 		.input_index = DST1_FIELD_IPV6,
30775795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
30875795fabSBruce Richardson 	},
30975795fabSBruce Richardson 	{
31075795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
31175795fabSBruce Richardson 		.size = sizeof(uint32_t),
31275795fabSBruce Richardson 		.field_index = DST2_FIELD_IPV6,
31375795fabSBruce Richardson 		.input_index = DST2_FIELD_IPV6,
31475795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_dst[1]),
31575795fabSBruce Richardson 	},
31675795fabSBruce Richardson 	{
31775795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
31875795fabSBruce Richardson 		.size = sizeof(uint32_t),
31975795fabSBruce Richardson 		.field_index = DST3_FIELD_IPV6,
32075795fabSBruce Richardson 		.input_index = DST3_FIELD_IPV6,
32175795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
32275795fabSBruce Richardson 	},
32375795fabSBruce Richardson 	{
32475795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_MASK,
32575795fabSBruce Richardson 		.size = sizeof(uint32_t),
32675795fabSBruce Richardson 		.field_index = DST4_FIELD_IPV6,
32775795fabSBruce Richardson 		.input_index = DST4_FIELD_IPV6,
32875795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, ip_dst[3]),
32975795fabSBruce Richardson 	},
33075795fabSBruce Richardson 	{
33175795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_RANGE,
33275795fabSBruce Richardson 		.size = sizeof(uint16_t),
33375795fabSBruce Richardson 		.field_index = SRCP_FIELD_IPV6,
33475795fabSBruce Richardson 		.input_index = SRCP_FIELD_IPV6,
33575795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, port_src),
33675795fabSBruce Richardson 	},
33775795fabSBruce Richardson 	{
33875795fabSBruce Richardson 		.type = RTE_ACL_FIELD_TYPE_RANGE,
33975795fabSBruce Richardson 		.size = sizeof(uint16_t),
34075795fabSBruce Richardson 		.field_index = DSTP_FIELD_IPV6,
34175795fabSBruce Richardson 		.input_index = SRCP_FIELD_IPV6,
34275795fabSBruce Richardson 		.offset = offsetof(struct ipv6_5tuple, port_dst),
34375795fabSBruce Richardson 	},
34475795fabSBruce Richardson };
34575795fabSBruce Richardson 
34660018ef4SKonstantin Ananyev struct rte_acl_field_def ipv6_u64_defs[NUM_FIELDS_IPV6_U64] = {
34760018ef4SKonstantin Ananyev 	{
34860018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
34960018ef4SKonstantin Ananyev 		.size = sizeof(uint8_t),
35060018ef4SKonstantin Ananyev 		.field_index = PROTO_FIELD_IPV6_U64,
35160018ef4SKonstantin Ananyev 		.input_index = PROTO_FIELD_IPV6_U64,
35260018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, proto),
35360018ef4SKonstantin Ananyev 	},
35460018ef4SKonstantin Ananyev 	{
35560018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_MASK,
35660018ef4SKonstantin Ananyev 		.size = sizeof(uint64_t),
35760018ef4SKonstantin Ananyev 		.field_index = SRC1_FIELD_IPV6_U64,
35860018ef4SKonstantin Ananyev 		.input_index = SRC1_INDEX_IPV6_U64,
35960018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, ip_src[0]),
36060018ef4SKonstantin Ananyev 	},
36160018ef4SKonstantin Ananyev 	{
36260018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_MASK,
36360018ef4SKonstantin Ananyev 		.size = sizeof(uint64_t),
36460018ef4SKonstantin Ananyev 		.field_index = SRC2_FIELD_IPV6_U64,
36560018ef4SKonstantin Ananyev 		.input_index = SRC2_INDEX_IPV6_U64,
36660018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, ip_src[2]),
36760018ef4SKonstantin Ananyev 	},
36860018ef4SKonstantin Ananyev 	{
36960018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_MASK,
37060018ef4SKonstantin Ananyev 		.size = sizeof(uint64_t),
37160018ef4SKonstantin Ananyev 		.field_index = DST1_FIELD_IPV6_U64,
37260018ef4SKonstantin Ananyev 		.input_index = DST1_INDEX_IPV6_U64,
37360018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
37460018ef4SKonstantin Ananyev 	},
37560018ef4SKonstantin Ananyev 	{
37660018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_MASK,
37760018ef4SKonstantin Ananyev 		.size = sizeof(uint64_t),
37860018ef4SKonstantin Ananyev 		.field_index = DST2_FIELD_IPV6_U64,
37960018ef4SKonstantin Ananyev 		.input_index = DST2_INDEX_IPV6_U64,
38060018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
38160018ef4SKonstantin Ananyev 	},
38260018ef4SKonstantin Ananyev 	{
38360018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_RANGE,
38460018ef4SKonstantin Ananyev 		.size = sizeof(uint16_t),
38560018ef4SKonstantin Ananyev 		.field_index = SRCP_FIELD_IPV6_U64,
38660018ef4SKonstantin Ananyev 		.input_index = PRT_INDEX_IPV6_U64,
38760018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, port_src),
38860018ef4SKonstantin Ananyev 	},
38960018ef4SKonstantin Ananyev 	{
39060018ef4SKonstantin Ananyev 		.type = RTE_ACL_FIELD_TYPE_RANGE,
39160018ef4SKonstantin Ananyev 		.size = sizeof(uint16_t),
39260018ef4SKonstantin Ananyev 		.field_index = DSTP_FIELD_IPV6_U64,
39360018ef4SKonstantin Ananyev 		.input_index = PRT_INDEX_IPV6_U64,
39460018ef4SKonstantin Ananyev 		.offset = offsetof(struct ipv6_5tuple, port_dst),
39560018ef4SKonstantin Ananyev 	},
39660018ef4SKonstantin Ananyev };
39775795fabSBruce Richardson 
39875795fabSBruce Richardson enum {
39975795fabSBruce Richardson 	CB_FLD_SRC_ADDR,
40075795fabSBruce Richardson 	CB_FLD_DST_ADDR,
40175795fabSBruce Richardson 	CB_FLD_SRC_PORT_LOW,
40275795fabSBruce Richardson 	CB_FLD_SRC_PORT_DLM,
40375795fabSBruce Richardson 	CB_FLD_SRC_PORT_HIGH,
40475795fabSBruce Richardson 	CB_FLD_DST_PORT_LOW,
40575795fabSBruce Richardson 	CB_FLD_DST_PORT_DLM,
40675795fabSBruce Richardson 	CB_FLD_DST_PORT_HIGH,
40775795fabSBruce Richardson 	CB_FLD_PROTO,
40875795fabSBruce Richardson 	CB_FLD_NUM,
40975795fabSBruce Richardson };
41075795fabSBruce Richardson 
41175795fabSBruce Richardson enum {
41275795fabSBruce Richardson 	CB_TRC_SRC_ADDR,
41375795fabSBruce Richardson 	CB_TRC_DST_ADDR,
41475795fabSBruce Richardson 	CB_TRC_SRC_PORT,
41575795fabSBruce Richardson 	CB_TRC_DST_PORT,
41675795fabSBruce Richardson 	CB_TRC_PROTO,
41775795fabSBruce Richardson 	CB_TRC_NUM,
41875795fabSBruce Richardson };
41975795fabSBruce Richardson 
42075795fabSBruce Richardson RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
42175795fabSBruce Richardson 
42275795fabSBruce Richardson static const char cb_port_delim[] = ":";
42375795fabSBruce Richardson 
42475795fabSBruce Richardson static char line[LINE_MAX];
42575795fabSBruce Richardson 
426*f7c9651cSAndre Muezerie #define	dump_verbose(lvl, fh, fmt, ...)	do { \
42775795fabSBruce Richardson 	if ((lvl) <= (int32_t)config.verbose)        \
428*f7c9651cSAndre Muezerie 		fprintf(fh, fmt, ##__VA_ARGS__);         \
42975795fabSBruce Richardson } while (0)
43075795fabSBruce Richardson 
43175795fabSBruce Richardson 
43275795fabSBruce Richardson /*
43375795fabSBruce Richardson  * Parse ClassBench input trace (test vectors and expected results) file.
43475795fabSBruce Richardson  * Expected format:
43575795fabSBruce Richardson  * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \
43675795fabSBruce Richardson  * <src_port> <space> <dst_port> <space> <proto>
43775795fabSBruce Richardson  */
43875795fabSBruce Richardson static int
43975795fabSBruce Richardson parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v)
44075795fabSBruce Richardson {
44175795fabSBruce Richardson 	int i;
44275795fabSBruce Richardson 	char *s, *sp, *in[CB_TRC_NUM];
44375795fabSBruce Richardson 	static const char *dlm = " \t\n";
44475795fabSBruce Richardson 
44575795fabSBruce Richardson 	s = str;
44675795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(in); i++) {
44775795fabSBruce Richardson 		in[i] = strtok_r(s, dlm, &sp);
44875795fabSBruce Richardson 		if (in[i] == NULL)
44975795fabSBruce Richardson 			return -EINVAL;
45075795fabSBruce Richardson 		s = NULL;
45175795fabSBruce Richardson 	}
45275795fabSBruce Richardson 
45375795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0);
45475795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0);
45575795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
45675795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
45775795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
45875795fabSBruce Richardson 
45975795fabSBruce Richardson 	/* convert to network byte order. */
46075795fabSBruce Richardson 	v->ip_src = rte_cpu_to_be_32(v->ip_src);
46175795fabSBruce Richardson 	v->ip_dst = rte_cpu_to_be_32(v->ip_dst);
46275795fabSBruce Richardson 	v->port_src = rte_cpu_to_be_16(v->port_src);
46375795fabSBruce Richardson 	v->port_dst = rte_cpu_to_be_16(v->port_dst);
46475795fabSBruce Richardson 
46575795fabSBruce Richardson 	return 0;
46675795fabSBruce Richardson }
46775795fabSBruce Richardson 
46875795fabSBruce Richardson static int
46975795fabSBruce Richardson parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
47075795fabSBruce Richardson {
47160018ef4SKonstantin Ananyev 	if (inet_pton(AF_INET6, in, v) != 1)
47260018ef4SKonstantin Ananyev 		return -EINVAL;
47375795fabSBruce Richardson 
47475795fabSBruce Richardson 	return 0;
47575795fabSBruce Richardson }
47675795fabSBruce Richardson 
47775795fabSBruce Richardson /*
47875795fabSBruce Richardson  * Parse ClassBench input trace (test vectors and expected results) file.
47975795fabSBruce Richardson  * Expected format:
48075795fabSBruce Richardson  * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \
48175795fabSBruce Richardson  * <src_port> <space> <dst_port> <space> <proto>
48275795fabSBruce Richardson  */
48375795fabSBruce Richardson static int
48475795fabSBruce Richardson parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v)
48575795fabSBruce Richardson {
48675795fabSBruce Richardson 	int32_t i, rc;
48775795fabSBruce Richardson 	char *s, *sp, *in[CB_TRC_NUM];
48875795fabSBruce Richardson 	static const char *dlm = " \t\n";
48975795fabSBruce Richardson 
49075795fabSBruce Richardson 	s = str;
49175795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(in); i++) {
49275795fabSBruce Richardson 		in[i] = strtok_r(s, dlm, &sp);
49375795fabSBruce Richardson 		if (in[i] == NULL)
49475795fabSBruce Richardson 			return -EINVAL;
49575795fabSBruce Richardson 		s = NULL;
49675795fabSBruce Richardson 	}
49775795fabSBruce Richardson 
49875795fabSBruce Richardson 	/* get ip6 src address. */
49975795fabSBruce Richardson 	rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
50075795fabSBruce Richardson 	if (rc != 0)
50175795fabSBruce Richardson 		return rc;
50275795fabSBruce Richardson 
50375795fabSBruce Richardson 	/* get ip6 dst address. */
50475795fabSBruce Richardson 	rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst);
50575795fabSBruce Richardson 	if (rc != 0)
50675795fabSBruce Richardson 		return rc;
50775795fabSBruce Richardson 
50875795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
50975795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
51075795fabSBruce Richardson 	GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
51175795fabSBruce Richardson 
51275795fabSBruce Richardson 	/* convert to network byte order. */
51375795fabSBruce Richardson 	v->port_src = rte_cpu_to_be_16(v->port_src);
51475795fabSBruce Richardson 	v->port_dst = rte_cpu_to_be_16(v->port_dst);
51575795fabSBruce Richardson 
51675795fabSBruce Richardson 	return 0;
51775795fabSBruce Richardson }
51875795fabSBruce Richardson 
519ca2183d3SKonstantin Ananyev /* Bypass comment and empty lines */
520ca2183d3SKonstantin Ananyev static int
521ca2183d3SKonstantin Ananyev skip_line(const char *buf)
522ca2183d3SKonstantin Ananyev {
523ca2183d3SKonstantin Ananyev 	uint32_t i;
524ca2183d3SKonstantin Ananyev 
525ca2183d3SKonstantin Ananyev 	for (i = 0; isspace(buf[i]) != 0; i++)
526ca2183d3SKonstantin Ananyev 		;
527ca2183d3SKonstantin Ananyev 
528ca2183d3SKonstantin Ananyev 	if (buf[i] == 0 || buf[i] == COMMENT_LEAD_CHAR)
529ca2183d3SKonstantin Ananyev 		return 1;
530ca2183d3SKonstantin Ananyev 
531ca2183d3SKonstantin Ananyev 	return 0;
532ca2183d3SKonstantin Ananyev }
533ca2183d3SKonstantin Ananyev 
53475795fabSBruce Richardson static void
53575795fabSBruce Richardson tracef_init(void)
53675795fabSBruce Richardson {
53775795fabSBruce Richardson 	static const char name[] = APP_NAME;
53875795fabSBruce Richardson 	FILE *f;
53975795fabSBruce Richardson 	size_t sz;
540ca2183d3SKonstantin Ananyev 	uint32_t i, k, n;
54175795fabSBruce Richardson 	struct ipv4_5tuple *v;
54275795fabSBruce Richardson 	struct ipv6_5tuple *w;
54375795fabSBruce Richardson 
54475795fabSBruce Richardson 	sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
54575795fabSBruce Richardson 	config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
54675795fabSBruce Richardson 			SOCKET_ID_ANY);
54775795fabSBruce Richardson 	if (config.traces == NULL)
54875795fabSBruce Richardson 		rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for "
54975795fabSBruce Richardson 			"requested %u number of trace records\n",
55075795fabSBruce Richardson 			sz, config.nb_traces);
55175795fabSBruce Richardson 
55275795fabSBruce Richardson 	f = fopen(config.trace_file, "r");
55375795fabSBruce Richardson 	if (f == NULL)
55475795fabSBruce Richardson 		rte_exit(-EINVAL, "failed to open file: %s\n",
55575795fabSBruce Richardson 			config.trace_file);
55675795fabSBruce Richardson 
55775795fabSBruce Richardson 	v = config.traces;
55875795fabSBruce Richardson 	w = config.traces;
559ca2183d3SKonstantin Ananyev 	k = 0;
560ca2183d3SKonstantin Ananyev 	n = 0;
561ca2183d3SKonstantin Ananyev 	for (i = 0; n != config.nb_traces; i++) {
56275795fabSBruce Richardson 
56375795fabSBruce Richardson 		if (fgets(line, sizeof(line), f) == NULL)
56475795fabSBruce Richardson 			break;
56575795fabSBruce Richardson 
566ca2183d3SKonstantin Ananyev 		if (skip_line(line) != 0) {
567ca2183d3SKonstantin Ananyev 			k++;
568ca2183d3SKonstantin Ananyev 			continue;
569ca2183d3SKonstantin Ananyev 		}
570ca2183d3SKonstantin Ananyev 
571ca2183d3SKonstantin Ananyev 		n = i - k;
572ca2183d3SKonstantin Ananyev 
57375795fabSBruce Richardson 		if (config.ipv6) {
57475795fabSBruce Richardson 			if (parse_cb_ipv6_trace(line, w + n) != 0)
57575795fabSBruce Richardson 				rte_exit(EXIT_FAILURE,
57675795fabSBruce Richardson 					"%s: failed to parse ipv6 trace "
57775795fabSBruce Richardson 					"record at line %u\n",
578ca2183d3SKonstantin Ananyev 					config.trace_file, i + 1);
57975795fabSBruce Richardson 		} else {
58075795fabSBruce Richardson 			if (parse_cb_ipv4_trace(line, v + n) != 0)
58175795fabSBruce Richardson 				rte_exit(EXIT_FAILURE,
58275795fabSBruce Richardson 					"%s: failed to parse ipv4 trace "
58375795fabSBruce Richardson 					"record at line %u\n",
584ca2183d3SKonstantin Ananyev 					config.trace_file, i + 1);
58575795fabSBruce Richardson 		}
58675795fabSBruce Richardson 	}
58775795fabSBruce Richardson 
588ca2183d3SKonstantin Ananyev 	config.used_traces = i - k;
58975795fabSBruce Richardson 	fclose(f);
59075795fabSBruce Richardson }
59175795fabSBruce Richardson 
59275795fabSBruce Richardson static int
59360018ef4SKonstantin Ananyev parse_ipv6_u32_net(char *in, struct rte_acl_field field[IPV6_ADDR_U32])
59475795fabSBruce Richardson {
59560018ef4SKonstantin Ananyev 	char *sa, *sm, *sv;
59660018ef4SKonstantin Ananyev 	uint32_t i, m, v[IPV6_ADDR_U32];
59760018ef4SKonstantin Ananyev 
59860018ef4SKonstantin Ananyev 	const char *dlm = "/";
59975795fabSBruce Richardson 	const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
60075795fabSBruce Richardson 
60175795fabSBruce Richardson 	/* get address. */
60260018ef4SKonstantin Ananyev 	sv = NULL;
60360018ef4SKonstantin Ananyev 	sa = strtok_r(in, dlm, &sv);
60460018ef4SKonstantin Ananyev 	if (sa == NULL)
60560018ef4SKonstantin Ananyev 		return -EINVAL;
60660018ef4SKonstantin Ananyev 	sm = strtok_r(NULL, dlm, &sv);
60760018ef4SKonstantin Ananyev 	if (sm == NULL)
60860018ef4SKonstantin Ananyev 		return -EINVAL;
60960018ef4SKonstantin Ananyev 
61060018ef4SKonstantin Ananyev 	if (inet_pton(AF_INET6, sa, v) != 1)
61160018ef4SKonstantin Ananyev 		return -EINVAL;
61260018ef4SKonstantin Ananyev 
61360018ef4SKonstantin Ananyev 	v[0] = rte_be_to_cpu_32(v[0]);
61460018ef4SKonstantin Ananyev 	v[1] = rte_be_to_cpu_32(v[1]);
61560018ef4SKonstantin Ananyev 	v[2] = rte_be_to_cpu_32(v[2]);
61660018ef4SKonstantin Ananyev 	v[3] = rte_be_to_cpu_32(v[3]);
61775795fabSBruce Richardson 
61875795fabSBruce Richardson 	/* get mask. */
61960018ef4SKonstantin Ananyev 	GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
62075795fabSBruce Richardson 
62175795fabSBruce Richardson 	/* put all together. */
62275795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(v); i++) {
62375795fabSBruce Richardson 		if (m >= (i + 1) * nbu32)
62475795fabSBruce Richardson 			field[i].mask_range.u32 = nbu32;
62575795fabSBruce Richardson 		else
62675795fabSBruce Richardson 			field[i].mask_range.u32 = m > (i * nbu32) ?
62760018ef4SKonstantin Ananyev 				m - (i * nbu32) : 0;
62875795fabSBruce Richardson 
62975795fabSBruce Richardson 		field[i].value.u32 = v[i];
63075795fabSBruce Richardson 	}
63175795fabSBruce Richardson 
63275795fabSBruce Richardson 	return 0;
63375795fabSBruce Richardson }
63475795fabSBruce Richardson 
63560018ef4SKonstantin Ananyev static int
63660018ef4SKonstantin Ananyev parse_ipv6_u64_net(char *in, struct rte_acl_field field[IPV6_ADDR_U64])
63760018ef4SKonstantin Ananyev {
63860018ef4SKonstantin Ananyev 	char *sa, *sm, *sv;
63960018ef4SKonstantin Ananyev 	uint32_t i, m;
64060018ef4SKonstantin Ananyev 	uint64_t v[IPV6_ADDR_U64];
64160018ef4SKonstantin Ananyev 
64260018ef4SKonstantin Ananyev 	const char *dlm = "/";
64360018ef4SKonstantin Ananyev 	const uint32_t nbu64 = sizeof(uint64_t) * CHAR_BIT;
64460018ef4SKonstantin Ananyev 
64560018ef4SKonstantin Ananyev 	/* get address. */
64660018ef4SKonstantin Ananyev 	sv = NULL;
64760018ef4SKonstantin Ananyev 	sa = strtok_r(in, dlm, &sv);
64860018ef4SKonstantin Ananyev 	if (sa == NULL)
64960018ef4SKonstantin Ananyev 		return -EINVAL;
65060018ef4SKonstantin Ananyev 	sm = strtok_r(NULL, dlm, &sv);
65160018ef4SKonstantin Ananyev 	if (sm == NULL)
65260018ef4SKonstantin Ananyev 		return -EINVAL;
65360018ef4SKonstantin Ananyev 
65460018ef4SKonstantin Ananyev 	if (inet_pton(AF_INET6, sa, v) != 1)
65560018ef4SKonstantin Ananyev 		return -EINVAL;
65660018ef4SKonstantin Ananyev 
65760018ef4SKonstantin Ananyev 	v[0] = rte_be_to_cpu_64(v[0]);
65860018ef4SKonstantin Ananyev 	v[1] = rte_be_to_cpu_64(v[1]);
65960018ef4SKonstantin Ananyev 
66060018ef4SKonstantin Ananyev 	/* get mask. */
66160018ef4SKonstantin Ananyev 	GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
66260018ef4SKonstantin Ananyev 
66360018ef4SKonstantin Ananyev 	/* put all together. */
66460018ef4SKonstantin Ananyev 	for (i = 0; i != RTE_DIM(v); i++) {
66560018ef4SKonstantin Ananyev 		if (m >= (i + 1) * nbu64)
66660018ef4SKonstantin Ananyev 			field[i].mask_range.u32 = nbu64;
66760018ef4SKonstantin Ananyev 		else
66860018ef4SKonstantin Ananyev 			field[i].mask_range.u32 = m > (i * nbu64) ?
66960018ef4SKonstantin Ananyev 				m - (i * nbu64) : 0;
67060018ef4SKonstantin Ananyev 
67160018ef4SKonstantin Ananyev 		field[i].value.u64 = v[i];
67260018ef4SKonstantin Ananyev 	}
67360018ef4SKonstantin Ananyev 
67460018ef4SKonstantin Ananyev 	return 0;
67560018ef4SKonstantin Ananyev }
67675795fabSBruce Richardson 
67775795fabSBruce Richardson static int
67860018ef4SKonstantin Ananyev parse_cb_ipv6_rule(char *str, struct acl_rule *v, int frmt)
67975795fabSBruce Richardson {
68075795fabSBruce Richardson 	int i, rc;
68160018ef4SKonstantin Ananyev 	uint32_t fidx;
68260018ef4SKonstantin Ananyev 	const uint32_t *field_map;
68375795fabSBruce Richardson 	char *s, *sp, *in[CB_FLD_NUM];
68460018ef4SKonstantin Ananyev 	int (*parse_ipv6_net)(char *s, struct rte_acl_field f[]);
68560018ef4SKonstantin Ananyev 
68675795fabSBruce Richardson 	static const char *dlm = " \t\n";
68775795fabSBruce Richardson 
68860018ef4SKonstantin Ananyev 	static const uint32_t field_map_u32[CB_FLD_NUM] = {
68960018ef4SKonstantin Ananyev 		[CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6,
69060018ef4SKonstantin Ananyev 		[CB_FLD_DST_ADDR] = DST1_FIELD_IPV6,
69160018ef4SKonstantin Ananyev 		[CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6,
69260018ef4SKonstantin Ananyev 		[CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6,
69360018ef4SKonstantin Ananyev 		[CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6,
69460018ef4SKonstantin Ananyev 		[CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6,
69560018ef4SKonstantin Ananyev 		[CB_FLD_PROTO] = PROTO_FIELD_IPV6,
69660018ef4SKonstantin Ananyev 	};
69760018ef4SKonstantin Ananyev 
69860018ef4SKonstantin Ananyev 	static const uint32_t field_map_u64[CB_FLD_NUM] = {
69960018ef4SKonstantin Ananyev 		[CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6_U64,
70060018ef4SKonstantin Ananyev 		[CB_FLD_DST_ADDR] = DST1_FIELD_IPV6_U64,
70160018ef4SKonstantin Ananyev 		[CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6_U64,
70260018ef4SKonstantin Ananyev 		[CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6_U64,
70360018ef4SKonstantin Ananyev 		[CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6_U64,
70460018ef4SKonstantin Ananyev 		[CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6_U64,
70560018ef4SKonstantin Ananyev 		[CB_FLD_PROTO] = PROTO_FIELD_IPV6_U64,
70660018ef4SKonstantin Ananyev 	};
70760018ef4SKonstantin Ananyev 
70860018ef4SKonstantin Ananyev 	if (frmt == IPV6_FRMT_U32) {
70960018ef4SKonstantin Ananyev 		field_map = field_map_u32;
71060018ef4SKonstantin Ananyev 		parse_ipv6_net = parse_ipv6_u32_net;
71160018ef4SKonstantin Ananyev 	} else if (frmt == IPV6_FRMT_U64) {
71260018ef4SKonstantin Ananyev 		field_map = field_map_u64;
71360018ef4SKonstantin Ananyev 		parse_ipv6_net = parse_ipv6_u64_net;
71460018ef4SKonstantin Ananyev 	} else
71560018ef4SKonstantin Ananyev 		return -ENOTSUP;
71660018ef4SKonstantin Ananyev 
71775795fabSBruce Richardson 	/*
71875795fabSBruce Richardson 	 * Skip leading '@'
71975795fabSBruce Richardson 	 */
72075795fabSBruce Richardson 	if (strchr(str, '@') != str)
72175795fabSBruce Richardson 		return -EINVAL;
72275795fabSBruce Richardson 
72375795fabSBruce Richardson 	s = str + 1;
72475795fabSBruce Richardson 
72575795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(in); i++) {
72675795fabSBruce Richardson 		in[i] = strtok_r(s, dlm, &sp);
72775795fabSBruce Richardson 		if (in[i] == NULL)
72875795fabSBruce Richardson 			return -EINVAL;
72975795fabSBruce Richardson 		s = NULL;
73075795fabSBruce Richardson 	}
73175795fabSBruce Richardson 
73260018ef4SKonstantin Ananyev 	fidx = CB_FLD_SRC_ADDR;
73360018ef4SKonstantin Ananyev 	rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
73475795fabSBruce Richardson 	if (rc != 0) {
73575795fabSBruce Richardson 		RTE_LOG(ERR, TESTACL,
73660018ef4SKonstantin Ananyev 			"failed to read source address/mask: %s\n", in[fidx]);
73775795fabSBruce Richardson 		return rc;
73875795fabSBruce Richardson 	}
73975795fabSBruce Richardson 
74060018ef4SKonstantin Ananyev 	fidx = CB_FLD_DST_ADDR;
74160018ef4SKonstantin Ananyev 	rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
74275795fabSBruce Richardson 	if (rc != 0) {
74375795fabSBruce Richardson 		RTE_LOG(ERR, TESTACL,
74475795fabSBruce Richardson 			"failed to read destination address/mask: %s\n",
74560018ef4SKonstantin Ananyev 			in[fidx]);
74675795fabSBruce Richardson 		return rc;
74775795fabSBruce Richardson 	}
74875795fabSBruce Richardson 
74975795fabSBruce Richardson 	/* source port. */
75060018ef4SKonstantin Ananyev 	fidx = CB_FLD_SRC_PORT_LOW;
75160018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
75275795fabSBruce Richardson 		0, UINT16_MAX, 0);
75360018ef4SKonstantin Ananyev 
75460018ef4SKonstantin Ananyev 	fidx = CB_FLD_SRC_PORT_HIGH;
75560018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
75675795fabSBruce Richardson 		0, UINT16_MAX, 0);
75775795fabSBruce Richardson 
75875795fabSBruce Richardson 	if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
75975795fabSBruce Richardson 			sizeof(cb_port_delim)) != 0)
76075795fabSBruce Richardson 		return -EINVAL;
76175795fabSBruce Richardson 
76275795fabSBruce Richardson 	/* destination port. */
76360018ef4SKonstantin Ananyev 	fidx = CB_FLD_DST_PORT_LOW;
76460018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
76575795fabSBruce Richardson 		0, UINT16_MAX, 0);
76660018ef4SKonstantin Ananyev 
76760018ef4SKonstantin Ananyev 	fidx = CB_FLD_DST_PORT_HIGH;
76860018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
76975795fabSBruce Richardson 		0, UINT16_MAX, 0);
77075795fabSBruce Richardson 
77175795fabSBruce Richardson 	if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
77275795fabSBruce Richardson 			sizeof(cb_port_delim)) != 0)
77375795fabSBruce Richardson 		return -EINVAL;
77475795fabSBruce Richardson 
77560018ef4SKonstantin Ananyev 	fidx = CB_FLD_PROTO;
77660018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u8,
77775795fabSBruce Richardson 		0, UINT8_MAX, '/');
77860018ef4SKonstantin Ananyev 	GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u8,
77975795fabSBruce Richardson 		0, UINT8_MAX, 0);
78075795fabSBruce Richardson 
78175795fabSBruce Richardson 	return 0;
78275795fabSBruce Richardson }
78375795fabSBruce Richardson 
78475795fabSBruce Richardson static int
78560018ef4SKonstantin Ananyev parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v)
78675795fabSBruce Richardson {
78760018ef4SKonstantin Ananyev 	return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32);
78860018ef4SKonstantin Ananyev }
78975795fabSBruce Richardson 
79060018ef4SKonstantin Ananyev static int
79160018ef4SKonstantin Ananyev parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v)
79260018ef4SKonstantin Ananyev {
79360018ef4SKonstantin Ananyev 	return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64);
79460018ef4SKonstantin Ananyev }
79575795fabSBruce Richardson 
79660018ef4SKonstantin Ananyev static int
79760018ef4SKonstantin Ananyev parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
79860018ef4SKonstantin Ananyev {
79960018ef4SKonstantin Ananyev 	char *sa, *sm, *sv;
80060018ef4SKonstantin Ananyev 	uint32_t m, v;
80160018ef4SKonstantin Ananyev 
80260018ef4SKonstantin Ananyev 	const char *dlm = "/";
80360018ef4SKonstantin Ananyev 
80460018ef4SKonstantin Ananyev 	sv = NULL;
80560018ef4SKonstantin Ananyev 	sa = strtok_r(in, dlm, &sv);
80660018ef4SKonstantin Ananyev 	if (sa == NULL)
80760018ef4SKonstantin Ananyev 		return -EINVAL;
80860018ef4SKonstantin Ananyev 	sm = strtok_r(NULL, dlm, &sv);
80960018ef4SKonstantin Ananyev 	if (sm == NULL)
81060018ef4SKonstantin Ananyev 		return -EINVAL;
81160018ef4SKonstantin Ananyev 
81260018ef4SKonstantin Ananyev 	if (inet_pton(AF_INET, sa, &v) != 1)
81360018ef4SKonstantin Ananyev 		return -EINVAL;
81460018ef4SKonstantin Ananyev 
81560018ef4SKonstantin Ananyev 	addr[0] = rte_be_to_cpu_32(v);
81660018ef4SKonstantin Ananyev 
81760018ef4SKonstantin Ananyev 	GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
81875795fabSBruce Richardson 	mask_len[0] = m;
81975795fabSBruce Richardson 
82075795fabSBruce Richardson 	return 0;
82175795fabSBruce Richardson }
82275795fabSBruce Richardson /*
82375795fabSBruce Richardson  * Parse ClassBench rules file.
82475795fabSBruce Richardson  * Expected format:
82575795fabSBruce Richardson  * '@'<src_ipv4_addr>'/'<masklen> <space> \
82675795fabSBruce Richardson  * <dst_ipv4_addr>'/'<masklen> <space> \
82775795fabSBruce Richardson  * <src_port_low> <space> ":" <src_port_high> <space> \
82875795fabSBruce Richardson  * <dst_port_low> <space> ":" <dst_port_high> <space> \
82975795fabSBruce Richardson  * <proto>'/'<mask>
83075795fabSBruce Richardson  */
83175795fabSBruce Richardson static int
83275795fabSBruce Richardson parse_cb_ipv4_rule(char *str, struct acl_rule *v)
83375795fabSBruce Richardson {
83475795fabSBruce Richardson 	int i, rc;
83575795fabSBruce Richardson 	char *s, *sp, *in[CB_FLD_NUM];
83675795fabSBruce Richardson 	static const char *dlm = " \t\n";
83775795fabSBruce Richardson 
83875795fabSBruce Richardson 	/*
83975795fabSBruce Richardson 	 * Skip leading '@'
84075795fabSBruce Richardson 	 */
84175795fabSBruce Richardson 	if (strchr(str, '@') != str)
84275795fabSBruce Richardson 		return -EINVAL;
84375795fabSBruce Richardson 
84475795fabSBruce Richardson 	s = str + 1;
84575795fabSBruce Richardson 
84675795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(in); i++) {
84775795fabSBruce Richardson 		in[i] = strtok_r(s, dlm, &sp);
84875795fabSBruce Richardson 		if (in[i] == NULL)
84975795fabSBruce Richardson 			return -EINVAL;
85075795fabSBruce Richardson 		s = NULL;
85175795fabSBruce Richardson 	}
85275795fabSBruce Richardson 
85375795fabSBruce Richardson 	rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
85475795fabSBruce Richardson 			&v->field[SRC_FIELD_IPV4].value.u32,
85575795fabSBruce Richardson 			&v->field[SRC_FIELD_IPV4].mask_range.u32);
85675795fabSBruce Richardson 	if (rc != 0) {
85775795fabSBruce Richardson 		RTE_LOG(ERR, TESTACL,
85875795fabSBruce Richardson 			"failed to read source address/mask: %s\n",
85975795fabSBruce Richardson 			in[CB_FLD_SRC_ADDR]);
86075795fabSBruce Richardson 		return rc;
86175795fabSBruce Richardson 	}
86275795fabSBruce Richardson 
86375795fabSBruce Richardson 	rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
86475795fabSBruce Richardson 			&v->field[DST_FIELD_IPV4].value.u32,
86575795fabSBruce Richardson 			&v->field[DST_FIELD_IPV4].mask_range.u32);
86675795fabSBruce Richardson 	if (rc != 0) {
86775795fabSBruce Richardson 		RTE_LOG(ERR, TESTACL,
86875795fabSBruce Richardson 			"failed to read destination address/mask: %s\n",
86975795fabSBruce Richardson 			in[CB_FLD_DST_ADDR]);
87075795fabSBruce Richardson 		return rc;
87175795fabSBruce Richardson 	}
87275795fabSBruce Richardson 
87375795fabSBruce Richardson 	/* source port. */
87475795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
87575795fabSBruce Richardson 		v->field[SRCP_FIELD_IPV4].value.u16,
87675795fabSBruce Richardson 		0, UINT16_MAX, 0);
87775795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
87875795fabSBruce Richardson 		v->field[SRCP_FIELD_IPV4].mask_range.u16,
87975795fabSBruce Richardson 		0, UINT16_MAX, 0);
88075795fabSBruce Richardson 
88175795fabSBruce Richardson 	if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
88275795fabSBruce Richardson 			sizeof(cb_port_delim)) != 0)
88375795fabSBruce Richardson 		return -EINVAL;
88475795fabSBruce Richardson 
88575795fabSBruce Richardson 	/* destination port. */
88675795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
88775795fabSBruce Richardson 		v->field[DSTP_FIELD_IPV4].value.u16,
88875795fabSBruce Richardson 		0, UINT16_MAX, 0);
88975795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
89075795fabSBruce Richardson 		v->field[DSTP_FIELD_IPV4].mask_range.u16,
89175795fabSBruce Richardson 		0, UINT16_MAX, 0);
89275795fabSBruce Richardson 
89375795fabSBruce Richardson 	if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
89475795fabSBruce Richardson 			sizeof(cb_port_delim)) != 0)
89575795fabSBruce Richardson 		return -EINVAL;
89675795fabSBruce Richardson 
89775795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8,
89875795fabSBruce Richardson 		0, UINT8_MAX, '/');
89975795fabSBruce Richardson 	GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8,
90075795fabSBruce Richardson 		0, UINT8_MAX, 0);
90175795fabSBruce Richardson 
90275795fabSBruce Richardson 	return 0;
90375795fabSBruce Richardson }
90475795fabSBruce Richardson 
90575795fabSBruce Richardson typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
90675795fabSBruce Richardson 
90775795fabSBruce Richardson static int
90875795fabSBruce Richardson add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
90975795fabSBruce Richardson {
91075795fabSBruce Richardson 	int rc;
911ca2183d3SKonstantin Ananyev 	uint32_t i, k, n;
91275795fabSBruce Richardson 	struct acl_rule v;
91375795fabSBruce Richardson 	parse_5tuple parser;
91475795fabSBruce Richardson 
91560018ef4SKonstantin Ananyev 	static const parse_5tuple parser_func[] = {
91660018ef4SKonstantin Ananyev 		[IPV6_FRMT_NONE] = parse_cb_ipv4_rule,
91760018ef4SKonstantin Ananyev 		[IPV6_FRMT_U32] = parse_cb_ipv6_u32_rule,
91860018ef4SKonstantin Ananyev 		[IPV6_FRMT_U64] = parse_cb_ipv6_u64_rule,
91960018ef4SKonstantin Ananyev 	};
92060018ef4SKonstantin Ananyev 
92175795fabSBruce Richardson 	memset(&v, 0, sizeof(v));
92260018ef4SKonstantin Ananyev 	parser = parser_func[config.ipv6];
92375795fabSBruce Richardson 
924ca2183d3SKonstantin Ananyev 	k = 0;
925ca2183d3SKonstantin Ananyev 	for (i = 1; fgets(line, sizeof(line), f) != NULL; i++) {
92675795fabSBruce Richardson 
927ca2183d3SKonstantin Ananyev 		if (skip_line(line) != 0) {
928ca2183d3SKonstantin Ananyev 			k++;
929ca2183d3SKonstantin Ananyev 			continue;
930ca2183d3SKonstantin Ananyev 		}
931ca2183d3SKonstantin Ananyev 
932ca2183d3SKonstantin Ananyev 		n = i - k;
93375795fabSBruce Richardson 		rc = parser(line, &v);
93475795fabSBruce Richardson 		if (rc != 0) {
93575795fabSBruce Richardson 			RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
93675795fabSBruce Richardson 				" failed, error code: %d (%s)\n",
937ca2183d3SKonstantin Ananyev 				i, rc, strerror(-rc));
93875795fabSBruce Richardson 			return rc;
93975795fabSBruce Richardson 		}
94075795fabSBruce Richardson 
94175795fabSBruce Richardson 		v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES,
94275795fabSBruce Richardson 			typeof(v.data.category_mask));
94375795fabSBruce Richardson 		v.data.priority = RTE_ACL_MAX_PRIORITY - n;
94475795fabSBruce Richardson 		v.data.userdata = n;
94575795fabSBruce Richardson 
94675795fabSBruce Richardson 		rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1);
94775795fabSBruce Richardson 		if (rc != 0) {
94875795fabSBruce Richardson 			RTE_LOG(ERR, TESTACL, "line %u: failed to add rules "
94975795fabSBruce Richardson 				"into ACL context, error code: %d (%s)\n",
950ca2183d3SKonstantin Ananyev 				i, rc, strerror(-rc));
95175795fabSBruce Richardson 			return rc;
95275795fabSBruce Richardson 		}
95375795fabSBruce Richardson 	}
95475795fabSBruce Richardson 
95575795fabSBruce Richardson 	return 0;
95675795fabSBruce Richardson }
95775795fabSBruce Richardson 
95875795fabSBruce Richardson static void
95975795fabSBruce Richardson acx_init(void)
96075795fabSBruce Richardson {
96175795fabSBruce Richardson 	int ret;
96275795fabSBruce Richardson 	FILE *f;
96375795fabSBruce Richardson 	struct rte_acl_config cfg;
96475795fabSBruce Richardson 
96575795fabSBruce Richardson 	memset(&cfg, 0, sizeof(cfg));
96675795fabSBruce Richardson 
96775795fabSBruce Richardson 	/* setup ACL build config. */
96860018ef4SKonstantin Ananyev 	if (config.ipv6 == IPV6_FRMT_U32) {
96975795fabSBruce Richardson 		cfg.num_fields = RTE_DIM(ipv6_defs);
97075795fabSBruce Richardson 		memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs));
97160018ef4SKonstantin Ananyev 	} else if (config.ipv6 == IPV6_FRMT_U64) {
97260018ef4SKonstantin Ananyev 		cfg.num_fields = RTE_DIM(ipv6_u64_defs);
97360018ef4SKonstantin Ananyev 		memcpy(&cfg.defs, ipv6_u64_defs, sizeof(ipv6_u64_defs));
97475795fabSBruce Richardson 	} else {
97575795fabSBruce Richardson 		cfg.num_fields = RTE_DIM(ipv4_defs);
97675795fabSBruce Richardson 		memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
97775795fabSBruce Richardson 	}
97875795fabSBruce Richardson 	cfg.num_categories = config.bld_categories;
97975795fabSBruce Richardson 	cfg.max_size = config.max_size;
98075795fabSBruce Richardson 
98175795fabSBruce Richardson 	/* setup ACL creation parameters. */
98275795fabSBruce Richardson 	prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
98375795fabSBruce Richardson 	prm.max_rule_num = config.nb_rules;
98475795fabSBruce Richardson 
98575795fabSBruce Richardson 	config.acx = rte_acl_create(&prm);
98675795fabSBruce Richardson 	if (config.acx == NULL)
98775795fabSBruce Richardson 		rte_exit(rte_errno, "failed to create ACL context\n");
98875795fabSBruce Richardson 
98975795fabSBruce Richardson 	/* set default classify method for this context. */
99075795fabSBruce Richardson 	if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) {
99175795fabSBruce Richardson 		ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg);
99275795fabSBruce Richardson 		if (ret != 0)
99375795fabSBruce Richardson 			rte_exit(ret, "failed to setup %s method "
99475795fabSBruce Richardson 				"for ACL context\n", config.alg.name);
99575795fabSBruce Richardson 	}
99675795fabSBruce Richardson 
99775795fabSBruce Richardson 	/* add ACL rules. */
99875795fabSBruce Richardson 	f = fopen(config.rule_file, "r");
99975795fabSBruce Richardson 	if (f == NULL)
100075795fabSBruce Richardson 		rte_exit(-EINVAL, "failed to open file %s\n",
100175795fabSBruce Richardson 			config.rule_file);
100275795fabSBruce Richardson 
100375795fabSBruce Richardson 	ret = add_cb_rules(f, config.acx);
100475795fabSBruce Richardson 	if (ret != 0)
100575795fabSBruce Richardson 		rte_exit(ret, "failed to add rules into ACL context\n");
100675795fabSBruce Richardson 
100775795fabSBruce Richardson 	fclose(f);
100875795fabSBruce Richardson 
100975795fabSBruce Richardson 	/* perform build. */
101075795fabSBruce Richardson 	ret = rte_acl_build(config.acx, &cfg);
101175795fabSBruce Richardson 
101275795fabSBruce Richardson 	dump_verbose(DUMP_NONE, stdout,
101375795fabSBruce Richardson 		"rte_acl_build(%u) finished with %d\n",
101475795fabSBruce Richardson 		config.bld_categories, ret);
101575795fabSBruce Richardson 
101675795fabSBruce Richardson 	rte_acl_dump(config.acx);
101775795fabSBruce Richardson 
101875795fabSBruce Richardson 	if (ret != 0)
101975795fabSBruce Richardson 		rte_exit(ret, "failed to build search context\n");
102075795fabSBruce Richardson }
102175795fabSBruce Richardson 
102275795fabSBruce Richardson static uint32_t
102375795fabSBruce Richardson search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
102475795fabSBruce Richardson {
102575795fabSBruce Richardson 	int ret;
102675795fabSBruce Richardson 	uint32_t i, j, k, n, r;
102775795fabSBruce Richardson 	const uint8_t *data[step], *v;
102875795fabSBruce Richardson 	uint32_t results[step * categories];
102975795fabSBruce Richardson 
103075795fabSBruce Richardson 	v = config.traces;
103175795fabSBruce Richardson 	for (i = 0; i != config.used_traces; i += n) {
103275795fabSBruce Richardson 
103375795fabSBruce Richardson 		n = RTE_MIN(step, config.used_traces - i);
103475795fabSBruce Richardson 
103575795fabSBruce Richardson 		for (j = 0; j != n; j++) {
103675795fabSBruce Richardson 			data[j] = v;
103775795fabSBruce Richardson 			v += config.trace_sz;
103875795fabSBruce Richardson 		}
103975795fabSBruce Richardson 
104075795fabSBruce Richardson 		ret = rte_acl_classify(config.acx, data, results,
104175795fabSBruce Richardson 			n, categories);
104275795fabSBruce Richardson 
104375795fabSBruce Richardson 		if (ret != 0)
104475795fabSBruce Richardson 			rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
104575795fabSBruce Richardson 				config.ipv6 ? '6' : '4', ret);
104675795fabSBruce Richardson 
104775795fabSBruce Richardson 		for (r = 0, j = 0; j != n; j++) {
104875795fabSBruce Richardson 			for (k = 0; k != categories; k++, r++) {
104975795fabSBruce Richardson 				dump_verbose(DUMP_PKT, stdout,
105075795fabSBruce Richardson 					"ipv%c_5tuple: %u, category: %u, "
105175795fabSBruce Richardson 					"result: %u\n",
105275795fabSBruce Richardson 					config.ipv6 ? '6' : '4',
105375795fabSBruce Richardson 					i + j + 1, k, results[r] - 1);
105475795fabSBruce Richardson 			}
105575795fabSBruce Richardson 
105675795fabSBruce Richardson 		}
105775795fabSBruce Richardson 	}
105875795fabSBruce Richardson 
105975795fabSBruce Richardson 	dump_verbose(DUMP_SEARCH, stdout,
106075795fabSBruce Richardson 		"%s(%u, %u, %s) returns %u\n", __func__,
106175795fabSBruce Richardson 		categories, step, alg, i);
106275795fabSBruce Richardson 	return i;
106375795fabSBruce Richardson }
106475795fabSBruce Richardson 
106575795fabSBruce Richardson static int
1066f2fc83b4SThomas Monjalon search_ip5tuples(__rte_unused void *arg)
106775795fabSBruce Richardson {
106875795fabSBruce Richardson 	uint64_t pkt, start, tm;
106975795fabSBruce Richardson 	uint32_t i, lcore;
1070bcb9a016SKonstantin Ananyev 	long double st;
107175795fabSBruce Richardson 
107275795fabSBruce Richardson 	lcore = rte_lcore_id();
1073bcb9a016SKonstantin Ananyev 	start = rte_rdtsc_precise();
107475795fabSBruce Richardson 	pkt = 0;
107575795fabSBruce Richardson 
107675795fabSBruce Richardson 	for (i = 0; i != config.iter_num; i++) {
107775795fabSBruce Richardson 		pkt += search_ip5tuples_once(config.run_categories,
107875795fabSBruce Richardson 			config.trace_step, config.alg.name);
107975795fabSBruce Richardson 	}
108075795fabSBruce Richardson 
1081bcb9a016SKonstantin Ananyev 	tm = rte_rdtsc_precise() - start;
1082bcb9a016SKonstantin Ananyev 
1083bcb9a016SKonstantin Ananyev 	st = (long double)tm / rte_get_timer_hz();
108475795fabSBruce Richardson 	dump_verbose(DUMP_NONE, stdout,
108575795fabSBruce Richardson 		"%s  @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %"
1086bcb9a016SKonstantin Ananyev 		PRIu32 " categories, %" PRIu64 " cycles (%.2Lf sec), "
1087bcb9a016SKonstantin Ananyev 		"%.2Lf cycles/pkt, %.2Lf pkt/sec\n",
1088bcb9a016SKonstantin Ananyev 		__func__, lcore, i, pkt,
1089bcb9a016SKonstantin Ananyev 		config.run_categories, tm, st,
1090bcb9a016SKonstantin Ananyev 		(pkt == 0) ? 0 : (long double)tm / pkt, pkt / st);
109175795fabSBruce Richardson 
109275795fabSBruce Richardson 	return 0;
109375795fabSBruce Richardson }
109475795fabSBruce Richardson 
109575795fabSBruce Richardson static unsigned long
109675795fabSBruce Richardson get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
109775795fabSBruce Richardson {
109875795fabSBruce Richardson 	unsigned long val;
109975795fabSBruce Richardson 	char *end;
110075795fabSBruce Richardson 
110175795fabSBruce Richardson 	errno = 0;
110275795fabSBruce Richardson 	val = strtoul(opt, &end, 0);
110375795fabSBruce Richardson 	if (errno != 0 || end[0] != 0 || val > max || val < min)
110475795fabSBruce Richardson 		rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
110575795fabSBruce Richardson 			opt, name);
110675795fabSBruce Richardson 	return val;
110775795fabSBruce Richardson }
110875795fabSBruce Richardson 
110975795fabSBruce Richardson static void
111075795fabSBruce Richardson get_alg_opt(const char *opt, const char *name)
111175795fabSBruce Richardson {
111275795fabSBruce Richardson 	uint32_t i;
111375795fabSBruce Richardson 
111475795fabSBruce Richardson 	for (i = 0; i != RTE_DIM(acl_alg); i++) {
111575795fabSBruce Richardson 		if (strcmp(opt, acl_alg[i].name) == 0) {
111675795fabSBruce Richardson 			config.alg = acl_alg[i];
111775795fabSBruce Richardson 			return;
111875795fabSBruce Richardson 		}
111975795fabSBruce Richardson 	}
112075795fabSBruce Richardson 
112175795fabSBruce Richardson 	rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
112275795fabSBruce Richardson 		opt, name);
112375795fabSBruce Richardson }
112475795fabSBruce Richardson 
112575795fabSBruce Richardson static void
112660018ef4SKonstantin Ananyev get_ipv6_opt(const char *opt, const char *name)
112760018ef4SKonstantin Ananyev {
112860018ef4SKonstantin Ananyev 	uint32_t i;
112960018ef4SKonstantin Ananyev 
113060018ef4SKonstantin Ananyev 	static const struct {
113160018ef4SKonstantin Ananyev 		const char *name;
113260018ef4SKonstantin Ananyev 		uint32_t val;
113360018ef4SKonstantin Ananyev 	} ipv6_opt[] = {
113460018ef4SKonstantin Ananyev 		{
113560018ef4SKonstantin Ananyev 			.name = "4B",
113660018ef4SKonstantin Ananyev 			.val = IPV6_FRMT_U32,
113760018ef4SKonstantin Ananyev 		},
113860018ef4SKonstantin Ananyev 		{
113960018ef4SKonstantin Ananyev 			.name = "8B",
114060018ef4SKonstantin Ananyev 			.val = IPV6_FRMT_U64,
114160018ef4SKonstantin Ananyev 		},
114260018ef4SKonstantin Ananyev 	};
114360018ef4SKonstantin Ananyev 
114460018ef4SKonstantin Ananyev 	for (i = 0; i != RTE_DIM(ipv6_opt); i++) {
114560018ef4SKonstantin Ananyev 		if (strcmp(opt, ipv6_opt[i].name) == 0) {
114660018ef4SKonstantin Ananyev 			config.ipv6 = ipv6_opt[i].val;
114760018ef4SKonstantin Ananyev 			return;
114860018ef4SKonstantin Ananyev 		}
114960018ef4SKonstantin Ananyev 	}
115060018ef4SKonstantin Ananyev 
115160018ef4SKonstantin Ananyev 	rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
115260018ef4SKonstantin Ananyev 		opt, name);
115360018ef4SKonstantin Ananyev }
115460018ef4SKonstantin Ananyev 
115560018ef4SKonstantin Ananyev 
115660018ef4SKonstantin Ananyev static void
115775795fabSBruce Richardson print_usage(const char *prgname)
115875795fabSBruce Richardson {
115975795fabSBruce Richardson 	uint32_t i, n, rc;
116075795fabSBruce Richardson 	char buf[PATH_MAX];
116175795fabSBruce Richardson 
116275795fabSBruce Richardson 	n = 0;
116375795fabSBruce Richardson 	buf[0] = 0;
116475795fabSBruce Richardson 
116575795fabSBruce Richardson 	for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
116675795fabSBruce Richardson 		rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
116775795fabSBruce Richardson 			acl_alg[i].name);
116875795fabSBruce Richardson 		if (rc > sizeof(buf) - n)
116975795fabSBruce Richardson 			break;
117075795fabSBruce Richardson 		n += rc;
117175795fabSBruce Richardson 	}
117275795fabSBruce Richardson 
11736723c0fcSBruce Richardson 	strlcpy(buf + n, acl_alg[i].name, sizeof(buf) - n);
117475795fabSBruce Richardson 
117575795fabSBruce Richardson 	fprintf(stdout,
117675795fabSBruce Richardson 		PRINT_USAGE_START
117775795fabSBruce Richardson 		"--" OPT_RULE_FILE "=<rules set file>\n"
117875795fabSBruce Richardson 		"[--" OPT_TRACE_FILE "=<input traces file>]\n"
117975795fabSBruce Richardson 		"[--" OPT_RULE_NUM
118075795fabSBruce Richardson 			"=<maximum number of rules for ACL context>]\n"
118175795fabSBruce Richardson 		"[--" OPT_TRACE_NUM
118275795fabSBruce Richardson 			"=<number of traces to read binary file in>]\n"
118375795fabSBruce Richardson 		"[--" OPT_TRACE_STEP
118475795fabSBruce Richardson 			"=<number of traces to classify per one call>]\n"
118575795fabSBruce Richardson 		"[--" OPT_BLD_CATEGORIES
118675795fabSBruce Richardson 			"=<number of categories to build with>]\n"
118775795fabSBruce Richardson 		"[--" OPT_RUN_CATEGORIES
118875795fabSBruce Richardson 			"=<number of categories to run with> "
118975795fabSBruce Richardson 			"should be either 1 or multiple of %zu, "
119075795fabSBruce Richardson 			"but not greater then %u]\n"
119175795fabSBruce Richardson 		"[--" OPT_MAX_SIZE
11927be78d02SJosh Soref 			"=<size limit (in bytes) for runtime ACL structures> "
119375795fabSBruce Richardson 			"leave 0 for default behaviour]\n"
119475795fabSBruce Richardson 		"[--" OPT_ITER_NUM "=<number of iterations to perform>]\n"
119575795fabSBruce Richardson 		"[--" OPT_VERBOSE "=<verbose level>]\n"
119675795fabSBruce Richardson 		"[--" OPT_SEARCH_ALG "=%s]\n"
119760018ef4SKonstantin Ananyev 		"[--" OPT_IPV6 "(=4B | 8B) <IPv6 rules and trace files>]\n",
119875795fabSBruce Richardson 		prgname, RTE_ACL_RESULTS_MULTIPLIER,
119975795fabSBruce Richardson 		(uint32_t)RTE_ACL_MAX_CATEGORIES,
120075795fabSBruce Richardson 		buf);
120175795fabSBruce Richardson }
120275795fabSBruce Richardson 
120375795fabSBruce Richardson static void
120475795fabSBruce Richardson dump_config(FILE *f)
120575795fabSBruce Richardson {
120675795fabSBruce Richardson 	fprintf(f, "%s:\n", __func__);
120775795fabSBruce Richardson 	fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file);
120875795fabSBruce Richardson 	fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file);
120975795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules);
121075795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces);
121175795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step);
121275795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories);
121375795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories);
121475795fabSBruce Richardson 	fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size);
121575795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num);
121675795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose);
121775795fabSBruce Richardson 	fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg,
121875795fabSBruce Richardson 		config.alg.name);
121975795fabSBruce Richardson 	fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
122075795fabSBruce Richardson }
122175795fabSBruce Richardson 
122275795fabSBruce Richardson static void
122375795fabSBruce Richardson check_config(void)
122475795fabSBruce Richardson {
122575795fabSBruce Richardson 	if (config.rule_file == NULL) {
122675795fabSBruce Richardson 		print_usage(config.prgname);
122775795fabSBruce Richardson 		rte_exit(-EINVAL, "mandatory option %s is not specified\n",
122875795fabSBruce Richardson 			OPT_RULE_FILE);
122975795fabSBruce Richardson 	}
123075795fabSBruce Richardson }
123175795fabSBruce Richardson 
123275795fabSBruce Richardson 
123375795fabSBruce Richardson static void
123475795fabSBruce Richardson get_input_opts(int argc, char **argv)
123575795fabSBruce Richardson {
123675795fabSBruce Richardson 	static struct option lgopts[] = {
123775795fabSBruce Richardson 		{OPT_RULE_FILE, 1, 0, 0},
123875795fabSBruce Richardson 		{OPT_TRACE_FILE, 1, 0, 0},
123975795fabSBruce Richardson 		{OPT_TRACE_NUM, 1, 0, 0},
124075795fabSBruce Richardson 		{OPT_RULE_NUM, 1, 0, 0},
124175795fabSBruce Richardson 		{OPT_MAX_SIZE, 1, 0, 0},
124275795fabSBruce Richardson 		{OPT_TRACE_STEP, 1, 0, 0},
124375795fabSBruce Richardson 		{OPT_BLD_CATEGORIES, 1, 0, 0},
124475795fabSBruce Richardson 		{OPT_RUN_CATEGORIES, 1, 0, 0},
124575795fabSBruce Richardson 		{OPT_ITER_NUM, 1, 0, 0},
124675795fabSBruce Richardson 		{OPT_VERBOSE, 1, 0, 0},
124775795fabSBruce Richardson 		{OPT_SEARCH_ALG, 1, 0, 0},
124860018ef4SKonstantin Ananyev 		{OPT_IPV6, 2, 0, 0},
124975795fabSBruce Richardson 		{NULL, 0, 0, 0}
125075795fabSBruce Richardson 	};
125175795fabSBruce Richardson 
125275795fabSBruce Richardson 	int opt, opt_idx;
125375795fabSBruce Richardson 
125475795fabSBruce Richardson 	while ((opt = getopt_long(argc, argv, "", lgopts,  &opt_idx)) != EOF) {
125575795fabSBruce Richardson 
125675795fabSBruce Richardson 		if (opt != 0) {
125775795fabSBruce Richardson 			print_usage(config.prgname);
125875795fabSBruce Richardson 			rte_exit(-EINVAL, "unknown option: %c", opt);
125975795fabSBruce Richardson 		}
126075795fabSBruce Richardson 
126175795fabSBruce Richardson 		if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) {
126275795fabSBruce Richardson 			config.rule_file = optarg;
126375795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) {
126475795fabSBruce Richardson 			config.trace_file = optarg;
126575795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) {
126675795fabSBruce Richardson 			config.nb_rules = get_ulong_opt(optarg,
126775795fabSBruce Richardson 				lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1);
126875795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) {
126975795fabSBruce Richardson 			config.max_size = get_ulong_opt(optarg,
127075795fabSBruce Richardson 				lgopts[opt_idx].name, 0, SIZE_MAX);
127175795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) {
127275795fabSBruce Richardson 			config.nb_traces = get_ulong_opt(optarg,
127375795fabSBruce Richardson 				lgopts[opt_idx].name, 1, UINT32_MAX);
127475795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) {
127575795fabSBruce Richardson 			config.trace_step = get_ulong_opt(optarg,
127675795fabSBruce Richardson 				lgopts[opt_idx].name, 1, TRACE_STEP_MAX);
127775795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name,
127875795fabSBruce Richardson 				OPT_BLD_CATEGORIES) == 0) {
127975795fabSBruce Richardson 			config.bld_categories = get_ulong_opt(optarg,
128075795fabSBruce Richardson 				lgopts[opt_idx].name, 1,
128175795fabSBruce Richardson 				RTE_ACL_MAX_CATEGORIES);
128275795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name,
128375795fabSBruce Richardson 				OPT_RUN_CATEGORIES) == 0) {
128475795fabSBruce Richardson 			config.run_categories = get_ulong_opt(optarg,
128575795fabSBruce Richardson 				lgopts[opt_idx].name, 1,
128675795fabSBruce Richardson 				RTE_ACL_MAX_CATEGORIES);
128775795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) {
128875795fabSBruce Richardson 			config.iter_num = get_ulong_opt(optarg,
128975795fabSBruce Richardson 				lgopts[opt_idx].name, 1, INT32_MAX);
129075795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) {
129175795fabSBruce Richardson 			config.verbose = get_ulong_opt(optarg,
129275795fabSBruce Richardson 				lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX);
129375795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name,
129475795fabSBruce Richardson 				OPT_SEARCH_ALG) == 0) {
129575795fabSBruce Richardson 			get_alg_opt(optarg, lgopts[opt_idx].name);
129675795fabSBruce Richardson 		} else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) {
129760018ef4SKonstantin Ananyev 			config.ipv6 = IPV6_FRMT_U32;
129860018ef4SKonstantin Ananyev 			if (optarg != NULL)
129960018ef4SKonstantin Ananyev 				get_ipv6_opt(optarg, lgopts[opt_idx].name);
130075795fabSBruce Richardson 		}
130175795fabSBruce Richardson 	}
130275795fabSBruce Richardson 	config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
130375795fabSBruce Richardson 						sizeof(struct ipv4_5tuple);
130475795fabSBruce Richardson 
130575795fabSBruce Richardson }
130675795fabSBruce Richardson 
130775795fabSBruce Richardson int
130875795fabSBruce Richardson main(int argc, char **argv)
130975795fabSBruce Richardson {
131075795fabSBruce Richardson 	int ret;
131175795fabSBruce Richardson 	uint32_t lcore;
131275795fabSBruce Richardson 
131375795fabSBruce Richardson 	ret = rte_eal_init(argc, argv);
131475795fabSBruce Richardson 	if (ret < 0)
131575795fabSBruce Richardson 		rte_panic("Cannot init EAL\n");
131675795fabSBruce Richardson 
131775795fabSBruce Richardson 	argc -= ret;
131875795fabSBruce Richardson 	argv += ret;
131975795fabSBruce Richardson 
132075795fabSBruce Richardson 	config.prgname = argv[0];
132175795fabSBruce Richardson 
132275795fabSBruce Richardson 	get_input_opts(argc, argv);
132375795fabSBruce Richardson 	dump_config(stdout);
132475795fabSBruce Richardson 	check_config();
132575795fabSBruce Richardson 
132675795fabSBruce Richardson 	acx_init();
132775795fabSBruce Richardson 
132875795fabSBruce Richardson 	if (config.trace_file != NULL)
132975795fabSBruce Richardson 		tracef_init();
133075795fabSBruce Richardson 
1331cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(lcore)
133275795fabSBruce Richardson 		 rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
133375795fabSBruce Richardson 
133475795fabSBruce Richardson 	search_ip5tuples(NULL);
133575795fabSBruce Richardson 
133675795fabSBruce Richardson 	rte_eal_mp_wait_lcore();
133775795fabSBruce Richardson 
133875795fabSBruce Richardson 	rte_acl_free(config.acx);
133975795fabSBruce Richardson 	return 0;
134075795fabSBruce Richardson }
1341