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