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;
102 uint32_t category_mask;
106 uint32_t num_build_rules;
108 struct tb_mem_pool pool;
109 struct rte_acl_trie tries[RTE_ACL_MAX_TRIES];
110 struct rte_acl_bld_trie bld_tries[RTE_ACL_MAX_TRIES];
111 uint32_t data_indexes[RTE_ACL_MAX_TRIES][RTE_ACL_MAX_FIELDS];
113 /* memory free lists for nodes and blocks used for node ptrs */
114 struct acl_mem_block blocks[MEM_BLOCK_NUM];
115 struct rte_acl_node *node_free_list;
118 static int acl_merge_trie(struct acl_build_context *context,
119 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
120 uint32_t level, uint32_t subtree_id, struct rte_acl_node **node_c);
122 static int acl_merge(struct acl_build_context *context,
123 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
124 int move, int a_subset, int level);
127 acl_deref_ptr(struct acl_build_context *context,
128 struct rte_acl_node *node, int index);
131 acl_build_alloc(struct acl_build_context *context, size_t n, size_t s)
135 size_t alloc_size = n * s;
138 * look for memory in free lists
140 for (m = 0; m < RTE_DIM(context->blocks); m++) {
141 if (context->blocks[m].block_size ==
142 alloc_size && context->blocks[m].mem_ptr != NULL) {
143 p = context->blocks[m].mem_ptr;
144 context->blocks[m].mem_ptr = *((void **)p);
145 memset(p, 0, alloc_size);
151 * return allocation from memory pool
153 p = tb_alloc(&context->pool, alloc_size);
158 * Free memory blocks (kept in context for reuse).
161 acl_build_free(struct acl_build_context *context, size_t s, void *p)
165 for (n = 0; n < RTE_DIM(context->blocks); n++) {
166 if (context->blocks[n].block_size == s) {
167 *((void **)p) = context->blocks[n].mem_ptr;
168 context->blocks[n].mem_ptr = p;
172 for (n = 0; n < RTE_DIM(context->blocks); n++) {
173 if (context->blocks[n].block_size == 0) {
174 context->blocks[n].block_size = s;
175 *((void **)p) = NULL;
176 context->blocks[n].mem_ptr = p;
183 * Allocate and initialize a new node.
185 static struct rte_acl_node *
186 acl_alloc_node(struct acl_build_context *context, int level)
188 struct rte_acl_node *node;
190 if (context->node_free_list != NULL) {
191 node = context->node_free_list;
192 context->node_free_list = node->next;
193 memset(node, 0, sizeof(struct rte_acl_node));
195 node = acl_build_alloc(context, sizeof(struct rte_acl_node), 1);
201 node->node_type = RTE_ACL_NODE_UNDEFINED;
202 node->node_index = RTE_ACL_NODE_UNDEFINED;
203 context->num_nodes++;
204 node->id = context->node_id++;
210 * Dereference all nodes to which this node points
213 acl_free_node(struct acl_build_context *context,
214 struct rte_acl_node *node)
218 if (node->prev != NULL)
219 node->prev->next = NULL;
220 for (n = 0; n < node->num_ptrs; n++)
221 acl_deref_ptr(context, node, n);
223 /* free mrt if this is a match node */
224 if (node->mrt != NULL) {
225 acl_build_free(context, sizeof(struct rte_acl_match_results),
230 /* free transitions to other nodes */
231 if (node->ptrs != NULL) {
232 acl_build_free(context,
233 node->max_ptrs * sizeof(struct rte_acl_ptr_set),
238 /* put it on the free list */
239 context->num_nodes--;
240 node->next = context->node_free_list;
241 context->node_free_list = node;
246 * Include src bitset in dst bitset
249 acl_include(struct rte_acl_bitset *dst, struct rte_acl_bitset *src, bits_t mask)
253 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
254 dst->bits[n] = (dst->bits[n] & mask) | src->bits[n];
258 * Set dst to bits of src1 that are not in src2
261 acl_exclude(struct rte_acl_bitset *dst,
262 struct rte_acl_bitset *src1,
263 struct rte_acl_bitset *src2)
268 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
269 dst->bits[n] = src1->bits[n] & ~src2->bits[n];
270 all_bits |= dst->bits[n];
272 return all_bits != 0;
276 * Add a pointer (ptr) to a node.
279 acl_add_ptr(struct acl_build_context *context,
280 struct rte_acl_node *node,
281 struct rte_acl_node *ptr,
282 struct rte_acl_bitset *bits)
284 uint32_t n, num_ptrs;
285 struct rte_acl_ptr_set *ptrs = NULL;
288 * If there's already a pointer to the same node, just add to the bitset
290 for (n = 0; n < node->num_ptrs; n++) {
291 if (node->ptrs[n].ptr != NULL) {
292 if (node->ptrs[n].ptr == ptr) {
293 acl_include(&node->ptrs[n].values, bits, -1);
294 acl_include(&node->values, bits, -1);
300 /* if there's no room for another pointer, make room */
301 if (node->num_ptrs >= node->max_ptrs) {
302 /* add room for more pointers */
303 num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
304 ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
306 /* copy current points to new memory allocation */
307 if (node->ptrs != NULL) {
308 memcpy(ptrs, node->ptrs,
309 node->num_ptrs * sizeof(*ptrs));
310 acl_build_free(context, node->max_ptrs * sizeof(*ptrs),
314 node->max_ptrs = num_ptrs;
317 /* Find available ptr and add a new pointer to this node */
318 for (n = node->min_add; n < node->max_ptrs; n++) {
319 if (node->ptrs[n].ptr == NULL) {
320 node->ptrs[n].ptr = ptr;
321 acl_include(&node->ptrs[n].values, bits, 0);
322 acl_include(&node->values, bits, -1);
325 if (node->num_ptrs <= n)
326 node->num_ptrs = n + 1;
335 * Add a pointer for a range of values
338 acl_add_ptr_range(struct acl_build_context *context,
339 struct rte_acl_node *root,
340 struct rte_acl_node *node,
345 struct rte_acl_bitset bitset;
347 /* clear the bitset values */
348 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
351 /* for each bit in range, add bit to set */
352 for (n = 0; n < UINT8_MAX + 1; n++)
353 if (n >= low && n <= high)
354 bitset.bits[n / (sizeof(bits_t) * 8)] |=
355 1 << (n % (sizeof(bits_t) * 8));
357 return acl_add_ptr(context, root, node, &bitset);
361 * Generate a bitset from a byte value and mask.
364 acl_gen_mask(struct rte_acl_bitset *bitset, uint32_t value, uint32_t mask)
369 /* clear the bitset values */
370 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
373 /* for each bit in value/mask, add bit to set */
374 for (n = 0; n < UINT8_MAX + 1; n++) {
375 if ((n & mask) == value) {
377 bitset->bits[n / (sizeof(bits_t) * 8)] |=
378 1 << (n % (sizeof(bits_t) * 8));
385 * Determine how A and B intersect.
386 * Determine if A and/or B are supersets of the intersection.
389 acl_intersect_type(struct rte_acl_bitset *a_bits,
390 struct rte_acl_bitset *b_bits,
391 struct rte_acl_bitset *intersect)
394 bits_t intersect_bits = 0;
395 bits_t a_superset = 0;
396 bits_t b_superset = 0;
399 * calculate and store intersection and check if A and/or B have
400 * bits outside the intersection (superset)
402 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
403 intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
404 a_superset |= a_bits->bits[n] ^ intersect->bits[n];
405 b_superset |= b_bits->bits[n] ^ intersect->bits[n];
406 intersect_bits |= intersect->bits[n];
409 n = (intersect_bits == 0 ? ACL_INTERSECT_NONE : ACL_INTERSECT) |
410 (b_superset == 0 ? 0 : ACL_INTERSECT_B) |
411 (a_superset == 0 ? 0 : ACL_INTERSECT_A);
417 * Check if all bits in the bitset are on
420 acl_full(struct rte_acl_node *node)
423 bits_t all_bits = -1;
425 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
426 all_bits &= node->values.bits[n];
427 return all_bits == -1;
431 * Check if all bits in the bitset are off
434 acl_empty(struct rte_acl_node *node)
438 if (node->ref_count == 0) {
439 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
440 if (0 != node->values.bits[n])
450 * Compute intersection of A and B
451 * return 1 if there is an intersection else 0.
454 acl_intersect(struct rte_acl_bitset *a_bits,
455 struct rte_acl_bitset *b_bits,
456 struct rte_acl_bitset *intersect)
461 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
462 intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
463 all_bits |= intersect->bits[n];
465 return all_bits != 0;
471 static struct rte_acl_node *
472 acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)
475 struct rte_acl_node *next;
477 next = acl_alloc_node(context, node->level);
479 /* allocate the pointers */
480 if (node->num_ptrs > 0) {
481 next->ptrs = acl_build_alloc(context,
483 sizeof(struct rte_acl_ptr_set));
484 next->max_ptrs = node->max_ptrs;
487 /* copy over the pointers */
488 for (n = 0; n < node->num_ptrs; n++) {
489 if (node->ptrs[n].ptr != NULL) {
490 next->ptrs[n].ptr = node->ptrs[n].ptr;
491 next->ptrs[n].ptr->ref_count++;
492 acl_include(&next->ptrs[n].values,
493 &node->ptrs[n].values, -1);
497 next->num_ptrs = node->num_ptrs;
499 /* copy over node's match results */
500 if (node->match_flag == 0)
501 next->match_flag = 0;
503 next->match_flag = -1;
504 next->mrt = acl_build_alloc(context, 1, sizeof(*next->mrt));
505 memcpy(next->mrt, node->mrt, sizeof(*next->mrt));
508 /* copy over node's bitset */
509 acl_include(&next->values, &node->values, -1);
518 * Dereference a pointer from a node
521 acl_deref_ptr(struct acl_build_context *context,
522 struct rte_acl_node *node, int index)
524 struct rte_acl_node *ref_node;
526 /* De-reference the node at the specified pointer */
527 if (node != NULL && node->ptrs[index].ptr != NULL) {
528 ref_node = node->ptrs[index].ptr;
529 ref_node->ref_count--;
530 if (ref_node->ref_count == 0)
531 acl_free_node(context, ref_node);
536 * Exclude bitset from a node pointer
537 * returns 0 if poiter was deref'd
541 acl_exclude_ptr(struct acl_build_context *context,
542 struct rte_acl_node *node,
544 struct rte_acl_bitset *b_bits)
549 * remove bitset from node pointer and deref
550 * if the bitset becomes empty.
552 if (!acl_exclude(&node->ptrs[index].values,
553 &node->ptrs[index].values,
555 acl_deref_ptr(context, node, index);
556 node->ptrs[index].ptr = NULL;
560 /* exclude bits from the composite bits for the node */
561 acl_exclude(&node->values, &node->values, b_bits);
566 * Remove a bitset from src ptr and move remaining ptr to dst
569 acl_move_ptr(struct acl_build_context *context,
570 struct rte_acl_node *dst,
571 struct rte_acl_node *src,
573 struct rte_acl_bitset *b_bits)
578 if (!acl_exclude_ptr(context, src, index, b_bits))
581 /* add src pointer to dst node */
582 rc = acl_add_ptr(context, dst, src->ptrs[index].ptr,
583 &src->ptrs[index].values);
587 /* remove ptr from src */
588 acl_exclude_ptr(context, src, index, &src->ptrs[index].values);
593 * acl_exclude rte_acl_bitset from src and copy remaining pointer to dst
596 acl_copy_ptr(struct acl_build_context *context,
597 struct rte_acl_node *dst,
598 struct rte_acl_node *src,
600 struct rte_acl_bitset *b_bits)
603 struct rte_acl_bitset bits;
606 if (!acl_exclude(&bits, &src->ptrs[index].values, b_bits))
609 rc = acl_add_ptr(context, dst, src->ptrs[index].ptr, &bits);
616 * Fill in gaps in ptrs list with the ptr at the end of the list
619 acl_compact_node_ptrs(struct rte_acl_node *node_a)
622 int min_add = node_a->min_add;
624 while (node_a->num_ptrs > 0 &&
625 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
628 for (n = min_add; n + 1 < node_a->num_ptrs; n++) {
630 /* if this entry is empty */
631 if (node_a->ptrs[n].ptr == NULL) {
633 /* move the last pointer to this entry */
634 acl_include(&node_a->ptrs[n].values,
635 &node_a->ptrs[node_a->num_ptrs - 1].values,
637 node_a->ptrs[n].ptr =
638 node_a->ptrs[node_a->num_ptrs - 1].ptr;
641 * mark the end as empty and adjust the number
642 * of used pointer enum_tries
644 node_a->ptrs[node_a->num_ptrs - 1].ptr = NULL;
645 while (node_a->num_ptrs > 0 &&
646 node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
653 * acl_merge helper routine.
656 acl_merge_intersect(struct acl_build_context *context,
657 struct rte_acl_node *node_a, uint32_t idx_a,
658 struct rte_acl_node *node_b, uint32_t idx_b,
659 int next_move, int level,
660 struct rte_acl_bitset *intersect_ptr)
662 struct rte_acl_node *node_c;
664 /* Duplicate A for intersection */
665 node_c = acl_dup_node(context, node_a->ptrs[idx_a].ptr);
667 /* Remove intersection from A */
668 acl_exclude_ptr(context, node_a, idx_a, intersect_ptr);
671 * Added link from A to C for all transitions
672 * in the intersection
674 if (acl_add_ptr(context, node_a, node_c, intersect_ptr) < 0)
677 /* merge B->node into C */
678 return acl_merge(context, node_c, node_b->ptrs[idx_b].ptr, next_move,
684 * Merge the children of nodes A and B together.
688 * node A result = highest priority result
689 * if any pointers in A intersect with any in B
690 * For each intersection
691 * C = copy of node that A points to
692 * remove intersection from A pointer
693 * add a pointer to A that points to C for the intersection
694 * Merge C and node that B points to
695 * Compact the pointers in A and B
697 * If B has only one reference
698 * Move B pointers to A
700 * Copy B pointers to A
703 acl_merge(struct acl_build_context *context,
704 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
705 int move, int a_subset, int level)
707 uint32_t n, m, ptrs_a, ptrs_b;
708 uint32_t min_add_a, min_add_b;
710 int node_intersect_type;
711 int b_full, next_move, rc;
712 struct rte_acl_bitset intersect_values;
713 struct rte_acl_bitset intersect_ptr;
718 node_intersect_type = 0;
724 * Resolve match priorities
726 if (node_a->match_flag != 0 || node_b->match_flag != 0) {
728 if (node_a->match_flag == 0 || node_b->match_flag == 0)
729 RTE_LOG(ERR, ACL, "Not both matches\n");
731 if (node_b->match_flag < node_a->match_flag)
732 RTE_LOG(ERR, ACL, "Not same match\n");
734 for (n = 0; n < context->cfg.num_categories; n++) {
735 if (node_a->mrt->priority[n] <
736 node_b->mrt->priority[n]) {
737 node_a->mrt->priority[n] =
738 node_b->mrt->priority[n];
739 node_a->mrt->results[n] =
740 node_b->mrt->results[n];
746 * If the two node transitions intersect then merge the transitions.
747 * Check intersection for entire node (all pointers)
749 node_intersect_type = acl_intersect_type(&node_a->values,
753 if (node_intersect_type & ACL_INTERSECT) {
755 b_full = acl_full(node_b);
757 min_add_b = node_b->min_add;
758 node_b->min_add = node_b->num_ptrs;
759 ptrs_b = node_b->num_ptrs;
761 min_add_a = node_a->min_add;
762 node_a->min_add = node_a->num_ptrs;
763 ptrs_a = node_a->num_ptrs;
765 for (n = 0; n < ptrs_a; n++) {
766 for (m = 0; m < ptrs_b; m++) {
768 if (node_a->ptrs[n].ptr == NULL ||
769 node_b->ptrs[m].ptr == NULL ||
770 node_a->ptrs[n].ptr ==
774 intersect_type = acl_intersect_type(
775 &node_a->ptrs[n].values,
776 &node_b->ptrs[m].values,
779 /* If this node is not a 'match' node */
780 if ((intersect_type & ACL_INTERSECT) &&
781 (context->cfg.num_categories != 1 ||
782 !(node_a->ptrs[n].ptr->match_flag))) {
785 * next merge is a 'move' pointer,
786 * if this one is and B is a
787 * subset of the intersection.
791 ACL_INTERSECT_B) == 0;
793 if (a_subset && b_full) {
794 rc = acl_merge(context,
802 rc = acl_merge_intersect(
804 node_b, m, next_move,
805 level, &intersect_ptr);
814 /* Compact pointers */
815 node_a->min_add = min_add_a;
816 acl_compact_node_ptrs(node_a);
817 node_b->min_add = min_add_b;
818 acl_compact_node_ptrs(node_b);
821 * Either COPY or MOVE pointers from B to A
823 acl_intersect(&node_a->values, &node_b->values, &intersect_values);
825 if (move && node_b->ref_count == 1) {
826 for (m = 0; m < node_b->num_ptrs; m++) {
827 if (node_b->ptrs[m].ptr != NULL &&
828 acl_move_ptr(context, node_a, node_b, m,
829 &intersect_values) < 0)
833 for (m = 0; m < node_b->num_ptrs; m++) {
834 if (node_b->ptrs[m].ptr != NULL &&
835 acl_copy_ptr(context, node_a, node_b, m,
836 &intersect_values) < 0)
842 * Free node if its empty (no longer used)
844 if (acl_empty(node_b))
845 acl_free_node(context, node_b);
850 acl_resolve_leaf(struct acl_build_context *context,
851 struct rte_acl_node *node_a,
852 struct rte_acl_node *node_b,
853 struct rte_acl_node **node_c)
856 int combined_priority = ACL_PRIORITY_EQUAL;
858 for (n = 0; n < context->cfg.num_categories; n++) {
859 if (node_a->mrt->priority[n] != node_b->mrt->priority[n]) {
860 combined_priority |= (node_a->mrt->priority[n] >
861 node_b->mrt->priority[n]) ?
862 ACL_PRIORITY_NODE_A : ACL_PRIORITY_NODE_B;
867 * if node a is higher or equal priority for all categories,
868 * then return node_a.
870 if (combined_priority == ACL_PRIORITY_NODE_A ||
871 combined_priority == ACL_PRIORITY_EQUAL) {
877 * if node b is higher or equal priority for all categories,
878 * then return node_b.
880 if (combined_priority == ACL_PRIORITY_NODE_B) {
886 * mixed priorities - create a new node with the highest priority
890 /* force new duplication. */
893 *node_c = acl_dup_node(context, node_a);
894 for (n = 0; n < context->cfg.num_categories; n++) {
895 if ((*node_c)->mrt->priority[n] < node_b->mrt->priority[n]) {
896 (*node_c)->mrt->priority[n] = node_b->mrt->priority[n];
897 (*node_c)->mrt->results[n] = node_b->mrt->results[n];
904 * Within the existing trie structure, determine which nodes are
905 * part of the subtree of the trie to be merged.
907 * For these purposes, a subtree is defined as the set of nodes that
908 * are 1) not a superset of the intersection with the same level of
909 * the merging tree, and 2) do not have any references from a node
910 * outside of the subtree.
913 mark_subtree(struct rte_acl_node *node,
914 struct rte_acl_bitset *level_bits,
920 /* mark this node as part of the subtree */
921 node->subtree_id = id | RTE_ACL_SUBTREE_NODE;
923 for (n = 0; n < node->num_ptrs; n++) {
925 if (node->ptrs[n].ptr != NULL) {
927 struct rte_acl_bitset intersect_bits;
932 * check if this child pointer is not a superset of the
933 * same level of the merging tree.
935 intersect = acl_intersect_type(&node->ptrs[n].values,
939 if ((intersect & ACL_INTERSECT_A) == 0) {
941 struct rte_acl_node *child = node->ptrs[n].ptr;
944 * reset subtree reference if this is
945 * the first visit by this subtree.
947 if (child->subtree_id != id) {
948 child->subtree_id = id;
949 child->subtree_ref_count = 0;
954 * increment the subtree reference count and if
955 * all references are from this subtree then
956 * recurse to that child
958 child->subtree_ref_count++;
959 if (child->subtree_ref_count ==
961 mark_subtree(child, level_bits,
969 * Build the set of bits that define the set of transitions
970 * for each level of a trie.
973 build_subset_mask(struct rte_acl_node *node,
974 struct rte_acl_bitset *level_bits,
979 /* Add this node's transitions to the set for this level */
980 for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
981 level_bits[level].bits[n] &= node->values.bits[n];
983 /* For each child, add the transitions for the next level */
984 for (n = 0; n < node->num_ptrs; n++)
985 if (node->ptrs[n].ptr != NULL)
986 build_subset_mask(node->ptrs[n].ptr, level_bits,
992 * Merge nodes A and B together,
993 * returns a node that is the path for the intersection
995 * If match node (leaf on trie)
997 * return node = highest priority result
999 * Create C as a duplicate of A to point to child intersections
1000 * If any pointers in C intersect with any in B
1001 * For each intersection
1003 * remove intersection from C pointer
1004 * add a pointer from C to child intersection node
1005 * Compact the pointers in A and B
1006 * Copy any B pointers that are outside of the intersection to C
1007 * If C has no references to the B trie
1008 * free C and return A
1009 * Else If C has no references to the A trie
1010 * free C and return B
1015 acl_merge_trie(struct acl_build_context *context,
1016 struct rte_acl_node *node_a, struct rte_acl_node *node_b,
1017 uint32_t level, uint32_t subtree_id, struct rte_acl_node **return_c)
1019 uint32_t n, m, ptrs_c, ptrs_b;
1020 uint32_t min_add_c, min_add_b;
1021 int node_intersect_type;
1022 struct rte_acl_bitset node_intersect;
1023 struct rte_acl_node *node_c;
1024 struct rte_acl_node *node_a_next;
1029 node_a_next = node_a->next;
1032 node_a_refs = node_a->num_ptrs;
1034 node_intersect_type = 0;
1036 /* Resolve leaf nodes (matches) */
1037 if (node_a->match_flag != 0) {
1038 acl_resolve_leaf(context, node_a, node_b, return_c);
1043 * Create node C as a copy of node A if node A is not part of
1044 * a subtree of the merging tree (node B side). Otherwise,
1048 node_a->subtree_id !=
1049 (subtree_id | RTE_ACL_SUBTREE_NODE)) {
1050 node_c = acl_dup_node(context, node_a);
1051 node_c->subtree_id = subtree_id | RTE_ACL_SUBTREE_NODE;
1055 * If the two node transitions intersect then merge the transitions.
1056 * Check intersection for entire node (all pointers)
1058 node_intersect_type = acl_intersect_type(&node_c->values,
1062 if (node_intersect_type & ACL_INTERSECT) {
1064 min_add_b = node_b->min_add;
1065 node_b->min_add = node_b->num_ptrs;
1066 ptrs_b = node_b->num_ptrs;
1068 min_add_c = node_c->min_add;
1069 node_c->min_add = node_c->num_ptrs;
1070 ptrs_c = node_c->num_ptrs;
1072 for (n = 0; n < ptrs_c; n++) {
1073 if (node_c->ptrs[n].ptr == NULL) {
1077 node_c->ptrs[n].ptr->next = NULL;
1078 for (m = 0; m < ptrs_b; m++) {
1080 struct rte_acl_bitset child_intersect;
1081 int child_intersect_type;
1082 struct rte_acl_node *child_node_c = NULL;
1084 if (node_b->ptrs[m].ptr == NULL ||
1085 node_c->ptrs[n].ptr ==
1086 node_b->ptrs[m].ptr)
1089 child_intersect_type = acl_intersect_type(
1090 &node_c->ptrs[n].values,
1091 &node_b->ptrs[m].values,
1094 if ((child_intersect_type & ACL_INTERSECT) !=
1096 if (acl_merge_trie(context,
1097 node_c->ptrs[n].ptr,
1098 node_b->ptrs[m].ptr,
1099 level + 1, subtree_id,
1103 if (child_node_c != NULL &&
1105 node_c->ptrs[n].ptr) {
1110 * Added link from C to
1111 * child_C for all transitions
1112 * in the intersection.
1114 acl_add_ptr(context, node_c,
1119 * inc refs if pointer is not
1122 node_a_refs += (child_node_c !=
1123 node_b->ptrs[m].ptr);
1126 * Remove intersection from C
1130 &node_c->ptrs[n].values,
1131 &node_c->ptrs[n].values,
1132 &child_intersect)) {
1133 acl_deref_ptr(context,
1135 node_c->ptrs[n].ptr =
1144 /* Compact pointers */
1145 node_c->min_add = min_add_c;
1146 acl_compact_node_ptrs(node_c);
1147 node_b->min_add = min_add_b;
1148 acl_compact_node_ptrs(node_b);
1152 * Copy pointers outside of the intersection from B to C
1154 if ((node_intersect_type & ACL_INTERSECT_B) != 0) {
1156 for (m = 0; m < node_b->num_ptrs; m++)
1157 if (node_b->ptrs[m].ptr != NULL)
1158 acl_copy_ptr(context, node_c,
1159 node_b, m, &node_intersect);
1163 * Free node C if top of trie is contained in A or B
1164 * if node C is a duplicate of node A &&
1165 * node C was not an existing duplicate
1167 if (node_c != node_a && node_c != node_a_next) {
1170 * if the intersection has no references to the
1171 * B side, then it is contained in A
1173 if (node_b_refs == 0) {
1174 acl_free_node(context, node_c);
1178 * if the intersection has no references to the
1179 * A side, then it is contained in B.
1181 if (node_a_refs == 0) {
1182 acl_free_node(context, node_c);
1188 if (return_c != NULL)
1192 acl_free_node(context, node_b);
1198 * Reset current runtime fields before next build:
1199 * - free allocated RT memory.
1200 * - reset all RT related fields to zero.
1203 acl_build_reset(struct rte_acl_ctx *ctx)
1206 memset(&ctx->num_categories, 0,
1207 sizeof(*ctx) - offsetof(struct rte_acl_ctx, num_categories));
1211 acl_gen_range(struct acl_build_context *context,
1212 const uint8_t *hi, const uint8_t *lo, int size, int level,
1213 struct rte_acl_node *root, struct rte_acl_node *end)
1215 struct rte_acl_node *node, *prev;
1219 for (n = size - 1; n > 0; n--) {
1220 node = acl_alloc_node(context, level++);
1221 acl_add_ptr_range(context, prev, node, lo[n], hi[n]);
1224 acl_add_ptr_range(context, prev, end, lo[0], hi[0]);
1227 static struct rte_acl_node *
1228 acl_gen_range_trie(struct acl_build_context *context,
1229 const void *min, const void *max,
1230 int size, int level, struct rte_acl_node **pend)
1233 struct rte_acl_node *root;
1234 const uint8_t *lo = (const uint8_t *)min;
1235 const uint8_t *hi = (const uint8_t *)max;
1237 *pend = acl_alloc_node(context, level+size);
1238 root = acl_alloc_node(context, level++);
1240 if (lo[size - 1] == hi[size - 1]) {
1241 acl_gen_range(context, hi, lo, size, level, root, *pend);
1243 uint8_t limit_lo[64];
1244 uint8_t limit_hi[64];
1245 uint8_t hi_ff = UINT8_MAX;
1248 memset(limit_lo, 0, RTE_DIM(limit_lo));
1249 memset(limit_hi, UINT8_MAX, RTE_DIM(limit_hi));
1251 for (n = size - 2; n >= 0; n--) {
1252 hi_ff = (uint8_t)(hi_ff & hi[n]);
1253 lo_00 = (uint8_t)(lo_00 | lo[n]);
1256 if (hi_ff != UINT8_MAX) {
1257 limit_lo[size - 1] = hi[size - 1];
1258 acl_gen_range(context, hi, limit_lo, size, level,
1263 limit_hi[size - 1] = lo[size - 1];
1264 acl_gen_range(context, limit_hi, lo, size, level,
1268 if (hi[size - 1] - lo[size - 1] > 1 ||
1270 hi_ff == UINT8_MAX) {
1271 limit_lo[size-1] = (uint8_t)(lo[size-1] + (lo_00 != 0));
1272 limit_hi[size-1] = (uint8_t)(hi[size-1] -
1273 (hi_ff != UINT8_MAX));
1274 acl_gen_range(context, limit_hi, limit_lo, size,
1275 level, root, *pend);
1281 static struct rte_acl_node *
1282 acl_gen_mask_trie(struct acl_build_context *context,
1283 const void *value, const void *mask,
1284 int size, int level, struct rte_acl_node **pend)
1287 struct rte_acl_node *root;
1288 struct rte_acl_node *node, *prev;
1289 struct rte_acl_bitset bits;
1290 const uint8_t *val = (const uint8_t *)value;
1291 const uint8_t *msk = (const uint8_t *)mask;
1293 root = acl_alloc_node(context, level++);
1296 for (n = size - 1; n >= 0; n--) {
1297 node = acl_alloc_node(context, level++);
1298 acl_gen_mask(&bits, val[n] & msk[n], msk[n]);
1299 acl_add_ptr(context, prev, node, &bits);
1307 static struct rte_acl_node *
1308 build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head,
1309 struct rte_acl_build_rule **last, uint32_t *count)
1312 int field_index, node_count;
1313 struct rte_acl_node *trie;
1314 struct rte_acl_build_rule *prev, *rule;
1315 struct rte_acl_node *end, *merge, *root, *end_prev;
1316 const struct rte_acl_field *fld;
1317 struct rte_acl_bitset level_bits[RTE_ACL_MAX_LEVELS];
1322 trie = acl_alloc_node(context, 0);
1324 while (rule != NULL) {
1326 root = acl_alloc_node(context, 0);
1328 root->ref_count = 1;
1331 for (n = 0; n < rule->config->num_fields; n++) {
1333 field_index = rule->config->defs[n].field_index;
1334 fld = rule->f->field + field_index;
1337 /* build a mini-trie for this field */
1338 switch (rule->config->defs[n].type) {
1340 case RTE_ACL_FIELD_TYPE_BITMASK:
1341 merge = acl_gen_mask_trie(context,
1344 rule->config->defs[n].size,
1349 case RTE_ACL_FIELD_TYPE_MASK:
1352 * set msb for the size of the field and
1357 if (fld->mask_range.u32 == 0) {
1361 * arithmetic right shift for the length of
1362 * the mask less the msb.
1366 (rule->config->defs[n].size *
1367 CHAR_BIT - fld->mask_range.u32);
1370 /* gen a mini-trie for this field */
1371 merge = acl_gen_mask_trie(context,
1374 rule->config->defs[n].size,
1380 case RTE_ACL_FIELD_TYPE_RANGE:
1381 merge = acl_gen_range_trie(context,
1382 &rule->f->field[field_index].value,
1383 &rule->f->field[field_index].mask_range,
1384 rule->config->defs[n].size,
1391 "Error in rule[%u] type - %hhu\n",
1392 rule->f->data.userdata,
1393 rule->config->defs[n].type);
1397 /* merge this field on to the end of the rule */
1398 if (acl_merge_trie(context, end_prev, merge, 0,
1404 end->match_flag = ++context->num_build_rules;
1407 * Setup the results for this rule.
1408 * The result and priority of each category.
1410 if (end->mrt == NULL)
1411 end->mrt = acl_build_alloc(context, 1,
1414 for (m = 0; m < context->cfg.num_categories; m++) {
1415 if (rule->f->data.category_mask & (1 << m)) {
1416 end->mrt->results[m] = rule->f->data.userdata;
1417 end->mrt->priority[m] = rule->f->data.priority;
1419 end->mrt->results[m] = 0;
1420 end->mrt->priority[m] = 0;
1424 node_count = context->num_nodes;
1426 memset(&level_bits[0], UINT8_MAX, sizeof(level_bits));
1427 build_subset_mask(root, &level_bits[0], 0);
1428 mark_subtree(trie, &level_bits[0], 0, end->match_flag);
1431 /* merge this rule into the trie */
1432 if (acl_merge_trie(context, trie, root, 0, end->match_flag,
1436 node_count = context->num_nodes - node_count;
1437 if (node_count > context->node_max) {
1451 acl_calc_wildness(struct rte_acl_build_rule *head,
1452 const struct rte_acl_config *config)
1455 struct rte_acl_build_rule *rule;
1457 for (rule = head; rule != NULL; rule = rule->next) {
1459 for (n = 0; n < config->num_fields; n++) {
1462 double size = CHAR_BIT * config->defs[n].size;
1463 int field_index = config->defs[n].field_index;
1464 const struct rte_acl_field *fld = rule->f->field +
1467 switch (rule->config->defs[n].type) {
1468 case RTE_ACL_FIELD_TYPE_BITMASK:
1469 wild = (size - __builtin_popcount(
1470 fld->mask_range.u8)) /
1474 case RTE_ACL_FIELD_TYPE_MASK:
1475 wild = (size - fld->mask_range.u32) / size;
1478 case RTE_ACL_FIELD_TYPE_RANGE:
1479 switch (rule->config->defs[n].size) {
1480 case sizeof(uint8_t):
1481 wild = ((double)fld->mask_range.u8 -
1482 fld->value.u8) / UINT8_MAX;
1484 case sizeof(uint16_t):
1485 wild = ((double)fld->mask_range.u16 -
1486 fld->value.u16) / UINT16_MAX;
1488 case sizeof(uint32_t):
1489 wild = ((double)fld->mask_range.u32 -
1490 fld->value.u32) / UINT32_MAX;
1492 case sizeof(uint64_t):
1493 wild = ((double)fld->mask_range.u64 -
1494 fld->value.u64) / UINT64_MAX;
1498 "%s(rule: %u) invalid %u-th "
1499 "field, type: %hhu, "
1500 "unknown size: %hhu\n",
1502 rule->f->data.userdata,
1504 rule->config->defs[n].type,
1505 rule->config->defs[n].size);
1512 "%s(rule: %u) invalid %u-th "
1513 "field, unknown type: %hhu\n",
1515 rule->f->data.userdata,
1517 rule->config->defs[n].type);
1522 rule->wildness[field_index] = (uint32_t)(wild * 100);
1530 acl_rule_stats(struct rte_acl_build_rule *head, struct rte_acl_config *config)
1532 struct rte_acl_build_rule *rule;
1533 uint32_t n, m, fields_deactivated = 0;
1534 uint32_t start = 0, deactivate = 0;
1535 int tally[RTE_ACL_MAX_LEVELS][TALLY_NUM];
1537 memset(tally, 0, sizeof(tally));
1539 for (rule = head; rule != NULL; rule = rule->next) {
1541 for (n = 0; n < config->num_fields; n++) {
1542 uint32_t field_index = config->defs[n].field_index;
1544 tally[n][TALLY_0]++;
1545 for (m = 1; m < RTE_DIM(wild_limits); m++) {
1546 if (rule->wildness[field_index] >=
1552 for (n = config->num_fields - 1; n > 0; n--) {
1553 uint32_t field_index = config->defs[n].field_index;
1555 if (rule->wildness[field_index] == 100)
1556 tally[n][TALLY_DEPTH]++;
1563 * Look for any field that is always wild and drop it from the config
1564 * Only deactivate if all fields for a given input loop are deactivated.
1566 for (n = 1; n < config->num_fields; n++) {
1567 if (config->defs[n].input_index !=
1568 config->defs[n - 1].input_index) {
1569 for (m = start; m < n; m++)
1570 tally[m][TALLY_DEACTIVATED] = deactivate;
1571 fields_deactivated += deactivate;
1576 /* if the field is not always completely wild */
1577 if (tally[n][TALLY_100] != tally[n][TALLY_0])
1581 for (m = start; m < n; m++)
1582 tally[m][TALLY_DEACTIVATED] = deactivate;
1584 fields_deactivated += deactivate;
1586 /* remove deactivated fields */
1587 if (fields_deactivated) {
1590 for (k = 0; k < config->num_fields; k++) {
1591 if (tally[k][TALLY_DEACTIVATED] == 0) {
1592 memmove(&tally[l][0], &tally[k][0],
1593 TALLY_NUM * sizeof(tally[0][0]));
1594 memmove(&config->defs[l++],
1596 sizeof(struct rte_acl_field_def));
1599 config->num_fields = l;
1604 rule_cmp_wildness(struct rte_acl_build_rule *r1, struct rte_acl_build_rule *r2)
1608 for (n = 1; n < r1->config->num_fields; n++) {
1609 int field_index = r1->config->defs[n].field_index;
1611 if (r1->wildness[field_index] != r2->wildness[field_index])
1612 return (r1->wildness[field_index] -
1613 r2->wildness[field_index]);
1619 * Sort list of rules based on the rules wildness.
1621 static struct rte_acl_build_rule *
1622 sort_rules(struct rte_acl_build_rule *head)
1624 struct rte_acl_build_rule *new_head;
1625 struct rte_acl_build_rule *l, *r, **p;
1628 while (head != NULL) {
1630 /* remove element from the head of the old list. */
1635 /* walk through new sorted list to find a proper place. */
1638 rule_cmp_wildness(l, r) >= 0;
1642 /* insert element into the new sorted list. */
1651 acl_build_index(const struct rte_acl_config *config, uint32_t *data_index)
1654 int32_t last_header;
1659 for (n = 0; n < config->num_fields; n++) {
1660 if (last_header != config->defs[n].input_index) {
1661 last_header = config->defs[n].input_index;
1662 data_index[m++] = config->defs[n].offset;
1669 static struct rte_acl_build_rule *
1670 build_one_trie(struct acl_build_context *context,
1671 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES],
1674 struct rte_acl_build_rule *last;
1675 struct rte_acl_config *config;
1677 config = rule_sets[n]->config;
1679 acl_rule_stats(rule_sets[n], config);
1680 rule_sets[n] = sort_rules(rule_sets[n]);
1682 context->tries[n].type = RTE_ACL_FULL_TRIE;
1683 context->tries[n].count = 0;
1685 context->tries[n].num_data_indexes = acl_build_index(config,
1686 context->data_indexes[n]);
1687 context->tries[n].data_index = context->data_indexes[n];
1689 context->bld_tries[n].trie = build_trie(context, rule_sets[n],
1690 &last, &context->tries[n].count);
1696 acl_build_tries(struct acl_build_context *context,
1697 struct rte_acl_build_rule *head)
1700 uint32_t n, num_tries;
1701 struct rte_acl_config *config;
1702 struct rte_acl_build_rule *last;
1703 struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES];
1705 config = head->config;
1706 rule_sets[0] = head;
1708 /* initialize tries */
1709 for (n = 0; n < RTE_DIM(context->tries); n++) {
1710 context->tries[n].type = RTE_ACL_UNUSED_TRIE;
1711 context->bld_tries[n].trie = NULL;
1712 context->tries[n].count = 0;
1715 context->tries[0].type = RTE_ACL_FULL_TRIE;
1717 /* calc wildness of each field of each rule */
1718 rc = acl_calc_wildness(head, config);
1722 for (n = 0;; n = num_tries) {
1726 last = build_one_trie(context, rule_sets, n);
1727 if (context->bld_tries[n].trie == NULL) {
1728 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1732 /* Build of the last trie completed. */
1736 if (num_tries == RTE_DIM(context->tries)) {
1738 "Exceeded max number of tries: %u\n",
1743 /* Trie is getting too big, split remaining rule set. */
1744 rule_sets[num_tries] = last->next;
1746 acl_free_node(context, context->bld_tries[n].trie);
1748 /* Create a new copy of config for remaining rules. */
1749 config = acl_build_alloc(context, 1, sizeof(*config));
1750 memcpy(config, rule_sets[n]->config, sizeof(*config));
1752 /* Make remaining rules use new config. */
1753 for (head = rule_sets[num_tries]; head != NULL;
1755 head->config = config;
1757 /* Rebuild the trie for the reduced rule-set. */
1758 last = build_one_trie(context, rule_sets, n);
1759 if (context->bld_tries[n].trie == NULL || last != NULL) {
1760 RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1766 context->num_tries = num_tries;
1771 acl_build_log(const struct acl_build_context *ctx)
1775 RTE_LOG(DEBUG, ACL, "Build phase for ACL \"%s\":\n"
1776 "node limit for tree split: %u\n"
1777 "nodes created: %u\n"
1778 "memory consumed: %zu\n",
1784 for (n = 0; n < RTE_DIM(ctx->tries); n++) {
1785 if (ctx->tries[n].count != 0)
1787 "trie %u: number of rules: %u, indexes: %u\n",
1788 n, ctx->tries[n].count,
1789 ctx->tries[n].num_data_indexes);
1794 acl_build_rules(struct acl_build_context *bcx)
1796 struct rte_acl_build_rule *br, *head;
1797 const struct rte_acl_rule *rule;
1799 uint32_t fn, i, n, num;
1802 fn = bcx->cfg.num_fields;
1803 n = bcx->acx->num_rules;
1804 ofs = n * sizeof(*br);
1805 sz = ofs + n * fn * sizeof(*wp);
1807 br = tb_alloc(&bcx->pool, sz);
1809 wp = (uint32_t *)((uintptr_t)br + ofs);
1813 for (i = 0; i != n; i++) {
1814 rule = (const struct rte_acl_rule *)
1815 ((uintptr_t)bcx->acx->rules + bcx->acx->rule_sz * i);
1816 if ((rule->data.category_mask & bcx->category_mask) != 0) {
1817 br[num].next = head;
1818 br[num].config = &bcx->cfg;
1820 br[num].wildness = wp;
1827 bcx->num_rules = num;
1828 bcx->build_rules = head;
1834 * Copy data_indexes for each trie into RT location.
1837 acl_set_data_indexes(struct rte_acl_ctx *ctx)
1842 for (i = 0; i != ctx->num_tries; i++) {
1843 n = ctx->trie[i].num_data_indexes;
1844 memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index,
1845 n * sizeof(ctx->data_indexes[0]));
1846 ctx->trie[i].data_index = ctx->data_indexes + ofs;
1847 ofs += RTE_ACL_MAX_FIELDS;
1852 * Internal routine, performs 'build' phase of trie generation:
1853 * - setups build context.
1854 * - analizes given set of rules.
1855 * - builds internal tree(s).
1858 acl_bld(struct acl_build_context *bcx, struct rte_acl_ctx *ctx,
1859 const struct rte_acl_config *cfg, uint32_t node_max)
1863 /* setup build context. */
1864 memset(bcx, 0, sizeof(*bcx));
1866 bcx->pool.alignment = ACL_POOL_ALIGN;
1867 bcx->pool.min_alloc = ACL_POOL_ALLOC_MIN;
1869 bcx->category_mask = LEN2MASK(bcx->cfg.num_categories);
1870 bcx->node_max = node_max;
1872 rc = sigsetjmp(bcx->pool.fail, 0);
1874 /* build phase runs out of memory. */
1877 "ACL context: %s, %s() failed with error code: %d\n",
1878 bcx->acx->name, __func__, rc);
1882 /* Create a build rules copy. */
1883 rc = acl_build_rules(bcx);
1887 /* No rules to build for that context+config */
1888 if (bcx->build_rules == NULL) {
1891 /* build internal trie representation. */
1892 rc = acl_build_tries(bcx, bcx->build_rules);
1898 rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1903 struct acl_build_context bcx;
1905 if (ctx == NULL || cfg == NULL || cfg->num_categories == 0 ||
1906 cfg->num_categories > RTE_ACL_MAX_CATEGORIES)
1909 acl_build_reset(ctx);
1911 if (cfg->max_size == 0) {
1913 max_size = SIZE_MAX;
1916 max_size = cfg->max_size;
1919 for (rc = -ERANGE; n >= NODE_MIN && rc == -ERANGE; n /= 2) {
1921 /* perform build phase. */
1922 rc = acl_bld(&bcx, ctx, cfg, n);
1925 /* allocate and fill run-time structures. */
1926 rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries,
1927 bcx.num_tries, bcx.cfg.num_categories,
1928 RTE_ACL_MAX_FIELDS * RTE_DIM(bcx.tries) *
1929 sizeof(ctx->data_indexes[0]), max_size);
1931 /* set data indexes. */
1932 acl_set_data_indexes(ctx);
1934 /* copy in build config. */
1939 acl_build_log(&bcx);
1941 /* cleanup after build. */
1942 tb_free_pool(&bcx.pool);