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