xref: /dpdk/lib/acl/rte_acl.c (revision b0986c39fa9dd0019a492fcd9329f8ed1cdff430)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_eal_memconfig.h>
699a2dd95SBruce Richardson #include <rte_string_fns.h>
799a2dd95SBruce Richardson #include <rte_acl.h>
899a2dd95SBruce Richardson #include <rte_tailq.h>
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #include "acl.h"
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson TAILQ_HEAD(rte_acl_list, rte_tailq_entry);
1399a2dd95SBruce Richardson 
1499a2dd95SBruce Richardson static struct rte_tailq_elem rte_acl_tailq = {
1599a2dd95SBruce Richardson 	.name = "RTE_ACL",
1699a2dd95SBruce Richardson };
1799a2dd95SBruce Richardson EAL_REGISTER_TAILQ(rte_acl_tailq)
1899a2dd95SBruce Richardson 
1999a2dd95SBruce Richardson #ifndef CC_AVX512_SUPPORT
2099a2dd95SBruce Richardson /*
2199a2dd95SBruce Richardson  * If the compiler doesn't support AVX512 instructions,
2299a2dd95SBruce Richardson  * then the dummy one would be used instead for AVX512 classify method.
2399a2dd95SBruce Richardson  */
2499a2dd95SBruce Richardson int
2599a2dd95SBruce Richardson rte_acl_classify_avx512x16(__rte_unused const struct rte_acl_ctx *ctx,
2699a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
2799a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
2899a2dd95SBruce Richardson 	__rte_unused uint32_t num,
2999a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
3099a2dd95SBruce Richardson {
3199a2dd95SBruce Richardson 	return -ENOTSUP;
3299a2dd95SBruce Richardson }
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson int
3599a2dd95SBruce Richardson rte_acl_classify_avx512x32(__rte_unused const struct rte_acl_ctx *ctx,
3699a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
3799a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
3899a2dd95SBruce Richardson 	__rte_unused uint32_t num,
3999a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
4099a2dd95SBruce Richardson {
4199a2dd95SBruce Richardson 	return -ENOTSUP;
4299a2dd95SBruce Richardson }
4399a2dd95SBruce Richardson #endif
4499a2dd95SBruce Richardson 
45*b0986c39SBruce Richardson #ifndef RTE_ARCH_X86
4699a2dd95SBruce Richardson /*
47*b0986c39SBruce Richardson  * If ISA doesn't have AVX2 or SSE, provide dummy fallbacks
4899a2dd95SBruce Richardson  */
4999a2dd95SBruce Richardson int
5099a2dd95SBruce Richardson rte_acl_classify_avx2(__rte_unused const struct rte_acl_ctx *ctx,
5199a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
5299a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
5399a2dd95SBruce Richardson 	__rte_unused uint32_t num,
5499a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
5599a2dd95SBruce Richardson {
5699a2dd95SBruce Richardson 	return -ENOTSUP;
5799a2dd95SBruce Richardson }
5899a2dd95SBruce Richardson int
5999a2dd95SBruce Richardson rte_acl_classify_sse(__rte_unused const struct rte_acl_ctx *ctx,
6099a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
6199a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
6299a2dd95SBruce Richardson 	__rte_unused uint32_t num,
6399a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
6499a2dd95SBruce Richardson {
6599a2dd95SBruce Richardson 	return -ENOTSUP;
6699a2dd95SBruce Richardson }
6799a2dd95SBruce Richardson #endif
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson #ifndef RTE_ARCH_ARM
7099a2dd95SBruce Richardson int
7199a2dd95SBruce Richardson rte_acl_classify_neon(__rte_unused const struct rte_acl_ctx *ctx,
7299a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
7399a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
7499a2dd95SBruce Richardson 	__rte_unused uint32_t num,
7599a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
7699a2dd95SBruce Richardson {
7799a2dd95SBruce Richardson 	return -ENOTSUP;
7899a2dd95SBruce Richardson }
7999a2dd95SBruce Richardson #endif
8099a2dd95SBruce Richardson 
8199a2dd95SBruce Richardson #ifndef RTE_ARCH_PPC_64
8299a2dd95SBruce Richardson int
8399a2dd95SBruce Richardson rte_acl_classify_altivec(__rte_unused const struct rte_acl_ctx *ctx,
8499a2dd95SBruce Richardson 	__rte_unused const uint8_t **data,
8599a2dd95SBruce Richardson 	__rte_unused uint32_t *results,
8699a2dd95SBruce Richardson 	__rte_unused uint32_t num,
8799a2dd95SBruce Richardson 	__rte_unused uint32_t categories)
8899a2dd95SBruce Richardson {
8999a2dd95SBruce Richardson 	return -ENOTSUP;
9099a2dd95SBruce Richardson }
9199a2dd95SBruce Richardson #endif
9299a2dd95SBruce Richardson 
9399a2dd95SBruce Richardson static const rte_acl_classify_t classify_fns[] = {
9499a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_DEFAULT] = rte_acl_classify_scalar,
9599a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_SCALAR] = rte_acl_classify_scalar,
9699a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_SSE] = rte_acl_classify_sse,
9799a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_AVX2] = rte_acl_classify_avx2,
9899a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_NEON] = rte_acl_classify_neon,
9999a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_ALTIVEC] = rte_acl_classify_altivec,
10099a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_AVX512X16] = rte_acl_classify_avx512x16,
10199a2dd95SBruce Richardson 	[RTE_ACL_CLASSIFY_AVX512X32] = rte_acl_classify_avx512x32,
10299a2dd95SBruce Richardson };
10399a2dd95SBruce Richardson 
10499a2dd95SBruce Richardson /*
10599a2dd95SBruce Richardson  * Helper function for acl_check_alg.
10699a2dd95SBruce Richardson  * Check support for ARM specific classify methods.
10799a2dd95SBruce Richardson  */
10899a2dd95SBruce Richardson static int
10999a2dd95SBruce Richardson acl_check_alg_arm(enum rte_acl_classify_alg alg)
11099a2dd95SBruce Richardson {
11199a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_NEON) {
11299a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM64)
11399a2dd95SBruce Richardson 		if (rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
11499a2dd95SBruce Richardson 			return 0;
11599a2dd95SBruce Richardson #elif defined(RTE_ARCH_ARM)
11699a2dd95SBruce Richardson 		if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) &&
11799a2dd95SBruce Richardson 				rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
11899a2dd95SBruce Richardson 			return 0;
11999a2dd95SBruce Richardson #endif
12099a2dd95SBruce Richardson 		return -ENOTSUP;
12199a2dd95SBruce Richardson 	}
12299a2dd95SBruce Richardson 
12399a2dd95SBruce Richardson 	return -EINVAL;
12499a2dd95SBruce Richardson }
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson /*
12799a2dd95SBruce Richardson  * Helper function for acl_check_alg.
12899a2dd95SBruce Richardson  * Check support for PPC specific classify methods.
12999a2dd95SBruce Richardson  */
13099a2dd95SBruce Richardson static int
13199a2dd95SBruce Richardson acl_check_alg_ppc(enum rte_acl_classify_alg alg)
13299a2dd95SBruce Richardson {
13399a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_ALTIVEC) {
13499a2dd95SBruce Richardson #if defined(RTE_ARCH_PPC_64)
13599a2dd95SBruce Richardson 		if (rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
13699a2dd95SBruce Richardson 			return 0;
13799a2dd95SBruce Richardson #endif
13899a2dd95SBruce Richardson 		return -ENOTSUP;
13999a2dd95SBruce Richardson 	}
14099a2dd95SBruce Richardson 
14199a2dd95SBruce Richardson 	return -EINVAL;
14299a2dd95SBruce Richardson }
14399a2dd95SBruce Richardson 
14499a2dd95SBruce Richardson #ifdef CC_AVX512_SUPPORT
14599a2dd95SBruce Richardson static int
14699a2dd95SBruce Richardson acl_check_avx512_cpu_flags(void)
14799a2dd95SBruce Richardson {
14899a2dd95SBruce Richardson 	return (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) &&
14999a2dd95SBruce Richardson 			rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512VL) &&
15099a2dd95SBruce Richardson 			rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512CD) &&
15199a2dd95SBruce Richardson 			rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW));
15299a2dd95SBruce Richardson }
15399a2dd95SBruce Richardson #endif
15499a2dd95SBruce Richardson 
15599a2dd95SBruce Richardson /*
15699a2dd95SBruce Richardson  * Helper function for acl_check_alg.
15799a2dd95SBruce Richardson  * Check support for x86 specific classify methods.
15899a2dd95SBruce Richardson  */
15999a2dd95SBruce Richardson static int
16099a2dd95SBruce Richardson acl_check_alg_x86(enum rte_acl_classify_alg alg)
16199a2dd95SBruce Richardson {
16299a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_AVX512X32) {
16399a2dd95SBruce Richardson #ifdef CC_AVX512_SUPPORT
16499a2dd95SBruce Richardson 		if (acl_check_avx512_cpu_flags() != 0 &&
16599a2dd95SBruce Richardson 			rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_512)
16699a2dd95SBruce Richardson 			return 0;
16799a2dd95SBruce Richardson #endif
16899a2dd95SBruce Richardson 		return -ENOTSUP;
16999a2dd95SBruce Richardson 	}
17099a2dd95SBruce Richardson 
17199a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_AVX512X16) {
17299a2dd95SBruce Richardson #ifdef CC_AVX512_SUPPORT
17399a2dd95SBruce Richardson 		if (acl_check_avx512_cpu_flags() != 0 &&
17499a2dd95SBruce Richardson 			rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
17599a2dd95SBruce Richardson 			return 0;
17699a2dd95SBruce Richardson #endif
17799a2dd95SBruce Richardson 		return -ENOTSUP;
17899a2dd95SBruce Richardson 	}
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_AVX2) {
181*b0986c39SBruce Richardson #ifdef RTE_ARCH_X86
18299a2dd95SBruce Richardson 		if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) &&
18399a2dd95SBruce Richardson 				rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
18499a2dd95SBruce Richardson 			return 0;
18599a2dd95SBruce Richardson #endif
18699a2dd95SBruce Richardson 		return -ENOTSUP;
18799a2dd95SBruce Richardson 	}
18899a2dd95SBruce Richardson 
18999a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_SSE) {
19099a2dd95SBruce Richardson #ifdef RTE_ARCH_X86
19199a2dd95SBruce Richardson 		if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1) &&
19299a2dd95SBruce Richardson 				rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
19399a2dd95SBruce Richardson 			return 0;
19499a2dd95SBruce Richardson #endif
19599a2dd95SBruce Richardson 		return -ENOTSUP;
19699a2dd95SBruce Richardson 	}
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 	return -EINVAL;
19999a2dd95SBruce Richardson }
20099a2dd95SBruce Richardson 
20199a2dd95SBruce Richardson /*
20299a2dd95SBruce Richardson  * Check if input alg is supported by given platform/binary.
20399a2dd95SBruce Richardson  * Note that both conditions should be met:
20499a2dd95SBruce Richardson  * - at build time compiler supports ISA used by given methods
20599a2dd95SBruce Richardson  * - at run time target cpu supports necessary ISA.
20699a2dd95SBruce Richardson  */
20799a2dd95SBruce Richardson static int
20899a2dd95SBruce Richardson acl_check_alg(enum rte_acl_classify_alg alg)
20999a2dd95SBruce Richardson {
21099a2dd95SBruce Richardson 	switch (alg) {
21199a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_NEON:
21299a2dd95SBruce Richardson 		return acl_check_alg_arm(alg);
21399a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_ALTIVEC:
21499a2dd95SBruce Richardson 		return acl_check_alg_ppc(alg);
21599a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_AVX512X32:
21699a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_AVX512X16:
21799a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_AVX2:
21899a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_SSE:
21999a2dd95SBruce Richardson 		return acl_check_alg_x86(alg);
22099a2dd95SBruce Richardson 	/* scalar method is supported on all platforms */
22199a2dd95SBruce Richardson 	case RTE_ACL_CLASSIFY_SCALAR:
22299a2dd95SBruce Richardson 		return 0;
22399a2dd95SBruce Richardson 	default:
22499a2dd95SBruce Richardson 		return -EINVAL;
22599a2dd95SBruce Richardson 	}
22699a2dd95SBruce Richardson }
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson /*
22999a2dd95SBruce Richardson  * Get preferred alg for given platform.
23099a2dd95SBruce Richardson  */
23199a2dd95SBruce Richardson static enum rte_acl_classify_alg
23299a2dd95SBruce Richardson acl_get_best_alg(void)
23399a2dd95SBruce Richardson {
23499a2dd95SBruce Richardson 	/*
23599a2dd95SBruce Richardson 	 * array of supported methods for each platform.
23699a2dd95SBruce Richardson 	 * Note that order is important - from most to less preferable.
23799a2dd95SBruce Richardson 	 */
23899a2dd95SBruce Richardson 	static const enum rte_acl_classify_alg alg[] = {
23999a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM)
24099a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_NEON,
24199a2dd95SBruce Richardson #elif defined(RTE_ARCH_PPC_64)
24299a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_ALTIVEC,
24399a2dd95SBruce Richardson #elif defined(RTE_ARCH_X86)
24499a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_AVX512X32,
24599a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_AVX512X16,
24699a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_AVX2,
24799a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_SSE,
24899a2dd95SBruce Richardson #endif
24999a2dd95SBruce Richardson 		RTE_ACL_CLASSIFY_SCALAR,
25099a2dd95SBruce Richardson 	};
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 	uint32_t i;
25399a2dd95SBruce Richardson 
25499a2dd95SBruce Richardson 	/* find best possible alg */
25599a2dd95SBruce Richardson 	for (i = 0; i != RTE_DIM(alg) && acl_check_alg(alg[i]) != 0; i++)
25699a2dd95SBruce Richardson 		;
25799a2dd95SBruce Richardson 
25899a2dd95SBruce Richardson 	/* we always have to find something suitable */
25999a2dd95SBruce Richardson 	RTE_VERIFY(i != RTE_DIM(alg));
26099a2dd95SBruce Richardson 	return alg[i];
26199a2dd95SBruce Richardson }
26299a2dd95SBruce Richardson 
26399a2dd95SBruce Richardson extern int
26499a2dd95SBruce Richardson rte_acl_set_ctx_classify(struct rte_acl_ctx *ctx, enum rte_acl_classify_alg alg)
26599a2dd95SBruce Richardson {
26699a2dd95SBruce Richardson 	int32_t rc;
26799a2dd95SBruce Richardson 
26899a2dd95SBruce Richardson 	/* formal parameters check */
26999a2dd95SBruce Richardson 	if (ctx == NULL || (uint32_t)alg >= RTE_DIM(classify_fns))
27099a2dd95SBruce Richardson 		return -EINVAL;
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	/* user asked us to select the *best* one */
27399a2dd95SBruce Richardson 	if (alg == RTE_ACL_CLASSIFY_DEFAULT)
27499a2dd95SBruce Richardson 		alg = acl_get_best_alg();
27599a2dd95SBruce Richardson 
27699a2dd95SBruce Richardson 	/* check that given alg is supported */
27799a2dd95SBruce Richardson 	rc = acl_check_alg(alg);
27899a2dd95SBruce Richardson 	if (rc != 0)
27999a2dd95SBruce Richardson 		return rc;
28099a2dd95SBruce Richardson 
28199a2dd95SBruce Richardson 	ctx->alg = alg;
28299a2dd95SBruce Richardson 	return 0;
28399a2dd95SBruce Richardson }
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson int
28699a2dd95SBruce Richardson rte_acl_classify_alg(const struct rte_acl_ctx *ctx, const uint8_t **data,
28799a2dd95SBruce Richardson 	uint32_t *results, uint32_t num, uint32_t categories,
28899a2dd95SBruce Richardson 	enum rte_acl_classify_alg alg)
28999a2dd95SBruce Richardson {
29099a2dd95SBruce Richardson 	if (categories != 1 &&
29199a2dd95SBruce Richardson 			((RTE_ACL_RESULTS_MULTIPLIER - 1) & categories) != 0)
29299a2dd95SBruce Richardson 		return -EINVAL;
29399a2dd95SBruce Richardson 
29499a2dd95SBruce Richardson 	return classify_fns[alg](ctx, data, results, num, categories);
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson 
29799a2dd95SBruce Richardson int
29899a2dd95SBruce Richardson rte_acl_classify(const struct rte_acl_ctx *ctx, const uint8_t **data,
29999a2dd95SBruce Richardson 	uint32_t *results, uint32_t num, uint32_t categories)
30099a2dd95SBruce Richardson {
30199a2dd95SBruce Richardson 	return rte_acl_classify_alg(ctx, data, results, num, categories,
30299a2dd95SBruce Richardson 		ctx->alg);
30399a2dd95SBruce Richardson }
30499a2dd95SBruce Richardson 
30599a2dd95SBruce Richardson struct rte_acl_ctx *
30699a2dd95SBruce Richardson rte_acl_find_existing(const char *name)
30799a2dd95SBruce Richardson {
30899a2dd95SBruce Richardson 	struct rte_acl_ctx *ctx = NULL;
30999a2dd95SBruce Richardson 	struct rte_acl_list *acl_list;
31099a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
31199a2dd95SBruce Richardson 
31299a2dd95SBruce Richardson 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
31399a2dd95SBruce Richardson 
31499a2dd95SBruce Richardson 	rte_mcfg_tailq_read_lock();
31599a2dd95SBruce Richardson 	TAILQ_FOREACH(te, acl_list, next) {
31699a2dd95SBruce Richardson 		ctx = (struct rte_acl_ctx *) te->data;
31799a2dd95SBruce Richardson 		if (strncmp(name, ctx->name, sizeof(ctx->name)) == 0)
31899a2dd95SBruce Richardson 			break;
31999a2dd95SBruce Richardson 	}
32099a2dd95SBruce Richardson 	rte_mcfg_tailq_read_unlock();
32199a2dd95SBruce Richardson 
32299a2dd95SBruce Richardson 	if (te == NULL) {
32399a2dd95SBruce Richardson 		rte_errno = ENOENT;
32499a2dd95SBruce Richardson 		return NULL;
32599a2dd95SBruce Richardson 	}
32699a2dd95SBruce Richardson 	return ctx;
32799a2dd95SBruce Richardson }
32899a2dd95SBruce Richardson 
32999a2dd95SBruce Richardson void
33099a2dd95SBruce Richardson rte_acl_free(struct rte_acl_ctx *ctx)
33199a2dd95SBruce Richardson {
33299a2dd95SBruce Richardson 	struct rte_acl_list *acl_list;
33399a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
33499a2dd95SBruce Richardson 
33599a2dd95SBruce Richardson 	if (ctx == NULL)
33699a2dd95SBruce Richardson 		return;
33799a2dd95SBruce Richardson 
33899a2dd95SBruce Richardson 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
33999a2dd95SBruce Richardson 
34099a2dd95SBruce Richardson 	rte_mcfg_tailq_write_lock();
34199a2dd95SBruce Richardson 
34299a2dd95SBruce Richardson 	/* find our tailq entry */
34399a2dd95SBruce Richardson 	TAILQ_FOREACH(te, acl_list, next) {
34499a2dd95SBruce Richardson 		if (te->data == (void *) ctx)
34599a2dd95SBruce Richardson 			break;
34699a2dd95SBruce Richardson 	}
34799a2dd95SBruce Richardson 	if (te == NULL) {
34899a2dd95SBruce Richardson 		rte_mcfg_tailq_write_unlock();
34999a2dd95SBruce Richardson 		return;
35099a2dd95SBruce Richardson 	}
35199a2dd95SBruce Richardson 
35299a2dd95SBruce Richardson 	TAILQ_REMOVE(acl_list, te, next);
35399a2dd95SBruce Richardson 
35499a2dd95SBruce Richardson 	rte_mcfg_tailq_write_unlock();
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson 	rte_free(ctx->mem);
35799a2dd95SBruce Richardson 	rte_free(ctx);
35899a2dd95SBruce Richardson 	rte_free(te);
35999a2dd95SBruce Richardson }
36099a2dd95SBruce Richardson 
36199a2dd95SBruce Richardson struct rte_acl_ctx *
36299a2dd95SBruce Richardson rte_acl_create(const struct rte_acl_param *param)
36399a2dd95SBruce Richardson {
36499a2dd95SBruce Richardson 	size_t sz;
36599a2dd95SBruce Richardson 	struct rte_acl_ctx *ctx;
36699a2dd95SBruce Richardson 	struct rte_acl_list *acl_list;
36799a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
36899a2dd95SBruce Richardson 	char name[sizeof(ctx->name)];
36999a2dd95SBruce Richardson 
37099a2dd95SBruce Richardson 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
37199a2dd95SBruce Richardson 
37299a2dd95SBruce Richardson 	/* check that input parameters are valid. */
37399a2dd95SBruce Richardson 	if (param == NULL || param->name == NULL) {
37499a2dd95SBruce Richardson 		rte_errno = EINVAL;
37599a2dd95SBruce Richardson 		return NULL;
37699a2dd95SBruce Richardson 	}
37799a2dd95SBruce Richardson 
37899a2dd95SBruce Richardson 	snprintf(name, sizeof(name), "ACL_%s", param->name);
37999a2dd95SBruce Richardson 
38099a2dd95SBruce Richardson 	/* calculate amount of memory required for pattern set. */
38199a2dd95SBruce Richardson 	sz = sizeof(*ctx) + param->max_rule_num * param->rule_size;
38299a2dd95SBruce Richardson 
38399a2dd95SBruce Richardson 	/* get EAL TAILQ lock. */
38499a2dd95SBruce Richardson 	rte_mcfg_tailq_write_lock();
38599a2dd95SBruce Richardson 
38699a2dd95SBruce Richardson 	/* if we already have one with that name */
38799a2dd95SBruce Richardson 	TAILQ_FOREACH(te, acl_list, next) {
38899a2dd95SBruce Richardson 		ctx = (struct rte_acl_ctx *) te->data;
38999a2dd95SBruce Richardson 		if (strncmp(param->name, ctx->name, sizeof(ctx->name)) == 0)
39099a2dd95SBruce Richardson 			break;
39199a2dd95SBruce Richardson 	}
39299a2dd95SBruce Richardson 
39399a2dd95SBruce Richardson 	/* if ACL with such name doesn't exist, then create a new one. */
39499a2dd95SBruce Richardson 	if (te == NULL) {
39599a2dd95SBruce Richardson 		ctx = NULL;
39699a2dd95SBruce Richardson 		te = rte_zmalloc("ACL_TAILQ_ENTRY", sizeof(*te), 0);
39799a2dd95SBruce Richardson 
39899a2dd95SBruce Richardson 		if (te == NULL) {
39999a2dd95SBruce Richardson 			RTE_LOG(ERR, ACL, "Cannot allocate tailq entry!\n");
40099a2dd95SBruce Richardson 			goto exit;
40199a2dd95SBruce Richardson 		}
40299a2dd95SBruce Richardson 
40399a2dd95SBruce Richardson 		ctx = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE, param->socket_id);
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson 		if (ctx == NULL) {
40699a2dd95SBruce Richardson 			RTE_LOG(ERR, ACL,
40799a2dd95SBruce Richardson 				"allocation of %zu bytes on socket %d for %s failed\n",
40899a2dd95SBruce Richardson 				sz, param->socket_id, name);
40999a2dd95SBruce Richardson 			rte_free(te);
41099a2dd95SBruce Richardson 			goto exit;
41199a2dd95SBruce Richardson 		}
41299a2dd95SBruce Richardson 		/* init new allocated context. */
41399a2dd95SBruce Richardson 		ctx->rules = ctx + 1;
41499a2dd95SBruce Richardson 		ctx->max_rules = param->max_rule_num;
41599a2dd95SBruce Richardson 		ctx->rule_sz = param->rule_size;
41699a2dd95SBruce Richardson 		ctx->socket_id = param->socket_id;
41799a2dd95SBruce Richardson 		ctx->alg = acl_get_best_alg();
41899a2dd95SBruce Richardson 		strlcpy(ctx->name, param->name, sizeof(ctx->name));
41999a2dd95SBruce Richardson 
42099a2dd95SBruce Richardson 		te->data = (void *) ctx;
42199a2dd95SBruce Richardson 
42299a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(acl_list, te, next);
42399a2dd95SBruce Richardson 	}
42499a2dd95SBruce Richardson 
42599a2dd95SBruce Richardson exit:
42699a2dd95SBruce Richardson 	rte_mcfg_tailq_write_unlock();
42799a2dd95SBruce Richardson 	return ctx;
42899a2dd95SBruce Richardson }
42999a2dd95SBruce Richardson 
43099a2dd95SBruce Richardson static int
43199a2dd95SBruce Richardson acl_add_rules(struct rte_acl_ctx *ctx, const void *rules, uint32_t num)
43299a2dd95SBruce Richardson {
43399a2dd95SBruce Richardson 	uint8_t *pos;
43499a2dd95SBruce Richardson 
43599a2dd95SBruce Richardson 	if (num + ctx->num_rules > ctx->max_rules)
43699a2dd95SBruce Richardson 		return -ENOMEM;
43799a2dd95SBruce Richardson 
43899a2dd95SBruce Richardson 	pos = ctx->rules;
43999a2dd95SBruce Richardson 	pos += ctx->rule_sz * ctx->num_rules;
44099a2dd95SBruce Richardson 	memcpy(pos, rules, num * ctx->rule_sz);
44199a2dd95SBruce Richardson 	ctx->num_rules += num;
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson 	return 0;
44499a2dd95SBruce Richardson }
44599a2dd95SBruce Richardson 
44699a2dd95SBruce Richardson static int
44799a2dd95SBruce Richardson acl_check_rule(const struct rte_acl_rule_data *rd)
44899a2dd95SBruce Richardson {
44999a2dd95SBruce Richardson 	if ((RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES, typeof(rd->category_mask)) &
45099a2dd95SBruce Richardson 			rd->category_mask) == 0 ||
45199a2dd95SBruce Richardson 			rd->priority > RTE_ACL_MAX_PRIORITY ||
45299a2dd95SBruce Richardson 			rd->priority < RTE_ACL_MIN_PRIORITY)
45399a2dd95SBruce Richardson 		return -EINVAL;
45499a2dd95SBruce Richardson 	return 0;
45599a2dd95SBruce Richardson }
45699a2dd95SBruce Richardson 
45799a2dd95SBruce Richardson int
45899a2dd95SBruce Richardson rte_acl_add_rules(struct rte_acl_ctx *ctx, const struct rte_acl_rule *rules,
45999a2dd95SBruce Richardson 	uint32_t num)
46099a2dd95SBruce Richardson {
46199a2dd95SBruce Richardson 	const struct rte_acl_rule *rv;
46299a2dd95SBruce Richardson 	uint32_t i;
46399a2dd95SBruce Richardson 	int32_t rc;
46499a2dd95SBruce Richardson 
46599a2dd95SBruce Richardson 	if (ctx == NULL || rules == NULL || 0 == ctx->rule_sz)
46699a2dd95SBruce Richardson 		return -EINVAL;
46799a2dd95SBruce Richardson 
46899a2dd95SBruce Richardson 	for (i = 0; i != num; i++) {
46999a2dd95SBruce Richardson 		rv = (const struct rte_acl_rule *)
47099a2dd95SBruce Richardson 			((uintptr_t)rules + i * ctx->rule_sz);
47199a2dd95SBruce Richardson 		rc = acl_check_rule(&rv->data);
47299a2dd95SBruce Richardson 		if (rc != 0) {
47399a2dd95SBruce Richardson 			RTE_LOG(ERR, ACL, "%s(%s): rule #%u is invalid\n",
47499a2dd95SBruce Richardson 				__func__, ctx->name, i + 1);
47599a2dd95SBruce Richardson 			return rc;
47699a2dd95SBruce Richardson 		}
47799a2dd95SBruce Richardson 	}
47899a2dd95SBruce Richardson 
47999a2dd95SBruce Richardson 	return acl_add_rules(ctx, rules, num);
48099a2dd95SBruce Richardson }
48199a2dd95SBruce Richardson 
48299a2dd95SBruce Richardson /*
48399a2dd95SBruce Richardson  * Reset all rules.
48499a2dd95SBruce Richardson  * Note that RT structures are not affected.
48599a2dd95SBruce Richardson  */
48699a2dd95SBruce Richardson void
48799a2dd95SBruce Richardson rte_acl_reset_rules(struct rte_acl_ctx *ctx)
48899a2dd95SBruce Richardson {
48999a2dd95SBruce Richardson 	if (ctx != NULL)
49099a2dd95SBruce Richardson 		ctx->num_rules = 0;
49199a2dd95SBruce Richardson }
49299a2dd95SBruce Richardson 
49399a2dd95SBruce Richardson /*
49499a2dd95SBruce Richardson  * Reset all rules and destroys RT structures.
49599a2dd95SBruce Richardson  */
49699a2dd95SBruce Richardson void
49799a2dd95SBruce Richardson rte_acl_reset(struct rte_acl_ctx *ctx)
49899a2dd95SBruce Richardson {
49999a2dd95SBruce Richardson 	if (ctx != NULL) {
50099a2dd95SBruce Richardson 		rte_acl_reset_rules(ctx);
50199a2dd95SBruce Richardson 		rte_acl_build(ctx, &ctx->config);
50299a2dd95SBruce Richardson 	}
50399a2dd95SBruce Richardson }
50499a2dd95SBruce Richardson 
50599a2dd95SBruce Richardson /*
50699a2dd95SBruce Richardson  * Dump ACL context to the stdout.
50799a2dd95SBruce Richardson  */
50899a2dd95SBruce Richardson void
50999a2dd95SBruce Richardson rte_acl_dump(const struct rte_acl_ctx *ctx)
51099a2dd95SBruce Richardson {
51199a2dd95SBruce Richardson 	if (!ctx)
51299a2dd95SBruce Richardson 		return;
51399a2dd95SBruce Richardson 	printf("acl context <%s>@%p\n", ctx->name, ctx);
51499a2dd95SBruce Richardson 	printf("  socket_id=%"PRId32"\n", ctx->socket_id);
51599a2dd95SBruce Richardson 	printf("  alg=%"PRId32"\n", ctx->alg);
51699a2dd95SBruce Richardson 	printf("  first_load_sz=%"PRIu32"\n", ctx->first_load_sz);
51799a2dd95SBruce Richardson 	printf("  max_rules=%"PRIu32"\n", ctx->max_rules);
51899a2dd95SBruce Richardson 	printf("  rule_size=%"PRIu32"\n", ctx->rule_sz);
51999a2dd95SBruce Richardson 	printf("  num_rules=%"PRIu32"\n", ctx->num_rules);
52099a2dd95SBruce Richardson 	printf("  num_categories=%"PRIu32"\n", ctx->num_categories);
52199a2dd95SBruce Richardson 	printf("  num_tries=%"PRIu32"\n", ctx->num_tries);
52299a2dd95SBruce Richardson }
52399a2dd95SBruce Richardson 
52499a2dd95SBruce Richardson /*
52599a2dd95SBruce Richardson  * Dump all ACL contexts to the stdout.
52699a2dd95SBruce Richardson  */
52799a2dd95SBruce Richardson void
52899a2dd95SBruce Richardson rte_acl_list_dump(void)
52999a2dd95SBruce Richardson {
53099a2dd95SBruce Richardson 	struct rte_acl_ctx *ctx;
53199a2dd95SBruce Richardson 	struct rte_acl_list *acl_list;
53299a2dd95SBruce Richardson 	struct rte_tailq_entry *te;
53399a2dd95SBruce Richardson 
53499a2dd95SBruce Richardson 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
53599a2dd95SBruce Richardson 
53699a2dd95SBruce Richardson 	rte_mcfg_tailq_read_lock();
53799a2dd95SBruce Richardson 	TAILQ_FOREACH(te, acl_list, next) {
53899a2dd95SBruce Richardson 		ctx = (struct rte_acl_ctx *) te->data;
53999a2dd95SBruce Richardson 		rte_acl_dump(ctx);
54099a2dd95SBruce Richardson 	}
54199a2dd95SBruce Richardson 	rte_mcfg_tailq_read_unlock();
54299a2dd95SBruce Richardson }
543