1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
9 #define ACL_POOL_ALIGN 8
10 #define ACL_POOL_ALLOC_MIN 0x800000
12 /* number of pointers per alloc */
13 #define ACL_PTR_ALLOC 32
15 /* macros for dividing rule sets heuristics */
16 #define NODE_MAX 0x4000
17 #define NODE_MIN 0x800
19 /* TALLY are statistics per field */
21 TALLY_0 = 0, /* number of rules that are 0% or more wild. */
22 TALLY_25, /* number of rules that are 25% or more wild. */
26 TALLY_DEACTIVATED, /* deactivated fields (100% wild in all rules). */
28 /* number of rules that are 100% wild for this field and higher. */
32 static const uint32_t wild_limits[TALLY_DEACTIVATED] = {0, 25, 50, 75, 100};
35 ACL_INTERSECT_NONE = 0,
36 ACL_INTERSECT_A = 1, /* set A is a superset of A and B intersect */
37 ACL_INTERSECT_B = 2, /* set B is a superset of A and B intersect */
38 ACL_INTERSECT = 4, /* sets A and B intersect */
42 ACL_PRIORITY_EQUAL = 0,
43 ACL_PRIORITY_NODE_A = 1,
44 ACL_PRIORITY_NODE_B = 2,
45 ACL_PRIORITY_MIXED = 3
49 struct acl_mem_block {
54 #define MEM_BLOCK_NUM 16
56 /* Single ACL rule, build representation.*/
57 struct rte_acl_build_rule {
58 struct rte_acl_build_rule *next;
59 struct rte_acl_config *config;
60 /**< configuration for each field in the rule. */
61 const struct rte_acl_rule *f;
65 /* Context for build phase */
66 struct acl_build_context {
67 const struct rte_acl_ctx *acx;
68 struct rte_acl_build_rule *build_rules;
69 struct rte_acl_config cfg;
74 uint32_t category_mask;
78 uint32_t num_build_rules;
80 struct tb_mem_pool pool;
81 struct rte_acl_trie tries[RTE_ACL_MAX_TRIES];
82 struct rte_acl_bld_trie bld_tries[RTE_ACL_MAX_TRIES];
83 uint32_t data_indexes[RTE_ACL_MAX_TRIES][RTE_ACL_MAX_FIELDS];
85 /* memory free lists for nodes and blocks used for node ptrs */
86 struct acl_mem_block blocks[MEM_BLOCK_NUM];
87 struct rte_acl_node *node_free_list;
90 static int acl_merge_trie(struct acl_build_context *context,
91 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
92 uint32_t level, struct rte_acl_node **node_c);
95 acl_deref_ptr(struct acl_build_context *context,
96 struct rte_acl_node *node, int index);
99 acl_build_alloc(struct acl_build_context *context, size_t n, size_t s)
103 size_t alloc_size = n * s;
106 * look for memory in free lists
108 for (m = 0; m < RTE_DIM(context->blocks); m++) {
109 if (context->blocks[m].block_size ==
110 alloc_size && context->blocks[m].mem_ptr != NULL) {
111 p = context->blocks[m].mem_ptr;
112 context->blocks[m].mem_ptr = *((void **)p);
113 memset(p, 0, alloc_size);
119 * return allocation from memory pool
121 p = tb_alloc(&context->pool, alloc_size);
126 * Free memory blocks (kept in context for reuse).
129 acl_build_free(struct acl_build_context *context, size_t s, void *p)
133 for (n = 0; n < RTE_DIM(context->blocks); n++) {
134 if (context->blocks[n].block_size == s) {
135 *((void **)p) = context->blocks[n].mem_ptr;
136 context->blocks[n].mem_ptr = p;
140 for (n = 0; n < RTE_DIM(context->blocks); n++) {
141 if (context->blocks[n].block_size == 0) {
142 context->blocks[n].block_size = s;
143 *((void **)p) = NULL;
144 context->blocks[n].mem_ptr = p;
151 * Allocate and initialize a new node.
153 static struct rte_acl_node *
154 acl_alloc_node(struct acl_build_context *context, int level)
156 struct rte_acl_node *node;
158 if (context->node_free_list != NULL) {
159 node = context->node_free_list;
160 context->node_free_list = node->next;
161 memset(node, 0, sizeof(struct rte_acl_node));
163 node = acl_build_alloc(context, sizeof(struct rte_acl_node), 1);
169 node->node_type = RTE_ACL_NODE_UNDEFINED;
170 node->node_index = RTE_ACL_NODE_UNDEFINED;
171 context->num_nodes++;
172 node->id = context->node_id++;
178 * Dereference all nodes to which this node points
181 acl_free_node(struct acl_build_context *context,
182 struct rte_acl_node *node)
186 if (node->prev != NULL)
187 node->prev->next = NULL;
188 for (n = 0; n < node->num_ptrs; n++)
189 acl_deref_ptr(context, node, n);
191 /* free mrt if this is a match node */
192 if (node->mrt != NULL) {
193 acl_build_free(context, sizeof(struct rte_acl_match_results),
198 /* free transitions to other nodes */
199 if (node->ptrs != NULL) {
200 acl_build_free(context,
201 node->max_ptrs * sizeof(struct rte_acl_ptr_set),
206 /* put it on the free list */
207 context->num_nodes--;
208 node->next = context->node_free_list;
209 context->node_free_list = node;
214 * Include src bitset in dst bitset
217 acl_include(struct rte_acl_bitset *dst, struct rte_acl_bitset *src, bits_t mask)
221 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
222 dst->bits[n] = (dst->bits[n] & mask) | src->bits[n];
226 * Set dst to bits of src1 that are not in src2
229 acl_exclude(struct rte_acl_bitset *dst,
230 struct rte_acl_bitset *src1,
231 struct rte_acl_bitset *src2)
236 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
237 dst->bits[n] = src1->bits[n] & ~src2->bits[n];
238 all_bits |= dst->bits[n];
240 return all_bits != 0;
244 * Add a pointer (ptr) to a node.
247 acl_add_ptr(struct acl_build_context *context,
248 struct rte_acl_node *node,
249 struct rte_acl_node *ptr,
250 struct rte_acl_bitset *bits)
252 uint32_t n, num_ptrs;
253 struct rte_acl_ptr_set *ptrs = NULL;
256 * If there's already a pointer to the same node, just add to the bitset
258 for (n = 0; n < node->num_ptrs; n++) {
259 if (node->ptrs[n].ptr != NULL) {
260 if (node->ptrs[n].ptr == ptr) {
261 acl_include(&node->ptrs[n].values, bits, -1);
262 acl_include(&node->values, bits, -1);
268 /* if there's no room for another pointer, make room */
269 if (node->num_ptrs >= node->max_ptrs) {
270 /* add room for more pointers */
271 num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
272 ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
274 /* copy current points to new memory allocation */
275 if (node->ptrs != NULL) {
276 memcpy(ptrs, node->ptrs,
277 node->num_ptrs * sizeof(*ptrs));
278 acl_build_free(context, node->max_ptrs * sizeof(*ptrs),
282 node->max_ptrs = num_ptrs;
285 /* Find available ptr and add a new pointer to this node */
286 for (n = node->min_add; n < node->max_ptrs; n++) {
287 if (node->ptrs[n].ptr == NULL) {
288 node->ptrs[n].ptr = ptr;
289 acl_include(&node->ptrs[n].values, bits, 0);
290 acl_include(&node->values, bits, -1);
293 if (node->num_ptrs <= n)
294 node->num_ptrs = n + 1;
303 * Add a pointer for a range of values
306 acl_add_ptr_range(struct acl_build_context *context,
307 struct rte_acl_node *root,
308 struct rte_acl_node *node,
313 struct rte_acl_bitset bitset;
315 /* clear the bitset values */
316 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
319 /* for each bit in range, add bit to set */
320 for (n = 0; n < UINT8_MAX + 1; n++)
321 if (n >= low && n <= high)
322 bitset.bits[n / (sizeof(bits_t) * 8)] |=
323 1 << (n % (sizeof(bits_t) * 8));
325 return acl_add_ptr(context, root, node, &bitset);
329 * Generate a bitset from a byte value and mask.
332 acl_gen_mask(struct rte_acl_bitset *bitset, uint32_t value, uint32_t mask)
337 /* clear the bitset values */
338 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
341 /* for each bit in value/mask, add bit to set */
342 for (n = 0; n < UINT8_MAX + 1; n++) {
343 if ((n & mask) == value) {
345 bitset->bits[n / (sizeof(bits_t) * 8)] |=
346 1 << (n % (sizeof(bits_t) * 8));
353 * Determine how A and B intersect.
354 * Determine if A and/or B are supersets of the intersection.
357 acl_intersect_type(const struct rte_acl_bitset *a_bits,
358 const struct rte_acl_bitset *b_bits,
359 struct rte_acl_bitset *intersect)
362 bits_t intersect_bits = 0;
363 bits_t a_superset = 0;
364 bits_t b_superset = 0;
367 * calculate and store intersection and check if A and/or B have
368 * bits outside the intersection (superset)
370 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
371 intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
372 a_superset |= a_bits->bits[n] ^ intersect->bits[n];
373 b_superset |= b_bits->bits[n] ^ intersect->bits[n];
374 intersect_bits |= intersect->bits[n];
377 n = (intersect_bits == 0 ? ACL_INTERSECT_NONE : ACL_INTERSECT) |
378 (b_superset == 0 ? 0 : ACL_INTERSECT_B) |
379 (a_superset == 0 ? 0 : ACL_INTERSECT_A);
387 static struct rte_acl_node *
388 acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)
391 struct rte_acl_node *next;
393 next = acl_alloc_node(context, node->level);
395 /* allocate the pointers */
396 if (node->num_ptrs > 0) {
397 next->ptrs = acl_build_alloc(context,
399 sizeof(struct rte_acl_ptr_set));
400 next->max_ptrs = node->max_ptrs;
403 /* copy over the pointers */
404 for (n = 0; n < node->num_ptrs; n++) {
405 if (node->ptrs[n].ptr != NULL) {
406 next->ptrs[n].ptr = node->ptrs[n].ptr;
407 next->ptrs[n].ptr->ref_count++;
408 acl_include(&next->ptrs[n].values,
409 &node->ptrs[n].values, -1);
413 next->num_ptrs = node->num_ptrs;
415 /* copy over node's match results */
416 if (node->match_flag == 0)
417 next->match_flag = 0;
419 next->match_flag = -1;
420 next->mrt = acl_build_alloc(context, 1, sizeof(*next->mrt));
421 memcpy(next->mrt, node->mrt, sizeof(*next->mrt));
424 /* copy over node's bitset */
425 acl_include(&next->values, &node->values, -1);
434 * Dereference a pointer from a node
437 acl_deref_ptr(struct acl_build_context *context,
438 struct rte_acl_node *node, int index)
440 struct rte_acl_node *ref_node;
442 /* De-reference the node at the specified pointer */
443 if (node != NULL && node->ptrs[index].ptr != NULL) {
444 ref_node = node->ptrs[index].ptr;
445 ref_node->ref_count--;
446 if (ref_node->ref_count == 0)
447 acl_free_node(context, ref_node);
452 * acl_exclude rte_acl_bitset from src and copy remaining pointer to dst
455 acl_copy_ptr(struct acl_build_context *context,
456 struct rte_acl_node *dst,
457 struct rte_acl_node *src,
459 struct rte_acl_bitset *b_bits)
462 struct rte_acl_bitset bits;
465 if (!acl_exclude(&bits, &src->ptrs[index].values, b_bits))
468 rc = acl_add_ptr(context, dst, src->ptrs[index].ptr, &bits);
475 * Fill in gaps in ptrs list with the ptr at the end of the list
478 acl_compact_node_ptrs(struct rte_acl_node *node_a)
481 int min_add = node_a->min_add;
483 while (node_a->num_ptrs > 0 &&
484 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
487 for (n = min_add; n + 1 < node_a->num_ptrs; n++) {
489 /* if this entry is empty */
490 if (node_a->ptrs[n].ptr == NULL) {
492 /* move the last pointer to this entry */
493 acl_include(&node_a->ptrs[n].values,
494 &node_a->ptrs[node_a->num_ptrs - 1].values,
496 node_a->ptrs[n].ptr =
497 node_a->ptrs[node_a->num_ptrs - 1].ptr;
500 * mark the end as empty and adjust the number
501 * of used pointer enum_tries
503 node_a->ptrs[node_a->num_ptrs - 1].ptr = NULL;
504 while (node_a->num_ptrs > 0 &&
505 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
512 acl_resolve_leaf(struct acl_build_context *context,
513 struct rte_acl_node *node_a,
514 struct rte_acl_node *node_b,
515 struct rte_acl_node **node_c)
518 int combined_priority = ACL_PRIORITY_EQUAL;
520 for (n = 0; n < context->cfg.num_categories; n++) {
521 if (node_a->mrt->priority[n] != node_b->mrt->priority[n]) {
522 combined_priority |= (node_a->mrt->priority[n] >
523 node_b->mrt->priority[n]) ?
524 ACL_PRIORITY_NODE_A : ACL_PRIORITY_NODE_B;
529 * if node a is higher or equal priority for all categories,
530 * then return node_a.
532 if (combined_priority == ACL_PRIORITY_NODE_A ||
533 combined_priority == ACL_PRIORITY_EQUAL) {
539 * if node b is higher or equal priority for all categories,
540 * then return node_b.
542 if (combined_priority == ACL_PRIORITY_NODE_B) {
548 * mixed priorities - create a new node with the highest priority
552 /* force new duplication. */
555 *node_c = acl_dup_node(context, node_a);
556 for (n = 0; n < context->cfg.num_categories; n++) {
557 if ((*node_c)->mrt->priority[n] < node_b->mrt->priority[n]) {
558 (*node_c)->mrt->priority[n] = node_b->mrt->priority[n];
559 (*node_c)->mrt->results[n] = node_b->mrt->results[n];
566 * Merge nodes A and B together,
567 * returns a node that is the path for the intersection
569 * If match node (leaf on trie)
571 * return node = highest priority result
573 * Create C as a duplicate of A to point to child intersections
574 * If any pointers in C intersect with any in B
575 * For each intersection
577 * remove intersection from C pointer
578 * add a pointer from C to child intersection node
579 * Compact the pointers in A and B
580 * Copy any B pointers that are outside of the intersection to C
581 * If C has no references to the B trie
582 * free C and return A
583 * Else If C has no references to the A trie
584 * free C and return B
589 acl_merge_trie(struct acl_build_context *context,
590 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
591 uint32_t level, struct rte_acl_node **return_c)
593 uint32_t n, m, ptrs_c, ptrs_b;
594 uint32_t min_add_c, min_add_b;
595 int node_intersect_type;
596 struct rte_acl_bitset node_intersect;
597 struct rte_acl_node *node_c;
598 struct rte_acl_node *node_a_next;
603 node_a_next = node_a->next;
606 node_a_refs = node_a->num_ptrs;
608 node_intersect_type = 0;
610 /* Resolve leaf nodes (matches) */
611 if (node_a->match_flag != 0) {
612 acl_resolve_leaf(context, node_a, node_b, return_c);
617 * Create node C as a copy of node A, and do: C = merge(A,B);
618 * If node A can be used instead (A==C), then later we'll
619 * destroy C and return A.
622 node_c = acl_dup_node(context, node_a);
625 * If the two node transitions intersect then merge the transitions.
626 * Check intersection for entire node (all pointers)
628 node_intersect_type = acl_intersect_type(&node_c->values,
632 if (node_intersect_type & ACL_INTERSECT) {
634 min_add_b = node_b->min_add;
635 node_b->min_add = node_b->num_ptrs;
636 ptrs_b = node_b->num_ptrs;
638 min_add_c = node_c->min_add;
639 node_c->min_add = node_c->num_ptrs;
640 ptrs_c = node_c->num_ptrs;
642 for (n = 0; n < ptrs_c; n++) {
643 if (node_c->ptrs[n].ptr == NULL) {
647 node_c->ptrs[n].ptr->next = NULL;
648 for (m = 0; m < ptrs_b; m++) {
650 struct rte_acl_bitset child_intersect;
651 int child_intersect_type;
652 struct rte_acl_node *child_node_c = NULL;
654 if (node_b->ptrs[m].ptr == NULL ||
655 node_c->ptrs[n].ptr ==
659 child_intersect_type = acl_intersect_type(
660 &node_c->ptrs[n].values,
661 &node_b->ptrs[m].values,
664 if ((child_intersect_type & ACL_INTERSECT) !=
666 if (acl_merge_trie(context,
673 if (child_node_c != NULL &&
675 node_c->ptrs[n].ptr) {
680 * Added link from C to
681 * child_C for all transitions
682 * in the intersection.
684 acl_add_ptr(context, node_c,
689 * inc refs if pointer is not
692 node_a_refs += (child_node_c !=
693 node_b->ptrs[m].ptr);
696 * Remove intersection from C
700 &node_c->ptrs[n].values,
701 &node_c->ptrs[n].values,
703 acl_deref_ptr(context,
705 node_c->ptrs[n].ptr =
714 /* Compact pointers */
715 node_c->min_add = min_add_c;
716 acl_compact_node_ptrs(node_c);
717 node_b->min_add = min_add_b;
718 acl_compact_node_ptrs(node_b);
722 * Copy pointers outside of the intersection from B to C
724 if ((node_intersect_type & ACL_INTERSECT_B) != 0) {
726 for (m = 0; m < node_b->num_ptrs; m++)
727 if (node_b->ptrs[m].ptr != NULL)
728 acl_copy_ptr(context, node_c,
729 node_b, m, &node_intersect);
733 * Free node C if top of trie is contained in A or B
734 * if node C is a duplicate of node A &&
735 * node C was not an existing duplicate
737 if (node_c != node_a && node_c != node_a_next) {
740 * if the intersection has no references to the
741 * B side, then it is contained in A
743 if (node_b_refs == 0) {
744 acl_free_node(context, node_c);
748 * if the intersection has no references to the
749 * A side, then it is contained in B.
751 if (node_a_refs == 0) {
752 acl_free_node(context, node_c);
758 if (return_c != NULL)
762 acl_free_node(context, node_b);
768 * Reset current runtime fields before next build:
769 * - free allocated RT memory.
770 * - reset all RT related fields to zero.
773 acl_build_reset(struct rte_acl_ctx *ctx)
776 memset(&ctx->num_categories, 0,
777 sizeof(*ctx) - offsetof(struct rte_acl_ctx, num_categories));
781 acl_gen_range(struct acl_build_context *context,
782 const uint8_t *hi, const uint8_t *lo, int size, int level,
783 struct rte_acl_node *root, struct rte_acl_node *end)
785 struct rte_acl_node *node, *prev;
789 for (n = size - 1; n > 0; n--) {
790 node = acl_alloc_node(context, level++);
791 acl_add_ptr_range(context, prev, node, lo[n], hi[n]);
794 acl_add_ptr_range(context, prev, end, lo[0], hi[0]);
797 static struct rte_acl_node *
798 acl_gen_range_trie(struct acl_build_context *context,
799 const void *min, const void *max,
800 int size, int level, struct rte_acl_node **pend)
803 struct rte_acl_node *root;
804 const uint8_t *lo = min;
805 const uint8_t *hi = max;
807 *pend = acl_alloc_node(context, level+size);
808 root = acl_alloc_node(context, level++);
810 if (lo[size - 1] == hi[size - 1]) {
811 acl_gen_range(context, hi, lo, size, level, root, *pend);
813 uint8_t limit_lo[64];
814 uint8_t limit_hi[64];
815 uint8_t hi_ff = UINT8_MAX;
818 memset(limit_lo, 0, RTE_DIM(limit_lo));
819 memset(limit_hi, UINT8_MAX, RTE_DIM(limit_hi));
821 for (n = size - 2; n >= 0; n--) {
822 hi_ff = (uint8_t)(hi_ff & hi[n]);
823 lo_00 = (uint8_t)(lo_00 | lo[n]);
826 if (hi_ff != UINT8_MAX) {
827 limit_lo[size - 1] = hi[size - 1];
828 acl_gen_range(context, hi, limit_lo, size, level,
833 limit_hi[size - 1] = lo[size - 1];
834 acl_gen_range(context, limit_hi, lo, size, level,
838 if (hi[size - 1] - lo[size - 1] > 1 ||
840 hi_ff == UINT8_MAX) {
841 limit_lo[size-1] = (uint8_t)(lo[size-1] + (lo_00 != 0));
842 limit_hi[size-1] = (uint8_t)(hi[size-1] -
843 (hi_ff != UINT8_MAX));
844 acl_gen_range(context, limit_hi, limit_lo, size,
851 static struct rte_acl_node *
852 acl_gen_mask_trie(struct acl_build_context *context,
853 const void *value, const void *mask,
854 int size, int level, struct rte_acl_node **pend)
857 struct rte_acl_node *root;
858 struct rte_acl_node *node, *prev;
859 struct rte_acl_bitset bits;
860 const uint8_t *val = value;
861 const uint8_t *msk = mask;
863 root = acl_alloc_node(context, level++);
866 for (n = size - 1; n >= 0; n--) {
867 node = acl_alloc_node(context, level++);
868 acl_gen_mask(&bits, val[n] & msk[n], msk[n]);
869 acl_add_ptr(context, prev, node, &bits);
877 static struct rte_acl_node *
878 build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head,
879 struct rte_acl_build_rule **last, uint32_t *count)
882 int field_index, node_count;
883 struct rte_acl_node *trie;
884 struct rte_acl_build_rule *prev, *rule;
885 struct rte_acl_node *end, *merge, *root, *end_prev;
886 const struct rte_acl_field *fld;
892 trie = acl_alloc_node(context, 0);
894 while (rule != NULL) {
896 root = acl_alloc_node(context, 0);
901 for (n = 0; n < rule->config->num_fields; n++) {
903 field_index = rule->config->defs[n].field_index;
904 fld = rule->f->field + field_index;
907 /* build a mini-trie for this field */
908 switch (rule->config->defs[n].type) {
910 case RTE_ACL_FIELD_TYPE_BITMASK:
911 merge = acl_gen_mask_trie(context,
914 rule->config->defs[n].size,
919 case RTE_ACL_FIELD_TYPE_MASK:
922 * set msb for the size of the field and
926 mask = RTE_ACL_MASKLEN_TO_BITMASK(
928 rule->config->defs[n].size);
930 /* gen a mini-trie for this field */
931 merge = acl_gen_mask_trie(context,
934 rule->config->defs[n].size,
940 case RTE_ACL_FIELD_TYPE_RANGE:
941 merge = acl_gen_range_trie(context,
942 &rule->f->field[field_index].value,
943 &rule->f->field[field_index].mask_range,
944 rule->config->defs[n].size,
951 "Error in rule[%u] type - %hhu\n",
952 rule->f->data.userdata,
953 rule->config->defs[n].type);
957 /* merge this field on to the end of the rule */
958 if (acl_merge_trie(context, end_prev, merge, 0,
964 end->match_flag = ++context->num_build_rules;
967 * Setup the results for this rule.
968 * The result and priority of each category.
970 if (end->mrt == NULL)
971 end->mrt = acl_build_alloc(context, 1,
974 for (m = context->cfg.num_categories; 0 != m--; ) {
975 if (rule->f->data.category_mask & (1 << m)) {
976 end->mrt->results[m] = rule->f->data.userdata;
977 end->mrt->priority[m] = rule->f->data.priority;
979 end->mrt->results[m] = 0;
980 end->mrt->priority[m] = 0;
984 node_count = context->num_nodes;
987 /* merge this rule into the trie */
988 if (acl_merge_trie(context, trie, root, 0, NULL))
991 node_count = context->num_nodes - node_count;
992 if (node_count > context->cur_node_max) {
1006 acl_calc_wildness(struct rte_acl_build_rule *head,
1007 const struct rte_acl_config *config)
1010 struct rte_acl_build_rule *rule;
1012 for (rule = head; rule != NULL; rule = rule->next) {
1014 for (n = 0; n < config->num_fields; n++) {
1017 uint32_t bit_len = CHAR_BIT * config->defs[n].size;
1018 uint64_t msk_val = RTE_LEN2MASK(bit_len,
1020 double size = bit_len;
1021 int field_index = config->defs[n].field_index;
1022 const struct rte_acl_field *fld = rule->f->field +
1025 switch (rule->config->defs[n].type) {
1026 case RTE_ACL_FIELD_TYPE_BITMASK:
1027 wild = (size - __builtin_popcountll(
1028 fld->mask_range.u64 & msk_val)) /
1032 case RTE_ACL_FIELD_TYPE_MASK:
1033 wild = (size - fld->mask_range.u32) / size;
1036 case RTE_ACL_FIELD_TYPE_RANGE:
1037 wild = (fld->mask_range.u64 & msk_val) -
1038 (fld->value.u64 & msk_val);
1039 wild = wild / msk_val;
1043 rule->wildness[field_index] = (uint32_t)(wild * 100);
1049 acl_rule_stats(struct rte_acl_build_rule *head, struct rte_acl_config *config)
1051 struct rte_acl_build_rule *rule;
1052 uint32_t n, m, fields_deactivated = 0;
1053 uint32_t start = 0, deactivate = 0;
1054 int tally[RTE_ACL_MAX_LEVELS][TALLY_NUM];
1056 memset(tally, 0, sizeof(tally));
1058 for (rule = head; rule != NULL; rule = rule->next) {
1060 for (n = 0; n < config->num_fields; n++) {
1061 uint32_t field_index = config->defs[n].field_index;
1063 tally[n][TALLY_0]++;
1064 for (m = 1; m < RTE_DIM(wild_limits); m++) {
1065 if (rule->wildness[field_index] >=
1071 for (n = config->num_fields - 1; n > 0; n--) {
1072 uint32_t field_index = config->defs[n].field_index;
1074 if (rule->wildness[field_index] == 100)
1075 tally[n][TALLY_DEPTH]++;
1082 * Look for any field that is always wild and drop it from the config
1083 * Only deactivate if all fields for a given input loop are deactivated.
1085 for (n = 1; n < config->num_fields; n++) {
1086 if (config->defs[n].input_index !=
1087 config->defs[n - 1].input_index) {
1088 for (m = start; m < n; m++)
1089 tally[m][TALLY_DEACTIVATED] = deactivate;
1090 fields_deactivated += deactivate;
1095 /* if the field is not always completely wild */
1096 if (tally[n][TALLY_100] != tally[n][TALLY_0])
1100 for (m = start; m < n; m++)
1101 tally[m][TALLY_DEACTIVATED] = deactivate;
1103 fields_deactivated += deactivate;
1105 /* remove deactivated fields */
1106 if (fields_deactivated) {
1109 for (k = 0; k < config->num_fields; k++) {
1110 if (tally[k][TALLY_DEACTIVATED] == 0) {
1111 memmove(&tally[l][0], &tally[k][0],
1112 TALLY_NUM * sizeof(tally[0][0]));
1113 memmove(&config->defs[l++],
1115 sizeof(struct rte_acl_field_def));
1118 config->num_fields = l;
1123 rule_cmp_wildness(struct rte_acl_build_rule *r1, struct rte_acl_build_rule *r2)
1127 for (n = 1; n < r1->config->num_fields; n++) {
1128 int field_index = r1->config->defs[n].field_index;
1130 if (r1->wildness[field_index] != r2->wildness[field_index])
1131 return r1->wildness[field_index] -
1132 r2->wildness[field_index];
1138 * Split the rte_acl_build_rule list into two lists.
1141 rule_list_split(struct rte_acl_build_rule *source,
1142 struct rte_acl_build_rule **list_a,
1143 struct rte_acl_build_rule **list_b)
1145 struct rte_acl_build_rule *fast;
1146 struct rte_acl_build_rule *slow;
1148 if (source == NULL || source->next == NULL) {
1149 /* length < 2 cases */
1154 fast = source->next;
1155 /* Advance 'fast' two nodes, and advance 'slow' one node */
1156 while (fast != NULL) {
1163 /* 'slow' is before the midpoint in the list, so split it in two
1166 *list_b = slow->next;
1172 * Merge two sorted lists.
1174 static struct rte_acl_build_rule *
1175 rule_list_sorted_merge(struct rte_acl_build_rule *a,
1176 struct rte_acl_build_rule *b)
1178 struct rte_acl_build_rule *result = NULL;
1179 struct rte_acl_build_rule **last_next = &result;
1185 } else if (b == NULL) {
1189 if (rule_cmp_wildness(a, b) >= 0) {
1191 last_next = &a->next;
1195 last_next = &b->next;
1203 * Sort list of rules based on the rules wildness.
1204 * Use recursive mergesort algorithm.
1206 static struct rte_acl_build_rule *
1207 sort_rules(struct rte_acl_build_rule *head)
1209 struct rte_acl_build_rule *a;
1210 struct rte_acl_build_rule *b;
1212 /* Base case -- length 0 or 1 */
1213 if (head == NULL || head->next == NULL)
1216 /* Split head into 'a' and 'b' sublists */
1217 rule_list_split(head, &a, &b);
1219 /* Recursively sort the sublists */
1223 /* answer = merge the two sorted lists together */
1224 return rule_list_sorted_merge(a, b);
1228 acl_build_index(const struct rte_acl_config *config, uint32_t *data_index)
1231 int32_t last_header;
1236 for (n = 0; n < config->num_fields; n++) {
1237 if (last_header != config->defs[n].input_index) {
1238 last_header = config->defs[n].input_index;
1239 data_index[m++] = config->defs[n].offset;
1246 static struct rte_acl_build_rule *
1247 build_one_trie(struct acl_build_context *context,
1248 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES],
1249 uint32_t n, int32_t node_max)
1251 struct rte_acl_build_rule *last;
1252 struct rte_acl_config *config;
1254 config = rule_sets[n]->config;
1256 acl_rule_stats(rule_sets[n], config);
1257 rule_sets[n] = sort_rules(rule_sets[n]);
1259 context->tries[n].type = RTE_ACL_FULL_TRIE;
1260 context->tries[n].count = 0;
1262 context->tries[n].num_data_indexes = acl_build_index(config,
1263 context->data_indexes[n]);
1264 context->tries[n].data_index = context->data_indexes[n];
1266 context->cur_node_max = node_max;
1268 context->bld_tries[n].trie = build_trie(context, rule_sets[n],
1269 &last, &context->tries[n].count);
1275 acl_build_tries(struct acl_build_context *context,
1276 struct rte_acl_build_rule *head)
1278 uint32_t n, num_tries;
1279 struct rte_acl_config *config;
1280 struct rte_acl_build_rule *last;
1281 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES];
1283 config = head->config;
1284 rule_sets[0] = head;
1286 /* initialize tries */
1287 for (n = 0; n < RTE_DIM(context->tries); n++) {
1288 context->tries[n].type = RTE_ACL_UNUSED_TRIE;
1289 context->bld_tries[n].trie = NULL;
1290 context->tries[n].count = 0;
1293 context->tries[0].type = RTE_ACL_FULL_TRIE;
1295 /* calc wildness of each field of each rule */
1296 acl_calc_wildness(head, config);
1298 for (n = 0;; n = num_tries) {
1302 last = build_one_trie(context, rule_sets, n, context->node_max);
1303 if (context->bld_tries[n].trie == NULL) {
1304 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1308 /* Build of the last trie completed. */
1312 if (num_tries == RTE_DIM(context->tries)) {
1314 "Exceeded max number of tries: %u\n",
1319 /* Trie is getting too big, split remaining rule set. */
1320 rule_sets[num_tries] = last->next;
1322 acl_free_node(context, context->bld_tries[n].trie);
1324 /* Create a new copy of config for remaining rules. */
1325 config = acl_build_alloc(context, 1, sizeof(*config));
1326 memcpy(config, rule_sets[n]->config, sizeof(*config));
1328 /* Make remaining rules use new config. */
1329 for (head = rule_sets[num_tries]; head != NULL;
1331 head->config = config;
1334 * Rebuild the trie for the reduced rule-set.
1335 * Don't try to split it any further.
1337 last = build_one_trie(context, rule_sets, n, INT32_MAX);
1338 if (context->bld_tries[n].trie == NULL || last != NULL) {
1339 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1345 context->num_tries = num_tries;
1350 acl_build_log(const struct acl_build_context *ctx)
1354 RTE_LOG(DEBUG, ACL, "Build phase for ACL \"%s\":\n"
1355 "node limit for tree split: %u\n"
1356 "nodes created: %u\n"
1357 "memory consumed: %zu\n",
1363 for (n = 0; n < RTE_DIM(ctx->tries); n++) {
1364 if (ctx->tries[n].count != 0)
1366 "trie %u: number of rules: %u, indexes: %u\n",
1367 n, ctx->tries[n].count,
1368 ctx->tries[n].num_data_indexes);
1373 acl_build_rules(struct acl_build_context *bcx)
1375 struct rte_acl_build_rule *br, *head;
1376 const struct rte_acl_rule *rule;
1378 uint32_t fn, i, n, num;
1381 fn = bcx->cfg.num_fields;
1382 n = bcx->acx->num_rules;
1383 ofs = n * sizeof(*br);
1384 sz = ofs + n * fn * sizeof(*wp);
1386 br = tb_alloc(&bcx->pool, sz);
1388 wp = (uint32_t *)((uintptr_t)br + ofs);
1392 for (i = 0; i != n; i++) {
1393 rule = (const struct rte_acl_rule *)
1394 ((uintptr_t)bcx->acx->rules + bcx->acx->rule_sz * i);
1395 if ((rule->data.category_mask & bcx->category_mask) != 0) {
1396 br[num].next = head;
1397 br[num].config = &bcx->cfg;
1399 br[num].wildness = wp;
1406 bcx->num_rules = num;
1407 bcx->build_rules = head;
1413 * Copy data_indexes for each trie into RT location.
1416 acl_set_data_indexes(struct rte_acl_ctx *ctx)
1421 for (i = 0; i != ctx->num_tries; i++) {
1422 n = ctx->trie[i].num_data_indexes;
1423 memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index,
1424 n * sizeof(ctx->data_indexes[0]));
1425 ctx->trie[i].data_index = ctx->data_indexes + ofs;
1426 ofs += RTE_ACL_MAX_FIELDS;
1431 * Internal routine, performs 'build' phase of trie generation:
1432 * - setups build context.
1433 * - analizes given set of rules.
1434 * - builds internal tree(s).
1437 acl_bld(struct acl_build_context *bcx, struct rte_acl_ctx *ctx,
1438 const struct rte_acl_config *cfg, uint32_t node_max)
1442 /* setup build context. */
1443 memset(bcx, 0, sizeof(*bcx));
1445 bcx->pool.alignment = ACL_POOL_ALIGN;
1446 bcx->pool.min_alloc = ACL_POOL_ALLOC_MIN;
1448 bcx->category_mask = RTE_LEN2MASK(bcx->cfg.num_categories,
1449 typeof(bcx->category_mask));
1450 bcx->node_max = node_max;
1452 rc = sigsetjmp(bcx->pool.fail, 0);
1454 /* build phase runs out of memory. */
1457 "ACL context: %s, %s() failed with error code: %d\n",
1458 bcx->acx->name, __func__, rc);
1462 /* Create a build rules copy. */
1463 rc = acl_build_rules(bcx);
1467 /* No rules to build for that context+config */
1468 if (bcx->build_rules == NULL) {
1471 /* build internal trie representation. */
1472 rc = acl_build_tries(bcx, bcx->build_rules);
1478 * Check that parameters for acl_build() are valid.
1481 acl_check_bld_param(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1483 static const size_t field_sizes[] = {
1484 sizeof(uint8_t), sizeof(uint16_t),
1485 sizeof(uint32_t), sizeof(uint64_t),
1490 if (ctx == NULL || cfg == NULL || cfg->num_categories == 0 ||
1491 cfg->num_categories > RTE_ACL_MAX_CATEGORIES ||
1492 cfg->num_fields == 0 ||
1493 cfg->num_fields > RTE_ACL_MAX_FIELDS)
1496 for (i = 0; i != cfg->num_fields; i++) {
1497 if (cfg->defs[i].type > RTE_ACL_FIELD_TYPE_BITMASK) {
1499 "ACL context: %s, invalid type: %hhu for %u-th field\n",
1500 ctx->name, cfg->defs[i].type, i);
1504 j != RTE_DIM(field_sizes) &&
1505 cfg->defs[i].size != field_sizes[j];
1509 if (j == RTE_DIM(field_sizes)) {
1511 "ACL context: %s, invalid size: %hhu for %u-th field\n",
1512 ctx->name, cfg->defs[i].size, i);
1521 rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1526 struct acl_build_context bcx;
1528 rc = acl_check_bld_param(ctx, cfg);
1532 acl_build_reset(ctx);
1534 if (cfg->max_size == 0) {
1536 max_size = SIZE_MAX;
1539 max_size = cfg->max_size;
1542 for (rc = -ERANGE; n >= NODE_MIN && rc == -ERANGE; n /= 2) {
1544 /* perform build phase. */
1545 rc = acl_bld(&bcx, ctx, cfg, n);
1548 /* allocate and fill run-time structures. */
1549 rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries,
1550 bcx.num_tries, bcx.cfg.num_categories,
1551 RTE_ACL_MAX_FIELDS * RTE_DIM(bcx.tries) *
1552 sizeof(ctx->data_indexes[0]), max_size);
1554 /* set data indexes. */
1555 acl_set_data_indexes(ctx);
1557 /* copy in build config. */
1562 acl_build_log(&bcx);
1564 /* cleanup after build. */
1565 tb_free_pool(&bcx.pool);