1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
8 #include <rte_common.h>
10 #include <rte_memory.h>
11 #include <rte_malloc.h>
14 #include "rte_table_acl.h"
15 #include <rte_ether.h>
17 #ifdef RTE_TABLE_STATS_COLLECT
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
26 #define RTE_TABLE_ACL_STATS_PKTS_IN_ADD(table, val)
27 #define RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(table, val)
31 struct rte_table_acl
{
32 struct rte_table_stats stats
;
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
;
41 /* Input parameters */
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 */
50 /* Memory to store the action table and stack of free entries */
51 uint8_t memory
[0] __rte_cache_aligned
;
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
;
66 RTE_BUILD_BUG_ON(((sizeof(struct rte_table_acl
) % RTE_CACHE_LINE_SIZE
)
69 /* Check input parameters */
71 RTE_LOG(ERR
, TABLE
, "%s: Invalid value for params\n", __func__
);
74 if (p
->name
== NULL
) {
75 RTE_LOG(ERR
, TABLE
, "%s: Invalid value for name\n", __func__
);
78 if (p
->n_rules
== 0) {
79 RTE_LOG(ERR
, TABLE
, "%s: Invalid value for n_rules\n",
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",
90 entry_size
= RTE_ALIGN(entry_size
, sizeof(uint64_t));
92 /* Memory allocation */
93 action_table_size
= RTE_CACHE_LINE_ROUNDUP(p
->n_rules
* entry_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
;
101 acl
= rte_zmalloc_socket("TABLE", total_size
, RTE_CACHE_LINE_SIZE
,
105 "%s: Cannot allocate %u bytes for ACL table\n",
106 __func__
, total_size
);
110 acl
->action_table
= &acl
->memory
[0];
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
];
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
);
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
;
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
));
133 acl
->n_rules
= p
->n_rules
;
134 acl
->entry_size
= entry_size
;
140 rte_table_acl_free(void *table
)
142 struct rte_table_acl
*acl
= table
;
144 /* Check input parameters */
146 RTE_LOG(ERR
, TABLE
, "%s: table parameter is NULL\n", __func__
);
150 /* Free previously allocated resources */
151 if (acl
->ctx
!= NULL
)
152 rte_acl_free(acl
->ctx
);
159 RTE_ACL_RULE_DEF(rte_pipeline_acl_rule
, RTE_ACL_MAX_FIELDS
);
162 rte_table_acl_build(struct rte_table_acl
*acl
, struct rte_acl_ctx
**acl_ctx
)
164 struct rte_acl_ctx
*ctx
= NULL
;
168 /* Create low level ACL table */
169 ctx
= rte_acl_create(&acl
->acl_params
);
171 RTE_LOG(ERR
, TABLE
, "%s: Cannot create low level ACL table\n",
176 /* Add rules to low level ACL table */
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
],
184 "%s: Cannot add rule to low level ACL table\n",
200 /* Build low level ACl table */
201 status
= rte_acl_build(ctx
, &acl
->cfg
);
204 "%s: Cannot build the low level ACL table\n",
215 rte_table_acl_entry_add(
222 struct rte_table_acl
*acl
= table
;
223 struct rte_table_acl_rule_add_params
*rule
=
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
;
231 /* Check input parameters */
233 RTE_LOG(ERR
, TABLE
, "%s: table parameter is NULL\n", __func__
);
237 RTE_LOG(ERR
, TABLE
, "%s: key parameter is NULL\n", __func__
);
241 RTE_LOG(ERR
, TABLE
, "%s: entry parameter is NULL\n", __func__
);
244 if (key_found
== NULL
) {
245 RTE_LOG(ERR
, TABLE
, "%s: key_found parameter is NULL\n",
249 if (entry_ptr
== NULL
) {
250 RTE_LOG(ERR
, TABLE
, "%s: entry_ptr parameter is NULL\n",
254 if (rule
->priority
> RTE_ACL_MAX_PRIORITY
) {
255 RTE_LOG(ERR
, TABLE
, "%s: Priority is too high\n", __func__
);
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
));
268 /* Look to see if the rule exists already in the table */
271 for (i
= 1; i
< acl
->n_rules
; i
++) {
272 if (acl
->acl_rule_list
[i
] == NULL
) {
273 if (free_pos_valid
== 0) {
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
));
286 /* Rule found: update data associated with the rule */
289 *entry_ptr
= &acl
->memory
[i
* acl
->entry_size
];
290 memcpy(*entry_ptr
, entry
, acl
->entry_size
);
296 /* Return if max rules */
297 if (free_pos_valid
== 0) {
298 RTE_LOG(ERR
, TABLE
, "%s: Max number of rules reached\n",
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
;
310 /* Build low level ACL table */
312 acl
->acl_params
.name
= acl
->name
[acl
->name_id
];
313 status
= rte_table_acl_build(acl
, &ctx
);
315 /* Roll back changes */
316 acl
->acl_rule_list
[free_pos
] = NULL
;
323 if (acl
->ctx
!= NULL
)
324 rte_acl_free(acl
->ctx
);
327 *entry_ptr
= &acl
->memory
[free_pos
* acl
->entry_size
];
328 memcpy(*entry_ptr
, entry
, acl
->entry_size
);
334 rte_table_acl_entry_delete(
340 struct rte_table_acl
*acl
= table
;
341 struct rte_table_acl_rule_delete_params
*rule
=
343 struct rte_acl_rule
*deleted_rule
= NULL
;
344 struct rte_acl_ctx
*ctx
;
345 uint32_t pos
, pos_valid
, i
;
348 /* Check input parameters */
350 RTE_LOG(ERR
, TABLE
, "%s: table parameter is NULL\n", __func__
);
354 RTE_LOG(ERR
, TABLE
, "%s: key parameter is NULL\n", __func__
);
357 if (key_found
== NULL
) {
358 RTE_LOG(ERR
, TABLE
, "%s: key_found parameter is NULL\n",
363 /* Look for the rule in the table */
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
));
373 /* Rule found: remove from table */
378 deleted_rule
= acl
->acl_rule_list
[i
];
379 acl
->acl_rule_list
[i
] = NULL
;
384 /* Return if rule not found */
385 if (pos_valid
== 0) {
390 /* Build low level ACL table */
392 acl
->acl_params
.name
= acl
->name
[acl
->name_id
];
393 status
= rte_table_acl_build(acl
, &ctx
);
395 /* Roll back changes */
396 acl
->acl_rule_list
[pos
] = deleted_rule
;
403 if (acl
->ctx
!= NULL
)
404 rte_acl_free(acl
->ctx
);
409 memcpy(entry
, &acl
->memory
[pos
* acl
->entry_size
],
416 rte_table_acl_entry_add_bulk(
424 struct rte_table_acl
*acl
= table
;
425 struct rte_acl_ctx
*ctx
;
426 uint32_t rule_pos
[n_keys
];
428 int err
= 0, build
= 0;
431 /* Check input parameters */
433 RTE_LOG(ERR
, TABLE
, "%s: table parameter is NULL\n", __func__
);
437 RTE_LOG(ERR
, TABLE
, "%s: keys parameter is NULL\n", __func__
);
440 if (entries
== NULL
) {
441 RTE_LOG(ERR
, TABLE
, "%s: entries parameter is NULL\n", __func__
);
445 RTE_LOG(ERR
, TABLE
, "%s: 0 rules to add\n", __func__
);
448 if (key_found
== NULL
) {
449 RTE_LOG(ERR
, TABLE
, "%s: key_found parameter is NULL\n",
453 if (entries_ptr
== NULL
) {
454 RTE_LOG(ERR
, TABLE
, "%s: entries_ptr parameter is NULL\n",
459 /* Check input parameters in arrays */
460 for (i
= 0; i
< n_keys
; i
++) {
461 struct rte_table_acl_rule_add_params
*rule
;
463 if (keys
[i
] == NULL
) {
464 RTE_LOG(ERR
, TABLE
, "%s: keys[%" PRIu32
"] parameter is NULL\n",
469 if (entries
[i
] == NULL
) {
470 RTE_LOG(ERR
, TABLE
, "%s: entries[%" PRIu32
"] parameter is NULL\n",
476 if (rule
->priority
> RTE_ACL_MAX_PRIORITY
) {
477 RTE_LOG(ERR
, TABLE
, "%s: Priority is too high\n", __func__
);
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
=
487 struct rte_pipeline_acl_rule acl_rule
;
488 struct rte_acl_rule
*rule_location
;
489 uint32_t free_pos
, free_pos_valid
, j
;
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
));
500 /* Look to see if the rule exists already in the table */
503 for (j
= 1; j
< acl
->n_rules
; j
++) {
504 if (acl
->acl_rule_list
[j
] == NULL
) {
505 if (free_pos_valid
== 0) {
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
));
518 /* Rule found: update data associated with the rule */
521 entries_ptr
[i
] = &acl
->memory
[j
* acl
->entry_size
];
522 memcpy(entries_ptr
[i
], entries
[i
], acl
->entry_size
);
528 /* Key already in the table */
529 if (key_found
[i
] != 0)
532 /* Maximum number of rules reached */
533 if (free_pos_valid
== 0) {
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
;
549 for (i
= 0; i
< n_keys
; i
++) {
550 if (rule_pos
[i
] == 0)
553 acl
->acl_rule_list
[rule_pos
[i
]] = NULL
;
562 /* Build low level ACL table */
564 acl
->acl_params
.name
= acl
->name
[acl
->name_id
];
565 status
= rte_table_acl_build(acl
, &ctx
);
567 /* Roll back changes */
568 for (i
= 0; i
< n_keys
; i
++) {
569 if (rule_pos
[i
] == 0)
572 acl
->acl_rule_list
[rule_pos
[i
]] = NULL
;
580 if (acl
->ctx
!= NULL
)
581 rte_acl_free(acl
->ctx
);
584 for (i
= 0; i
< n_keys
; i
++) {
585 if (rule_pos
[i
] == 0)
589 entries_ptr
[i
] = &acl
->memory
[rule_pos
[i
] * acl
->entry_size
];
590 memcpy(entries_ptr
[i
], entries
[i
], acl
->entry_size
);
597 rte_table_acl_entry_delete_bulk(
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
;
612 /* Check input parameters */
614 RTE_LOG(ERR
, TABLE
, "%s: table parameter is NULL\n", __func__
);
618 RTE_LOG(ERR
, TABLE
, "%s: key parameter is NULL\n", __func__
);
622 RTE_LOG(ERR
, TABLE
, "%s: 0 rules to delete\n", __func__
);
625 if (key_found
== NULL
) {
626 RTE_LOG(ERR
, TABLE
, "%s: key_found parameter is NULL\n",
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",
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
=
644 uint32_t pos_valid
, j
;
646 /* Look for the rule in the table */
648 for (j
= 1; j
< acl
->n_rules
; j
++) {
649 if (acl
->acl_rule_list
[j
] == NULL
)
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
));
657 /* Rule found: remove from table */
661 deleted_rules
[i
] = acl
->acl_rule_list
[j
];
662 acl
->acl_rule_list
[j
] = NULL
;
669 if (pos_valid
== 0) {
675 /* Return if no changes to acl table */
680 /* Build low level ACL table */
682 acl
->acl_params
.name
= acl
->name
[acl
->name_id
];
683 status
= rte_table_acl_build(acl
, &ctx
);
685 /* Roll back changes */
686 for (i
= 0; i
< n_keys
; i
++) {
687 if (rule_pos
[i
] == 0)
690 acl
->acl_rule_list
[rule_pos
[i
]] = deleted_rules
[i
];
699 if (acl
->ctx
!= NULL
)
700 rte_acl_free(acl
->ctx
);
703 for (i
= 0; i
< n_keys
; i
++) {
704 if (rule_pos
[i
] == 0)
708 if (entries
!= NULL
&& entries
[i
] != NULL
)
709 memcpy(entries
[i
], &acl
->memory
[rule_pos
[i
] * acl
->entry_size
],
717 rte_table_acl_lookup(
719 struct rte_mbuf
**pkts
,
721 uint64_t *lookup_hit_mask
,
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
;
730 __rte_unused
uint32_t n_pkts_in
= __builtin_popcountll(pkts_mask
);
731 RTE_TABLE_ACL_STATS_PKTS_IN_ADD(acl
, n_pkts_in
);
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
;
738 if (pkt_mask
& pkts_mask
) {
739 pkts_data
[j
] = rte_pktmbuf_mtod(pkts
[i
], uint8_t *);
745 /* Low-level ACL table lookup */
746 if (acl
->ctx
!= NULL
)
747 rte_acl_classify(acl
->ctx
, pkts_data
, results
, n_pkts
, 1);
751 /* Output conversion */
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
;
758 pkts_mask
&= ~pkt_mask
;
760 if (action_table_pos
!= 0) {
761 pkts_out_mask
|= pkt_mask
;
762 entries
[pkt_pos
] = (void *)
763 &acl
->memory
[action_table_pos
*
765 rte_prefetch0(entries
[pkt_pos
]);
769 *lookup_hit_mask
= pkts_out_mask
;
770 RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(acl
, n_pkts_in
- __builtin_popcountll(pkts_out_mask
));
776 rte_table_acl_stats_read(void *table
, struct rte_table_stats
*stats
, int clear
)
778 struct rte_table_acl
*acl
= table
;
781 memcpy(stats
, &acl
->stats
, sizeof(acl
->stats
));
784 memset(&acl
->stats
, 0, sizeof(acl
->stats
));
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
,