xref: /f-stack/dpdk/lib/librte_acl/rte_acl.c (revision 8850115b)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <rte_acl.h>
6 #include "acl.h"
7 
8 TAILQ_HEAD(rte_acl_list, rte_tailq_entry);
9 
10 static struct rte_tailq_elem rte_acl_tailq = {
11 	.name = "RTE_ACL",
12 };
13 EAL_REGISTER_TAILQ(rte_acl_tailq)
14 
15 /*
16  * If the compiler doesn't support AVX2 instructions,
17  * then the dummy one would be used instead for AVX2 classify method.
18  */
19 __rte_weak int
20 rte_acl_classify_avx2(__rte_unused const struct rte_acl_ctx *ctx,
21 	__rte_unused const uint8_t **data,
22 	__rte_unused uint32_t *results,
23 	__rte_unused uint32_t num,
24 	__rte_unused uint32_t categories)
25 {
26 	return -ENOTSUP;
27 }
28 
29 __rte_weak int
30 rte_acl_classify_sse(__rte_unused const struct rte_acl_ctx *ctx,
31 	__rte_unused const uint8_t **data,
32 	__rte_unused uint32_t *results,
33 	__rte_unused uint32_t num,
34 	__rte_unused uint32_t categories)
35 {
36 	return -ENOTSUP;
37 }
38 
39 __rte_weak int
40 rte_acl_classify_neon(__rte_unused const struct rte_acl_ctx *ctx,
41 	__rte_unused const uint8_t **data,
42 	__rte_unused uint32_t *results,
43 	__rte_unused uint32_t num,
44 	__rte_unused uint32_t categories)
45 {
46 	return -ENOTSUP;
47 }
48 
49 __rte_weak int
50 rte_acl_classify_altivec(__rte_unused const struct rte_acl_ctx *ctx,
51 	__rte_unused const uint8_t **data,
52 	__rte_unused uint32_t *results,
53 	__rte_unused uint32_t num,
54 	__rte_unused uint32_t categories)
55 {
56 	return -ENOTSUP;
57 }
58 
59 static const rte_acl_classify_t classify_fns[] = {
60 	[RTE_ACL_CLASSIFY_DEFAULT] = rte_acl_classify_scalar,
61 	[RTE_ACL_CLASSIFY_SCALAR] = rte_acl_classify_scalar,
62 	[RTE_ACL_CLASSIFY_SSE] = rte_acl_classify_sse,
63 	[RTE_ACL_CLASSIFY_AVX2] = rte_acl_classify_avx2,
64 	[RTE_ACL_CLASSIFY_NEON] = rte_acl_classify_neon,
65 	[RTE_ACL_CLASSIFY_ALTIVEC] = rte_acl_classify_altivec,
66 };
67 
68 /* by default, use always available scalar code path. */
69 static enum rte_acl_classify_alg rte_acl_default_classify =
70 	RTE_ACL_CLASSIFY_SCALAR;
71 
72 static void
73 rte_acl_set_default_classify(enum rte_acl_classify_alg alg)
74 {
75 	rte_acl_default_classify = alg;
76 }
77 
78 extern int
79 rte_acl_set_ctx_classify(struct rte_acl_ctx *ctx, enum rte_acl_classify_alg alg)
80 {
81 	if (ctx == NULL || (uint32_t)alg >= RTE_DIM(classify_fns))
82 		return -EINVAL;
83 
84 	ctx->alg = alg;
85 	return 0;
86 }
87 
88 /*
89  * Select highest available classify method as default one.
90  * Note that CLASSIFY_AVX2 should be set as a default only
91  * if both conditions are met:
92  * at build time compiler supports AVX2 and target cpu supports AVX2.
93  */
94 RTE_INIT(rte_acl_init)
95 {
96 	enum rte_acl_classify_alg alg = RTE_ACL_CLASSIFY_DEFAULT;
97 
98 #if defined(RTE_ARCH_ARM64)
99 	alg =  RTE_ACL_CLASSIFY_NEON;
100 #elif defined(RTE_ARCH_ARM)
101 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON))
102 		alg =  RTE_ACL_CLASSIFY_NEON;
103 #elif defined(RTE_ARCH_PPC_64)
104 	alg = RTE_ACL_CLASSIFY_ALTIVEC;
105 #else
106 #ifdef CC_AVX2_SUPPORT
107 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
108 		alg = RTE_ACL_CLASSIFY_AVX2;
109 	else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
110 #else
111 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
112 #endif
113 		alg = RTE_ACL_CLASSIFY_SSE;
114 
115 #endif
116 	rte_acl_set_default_classify(alg);
117 }
118 
119 int
120 rte_acl_classify_alg(const struct rte_acl_ctx *ctx, const uint8_t **data,
121 	uint32_t *results, uint32_t num, uint32_t categories,
122 	enum rte_acl_classify_alg alg)
123 {
124 	if (categories != 1 &&
125 			((RTE_ACL_RESULTS_MULTIPLIER - 1) & categories) != 0)
126 		return -EINVAL;
127 
128 	return classify_fns[alg](ctx, data, results, num, categories);
129 }
130 
131 int
132 rte_acl_classify(const struct rte_acl_ctx *ctx, const uint8_t **data,
133 	uint32_t *results, uint32_t num, uint32_t categories)
134 {
135 	return rte_acl_classify_alg(ctx, data, results, num, categories,
136 		ctx->alg);
137 }
138 
139 struct rte_acl_ctx *
140 rte_acl_find_existing(const char *name)
141 {
142 	struct rte_acl_ctx *ctx = NULL;
143 	struct rte_acl_list *acl_list;
144 	struct rte_tailq_entry *te;
145 
146 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
147 
148 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
149 	TAILQ_FOREACH(te, acl_list, next) {
150 		ctx = (struct rte_acl_ctx *) te->data;
151 		if (strncmp(name, ctx->name, sizeof(ctx->name)) == 0)
152 			break;
153 	}
154 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
155 
156 	if (te == NULL) {
157 		rte_errno = ENOENT;
158 		return NULL;
159 	}
160 	return ctx;
161 }
162 
163 void
164 rte_acl_free(struct rte_acl_ctx *ctx)
165 {
166 	struct rte_acl_list *acl_list;
167 	struct rte_tailq_entry *te;
168 
169 	if (ctx == NULL)
170 		return;
171 
172 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
173 
174 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
175 
176 	/* find our tailq entry */
177 	TAILQ_FOREACH(te, acl_list, next) {
178 		if (te->data == (void *) ctx)
179 			break;
180 	}
181 	if (te == NULL) {
182 		rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
183 		return;
184 	}
185 
186 	TAILQ_REMOVE(acl_list, te, next);
187 
188 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
189 
190 	rte_free(ctx->mem);
191 	rte_free(ctx);
192 	rte_free(te);
193 }
194 
195 struct rte_acl_ctx *
196 rte_acl_create(const struct rte_acl_param *param)
197 {
198 	size_t sz;
199 	struct rte_acl_ctx *ctx;
200 	struct rte_acl_list *acl_list;
201 	struct rte_tailq_entry *te;
202 	char name[sizeof(ctx->name)];
203 
204 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
205 
206 	/* check that input parameters are valid. */
207 	if (param == NULL || param->name == NULL) {
208 		rte_errno = EINVAL;
209 		return NULL;
210 	}
211 
212 	snprintf(name, sizeof(name), "ACL_%s", param->name);
213 
214 	/* calculate amount of memory required for pattern set. */
215 	sz = sizeof(*ctx) + param->max_rule_num * param->rule_size;
216 
217 	/* get EAL TAILQ lock. */
218 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
219 
220 	/* if we already have one with that name */
221 	TAILQ_FOREACH(te, acl_list, next) {
222 		ctx = (struct rte_acl_ctx *) te->data;
223 		if (strncmp(param->name, ctx->name, sizeof(ctx->name)) == 0)
224 			break;
225 	}
226 
227 	/* if ACL with such name doesn't exist, then create a new one. */
228 	if (te == NULL) {
229 		ctx = NULL;
230 		te = rte_zmalloc("ACL_TAILQ_ENTRY", sizeof(*te), 0);
231 
232 		if (te == NULL) {
233 			RTE_LOG(ERR, ACL, "Cannot allocate tailq entry!\n");
234 			goto exit;
235 		}
236 
237 		ctx = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE, param->socket_id);
238 
239 		if (ctx == NULL) {
240 			RTE_LOG(ERR, ACL,
241 				"allocation of %zu bytes on socket %d for %s failed\n",
242 				sz, param->socket_id, name);
243 			rte_free(te);
244 			goto exit;
245 		}
246 		/* init new allocated context. */
247 		ctx->rules = ctx + 1;
248 		ctx->max_rules = param->max_rule_num;
249 		ctx->rule_sz = param->rule_size;
250 		ctx->socket_id = param->socket_id;
251 		ctx->alg = rte_acl_default_classify;
252 		snprintf(ctx->name, sizeof(ctx->name), "%s", param->name);
253 
254 		te->data = (void *) ctx;
255 
256 		TAILQ_INSERT_TAIL(acl_list, te, next);
257 	}
258 
259 exit:
260 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
261 	return ctx;
262 }
263 
264 static int
265 acl_add_rules(struct rte_acl_ctx *ctx, const void *rules, uint32_t num)
266 {
267 	uint8_t *pos;
268 
269 	if (num + ctx->num_rules > ctx->max_rules)
270 		return -ENOMEM;
271 
272 	pos = ctx->rules;
273 	pos += ctx->rule_sz * ctx->num_rules;
274 	memcpy(pos, rules, num * ctx->rule_sz);
275 	ctx->num_rules += num;
276 
277 	return 0;
278 }
279 
280 static int
281 acl_check_rule(const struct rte_acl_rule_data *rd)
282 {
283 	if ((RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES, typeof(rd->category_mask)) &
284 			rd->category_mask) == 0 ||
285 			rd->priority > RTE_ACL_MAX_PRIORITY ||
286 			rd->priority < RTE_ACL_MIN_PRIORITY)
287 		return -EINVAL;
288 	return 0;
289 }
290 
291 int
292 rte_acl_add_rules(struct rte_acl_ctx *ctx, const struct rte_acl_rule *rules,
293 	uint32_t num)
294 {
295 	const struct rte_acl_rule *rv;
296 	uint32_t i;
297 	int32_t rc;
298 
299 	if (ctx == NULL || rules == NULL || 0 == ctx->rule_sz)
300 		return -EINVAL;
301 
302 	for (i = 0; i != num; i++) {
303 		rv = (const struct rte_acl_rule *)
304 			((uintptr_t)rules + i * ctx->rule_sz);
305 		rc = acl_check_rule(&rv->data);
306 		if (rc != 0) {
307 			RTE_LOG(ERR, ACL, "%s(%s): rule #%u is invalid\n",
308 				__func__, ctx->name, i + 1);
309 			return rc;
310 		}
311 	}
312 
313 	return acl_add_rules(ctx, rules, num);
314 }
315 
316 /*
317  * Reset all rules.
318  * Note that RT structures are not affected.
319  */
320 void
321 rte_acl_reset_rules(struct rte_acl_ctx *ctx)
322 {
323 	if (ctx != NULL)
324 		ctx->num_rules = 0;
325 }
326 
327 /*
328  * Reset all rules and destroys RT structures.
329  */
330 void
331 rte_acl_reset(struct rte_acl_ctx *ctx)
332 {
333 	if (ctx != NULL) {
334 		rte_acl_reset_rules(ctx);
335 		rte_acl_build(ctx, &ctx->config);
336 	}
337 }
338 
339 /*
340  * Dump ACL context to the stdout.
341  */
342 void
343 rte_acl_dump(const struct rte_acl_ctx *ctx)
344 {
345 	if (!ctx)
346 		return;
347 	printf("acl context <%s>@%p\n", ctx->name, ctx);
348 	printf("  socket_id=%"PRId32"\n", ctx->socket_id);
349 	printf("  alg=%"PRId32"\n", ctx->alg);
350 	printf("  max_rules=%"PRIu32"\n", ctx->max_rules);
351 	printf("  rule_size=%"PRIu32"\n", ctx->rule_sz);
352 	printf("  num_rules=%"PRIu32"\n", ctx->num_rules);
353 	printf("  num_categories=%"PRIu32"\n", ctx->num_categories);
354 	printf("  num_tries=%"PRIu32"\n", ctx->num_tries);
355 }
356 
357 /*
358  * Dump all ACL contexts to the stdout.
359  */
360 void
361 rte_acl_list_dump(void)
362 {
363 	struct rte_acl_ctx *ctx;
364 	struct rte_acl_list *acl_list;
365 	struct rte_tailq_entry *te;
366 
367 	acl_list = RTE_TAILQ_CAST(rte_acl_tailq.head, rte_acl_list);
368 
369 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
370 	TAILQ_FOREACH(te, acl_list, next) {
371 		ctx = (struct rte_acl_ctx *) te->data;
372 		rte_acl_dump(ctx);
373 	}
374 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
375 }
376