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
);