xref: /dpdk/lib/table/rte_table_acl.c (revision da7e701151ea8b742d4c38ace3e4fefd1b4507fc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <string.h>
6 #include <stdio.h>
7 
8 #include <rte_common.h>
9 #include <rte_malloc.h>
10 #include <rte_log.h>
11 
12 #include "rte_table_acl.h"
13 
14 #ifdef RTE_TABLE_STATS_COLLECT
15 
16 #define RTE_TABLE_ACL_STATS_PKTS_IN_ADD(table, val) \
17 	table->stats.n_pkts_in += val
18 #define RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(table, val) \
19 	table->stats.n_pkts_lookup_miss += val
20 
21 #else
22 
23 #define RTE_TABLE_ACL_STATS_PKTS_IN_ADD(table, val)
24 #define RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(table, val)
25 
26 #endif
27 
28 struct rte_table_acl {
29 	struct rte_table_stats stats;
30 
31 	/* Low-level ACL table */
32 	char name[2][RTE_ACL_NAMESIZE];
33 	struct rte_acl_param acl_params; /* for creating low level acl table */
34 	struct rte_acl_config cfg; /* Holds the field definitions (metadata) */
35 	struct rte_acl_ctx *ctx;
36 	uint32_t name_id;
37 
38 	/* Input parameters */
39 	uint32_t n_rules;
40 	uint32_t entry_size;
41 
42 	/* Internal tables */
43 	uint8_t *action_table;
44 	struct rte_acl_rule **acl_rule_list; /* Array of pointers to rules */
45 	uint8_t *acl_rule_memory; /* Memory to store the rules */
46 
47 	/* Memory to store the action table and stack of free entries */
48 	uint8_t memory[0] __rte_cache_aligned;
49 };
50 
51 
52 static void *
53 rte_table_acl_create(
54 	void *params,
55 	int socket_id,
56 	uint32_t entry_size)
57 {
58 	struct rte_table_acl_params *p = params;
59 	struct rte_table_acl *acl;
60 	uint32_t action_table_size, acl_rule_list_size, acl_rule_memory_size;
61 	uint32_t total_size;
62 
63 	RTE_BUILD_BUG_ON(((sizeof(struct rte_table_acl) % RTE_CACHE_LINE_SIZE)
64 		!= 0));
65 
66 	/* Check input parameters */
67 	if (p == NULL) {
68 		RTE_LOG(ERR, TABLE, "%s: Invalid value for params\n", __func__);
69 		return NULL;
70 	}
71 	if (p->name == NULL) {
72 		RTE_LOG(ERR, TABLE, "%s: Invalid value for name\n", __func__);
73 		return NULL;
74 	}
75 	if (p->n_rules == 0) {
76 		RTE_LOG(ERR, TABLE, "%s: Invalid value for n_rules\n",
77 			__func__);
78 		return NULL;
79 	}
80 	if ((p->n_rule_fields == 0) ||
81 	    (p->n_rule_fields > RTE_ACL_MAX_FIELDS)) {
82 		RTE_LOG(ERR, TABLE, "%s: Invalid value for n_rule_fields\n",
83 			__func__);
84 		return NULL;
85 	}
86 
87 	entry_size = RTE_ALIGN(entry_size, sizeof(uint64_t));
88 
89 	/* Memory allocation */
90 	action_table_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules * entry_size);
91 	acl_rule_list_size =
92 		RTE_CACHE_LINE_ROUNDUP(p->n_rules * sizeof(struct rte_acl_rule *));
93 	acl_rule_memory_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules *
94 		RTE_ACL_RULE_SZ(p->n_rule_fields));
95 	total_size = sizeof(struct rte_table_acl) + action_table_size +
96 		acl_rule_list_size + acl_rule_memory_size;
97 
98 	acl = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE,
99 		socket_id);
100 	if (acl == NULL) {
101 		RTE_LOG(ERR, TABLE,
102 			"%s: Cannot allocate %u bytes for ACL table\n",
103 			__func__, total_size);
104 		return NULL;
105 	}
106 
107 	acl->action_table = &acl->memory[0];
108 	acl->acl_rule_list =
109 		(struct rte_acl_rule **) &acl->memory[action_table_size];
110 	acl->acl_rule_memory = (uint8_t *)
111 		&acl->memory[action_table_size + acl_rule_list_size];
112 
113 	/* Initialization of internal fields */
114 	snprintf(acl->name[0], RTE_ACL_NAMESIZE, "%s_a", p->name);
115 	snprintf(acl->name[1], RTE_ACL_NAMESIZE, "%s_b", p->name);
116 	acl->name_id = 1;
117 
118 	acl->acl_params.name = acl->name[acl->name_id];
119 	acl->acl_params.socket_id = socket_id;
120 	acl->acl_params.rule_size = RTE_ACL_RULE_SZ(p->n_rule_fields);
121 	acl->acl_params.max_rule_num = p->n_rules;
122 
123 	acl->cfg.num_categories = 1;
124 	acl->cfg.num_fields = p->n_rule_fields;
125 	memcpy(&acl->cfg.defs[0], &p->field_format[0],
126 		p->n_rule_fields * sizeof(struct rte_acl_field_def));
127 
128 	acl->ctx = NULL;
129 
130 	acl->n_rules = p->n_rules;
131 	acl->entry_size = entry_size;
132 
133 	return acl;
134 }
135 
136 static int
137 rte_table_acl_free(void *table)
138 {
139 	struct rte_table_acl *acl = table;
140 
141 	/* Check input parameters */
142 	if (table == NULL) {
143 		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
144 		return -EINVAL;
145 	}
146 
147 	/* Free previously allocated resources */
148 	rte_acl_free(acl->ctx);
149 
150 	rte_free(acl);
151 
152 	return 0;
153 }
154 
155 RTE_ACL_RULE_DEF(rte_pipeline_acl_rule, RTE_ACL_MAX_FIELDS);
156 
157 static int
158 rte_table_acl_build(struct rte_table_acl *acl, struct rte_acl_ctx **acl_ctx)
159 {
160 	struct rte_acl_ctx *ctx = NULL;
161 	uint32_t n_rules, i;
162 	int status;
163 
164 	/* Create low level ACL table */
165 	ctx = rte_acl_create(&acl->acl_params);
166 	if (ctx == NULL) {
167 		RTE_LOG(ERR, TABLE, "%s: Cannot create low level ACL table\n",
168 			__func__);
169 		return -1;
170 	}
171 
172 	/* Add rules to low level ACL table */
173 	n_rules = 0;
174 	for (i = 1; i < acl->n_rules; i++) {
175 		if (acl->acl_rule_list[i] != NULL) {
176 			status = rte_acl_add_rules(ctx, acl->acl_rule_list[i],
177 				1);
178 			if (status != 0) {
179 				RTE_LOG(ERR, TABLE,
180 				"%s: Cannot add rule to low level ACL table\n",
181 					__func__);
182 				rte_acl_free(ctx);
183 				return -1;
184 			}
185 
186 			n_rules++;
187 		}
188 	}
189 
190 	if (n_rules == 0) {
191 		rte_acl_free(ctx);
192 		*acl_ctx = NULL;
193 		return 0;
194 	}
195 
196 	/* Build low level ACl table */
197 	status = rte_acl_build(ctx, &acl->cfg);
198 	if (status != 0) {
199 		RTE_LOG(ERR, TABLE,
200 			"%s: Cannot build the low level ACL table\n",
201 			__func__);
202 		rte_acl_free(ctx);
203 		return -1;
204 	}
205 
206 	*acl_ctx = ctx;
207 	return 0;
208 }
209 
210 static int
211 rte_table_acl_entry_add(
212 	void *table,
213 	void *key,
214 	void *entry,
215 	int *key_found,
216 	void **entry_ptr)
217 {
218 	struct rte_table_acl *acl = table;
219 	struct rte_table_acl_rule_add_params *rule =
220 		key;
221 	struct rte_pipeline_acl_rule acl_rule;
222 	struct rte_acl_rule *rule_location;
223 	struct rte_acl_ctx *ctx;
224 	uint32_t free_pos, free_pos_valid, i;
225 	int status;
226 
227 	/* Check input parameters */
228 	if (table == NULL) {
229 		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
230 		return -EINVAL;
231 	}
232 	if (key == NULL) {
233 		RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
234 		return -EINVAL;
235 	}
236 	if (entry == NULL) {
237 		RTE_LOG(ERR, TABLE, "%s: entry parameter is NULL\n", __func__);
238 		return -EINVAL;
239 	}
240 	if (key_found == NULL) {
241 		RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
242 			__func__);
243 		return -EINVAL;
244 	}
245 	if (entry_ptr == NULL) {
246 		RTE_LOG(ERR, TABLE, "%s: entry_ptr parameter is NULL\n",
247 			__func__);
248 		return -EINVAL;
249 	}
250 	if (rule->priority > RTE_ACL_MAX_PRIORITY) {
251 		RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
252 		return -EINVAL;
253 	}
254 
255 	/* Setup rule data structure */
256 	memset(&acl_rule, 0, sizeof(acl_rule));
257 	acl_rule.data.category_mask = 1;
258 	acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
259 	acl_rule.data.userdata = 0; /* To be set up later */
260 	memcpy(&acl_rule.field[0],
261 		&rule->field_value[0],
262 		acl->cfg.num_fields * sizeof(struct rte_acl_field));
263 
264 	/* Look to see if the rule exists already in the table */
265 	free_pos = 0;
266 	free_pos_valid = 0;
267 	for (i = 1; i < acl->n_rules; i++) {
268 		if (acl->acl_rule_list[i] == NULL) {
269 			if (free_pos_valid == 0) {
270 				free_pos = i;
271 				free_pos_valid = 1;
272 			}
273 
274 			continue;
275 		}
276 
277 		/* Compare the key fields */
278 		status = memcmp(&acl->acl_rule_list[i]->field[0],
279 			&rule->field_value[0],
280 			acl->cfg.num_fields * sizeof(struct rte_acl_field));
281 
282 		/* Rule found: update data associated with the rule */
283 		if (status == 0) {
284 			*key_found = 1;
285 			*entry_ptr = &acl->memory[i * acl->entry_size];
286 			memcpy(*entry_ptr, entry, acl->entry_size);
287 
288 			return 0;
289 		}
290 	}
291 
292 	/* Return if max rules */
293 	if (free_pos_valid == 0) {
294 		RTE_LOG(ERR, TABLE, "%s: Max number of rules reached\n",
295 			__func__);
296 		return -ENOSPC;
297 	}
298 
299 	/* Add the new rule to the rule set */
300 	acl_rule.data.userdata = free_pos;
301 	rule_location = (struct rte_acl_rule *)
302 		&acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
303 	memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
304 	acl->acl_rule_list[free_pos] = rule_location;
305 
306 	/* Build low level ACL table */
307 	acl->name_id ^= 1;
308 	acl->acl_params.name = acl->name[acl->name_id];
309 	status = rte_table_acl_build(acl, &ctx);
310 	if (status != 0) {
311 		/* Roll back changes */
312 		acl->acl_rule_list[free_pos] = NULL;
313 		acl->name_id ^= 1;
314 
315 		return -EINVAL;
316 	}
317 
318 	/* Commit changes */
319 	rte_acl_free(acl->ctx);
320 	acl->ctx = ctx;
321 	*key_found = 0;
322 	*entry_ptr = &acl->memory[free_pos * acl->entry_size];
323 	memcpy(*entry_ptr, entry, acl->entry_size);
324 
325 	return 0;
326 }
327 
328 static int
329 rte_table_acl_entry_delete(
330 	void *table,
331 	void *key,
332 	int *key_found,
333 	void *entry)
334 {
335 	struct rte_table_acl *acl = table;
336 	struct rte_table_acl_rule_delete_params *rule =
337 		key;
338 	struct rte_acl_rule *deleted_rule = NULL;
339 	struct rte_acl_ctx *ctx;
340 	uint32_t pos, pos_valid, i;
341 	int status;
342 
343 	/* Check input parameters */
344 	if (table == NULL) {
345 		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
346 		return -EINVAL;
347 	}
348 	if (key == NULL) {
349 		RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
350 		return -EINVAL;
351 	}
352 	if (key_found == NULL) {
353 		RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
354 			__func__);
355 		return -EINVAL;
356 	}
357 
358 	/* Look for the rule in the table */
359 	pos = 0;
360 	pos_valid = 0;
361 	for (i = 1; i < acl->n_rules; i++) {
362 		if (acl->acl_rule_list[i] != NULL) {
363 			/* Compare the key fields */
364 			status = memcmp(&acl->acl_rule_list[i]->field[0],
365 				&rule->field_value[0], acl->cfg.num_fields *
366 				sizeof(struct rte_acl_field));
367 
368 			/* Rule found: remove from table */
369 			if (status == 0) {
370 				pos = i;
371 				pos_valid = 1;
372 
373 				deleted_rule = acl->acl_rule_list[i];
374 				acl->acl_rule_list[i] = NULL;
375 			}
376 		}
377 	}
378 
379 	/* Return if rule not found */
380 	if (pos_valid == 0) {
381 		*key_found = 0;
382 		return 0;
383 	}
384 
385 	/* Build low level ACL table */
386 	acl->name_id ^= 1;
387 	acl->acl_params.name = acl->name[acl->name_id];
388 	status = rte_table_acl_build(acl, &ctx);
389 	if (status != 0) {
390 		/* Roll back changes */
391 		acl->acl_rule_list[pos] = deleted_rule;
392 		acl->name_id ^= 1;
393 
394 		return -EINVAL;
395 	}
396 
397 	/* Commit changes */
398 	rte_acl_free(acl->ctx);
399 
400 	acl->ctx = ctx;
401 	*key_found = 1;
402 	if (entry != NULL)
403 		memcpy(entry, &acl->memory[pos * acl->entry_size],
404 			acl->entry_size);
405 
406 	return 0;
407 }
408 
409 static int
410 rte_table_acl_entry_add_bulk(
411 	void *table,
412 	void **keys,
413 	void **entries,
414 	uint32_t n_keys,
415 	int *key_found,
416 	void **entries_ptr)
417 {
418 	struct rte_table_acl *acl = table;
419 	struct rte_acl_ctx *ctx;
420 	uint32_t rule_pos[n_keys];
421 	uint32_t i;
422 	int err = 0, build = 0;
423 	int status;
424 
425 	/* Check input parameters */
426 	if (table == NULL) {
427 		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
428 		return -EINVAL;
429 	}
430 	if (keys == NULL) {
431 		RTE_LOG(ERR, TABLE, "%s: keys parameter is NULL\n", __func__);
432 		return -EINVAL;
433 	}
434 	if (entries == NULL) {
435 		RTE_LOG(ERR, TABLE, "%s: entries parameter is NULL\n", __func__);
436 		return -EINVAL;
437 	}
438 	if (n_keys == 0) {
439 		RTE_LOG(ERR, TABLE, "%s: 0 rules to add\n", __func__);
440 		return -EINVAL;
441 	}
442 	if (key_found == NULL) {
443 		RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
444 			__func__);
445 		return -EINVAL;
446 	}
447 	if (entries_ptr == NULL) {
448 		RTE_LOG(ERR, TABLE, "%s: entries_ptr parameter is NULL\n",
449 			__func__);
450 		return -EINVAL;
451 	}
452 
453 	/* Check input parameters in arrays */
454 	for (i = 0; i < n_keys; i++) {
455 		struct rte_table_acl_rule_add_params *rule;
456 
457 		if (keys[i] == NULL) {
458 			RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
459 					__func__, i);
460 			return -EINVAL;
461 		}
462 
463 		if (entries[i] == NULL) {
464 			RTE_LOG(ERR, TABLE, "%s: entries[%" PRIu32 "] parameter is NULL\n",
465 					__func__, i);
466 			return -EINVAL;
467 		}
468 
469 		rule = keys[i];
470 		if (rule->priority > RTE_ACL_MAX_PRIORITY) {
471 			RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
472 			return -EINVAL;
473 		}
474 	}
475 
476 	memset(rule_pos, 0, n_keys * sizeof(uint32_t));
477 	memset(key_found, 0, n_keys * sizeof(int));
478 	for (i = 0; i < n_keys; i++) {
479 		struct rte_table_acl_rule_add_params *rule =
480 				keys[i];
481 		struct rte_pipeline_acl_rule acl_rule;
482 		struct rte_acl_rule *rule_location;
483 		uint32_t free_pos, free_pos_valid, j;
484 
485 		/* Setup rule data structure */
486 		memset(&acl_rule, 0, sizeof(acl_rule));
487 		acl_rule.data.category_mask = 1;
488 		acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
489 		acl_rule.data.userdata = 0; /* To be set up later */
490 		memcpy(&acl_rule.field[0],
491 			&rule->field_value[0],
492 			acl->cfg.num_fields * sizeof(struct rte_acl_field));
493 
494 		/* Look to see if the rule exists already in the table */
495 		free_pos = 0;
496 		free_pos_valid = 0;
497 		for (j = 1; j < acl->n_rules; j++) {
498 			if (acl->acl_rule_list[j] == NULL) {
499 				if (free_pos_valid == 0) {
500 					free_pos = j;
501 					free_pos_valid = 1;
502 				}
503 
504 				continue;
505 			}
506 
507 			/* Compare the key fields */
508 			status = memcmp(&acl->acl_rule_list[j]->field[0],
509 				&rule->field_value[0],
510 				acl->cfg.num_fields * sizeof(struct rte_acl_field));
511 
512 			/* Rule found: update data associated with the rule */
513 			if (status == 0) {
514 				key_found[i] = 1;
515 				entries_ptr[i] = &acl->memory[j * acl->entry_size];
516 				memcpy(entries_ptr[i], entries[i], acl->entry_size);
517 
518 				break;
519 			}
520 		}
521 
522 		/* Key already in the table */
523 		if (key_found[i] != 0)
524 			continue;
525 
526 		/* Maximum number of rules reached */
527 		if (free_pos_valid == 0) {
528 			err = 1;
529 			break;
530 		}
531 
532 		/* Add the new rule to the rule set */
533 		acl_rule.data.userdata = free_pos;
534 		rule_location = (struct rte_acl_rule *)
535 			&acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
536 		memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
537 		acl->acl_rule_list[free_pos] = rule_location;
538 		rule_pos[i] = free_pos;
539 		build = 1;
540 	}
541 
542 	if (err != 0) {
543 		for (i = 0; i < n_keys; i++) {
544 			if (rule_pos[i] == 0)
545 				continue;
546 
547 			acl->acl_rule_list[rule_pos[i]] = NULL;
548 		}
549 
550 		return -ENOSPC;
551 	}
552 
553 	if (build == 0)
554 		return 0;
555 
556 	/* Build low level ACL table */
557 	acl->name_id ^= 1;
558 	acl->acl_params.name = acl->name[acl->name_id];
559 	status = rte_table_acl_build(acl, &ctx);
560 	if (status != 0) {
561 		/* Roll back changes */
562 		for (i = 0; i < n_keys; i++) {
563 			if (rule_pos[i] == 0)
564 				continue;
565 
566 			acl->acl_rule_list[rule_pos[i]] = NULL;
567 		}
568 		acl->name_id ^= 1;
569 
570 		return -EINVAL;
571 	}
572 
573 	/* Commit changes */
574 	rte_acl_free(acl->ctx);
575 	acl->ctx = ctx;
576 
577 	for (i = 0; i < n_keys; i++) {
578 		if (rule_pos[i] == 0)
579 			continue;
580 
581 		key_found[i] = 0;
582 		entries_ptr[i] = &acl->memory[rule_pos[i] * acl->entry_size];
583 		memcpy(entries_ptr[i], entries[i], acl->entry_size);
584 	}
585 
586 	return 0;
587 }
588 
589 static int
590 rte_table_acl_entry_delete_bulk(
591 	void *table,
592 	void **keys,
593 	uint32_t n_keys,
594 	int *key_found,
595 	void **entries)
596 {
597 	struct rte_table_acl *acl = table;
598 	struct rte_acl_rule *deleted_rules[n_keys];
599 	uint32_t rule_pos[n_keys];
600 	struct rte_acl_ctx *ctx;
601 	uint32_t i;
602 	int status;
603 	int build = 0;
604 
605 	/* Check input parameters */
606 	if (table == NULL) {
607 		RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
608 		return -EINVAL;
609 	}
610 	if (keys == NULL) {
611 		RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
612 		return -EINVAL;
613 	}
614 	if (n_keys == 0) {
615 		RTE_LOG(ERR, TABLE, "%s: 0 rules to delete\n", __func__);
616 		return -EINVAL;
617 	}
618 	if (key_found == NULL) {
619 		RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
620 			__func__);
621 		return -EINVAL;
622 	}
623 
624 	for (i = 0; i < n_keys; i++) {
625 		if (keys[i] == NULL) {
626 			RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
627 					__func__, i);
628 			return -EINVAL;
629 		}
630 	}
631 
632 	memset(deleted_rules, 0, n_keys * sizeof(struct rte_acl_rule *));
633 	memset(rule_pos, 0, n_keys * sizeof(uint32_t));
634 	for (i = 0; i < n_keys; i++) {
635 		struct rte_table_acl_rule_delete_params *rule =
636 			keys[i];
637 		uint32_t pos_valid, j;
638 
639 		/* Look for the rule in the table */
640 		pos_valid = 0;
641 		for (j = 1; j < acl->n_rules; j++) {
642 			if (acl->acl_rule_list[j] == NULL)
643 				continue;
644 
645 			/* Compare the key fields */
646 			status = memcmp(&acl->acl_rule_list[j]->field[0],
647 					&rule->field_value[0],
648 					acl->cfg.num_fields * sizeof(struct rte_acl_field));
649 
650 			/* Rule found: remove from table */
651 			if (status == 0) {
652 				pos_valid = 1;
653 
654 				deleted_rules[i] = acl->acl_rule_list[j];
655 				acl->acl_rule_list[j] = NULL;
656 				rule_pos[i] = j;
657 
658 				build = 1;
659 			}
660 		}
661 
662 		if (pos_valid == 0) {
663 			key_found[i] = 0;
664 			continue;
665 		}
666 	}
667 
668 	/* Return if no changes to acl table */
669 	if (build == 0) {
670 		return 0;
671 	}
672 
673 	/* Build low level ACL table */
674 	acl->name_id ^= 1;
675 	acl->acl_params.name = acl->name[acl->name_id];
676 	status = rte_table_acl_build(acl, &ctx);
677 	if (status != 0) {
678 		/* Roll back changes */
679 		for (i = 0; i < n_keys; i++) {
680 			if (rule_pos[i] == 0)
681 				continue;
682 
683 			acl->acl_rule_list[rule_pos[i]] = deleted_rules[i];
684 		}
685 
686 		acl->name_id ^= 1;
687 
688 		return -EINVAL;
689 	}
690 
691 	/* Commit changes */
692 	rte_acl_free(acl->ctx);
693 
694 	acl->ctx = ctx;
695 	for (i = 0; i < n_keys; i++) {
696 		if (rule_pos[i] == 0)
697 			continue;
698 
699 		key_found[i] = 1;
700 		if (entries != NULL && entries[i] != NULL)
701 			memcpy(entries[i], &acl->memory[rule_pos[i] * acl->entry_size],
702 					acl->entry_size);
703 	}
704 
705 	return 0;
706 }
707 
708 static int
709 rte_table_acl_lookup(
710 	void *table,
711 	struct rte_mbuf **pkts,
712 	uint64_t pkts_mask,
713 	uint64_t *lookup_hit_mask,
714 	void **entries)
715 {
716 	struct rte_table_acl *acl = (struct rte_table_acl *) table;
717 	const uint8_t *pkts_data[RTE_PORT_IN_BURST_SIZE_MAX];
718 	uint32_t results[RTE_PORT_IN_BURST_SIZE_MAX];
719 	uint64_t pkts_out_mask;
720 	uint32_t n_pkts, i, j;
721 
722 	__rte_unused uint32_t n_pkts_in = rte_popcount64(pkts_mask);
723 	RTE_TABLE_ACL_STATS_PKTS_IN_ADD(acl, n_pkts_in);
724 
725 	/* Input conversion */
726 	for (i = 0, j = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX -
727 		rte_clz64(pkts_mask)); i++) {
728 		uint64_t pkt_mask = 1LLU << i;
729 
730 		if (pkt_mask & pkts_mask) {
731 			pkts_data[j] = rte_pktmbuf_mtod(pkts[i], uint8_t *);
732 			j++;
733 		}
734 	}
735 	n_pkts = j;
736 
737 	/* Low-level ACL table lookup */
738 	if (acl->ctx != NULL)
739 		rte_acl_classify(acl->ctx, pkts_data, results, n_pkts, 1);
740 	else
741 		n_pkts = 0;
742 
743 	/* Output conversion */
744 	pkts_out_mask = 0;
745 	for (i = 0; i < n_pkts; i++) {
746 		uint32_t action_table_pos = results[i];
747 		uint32_t pkt_pos = rte_ctz64(pkts_mask);
748 		uint64_t pkt_mask = 1LLU << pkt_pos;
749 
750 		pkts_mask &= ~pkt_mask;
751 
752 		if (action_table_pos != 0) {
753 			pkts_out_mask |= pkt_mask;
754 			entries[pkt_pos] = (void *)
755 				&acl->memory[action_table_pos *
756 				acl->entry_size];
757 			rte_prefetch0(entries[pkt_pos]);
758 		}
759 	}
760 
761 	*lookup_hit_mask = pkts_out_mask;
762 	RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(acl, n_pkts_in - rte_popcount64(pkts_out_mask));
763 
764 	return 0;
765 }
766 
767 static int
768 rte_table_acl_stats_read(void *table, struct rte_table_stats *stats, int clear)
769 {
770 	struct rte_table_acl *acl = table;
771 
772 	if (stats != NULL)
773 		memcpy(stats, &acl->stats, sizeof(acl->stats));
774 
775 	if (clear)
776 		memset(&acl->stats, 0, sizeof(acl->stats));
777 
778 	return 0;
779 }
780 
781 struct rte_table_ops rte_table_acl_ops = {
782 	.f_create = rte_table_acl_create,
783 	.f_free = rte_table_acl_free,
784 	.f_add = rte_table_acl_entry_add,
785 	.f_delete = rte_table_acl_entry_delete,
786 	.f_add_bulk = rte_table_acl_entry_add_bulk,
787 	.f_delete_bulk = rte_table_acl_entry_delete_bulk,
788 	.f_lookup = rte_table_acl_lookup,
789 	.f_stats = rte_table_acl_stats_read,
790 };
791