4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #define ACL_POOL_ALIGN 8
39 #define ACL_POOL_ALLOC_MIN 0x800000
41 /* number of pointers per alloc */
42 #define ACL_PTR_ALLOC 32
44 /* macros for dividing rule sets heuristics */
45 #define NODE_MAX 0x4000
46 #define NODE_MIN 0x800
48 /* TALLY are statistics per field */
50 TALLY_0 = 0, /* number of rules that are 0% or more wild. */
51 TALLY_25, /* number of rules that are 25% or more wild. */
55 TALLY_DEACTIVATED, /* deactivated fields (100% wild in all rules). */
57 /* number of rules that are 100% wild for this field and higher. */
61 static const uint32_t wild_limits[TALLY_DEACTIVATED] = {0, 25, 50, 75, 100};
64 ACL_INTERSECT_NONE = 0,
65 ACL_INTERSECT_A = 1, /* set A is a superset of A and B intersect */
66 ACL_INTERSECT_B = 2, /* set B is a superset of A and B intersect */
67 ACL_INTERSECT = 4, /* sets A and B intersect */
71 ACL_PRIORITY_EQUAL = 0,
72 ACL_PRIORITY_NODE_A = 1,
73 ACL_PRIORITY_NODE_B = 2,
74 ACL_PRIORITY_MIXED = 3
78 struct acl_mem_block {
83 #define MEM_BLOCK_NUM 16
85 /* Single ACL rule, build representation.*/
86 struct rte_acl_build_rule {
87 struct rte_acl_build_rule *next;
88 struct rte_acl_config *config;
89 /**< configuration for each field in the rule. */
90 const struct rte_acl_rule *f;
94 /* Context for build phase */
95 struct acl_build_context {
96 const struct rte_acl_ctx *acx;
97 struct rte_acl_build_rule *build_rules;
98 struct rte_acl_config cfg;
100 int32_t cur_node_max;
103 uint32_t category_mask;
107 uint32_t num_build_rules;
109 struct tb_mem_pool pool;
110 struct rte_acl_trie tries[RTE_ACL_MAX_TRIES];
111 struct rte_acl_bld_trie bld_tries[RTE_ACL_MAX_TRIES];
112 uint32_t data_indexes[RTE_ACL_MAX_TRIES][RTE_ACL_MAX_FIELDS];
114 /* memory free lists for nodes and blocks used for node ptrs */
115 struct acl_mem_block blocks[MEM_BLOCK_NUM];
116 struct rte_acl_node *node_free_list;
119 static int acl_merge_trie(struct acl_build_context *context,
120 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
121 uint32_t level, struct rte_acl_node **node_c);
124 acl_deref_ptr(struct acl_build_context *context,
125 struct rte_acl_node *node, int index);
128 acl_build_alloc(struct acl_build_context *context, size_t n, size_t s)
132 size_t alloc_size = n * s;
135 * look for memory in free lists
137 for (m = 0; m < RTE_DIM(context->blocks); m++) {
138 if (context->blocks[m].block_size ==
139 alloc_size && context->blocks[m].mem_ptr != NULL) {
140 p = context->blocks[m].mem_ptr;
141 context->blocks[m].mem_ptr = *((void **)p);
142 memset(p, 0, alloc_size);
148 * return allocation from memory pool
150 p = tb_alloc(&context->pool, alloc_size);
155 * Free memory blocks (kept in context for reuse).
158 acl_build_free(struct acl_build_context *context, size_t s, void *p)
162 for (n = 0; n < RTE_DIM(context->blocks); n++) {
163 if (context->blocks[n].block_size == s) {
164 *((void **)p) = context->blocks[n].mem_ptr;
165 context->blocks[n].mem_ptr = p;
169 for (n = 0; n < RTE_DIM(context->blocks); n++) {
170 if (context->blocks[n].block_size == 0) {
171 context->blocks[n].block_size = s;
172 *((void **)p) = NULL;
173 context->blocks[n].mem_ptr = p;
180 * Allocate and initialize a new node.
182 static struct rte_acl_node *
183 acl_alloc_node(struct acl_build_context *context, int level)
185 struct rte_acl_node *node;
187 if (context->node_free_list != NULL) {
188 node = context->node_free_list;
189 context->node_free_list = node->next;
190 memset(node, 0, sizeof(struct rte_acl_node));
192 node = acl_build_alloc(context, sizeof(struct rte_acl_node), 1);
198 node->node_type = RTE_ACL_NODE_UNDEFINED;
199 node->node_index = RTE_ACL_NODE_UNDEFINED;
200 context->num_nodes++;
201 node->id = context->node_id++;
207 * Dereference all nodes to which this node points
210 acl_free_node(struct acl_build_context *context,
211 struct rte_acl_node *node)
215 if (node->prev != NULL)
216 node->prev->next = NULL;
217 for (n = 0; n < node->num_ptrs; n++)
218 acl_deref_ptr(context, node, n);
220 /* free mrt if this is a match node */
221 if (node->mrt != NULL) {
222 acl_build_free(context, sizeof(struct rte_acl_match_results),
227 /* free transitions to other nodes */
228 if (node->ptrs != NULL) {
229 acl_build_free(context,
230 node->max_ptrs * sizeof(struct rte_acl_ptr_set),
235 /* put it on the free list */
236 context->num_nodes--;
237 node->next = context->node_free_list;
238 context->node_free_list = node;
243 * Include src bitset in dst bitset
246 acl_include(struct rte_acl_bitset *dst, struct rte_acl_bitset *src, bits_t mask)
250 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
251 dst->bits[n] = (dst->bits[n] & mask) | src->bits[n];
255 * Set dst to bits of src1 that are not in src2
258 acl_exclude(struct rte_acl_bitset *dst,
259 struct rte_acl_bitset *src1,
260 struct rte_acl_bitset *src2)
265 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
266 dst->bits[n] = src1->bits[n] & ~src2->bits[n];
267 all_bits |= dst->bits[n];
269 return all_bits != 0;
273 * Add a pointer (ptr) to a node.
276 acl_add_ptr(struct acl_build_context *context,
277 struct rte_acl_node *node,
278 struct rte_acl_node *ptr,
279 struct rte_acl_bitset *bits)
281 uint32_t n, num_ptrs;
282 struct rte_acl_ptr_set *ptrs = NULL;
285 * If there's already a pointer to the same node, just add to the bitset
287 for (n = 0; n < node->num_ptrs; n++) {
288 if (node->ptrs[n].ptr != NULL) {
289 if (node->ptrs[n].ptr == ptr) {
290 acl_include(&node->ptrs[n].values, bits, -1);
291 acl_include(&node->values, bits, -1);
297 /* if there's no room for another pointer, make room */
298 if (node->num_ptrs >= node->max_ptrs) {
299 /* add room for more pointers */
300 num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
301 ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
303 /* copy current points to new memory allocation */
304 if (node->ptrs != NULL) {
305 memcpy(ptrs, node->ptrs,
306 node->num_ptrs * sizeof(*ptrs));
307 acl_build_free(context, node->max_ptrs * sizeof(*ptrs),
311 node->max_ptrs = num_ptrs;
314 /* Find available ptr and add a new pointer to this node */
315 for (n = node->min_add; n < node->max_ptrs; n++) {
316 if (node->ptrs[n].ptr == NULL) {
317 node->ptrs[n].ptr = ptr;
318 acl_include(&node->ptrs[n].values, bits, 0);
319 acl_include(&node->values, bits, -1);
322 if (node->num_ptrs <= n)
323 node->num_ptrs = n + 1;
332 * Add a pointer for a range of values
335 acl_add_ptr_range(struct acl_build_context *context,
336 struct rte_acl_node *root,
337 struct rte_acl_node *node,
342 struct rte_acl_bitset bitset;
344 /* clear the bitset values */
345 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
348 /* for each bit in range, add bit to set */
349 for (n = 0; n < UINT8_MAX + 1; n++)
350 if (n >= low && n <= high)
351 bitset.bits[n / (sizeof(bits_t) * 8)] |=
352 1 << (n % (sizeof(bits_t) * 8));
354 return acl_add_ptr(context, root, node, &bitset);
358 * Generate a bitset from a byte value and mask.
361 acl_gen_mask(struct rte_acl_bitset *bitset, uint32_t value, uint32_t mask)
366 /* clear the bitset values */
367 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
370 /* for each bit in value/mask, add bit to set */
371 for (n = 0; n < UINT8_MAX + 1; n++) {
372 if ((n & mask) == value) {
374 bitset->bits[n / (sizeof(bits_t) * 8)] |=
375 1 << (n % (sizeof(bits_t) * 8));
382 * Determine how A and B intersect.
383 * Determine if A and/or B are supersets of the intersection.
386 acl_intersect_type(const struct rte_acl_bitset *a_bits,
387 const struct rte_acl_bitset *b_bits,
388 struct rte_acl_bitset *intersect)
391 bits_t intersect_bits = 0;
392 bits_t a_superset = 0;
393 bits_t b_superset = 0;
396 * calculate and store intersection and check if A and/or B have
397 * bits outside the intersection (superset)
399 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
400 intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
401 a_superset |= a_bits->bits[n] ^ intersect->bits[n];
402 b_superset |= b_bits->bits[n] ^ intersect->bits[n];
403 intersect_bits |= intersect->bits[n];
406 n = (intersect_bits == 0 ? ACL_INTERSECT_NONE : ACL_INTERSECT) |
407 (b_superset == 0 ? 0 : ACL_INTERSECT_B) |
408 (a_superset == 0 ? 0 : ACL_INTERSECT_A);
416 static struct rte_acl_node *
417 acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)
420 struct rte_acl_node *next;
422 next = acl_alloc_node(context, node->level);
424 /* allocate the pointers */
425 if (node->num_ptrs > 0) {
426 next->ptrs = acl_build_alloc(context,
428 sizeof(struct rte_acl_ptr_set));
429 next->max_ptrs = node->max_ptrs;
432 /* copy over the pointers */
433 for (n = 0; n < node->num_ptrs; n++) {
434 if (node->ptrs[n].ptr != NULL) {
435 next->ptrs[n].ptr = node->ptrs[n].ptr;
436 next->ptrs[n].ptr->ref_count++;
437 acl_include(&next->ptrs[n].values,
438 &node->ptrs[n].values, -1);
442 next->num_ptrs = node->num_ptrs;
444 /* copy over node's match results */
445 if (node->match_flag == 0)
446 next->match_flag = 0;
448 next->match_flag = -1;
449 next->mrt = acl_build_alloc(context, 1, sizeof(*next->mrt));
450 memcpy(next->mrt, node->mrt, sizeof(*next->mrt));
453 /* copy over node's bitset */
454 acl_include(&next->values, &node->values, -1);
463 * Dereference a pointer from a node
466 acl_deref_ptr(struct acl_build_context *context,
467 struct rte_acl_node *node, int index)
469 struct rte_acl_node *ref_node;
471 /* De-reference the node at the specified pointer */
472 if (node != NULL && node->ptrs[index].ptr != NULL) {
473 ref_node = node->ptrs[index].ptr;
474 ref_node->ref_count--;
475 if (ref_node->ref_count == 0)
476 acl_free_node(context, ref_node);
481 * acl_exclude rte_acl_bitset from src and copy remaining pointer to dst
484 acl_copy_ptr(struct acl_build_context *context,
485 struct rte_acl_node *dst,
486 struct rte_acl_node *src,
488 struct rte_acl_bitset *b_bits)
491 struct rte_acl_bitset bits;
494 if (!acl_exclude(&bits, &src->ptrs[index].values, b_bits))
497 rc = acl_add_ptr(context, dst, src->ptrs[index].ptr, &bits);
504 * Fill in gaps in ptrs list with the ptr at the end of the list
507 acl_compact_node_ptrs(struct rte_acl_node *node_a)
510 int min_add = node_a->min_add;
512 while (node_a->num_ptrs > 0 &&
513 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
516 for (n = min_add; n + 1 < node_a->num_ptrs; n++) {
518 /* if this entry is empty */
519 if (node_a->ptrs[n].ptr == NULL) {
521 /* move the last pointer to this entry */
522 acl_include(&node_a->ptrs[n].values,
523 &node_a->ptrs[node_a->num_ptrs - 1].values,
525 node_a->ptrs[n].ptr =
526 node_a->ptrs[node_a->num_ptrs - 1].ptr;
529 * mark the end as empty and adjust the number
530 * of used pointer enum_tries
532 node_a->ptrs[node_a->num_ptrs - 1].ptr = NULL;
533 while (node_a->num_ptrs > 0 &&
534 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
541 acl_resolve_leaf(struct acl_build_context *context,
542 struct rte_acl_node *node_a,
543 struct rte_acl_node *node_b,
544 struct rte_acl_node **node_c)
547 int combined_priority = ACL_PRIORITY_EQUAL;
549 for (n = 0; n < context->cfg.num_categories; n++) {
550 if (node_a->mrt->priority[n] != node_b->mrt->priority[n]) {
551 combined_priority |= (node_a->mrt->priority[n] >
552 node_b->mrt->priority[n]) ?
553 ACL_PRIORITY_NODE_A : ACL_PRIORITY_NODE_B;
558 * if node a is higher or equal priority for all categories,
559 * then return node_a.
561 if (combined_priority == ACL_PRIORITY_NODE_A ||
562 combined_priority == ACL_PRIORITY_EQUAL) {
568 * if node b is higher or equal priority for all categories,
569 * then return node_b.
571 if (combined_priority == ACL_PRIORITY_NODE_B) {
577 * mixed priorities - create a new node with the highest priority
581 /* force new duplication. */
584 *node_c = acl_dup_node(context, node_a);
585 for (n = 0; n < context->cfg.num_categories; n++) {
586 if ((*node_c)->mrt->priority[n] < node_b->mrt->priority[n]) {
587 (*node_c)->mrt->priority[n] = node_b->mrt->priority[n];
588 (*node_c)->mrt->results[n] = node_b->mrt->results[n];
595 * Merge nodes A and B together,
596 * returns a node that is the path for the intersection
598 * If match node (leaf on trie)
600 * return node = highest priority result
602 * Create C as a duplicate of A to point to child intersections
603 * If any pointers in C intersect with any in B
604 * For each intersection
606 * remove intersection from C pointer
607 * add a pointer from C to child intersection node
608 * Compact the pointers in A and B
609 * Copy any B pointers that are outside of the intersection to C
610 * If C has no references to the B trie
611 * free C and return A
612 * Else If C has no references to the A trie
613 * free C and return B
618 acl_merge_trie(struct acl_build_context *context,
619 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
620 uint32_t level, struct rte_acl_node **return_c)
622 uint32_t n, m, ptrs_c, ptrs_b;
623 uint32_t min_add_c, min_add_b;
624 int node_intersect_type;
625 struct rte_acl_bitset node_intersect;
626 struct rte_acl_node *node_c;
627 struct rte_acl_node *node_a_next;
632 node_a_next = node_a->next;
635 node_a_refs = node_a->num_ptrs;
637 node_intersect_type = 0;
639 /* Resolve leaf nodes (matches) */
640 if (node_a->match_flag != 0) {
641 acl_resolve_leaf(context, node_a, node_b, return_c);
646 * Create node C as a copy of node A, and do: C = merge(A,B);
647 * If node A can be used instead (A==C), then later we'll
648 * destroy C and return A.
651 node_c = acl_dup_node(context, node_a);
654 * If the two node transitions intersect then merge the transitions.
655 * Check intersection for entire node (all pointers)
657 node_intersect_type = acl_intersect_type(&node_c->values,
661 if (node_intersect_type & ACL_INTERSECT) {
663 min_add_b = node_b->min_add;
664 node_b->min_add = node_b->num_ptrs;
665 ptrs_b = node_b->num_ptrs;
667 min_add_c = node_c->min_add;
668 node_c->min_add = node_c->num_ptrs;
669 ptrs_c = node_c->num_ptrs;
671 for (n = 0; n < ptrs_c; n++) {
672 if (node_c->ptrs[n].ptr == NULL) {
676 node_c->ptrs[n].ptr->next = NULL;
677 for (m = 0; m < ptrs_b; m++) {
679 struct rte_acl_bitset child_intersect;
680 int child_intersect_type;
681 struct rte_acl_node *child_node_c = NULL;
683 if (node_b->ptrs[m].ptr == NULL ||
684 node_c->ptrs[n].ptr ==
688 child_intersect_type = acl_intersect_type(
689 &node_c->ptrs[n].values,
690 &node_b->ptrs[m].values,
693 if ((child_intersect_type & ACL_INTERSECT) !=
695 if (acl_merge_trie(context,
702 if (child_node_c != NULL &&
704 node_c->ptrs[n].ptr) {
709 * Added link from C to
710 * child_C for all transitions
711 * in the intersection.
713 acl_add_ptr(context, node_c,
718 * inc refs if pointer is not
721 node_a_refs += (child_node_c !=
722 node_b->ptrs[m].ptr);
725 * Remove intersection from C
729 &node_c->ptrs[n].values,
730 &node_c->ptrs[n].values,
732 acl_deref_ptr(context,
734 node_c->ptrs[n].ptr =
743 /* Compact pointers */
744 node_c->min_add = min_add_c;
745 acl_compact_node_ptrs(node_c);
746 node_b->min_add = min_add_b;
747 acl_compact_node_ptrs(node_b);
751 * Copy pointers outside of the intersection from B to C
753 if ((node_intersect_type & ACL_INTERSECT_B) != 0) {
755 for (m = 0; m < node_b->num_ptrs; m++)
756 if (node_b->ptrs[m].ptr != NULL)
757 acl_copy_ptr(context, node_c,
758 node_b, m, &node_intersect);
762 * Free node C if top of trie is contained in A or B
763 * if node C is a duplicate of node A &&
764 * node C was not an existing duplicate
766 if (node_c != node_a && node_c != node_a_next) {
769 * if the intersection has no references to the
770 * B side, then it is contained in A
772 if (node_b_refs == 0) {
773 acl_free_node(context, node_c);
777 * if the intersection has no references to the
778 * A side, then it is contained in B.
780 if (node_a_refs == 0) {
781 acl_free_node(context, node_c);
787 if (return_c != NULL)
791 acl_free_node(context, node_b);
797 * Reset current runtime fields before next build:
798 * - free allocated RT memory.
799 * - reset all RT related fields to zero.
802 acl_build_reset(struct rte_acl_ctx *ctx)
805 memset(&ctx->num_categories, 0,
806 sizeof(*ctx) - offsetof(struct rte_acl_ctx, num_categories));
810 acl_gen_range(struct acl_build_context *context,
811 const uint8_t *hi, const uint8_t *lo, int size, int level,
812 struct rte_acl_node *root, struct rte_acl_node *end)
814 struct rte_acl_node *node, *prev;
818 for (n = size - 1; n > 0; n--) {
819 node = acl_alloc_node(context, level++);
820 acl_add_ptr_range(context, prev, node, lo[n], hi[n]);
823 acl_add_ptr_range(context, prev, end, lo[0], hi[0]);
826 static struct rte_acl_node *
827 acl_gen_range_trie(struct acl_build_context *context,
828 const void *min, const void *max,
829 int size, int level, struct rte_acl_node **pend)
832 struct rte_acl_node *root;
833 const uint8_t *lo = (const uint8_t *)min;
834 const uint8_t *hi = (const uint8_t *)max;
836 *pend = acl_alloc_node(context, level+size);
837 root = acl_alloc_node(context, level++);
839 if (lo[size - 1] == hi[size - 1]) {
840 acl_gen_range(context, hi, lo, size, level, root, *pend);
842 uint8_t limit_lo[64];
843 uint8_t limit_hi[64];
844 uint8_t hi_ff = UINT8_MAX;
847 memset(limit_lo, 0, RTE_DIM(limit_lo));
848 memset(limit_hi, UINT8_MAX, RTE_DIM(limit_hi));
850 for (n = size - 2; n >= 0; n--) {
851 hi_ff = (uint8_t)(hi_ff & hi[n]);
852 lo_00 = (uint8_t)(lo_00 | lo[n]);
855 if (hi_ff != UINT8_MAX) {
856 limit_lo[size - 1] = hi[size - 1];
857 acl_gen_range(context, hi, limit_lo, size, level,
862 limit_hi[size - 1] = lo[size - 1];
863 acl_gen_range(context, limit_hi, lo, size, level,
867 if (hi[size - 1] - lo[size - 1] > 1 ||
869 hi_ff == UINT8_MAX) {
870 limit_lo[size-1] = (uint8_t)(lo[size-1] + (lo_00 != 0));
871 limit_hi[size-1] = (uint8_t)(hi[size-1] -
872 (hi_ff != UINT8_MAX));
873 acl_gen_range(context, limit_hi, limit_lo, size,
880 static struct rte_acl_node *
881 acl_gen_mask_trie(struct acl_build_context *context,
882 const void *value, const void *mask,
883 int size, int level, struct rte_acl_node **pend)
886 struct rte_acl_node *root;
887 struct rte_acl_node *node, *prev;
888 struct rte_acl_bitset bits;
889 const uint8_t *val = (const uint8_t *)value;
890 const uint8_t *msk = (const uint8_t *)mask;
892 root = acl_alloc_node(context, level++);
895 for (n = size - 1; n >= 0; n--) {
896 node = acl_alloc_node(context, level++);
897 acl_gen_mask(&bits, val[n] & msk[n], msk[n]);
898 acl_add_ptr(context, prev, node, &bits);
906 static struct rte_acl_node *
907 build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head,
908 struct rte_acl_build_rule **last, uint32_t *count)
911 int field_index, node_count;
912 struct rte_acl_node *trie;
913 struct rte_acl_build_rule *prev, *rule;
914 struct rte_acl_node *end, *merge, *root, *end_prev;
915 const struct rte_acl_field *fld;
921 trie = acl_alloc_node(context, 0);
923 while (rule != NULL) {
925 root = acl_alloc_node(context, 0);
930 for (n = 0; n < rule->config->num_fields; n++) {
932 field_index = rule->config->defs[n].field_index;
933 fld = rule->f->field + field_index;
936 /* build a mini-trie for this field */
937 switch (rule->config->defs[n].type) {
939 case RTE_ACL_FIELD_TYPE_BITMASK:
940 merge = acl_gen_mask_trie(context,
943 rule->config->defs[n].size,
948 case RTE_ACL_FIELD_TYPE_MASK:
951 * set msb for the size of the field and
955 mask = RTE_ACL_MASKLEN_TO_BITMASK(
957 rule->config->defs[n].size);
959 /* gen a mini-trie for this field */
960 merge = acl_gen_mask_trie(context,
963 rule->config->defs[n].size,
969 case RTE_ACL_FIELD_TYPE_RANGE:
970 merge = acl_gen_range_trie(context,
971 &rule->f->field[field_index].value,
972 &rule->f->field[field_index].mask_range,
973 rule->config->defs[n].size,
980 "Error in rule[%u] type - %hhu\n",
981 rule->f->data.userdata,
982 rule->config->defs[n].type);
986 /* merge this field on to the end of the rule */
987 if (acl_merge_trie(context, end_prev, merge, 0,
993 end->match_flag = ++context->num_build_rules;
996 * Setup the results for this rule.
997 * The result and priority of each category.
999 if (end->mrt == NULL)
1000 end->mrt = acl_build_alloc(context, 1,
1003 for (m = context->cfg.num_categories; 0 != m--; ) {
1004 if (rule->f->data.category_mask & (1 << m)) {
1005 end->mrt->results[m] = rule->f->data.userdata;
1006 end->mrt->priority[m] = rule->f->data.priority;
1008 end->mrt->results[m] = 0;
1009 end->mrt->priority[m] = 0;
1013 node_count = context->num_nodes;
1016 /* merge this rule into the trie */
1017 if (acl_merge_trie(context, trie, root, 0, NULL))
1020 node_count = context->num_nodes - node_count;
1021 if (node_count > context->cur_node_max) {
1035 acl_calc_wildness(struct rte_acl_build_rule *head,
1036 const struct rte_acl_config *config)
1039 struct rte_acl_build_rule *rule;
1041 for (rule = head; rule != NULL; rule = rule->next) {
1043 for (n = 0; n < config->num_fields; n++) {
1046 uint32_t bit_len = CHAR_BIT * config->defs[n].size;
1047 uint64_t msk_val = RTE_LEN2MASK(bit_len,
1049 double size = bit_len;
1050 int field_index = config->defs[n].field_index;
1051 const struct rte_acl_field *fld = rule->f->field +
1054 switch (rule->config->defs[n].type) {
1055 case RTE_ACL_FIELD_TYPE_BITMASK:
1056 wild = (size - __builtin_popcountll(
1057 fld->mask_range.u64 & msk_val)) /
1061 case RTE_ACL_FIELD_TYPE_MASK:
1062 wild = (size - fld->mask_range.u32) / size;
1065 case RTE_ACL_FIELD_TYPE_RANGE:
1066 wild = (fld->mask_range.u64 & msk_val) -
1067 (fld->value.u64 & msk_val);
1068 wild = wild / msk_val;
1072 rule->wildness[field_index] = (uint32_t)(wild * 100);
1078 acl_rule_stats(struct rte_acl_build_rule *head, struct rte_acl_config *config)
1080 struct rte_acl_build_rule *rule;
1081 uint32_t n, m, fields_deactivated = 0;
1082 uint32_t start = 0, deactivate = 0;
1083 int tally[RTE_ACL_MAX_LEVELS][TALLY_NUM];
1085 memset(tally, 0, sizeof(tally));
1087 for (rule = head; rule != NULL; rule = rule->next) {
1089 for (n = 0; n < config->num_fields; n++) {
1090 uint32_t field_index = config->defs[n].field_index;
1092 tally[n][TALLY_0]++;
1093 for (m = 1; m < RTE_DIM(wild_limits); m++) {
1094 if (rule->wildness[field_index] >=
1100 for (n = config->num_fields - 1; n > 0; n--) {
1101 uint32_t field_index = config->defs[n].field_index;
1103 if (rule->wildness[field_index] == 100)
1104 tally[n][TALLY_DEPTH]++;
1111 * Look for any field that is always wild and drop it from the config
1112 * Only deactivate if all fields for a given input loop are deactivated.
1114 for (n = 1; n < config->num_fields; n++) {
1115 if (config->defs[n].input_index !=
1116 config->defs[n - 1].input_index) {
1117 for (m = start; m < n; m++)
1118 tally[m][TALLY_DEACTIVATED] = deactivate;
1119 fields_deactivated += deactivate;
1124 /* if the field is not always completely wild */
1125 if (tally[n][TALLY_100] != tally[n][TALLY_0])
1129 for (m = start; m < n; m++)
1130 tally[m][TALLY_DEACTIVATED] = deactivate;
1132 fields_deactivated += deactivate;
1134 /* remove deactivated fields */
1135 if (fields_deactivated) {
1138 for (k = 0; k < config->num_fields; k++) {
1139 if (tally[k][TALLY_DEACTIVATED] == 0) {
1140 memmove(&tally[l][0], &tally[k][0],
1141 TALLY_NUM * sizeof(tally[0][0]));
1142 memmove(&config->defs[l++],
1144 sizeof(struct rte_acl_field_def));
1147 config->num_fields = l;
1152 rule_cmp_wildness(struct rte_acl_build_rule *r1, struct rte_acl_build_rule *r2)
1156 for (n = 1; n < r1->config->num_fields; n++) {
1157 int field_index = r1->config->defs[n].field_index;
1159 if (r1->wildness[field_index] != r2->wildness[field_index])
1160 return (r1->wildness[field_index] -
1161 r2->wildness[field_index]);
1167 * Sort list of rules based on the rules wildness.
1169 static struct rte_acl_build_rule *
1170 sort_rules(struct rte_acl_build_rule *head)
1172 struct rte_acl_build_rule *new_head;
1173 struct rte_acl_build_rule *l, *r, **p;
1176 while (head != NULL) {
1178 /* remove element from the head of the old list. */
1183 /* walk through new sorted list to find a proper place. */
1186 rule_cmp_wildness(l, r) >= 0;
1190 /* insert element into the new sorted list. */
1199 acl_build_index(const struct rte_acl_config *config, uint32_t *data_index)
1202 int32_t last_header;
1207 for (n = 0; n < config->num_fields; n++) {
1208 if (last_header != config->defs[n].input_index) {
1209 last_header = config->defs[n].input_index;
1210 data_index[m++] = config->defs[n].offset;
1217 static struct rte_acl_build_rule *
1218 build_one_trie(struct acl_build_context *context,
1219 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES],
1220 uint32_t n, int32_t node_max)
1222 struct rte_acl_build_rule *last;
1223 struct rte_acl_config *config;
1225 config = rule_sets[n]->config;
1227 acl_rule_stats(rule_sets[n], config);
1228 rule_sets[n] = sort_rules(rule_sets[n]);
1230 context->tries[n].type = RTE_ACL_FULL_TRIE;
1231 context->tries[n].count = 0;
1233 context->tries[n].num_data_indexes = acl_build_index(config,
1234 context->data_indexes[n]);
1235 context->tries[n].data_index = context->data_indexes[n];
1237 context->cur_node_max = node_max;
1239 context->bld_tries[n].trie = build_trie(context, rule_sets[n],
1240 &last, &context->tries[n].count);
1246 acl_build_tries(struct acl_build_context *context,
1247 struct rte_acl_build_rule *head)
1249 uint32_t n, num_tries;
1250 struct rte_acl_config *config;
1251 struct rte_acl_build_rule *last;
1252 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES];
1254 config = head->config;
1255 rule_sets[0] = head;
1257 /* initialize tries */
1258 for (n = 0; n < RTE_DIM(context->tries); n++) {
1259 context->tries[n].type = RTE_ACL_UNUSED_TRIE;
1260 context->bld_tries[n].trie = NULL;
1261 context->tries[n].count = 0;
1264 context->tries[0].type = RTE_ACL_FULL_TRIE;
1266 /* calc wildness of each field of each rule */
1267 acl_calc_wildness(head, config);
1269 for (n = 0;; n = num_tries) {
1273 last = build_one_trie(context, rule_sets, n, context->node_max);
1274 if (context->bld_tries[n].trie == NULL) {
1275 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1279 /* Build of the last trie completed. */
1283 if (num_tries == RTE_DIM(context->tries)) {
1285 "Exceeded max number of tries: %u\n",
1290 /* Trie is getting too big, split remaining rule set. */
1291 rule_sets[num_tries] = last->next;
1293 acl_free_node(context, context->bld_tries[n].trie);
1295 /* Create a new copy of config for remaining rules. */
1296 config = acl_build_alloc(context, 1, sizeof(*config));
1297 memcpy(config, rule_sets[n]->config, sizeof(*config));
1299 /* Make remaining rules use new config. */
1300 for (head = rule_sets[num_tries]; head != NULL;
1302 head->config = config;
1305 * Rebuild the trie for the reduced rule-set.
1306 * Don't try to split it any further.
1308 last = build_one_trie(context, rule_sets, n, INT32_MAX);
1309 if (context->bld_tries[n].trie == NULL || last != NULL) {
1310 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1316 context->num_tries = num_tries;
1321 acl_build_log(const struct acl_build_context *ctx)
1325 RTE_LOG(DEBUG, ACL, "Build phase for ACL \"%s\":\n"
1326 "node limit for tree split: %u\n"
1327 "nodes created: %u\n"
1328 "memory consumed: %zu\n",
1334 for (n = 0; n < RTE_DIM(ctx->tries); n++) {
1335 if (ctx->tries[n].count != 0)
1337 "trie %u: number of rules: %u, indexes: %u\n",
1338 n, ctx->tries[n].count,
1339 ctx->tries[n].num_data_indexes);
1344 acl_build_rules(struct acl_build_context *bcx)
1346 struct rte_acl_build_rule *br, *head;
1347 const struct rte_acl_rule *rule;
1349 uint32_t fn, i, n, num;
1352 fn = bcx->cfg.num_fields;
1353 n = bcx->acx->num_rules;
1354 ofs = n * sizeof(*br);
1355 sz = ofs + n * fn * sizeof(*wp);
1357 br = tb_alloc(&bcx->pool, sz);
1359 wp = (uint32_t *)((uintptr_t)br + ofs);
1363 for (i = 0; i != n; i++) {
1364 rule = (const struct rte_acl_rule *)
1365 ((uintptr_t)bcx->acx->rules + bcx->acx->rule_sz * i);
1366 if ((rule->data.category_mask & bcx->category_mask) != 0) {
1367 br[num].next = head;
1368 br[num].config = &bcx->cfg;
1370 br[num].wildness = wp;
1377 bcx->num_rules = num;
1378 bcx->build_rules = head;
1384 * Copy data_indexes for each trie into RT location.
1387 acl_set_data_indexes(struct rte_acl_ctx *ctx)
1392 for (i = 0; i != ctx->num_tries; i++) {
1393 n = ctx->trie[i].num_data_indexes;
1394 memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index,
1395 n * sizeof(ctx->data_indexes[0]));
1396 ctx->trie[i].data_index = ctx->data_indexes + ofs;
1397 ofs += RTE_ACL_MAX_FIELDS;
1402 * Internal routine, performs 'build' phase of trie generation:
1403 * - setups build context.
1404 * - analizes given set of rules.
1405 * - builds internal tree(s).
1408 acl_bld(struct acl_build_context *bcx, struct rte_acl_ctx *ctx,
1409 const struct rte_acl_config *cfg, uint32_t node_max)
1413 /* setup build context. */
1414 memset(bcx, 0, sizeof(*bcx));
1416 bcx->pool.alignment = ACL_POOL_ALIGN;
1417 bcx->pool.min_alloc = ACL_POOL_ALLOC_MIN;
1419 bcx->category_mask = RTE_LEN2MASK(bcx->cfg.num_categories,
1420 typeof(bcx->category_mask));
1421 bcx->node_max = node_max;
1423 rc = sigsetjmp(bcx->pool.fail, 0);
1425 /* build phase runs out of memory. */
1428 "ACL context: %s, %s() failed with error code: %d\n",
1429 bcx->acx->name, __func__, rc);
1433 /* Create a build rules copy. */
1434 rc = acl_build_rules(bcx);
1438 /* No rules to build for that context+config */
1439 if (bcx->build_rules == NULL) {
1442 /* build internal trie representation. */
1443 rc = acl_build_tries(bcx, bcx->build_rules);
1449 * Check that parameters for acl_build() are valid.
1452 acl_check_bld_param(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1454 static const size_t field_sizes[] = {
1455 sizeof(uint8_t), sizeof(uint16_t),
1456 sizeof(uint32_t), sizeof(uint64_t),
1461 if (ctx == NULL || cfg == NULL || cfg->num_categories == 0 ||
1462 cfg->num_categories > RTE_ACL_MAX_CATEGORIES ||
1463 cfg->num_fields == 0 ||
1464 cfg->num_fields > RTE_ACL_MAX_FIELDS)
1467 for (i = 0; i != cfg->num_fields; i++) {
1468 if (cfg->defs[i].type > RTE_ACL_FIELD_TYPE_BITMASK) {
1470 "ACL context: %s, invalid type: %hhu for %u-th field\n",
1471 ctx->name, cfg->defs[i].type, i);
1475 j != RTE_DIM(field_sizes) &&
1476 cfg->defs[i].size != field_sizes[j];
1480 if (j == RTE_DIM(field_sizes)) {
1482 "ACL context: %s, invalid size: %hhu for %u-th field\n",
1483 ctx->name, cfg->defs[i].size, i);
1492 rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1497 struct acl_build_context bcx;
1499 rc = acl_check_bld_param(ctx, cfg);
1503 acl_build_reset(ctx);
1505 if (cfg->max_size == 0) {
1507 max_size = SIZE_MAX;
1510 max_size = cfg->max_size;
1513 for (rc = -ERANGE; n >= NODE_MIN && rc == -ERANGE; n /= 2) {
1515 /* perform build phase. */
1516 rc = acl_bld(&bcx, ctx, cfg, n);
1519 /* allocate and fill run-time structures. */
1520 rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries,
1521 bcx.num_tries, bcx.cfg.num_categories,
1522 RTE_ACL_MAX_FIELDS * RTE_DIM(bcx.tries) *
1523 sizeof(ctx->data_indexes[0]), max_size);
1525 /* set data indexes. */
1526 acl_set_data_indexes(ctx);
1528 /* copy in build config. */
1533 acl_build_log(&bcx);
1535 /* cleanup after build. */
1536 tb_free_pool(&bcx.pool);