xref: /dpdk/lib/acl/acl_bld.c (revision c56185fc183fc0532d2f03aaf04bbf0989ea91a5)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <rte_acl.h>
6 #include "tb_mem.h"
7 #include "acl.h"
8 
9 #define	ACL_POOL_ALIGN		8
10 #define	ACL_POOL_ALLOC_MIN	0x800000
11 
12 /* number of pointers per alloc */
13 #define ACL_PTR_ALLOC	32
14 
15 /* account for situation when all fields are 8B long */
16 #define ACL_MAX_INDEXES	(2 * RTE_ACL_MAX_FIELDS)
17 
18 /* macros for dividing rule sets heuristics */
19 #define NODE_MAX	0x4000
20 #define NODE_MIN	0x800
21 
22 /* TALLY are statistics per field */
23 enum {
24 	TALLY_0 = 0,        /* number of rules that are 0% or more wild. */
25 	TALLY_25,	    /* number of rules that are 25% or more wild. */
26 	TALLY_50,
27 	TALLY_75,
28 	TALLY_100,
29 	TALLY_DEACTIVATED, /* deactivated fields (100% wild in all rules). */
30 	TALLY_DEPTH,
31 	/* number of rules that are 100% wild for this field and higher. */
32 	TALLY_NUM
33 };
34 
35 static const uint32_t wild_limits[TALLY_DEACTIVATED] = {0, 25, 50, 75, 100};
36 
37 enum {
38 	ACL_INTERSECT_NONE = 0,
39 	ACL_INTERSECT_A = 1,    /* set A is a superset of A and B intersect */
40 	ACL_INTERSECT_B = 2,    /* set B is a superset of A and B intersect */
41 	ACL_INTERSECT = 4,	/* sets A and B intersect */
42 };
43 
44 enum {
45 	ACL_PRIORITY_EQUAL = 0,
46 	ACL_PRIORITY_NODE_A = 1,
47 	ACL_PRIORITY_NODE_B = 2,
48 	ACL_PRIORITY_MIXED = 3
49 };
50 
51 
52 struct acl_mem_block {
53 	uint32_t block_size;
54 	void     *mem_ptr;
55 };
56 
57 #define	MEM_BLOCK_NUM	16
58 
59 /* Single ACL rule, build representation.*/
60 struct rte_acl_build_rule {
61 	struct rte_acl_build_rule   *next;
62 	struct rte_acl_config       *config;
63 	/**< configuration for each field in the rule. */
64 	const struct rte_acl_rule   *f;
65 	uint32_t                    *wildness;
66 };
67 
68 /* Context for build phase */
69 struct acl_build_context {
70 	const struct rte_acl_ctx *acx;
71 	struct rte_acl_build_rule *build_rules;
72 	struct rte_acl_config     cfg;
73 	int32_t                   node_max;
74 	int32_t                   cur_node_max;
75 	uint32_t                  node;
76 	uint32_t                  num_nodes;
77 	uint32_t                  category_mask;
78 	uint32_t                  num_rules;
79 	uint32_t                  node_id;
80 	uint32_t                  src_mask;
81 	uint32_t                  num_build_rules;
82 	uint32_t                  num_tries;
83 	struct tb_mem_pool        pool;
84 	struct rte_acl_trie       tries[RTE_ACL_MAX_TRIES];
85 	struct rte_acl_bld_trie   bld_tries[RTE_ACL_MAX_TRIES];
86 	uint32_t            data_indexes[RTE_ACL_MAX_TRIES][ACL_MAX_INDEXES];
87 
88 	/* memory free lists for nodes and blocks used for node ptrs */
89 	struct acl_mem_block      blocks[MEM_BLOCK_NUM];
90 	struct rte_acl_node       *node_free_list;
91 };
92 
93 static int acl_merge_trie(struct acl_build_context *context,
94 	struct rte_acl_node *node_a, struct rte_acl_node *node_b,
95 	uint32_t level, struct rte_acl_node **node_c);
96 
97 static void
98 acl_deref_ptr(struct acl_build_context *context,
99 	struct rte_acl_node *node, int index);
100 
101 static void *
102 acl_build_alloc(struct acl_build_context *context, size_t n, size_t s)
103 {
104 	uint32_t m;
105 	void *p;
106 	size_t alloc_size = n * s;
107 
108 	/*
109 	 * look for memory in free lists
110 	 */
111 	for (m = 0; m < RTE_DIM(context->blocks); m++) {
112 		if (context->blocks[m].block_size ==
113 		   alloc_size && context->blocks[m].mem_ptr != NULL) {
114 			p = context->blocks[m].mem_ptr;
115 			context->blocks[m].mem_ptr = *((void **)p);
116 			memset(p, 0, alloc_size);
117 			return p;
118 		}
119 	}
120 
121 	/*
122 	 * return allocation from memory pool
123 	 */
124 	p = tb_alloc(&context->pool, alloc_size);
125 	return p;
126 }
127 
128 /*
129  * Free memory blocks (kept in context for reuse).
130  */
131 static void
132 acl_build_free(struct acl_build_context *context, size_t s, void *p)
133 {
134 	uint32_t n;
135 
136 	for (n = 0; n < RTE_DIM(context->blocks); n++) {
137 		if (context->blocks[n].block_size == s) {
138 			*((void **)p) = context->blocks[n].mem_ptr;
139 			context->blocks[n].mem_ptr = p;
140 			return;
141 		}
142 	}
143 	for (n = 0; n < RTE_DIM(context->blocks); n++) {
144 		if (context->blocks[n].block_size == 0) {
145 			context->blocks[n].block_size = s;
146 			*((void **)p) = NULL;
147 			context->blocks[n].mem_ptr = p;
148 			return;
149 		}
150 	}
151 }
152 
153 /*
154  * Allocate and initialize a new node.
155  */
156 static struct rte_acl_node *
157 acl_alloc_node(struct acl_build_context *context, int level)
158 {
159 	struct rte_acl_node *node;
160 
161 	if (context->node_free_list != NULL) {
162 		node = context->node_free_list;
163 		context->node_free_list = node->next;
164 		memset(node, 0, sizeof(struct rte_acl_node));
165 	} else {
166 		node = acl_build_alloc(context, sizeof(struct rte_acl_node), 1);
167 	}
168 
169 	if (node != NULL) {
170 		node->num_ptrs = 0;
171 		node->level = level;
172 		node->node_type = RTE_ACL_NODE_UNDEFINED;
173 		node->node_index = RTE_ACL_NODE_UNDEFINED;
174 		context->num_nodes++;
175 		node->id = context->node_id++;
176 	}
177 	return node;
178 }
179 
180 /*
181  * Dereference all nodes to which this node points
182  */
183 static void
184 acl_free_node(struct acl_build_context *context,
185 	struct rte_acl_node *node)
186 {
187 	uint32_t n;
188 
189 	if (node->prev != NULL)
190 		node->prev->next = NULL;
191 	for (n = 0; n < node->num_ptrs; n++)
192 		acl_deref_ptr(context, node, n);
193 
194 	/* free mrt if this is a match node */
195 	if (node->mrt != NULL) {
196 		acl_build_free(context, sizeof(struct rte_acl_match_results),
197 			node->mrt);
198 		node->mrt = NULL;
199 	}
200 
201 	/* free transitions to other nodes */
202 	if (node->ptrs != NULL) {
203 		acl_build_free(context,
204 			node->max_ptrs * sizeof(struct rte_acl_ptr_set),
205 			node->ptrs);
206 		node->ptrs = NULL;
207 	}
208 
209 	/* put it on the free list */
210 	context->num_nodes--;
211 	node->next = context->node_free_list;
212 	context->node_free_list = node;
213 }
214 
215 
216 /*
217  * Include src bitset in dst bitset
218  */
219 static void
220 acl_include(struct rte_acl_bitset *dst, struct rte_acl_bitset *src, bits_t mask)
221 {
222 	uint32_t n;
223 
224 	for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
225 		dst->bits[n] = (dst->bits[n] & mask) | src->bits[n];
226 }
227 
228 /*
229  * Set dst to bits of src1 that are not in src2
230  */
231 static int
232 acl_exclude(struct rte_acl_bitset *dst,
233 	struct rte_acl_bitset *src1,
234 	struct rte_acl_bitset *src2)
235 {
236 	uint32_t n;
237 	bits_t all_bits = 0;
238 
239 	for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
240 		dst->bits[n] = src1->bits[n] & ~src2->bits[n];
241 		all_bits |= dst->bits[n];
242 	}
243 	return all_bits != 0;
244 }
245 
246 /*
247  * Add a pointer (ptr) to a node.
248  */
249 static int
250 acl_add_ptr(struct acl_build_context *context,
251 	struct rte_acl_node *node,
252 	struct rte_acl_node *ptr,
253 	struct rte_acl_bitset *bits)
254 {
255 	uint32_t n, num_ptrs;
256 	struct rte_acl_ptr_set *ptrs = NULL;
257 
258 	/*
259 	 * If there's already a pointer to the same node, just add to the bitset
260 	 */
261 	for (n = 0; n < node->num_ptrs; n++) {
262 		if (node->ptrs[n].ptr != NULL) {
263 			if (node->ptrs[n].ptr == ptr) {
264 				acl_include(&node->ptrs[n].values, bits, -1);
265 				acl_include(&node->values, bits, -1);
266 				return 0;
267 			}
268 		}
269 	}
270 
271 	/* if there's no room for another pointer, make room */
272 	if (node->num_ptrs >= node->max_ptrs) {
273 		/* add room for more pointers */
274 		num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
275 		ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
276 
277 		/* copy current points to new memory allocation */
278 		if (node->ptrs != NULL) {
279 			memcpy(ptrs, node->ptrs,
280 				node->num_ptrs * sizeof(*ptrs));
281 			acl_build_free(context, node->max_ptrs * sizeof(*ptrs),
282 				node->ptrs);
283 		}
284 		node->ptrs = ptrs;
285 		node->max_ptrs = num_ptrs;
286 	}
287 
288 	/* Find available ptr and add a new pointer to this node */
289 	for (n = node->min_add; n < node->max_ptrs; n++) {
290 		if (node->ptrs[n].ptr == NULL) {
291 			node->ptrs[n].ptr = ptr;
292 			acl_include(&node->ptrs[n].values, bits, 0);
293 			acl_include(&node->values, bits, -1);
294 			if (ptr != NULL)
295 				ptr->ref_count++;
296 			if (node->num_ptrs <= n)
297 				node->num_ptrs = n + 1;
298 			return 0;
299 		}
300 	}
301 
302 	return 0;
303 }
304 
305 /*
306  * Add a pointer for a range of values
307  */
308 static int
309 acl_add_ptr_range(struct acl_build_context *context,
310 	struct rte_acl_node *root,
311 	struct rte_acl_node *node,
312 	uint8_t low,
313 	uint8_t high)
314 {
315 	uint32_t n;
316 	struct rte_acl_bitset bitset;
317 
318 	/* clear the bitset values */
319 	for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
320 		bitset.bits[n] = 0;
321 
322 	/* for each bit in range, add bit to set */
323 	for (n = 0; n < UINT8_MAX + 1; n++)
324 		if (n >= low && n <= high)
325 			bitset.bits[n / (sizeof(bits_t) * 8)] |=
326 				1U << (n % (sizeof(bits_t) * CHAR_BIT));
327 
328 	return acl_add_ptr(context, root, node, &bitset);
329 }
330 
331 /*
332  * Generate a bitset from a byte value and mask.
333  */
334 static int
335 acl_gen_mask(struct rte_acl_bitset *bitset, uint32_t value, uint32_t mask)
336 {
337 	int range = 0;
338 	uint32_t n;
339 
340 	/* clear the bitset values */
341 	for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
342 		bitset->bits[n] = 0;
343 
344 	/* for each bit in value/mask, add bit to set */
345 	for (n = 0; n < UINT8_MAX + 1; n++) {
346 		if ((n & mask) == value) {
347 			range++;
348 			bitset->bits[n / (sizeof(bits_t) * 8)] |=
349 				1U << (n % (sizeof(bits_t) * CHAR_BIT));
350 		}
351 	}
352 	return range;
353 }
354 
355 /*
356  * Determine how A and B intersect.
357  * Determine if A and/or B are supersets of the intersection.
358  */
359 static int
360 acl_intersect_type(const struct rte_acl_bitset *a_bits,
361 	const struct rte_acl_bitset *b_bits,
362 	struct rte_acl_bitset *intersect)
363 {
364 	uint32_t n;
365 	bits_t intersect_bits = 0;
366 	bits_t a_superset = 0;
367 	bits_t b_superset = 0;
368 
369 	/*
370 	 * calculate and store intersection and check if A and/or B have
371 	 * bits outside the intersection (superset)
372 	 */
373 	for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
374 		intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
375 		a_superset |= a_bits->bits[n] ^ intersect->bits[n];
376 		b_superset |= b_bits->bits[n] ^ intersect->bits[n];
377 		intersect_bits |= intersect->bits[n];
378 	}
379 
380 	n = (intersect_bits == 0 ? ACL_INTERSECT_NONE : ACL_INTERSECT) |
381 		(b_superset == 0 ? 0 : ACL_INTERSECT_B) |
382 		(a_superset == 0 ? 0 : ACL_INTERSECT_A);
383 
384 	return n;
385 }
386 
387 /*
388  * Duplicate a node
389  */
390 static struct rte_acl_node *
391 acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)
392 {
393 	uint32_t n;
394 	struct rte_acl_node *next;
395 
396 	next = acl_alloc_node(context, node->level);
397 
398 	/* allocate the pointers */
399 	if (node->num_ptrs > 0) {
400 		next->ptrs = acl_build_alloc(context,
401 			node->max_ptrs,
402 			sizeof(struct rte_acl_ptr_set));
403 		next->max_ptrs = node->max_ptrs;
404 	}
405 
406 	/* copy over the pointers */
407 	for (n = 0; n < node->num_ptrs; n++) {
408 		if (node->ptrs[n].ptr != NULL) {
409 			next->ptrs[n].ptr = node->ptrs[n].ptr;
410 			next->ptrs[n].ptr->ref_count++;
411 			acl_include(&next->ptrs[n].values,
412 				&node->ptrs[n].values, -1);
413 		}
414 	}
415 
416 	next->num_ptrs = node->num_ptrs;
417 
418 	/* copy over node's match results */
419 	if (node->match_flag == 0)
420 		next->match_flag = 0;
421 	else {
422 		next->match_flag = -1;
423 		next->mrt = acl_build_alloc(context, 1, sizeof(*next->mrt));
424 		memcpy(next->mrt, node->mrt, sizeof(*next->mrt));
425 	}
426 
427 	/* copy over node's bitset */
428 	acl_include(&next->values, &node->values, -1);
429 
430 	node->next = next;
431 	next->prev = node;
432 
433 	return next;
434 }
435 
436 /*
437  * Dereference a pointer from a node
438  */
439 static void
440 acl_deref_ptr(struct acl_build_context *context,
441 	struct rte_acl_node *node, int index)
442 {
443 	struct rte_acl_node *ref_node;
444 
445 	/* De-reference the node at the specified pointer */
446 	if (node != NULL && node->ptrs[index].ptr != NULL) {
447 		ref_node = node->ptrs[index].ptr;
448 		ref_node->ref_count--;
449 		if (ref_node->ref_count == 0)
450 			acl_free_node(context, ref_node);
451 	}
452 }
453 
454 /*
455  * acl_exclude rte_acl_bitset from src and copy remaining pointer to dst
456  */
457 static int
458 acl_copy_ptr(struct acl_build_context *context,
459 	struct rte_acl_node *dst,
460 	struct rte_acl_node *src,
461 	int index,
462 	struct rte_acl_bitset *b_bits)
463 {
464 	int rc;
465 	struct rte_acl_bitset bits;
466 
467 	if (b_bits != NULL)
468 		if (!acl_exclude(&bits, &src->ptrs[index].values, b_bits))
469 			return 0;
470 
471 	rc = acl_add_ptr(context, dst, src->ptrs[index].ptr, &bits);
472 	if (rc < 0)
473 		return rc;
474 	return 1;
475 }
476 
477 /*
478  * Fill in gaps in ptrs list with the ptr at the end of the list
479  */
480 static void
481 acl_compact_node_ptrs(struct rte_acl_node *node_a)
482 {
483 	uint32_t n;
484 	int min_add = node_a->min_add;
485 
486 	while (node_a->num_ptrs > 0  &&
487 			node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
488 		node_a->num_ptrs--;
489 
490 	for (n = min_add; n + 1 < node_a->num_ptrs; n++) {
491 
492 		/* if this entry is empty */
493 		if (node_a->ptrs[n].ptr == NULL) {
494 
495 			/* move the last pointer to this entry */
496 			acl_include(&node_a->ptrs[n].values,
497 				&node_a->ptrs[node_a->num_ptrs - 1].values,
498 				0);
499 			node_a->ptrs[n].ptr =
500 				node_a->ptrs[node_a->num_ptrs - 1].ptr;
501 
502 			/*
503 			 * mark the end as empty and adjust the number
504 			 * of used pointer enum_tries
505 			 */
506 			node_a->ptrs[node_a->num_ptrs - 1].ptr = NULL;
507 			while (node_a->num_ptrs > 0  &&
508 				node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
509 				node_a->num_ptrs--;
510 		}
511 	}
512 }
513 
514 static int
515 acl_resolve_leaf(struct acl_build_context *context,
516 	struct rte_acl_node *node_a,
517 	struct rte_acl_node *node_b,
518 	struct rte_acl_node **node_c)
519 {
520 	uint32_t n;
521 	int combined_priority = ACL_PRIORITY_EQUAL;
522 
523 	for (n = 0; n < context->cfg.num_categories; n++) {
524 		if (node_a->mrt->priority[n] != node_b->mrt->priority[n]) {
525 			combined_priority |= (node_a->mrt->priority[n] >
526 				node_b->mrt->priority[n]) ?
527 				ACL_PRIORITY_NODE_A : ACL_PRIORITY_NODE_B;
528 		}
529 	}
530 
531 	/*
532 	 * if node a is higher or equal priority for all categories,
533 	 * then return node_a.
534 	 */
535 	if (combined_priority == ACL_PRIORITY_NODE_A ||
536 			combined_priority == ACL_PRIORITY_EQUAL) {
537 		*node_c = node_a;
538 		return 0;
539 	}
540 
541 	/*
542 	 * if node b is higher or equal priority for all categories,
543 	 * then return node_b.
544 	 */
545 	if (combined_priority == ACL_PRIORITY_NODE_B) {
546 		*node_c = node_b;
547 		return 0;
548 	}
549 
550 	/*
551 	 * mixed priorities - create a new node with the highest priority
552 	 * for each category.
553 	 */
554 
555 	/* force new duplication. */
556 	node_a->next = NULL;
557 
558 	*node_c = acl_dup_node(context, node_a);
559 	for (n = 0; n < context->cfg.num_categories; n++) {
560 		if ((*node_c)->mrt->priority[n] < node_b->mrt->priority[n]) {
561 			(*node_c)->mrt->priority[n] = node_b->mrt->priority[n];
562 			(*node_c)->mrt->results[n] = node_b->mrt->results[n];
563 		}
564 	}
565 	return 0;
566 }
567 
568 /*
569  * Merge nodes A and B together,
570  *   returns a node that is the path for the intersection
571  *
572  * If match node (leaf on trie)
573  *	For each category
574  *		return node = highest priority result
575  *
576  * Create C as a duplicate of A to point to child intersections
577  * If any pointers in C intersect with any in B
578  *	For each intersection
579  *		merge children
580  *		remove intersection from C pointer
581  *		add a pointer from C to child intersection node
582  * Compact the pointers in A and B
583  * Copy any B pointers that are outside of the intersection to C
584  * If C has no references to the B trie
585  *   free C and return A
586  * Else If C has no references to the A trie
587  *   free C and return B
588  * Else
589  *   return C
590  */
591 static int
592 acl_merge_trie(struct acl_build_context *context,
593 	struct rte_acl_node *node_a, struct rte_acl_node *node_b,
594 	uint32_t level, struct rte_acl_node **return_c)
595 {
596 	uint32_t n, m, ptrs_c, ptrs_b;
597 	uint32_t min_add_c, min_add_b;
598 	int node_intersect_type;
599 	struct rte_acl_bitset node_intersect;
600 	struct rte_acl_node *node_c;
601 	struct rte_acl_node *node_a_next;
602 	int node_b_refs;
603 	int node_a_refs;
604 
605 	node_c = node_a;
606 	node_a_next = node_a->next;
607 	min_add_c = 0;
608 	min_add_b = 0;
609 	node_a_refs = node_a->num_ptrs;
610 	node_b_refs = 0;
611 	node_intersect_type = 0;
612 
613 	/* Resolve leaf nodes (matches) */
614 	if (node_a->match_flag != 0) {
615 		acl_resolve_leaf(context, node_a, node_b, return_c);
616 		return 0;
617 	}
618 
619 	/*
620 	 * Create node C as a copy of node A, and do: C = merge(A,B);
621 	 * If node A can be used instead (A==C), then later we'll
622 	 * destroy C and return A.
623 	 */
624 	if (level > 0)
625 		node_c = acl_dup_node(context, node_a);
626 
627 	/*
628 	 * If the two node transitions intersect then merge the transitions.
629 	 * Check intersection for entire node (all pointers)
630 	 */
631 	node_intersect_type = acl_intersect_type(&node_c->values,
632 		&node_b->values,
633 		&node_intersect);
634 
635 	if (node_intersect_type & ACL_INTERSECT) {
636 
637 		min_add_b = node_b->min_add;
638 		node_b->min_add = node_b->num_ptrs;
639 		ptrs_b = node_b->num_ptrs;
640 
641 		min_add_c = node_c->min_add;
642 		node_c->min_add = node_c->num_ptrs;
643 		ptrs_c = node_c->num_ptrs;
644 
645 		for (n = 0; n < ptrs_c; n++) {
646 			if (node_c->ptrs[n].ptr == NULL) {
647 				node_a_refs--;
648 				continue;
649 			}
650 			node_c->ptrs[n].ptr->next = NULL;
651 			for (m = 0; m < ptrs_b; m++) {
652 
653 				struct rte_acl_bitset child_intersect;
654 				int child_intersect_type;
655 				struct rte_acl_node *child_node_c = NULL;
656 
657 				if (node_b->ptrs[m].ptr == NULL ||
658 						node_c->ptrs[n].ptr ==
659 						node_b->ptrs[m].ptr)
660 						continue;
661 
662 				child_intersect_type = acl_intersect_type(
663 					&node_c->ptrs[n].values,
664 					&node_b->ptrs[m].values,
665 					&child_intersect);
666 
667 				if ((child_intersect_type & ACL_INTERSECT) !=
668 						0) {
669 					if (acl_merge_trie(context,
670 							node_c->ptrs[n].ptr,
671 							node_b->ptrs[m].ptr,
672 							level + 1,
673 							&child_node_c))
674 						return 1;
675 
676 					if (child_node_c != NULL &&
677 							child_node_c !=
678 							node_c->ptrs[n].ptr) {
679 
680 						node_b_refs++;
681 
682 						/*
683 						 * Added link from C to
684 						 * child_C for all transitions
685 						 * in the intersection.
686 						 */
687 						acl_add_ptr(context, node_c,
688 							child_node_c,
689 							&child_intersect);
690 
691 						/*
692 						 * inc refs if pointer is not
693 						 * to node b.
694 						 */
695 						node_a_refs += (child_node_c !=
696 							node_b->ptrs[m].ptr);
697 
698 						/*
699 						 * Remove intersection from C
700 						 * pointer.
701 						 */
702 						if (!acl_exclude(
703 							&node_c->ptrs[n].values,
704 							&node_c->ptrs[n].values,
705 							&child_intersect)) {
706 							acl_deref_ptr(context,
707 								node_c, n);
708 							node_c->ptrs[n].ptr =
709 								NULL;
710 							node_a_refs--;
711 						}
712 					}
713 				}
714 			}
715 		}
716 
717 		/* Compact pointers */
718 		node_c->min_add = min_add_c;
719 		acl_compact_node_ptrs(node_c);
720 		node_b->min_add = min_add_b;
721 		acl_compact_node_ptrs(node_b);
722 	}
723 
724 	/*
725 	 *  Copy pointers outside of the intersection from B to C
726 	 */
727 	if ((node_intersect_type & ACL_INTERSECT_B) != 0) {
728 		node_b_refs++;
729 		for (m = 0; m < node_b->num_ptrs; m++)
730 			if (node_b->ptrs[m].ptr != NULL)
731 				acl_copy_ptr(context, node_c,
732 					node_b, m, &node_intersect);
733 	}
734 
735 	/*
736 	 * Free node C if top of trie is contained in A or B
737 	 *  if node C is a duplicate of node A &&
738 	 *     node C was not an existing duplicate
739 	 */
740 	if (node_c != node_a && node_c != node_a_next) {
741 
742 		/*
743 		 * if the intersection has no references to the
744 		 * B side, then it is contained in A
745 		 */
746 		if (node_b_refs == 0) {
747 			acl_free_node(context, node_c);
748 			node_c = node_a;
749 		} else {
750 			/*
751 			 * if the intersection has no references to the
752 			 * A side, then it is contained in B.
753 			 */
754 			if (node_a_refs == 0) {
755 				acl_free_node(context, node_c);
756 				node_c = node_b;
757 			}
758 		}
759 	}
760 
761 	if (return_c != NULL)
762 		*return_c = node_c;
763 
764 	if (level == 0)
765 		acl_free_node(context, node_b);
766 
767 	return 0;
768 }
769 
770 /*
771  * Reset current runtime fields before next build:
772  *  - free allocated RT memory.
773  *  - reset all RT related fields to zero.
774  */
775 static void
776 acl_build_reset(struct rte_acl_ctx *ctx)
777 {
778 	rte_free(ctx->mem);
779 	memset(&ctx->num_categories, 0,
780 		sizeof(*ctx) - offsetof(struct rte_acl_ctx, num_categories));
781 }
782 
783 static void
784 acl_gen_full_range(struct acl_build_context *context, struct rte_acl_node *root,
785 	struct rte_acl_node *end, int size, int level)
786 {
787 	struct rte_acl_node *node, *prev;
788 	uint32_t n;
789 
790 	prev = root;
791 	for (n = size - 1; n > 0; n--) {
792 		node = acl_alloc_node(context, level++);
793 		acl_add_ptr_range(context, prev, node, 0, UINT8_MAX);
794 		prev = node;
795 	}
796 	acl_add_ptr_range(context, prev, end, 0, UINT8_MAX);
797 }
798 
799 static void
800 acl_gen_range_mdl(struct acl_build_context *context, struct rte_acl_node *root,
801 	struct rte_acl_node *end, uint8_t lo, uint8_t hi, int size, int level)
802 {
803 	struct rte_acl_node *node;
804 
805 	node = acl_alloc_node(context, level++);
806 	acl_add_ptr_range(context, root, node, lo, hi);
807 	acl_gen_full_range(context, node, end, size - 1, level);
808 }
809 
810 static void
811 acl_gen_range_low(struct acl_build_context *context, struct rte_acl_node *root,
812 	struct rte_acl_node *end, const uint8_t *lo, int size, int level)
813 {
814 	struct rte_acl_node *node;
815 	uint32_t n;
816 
817 	n = size - 1;
818 	if (n == 0) {
819 		acl_add_ptr_range(context, root, end, lo[0], UINT8_MAX);
820 		return;
821 	}
822 
823 	node = acl_alloc_node(context, level++);
824 	acl_add_ptr_range(context, root, node, lo[n], lo[n]);
825 
826 	/* generate lower-bound sub-trie */
827 	acl_gen_range_low(context, node, end, lo, n, level);
828 
829 	/* generate middle sub-trie */
830 	if (n > 1 && lo[n - 1] != UINT8_MAX)
831 		acl_gen_range_mdl(context, node, end, lo[n - 1] + 1, UINT8_MAX,
832 			n, level);
833 }
834 
835 static void
836 acl_gen_range_high(struct acl_build_context *context, struct rte_acl_node *root,
837 	struct rte_acl_node *end, const uint8_t *hi, int size, int level)
838 {
839 	struct rte_acl_node *node;
840 	uint32_t n;
841 
842 	n = size - 1;
843 	if (n == 0) {
844 		acl_add_ptr_range(context, root, end, 0, hi[0]);
845 		return;
846 	}
847 
848 	node = acl_alloc_node(context, level++);
849 	acl_add_ptr_range(context, root, node, hi[n], hi[n]);
850 
851 	/* generate upper-bound sub-trie */
852 	acl_gen_range_high(context, node, end, hi, n, level);
853 
854 	/* generate middle sub-trie */
855 	if (n > 1 && hi[n - 1] != 0)
856 		acl_gen_range_mdl(context, node, end, 0, hi[n - 1] - 1,
857 			n, level);
858 }
859 
860 static struct rte_acl_node *
861 acl_gen_range_trie(struct acl_build_context *context,
862 	const void *min, const void *max,
863 	int size, int level, struct rte_acl_node **pend)
864 {
865 	int32_t k, n;
866 	uint8_t hi_ff, lo_00;
867 	struct rte_acl_node *node, *prev, *root;
868 	const uint8_t *lo;
869 	const uint8_t *hi;
870 
871 	lo = min;
872 	hi = max;
873 
874 	*pend = acl_alloc_node(context, level + size);
875 	root = acl_alloc_node(context, level++);
876 	prev = root;
877 
878 	/* build common sub-trie till possible */
879 	for (n = size - 1; n > 0 && lo[n] == hi[n]; n--) {
880 		node = acl_alloc_node(context, level++);
881 		acl_add_ptr_range(context, prev, node, lo[n], hi[n]);
882 		prev = node;
883 	}
884 
885 	/* no branch needed, just one sub-trie */
886 	if (n == 0) {
887 		acl_add_ptr_range(context, prev, *pend, lo[0], hi[0]);
888 		return root;
889 	}
890 
891 	/* gather information about divergent paths */
892 	lo_00 = 0;
893 	hi_ff = UINT8_MAX;
894 	for (k = n - 1; k >= 0; k--) {
895 		hi_ff &= hi[k];
896 		lo_00 |= lo[k];
897 	}
898 
899 	/* generate left (lower-bound) sub-trie */
900 	if (lo_00 != 0)
901 		acl_gen_range_low(context, prev, *pend, lo, n + 1, level);
902 
903 	/* generate right (upper-bound) sub-trie */
904 	if (hi_ff != UINT8_MAX)
905 		acl_gen_range_high(context, prev, *pend, hi, n + 1, level);
906 
907 	/* generate sub-trie in the middle */
908 	if (lo[n] + 1 != hi[n] || lo_00 == 0 || hi_ff == UINT8_MAX) {
909 		lo_00 = lo[n] + (lo_00 != 0);
910 		hi_ff = hi[n] - (hi_ff != UINT8_MAX);
911 		acl_gen_range_mdl(context, prev, *pend, lo_00, hi_ff,
912 			n + 1, level);
913 	}
914 
915 	return root;
916 }
917 
918 static struct rte_acl_node *
919 acl_gen_mask_trie(struct acl_build_context *context,
920 	const void *value, const void *mask,
921 	int size, int level, struct rte_acl_node **pend)
922 {
923 	int32_t n;
924 	struct rte_acl_node *root;
925 	struct rte_acl_node *node, *prev;
926 	struct rte_acl_bitset bits;
927 	const uint8_t *val = value;
928 	const uint8_t *msk = mask;
929 
930 	root = acl_alloc_node(context, level++);
931 	prev = root;
932 
933 	for (n = size - 1; n >= 0; n--) {
934 		node = acl_alloc_node(context, level++);
935 		acl_gen_mask(&bits, val[n] & msk[n], msk[n]);
936 		acl_add_ptr(context, prev, node, &bits);
937 		prev = node;
938 	}
939 
940 	*pend = prev;
941 	return root;
942 }
943 
944 static struct rte_acl_node *
945 build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head,
946 	struct rte_acl_build_rule **last, uint32_t *count)
947 {
948 	uint32_t n, m;
949 	int field_index, node_count;
950 	struct rte_acl_node *trie;
951 	struct rte_acl_build_rule *prev, *rule;
952 	struct rte_acl_node *end, *merge, *root, *end_prev;
953 	const struct rte_acl_field *fld;
954 
955 	prev = head;
956 	rule = head;
957 	*last = prev;
958 
959 	trie = acl_alloc_node(context, 0);
960 
961 	while (rule != NULL) {
962 
963 		root = acl_alloc_node(context, 0);
964 
965 		root->ref_count = 1;
966 		end = root;
967 
968 		for (n = 0; n < rule->config->num_fields; n++) {
969 
970 			field_index = rule->config->defs[n].field_index;
971 			fld = rule->f->field + field_index;
972 			end_prev = end;
973 
974 			/* build a mini-trie for this field */
975 			switch (rule->config->defs[n].type) {
976 
977 			case RTE_ACL_FIELD_TYPE_BITMASK:
978 				merge = acl_gen_mask_trie(context,
979 					&fld->value,
980 					&fld->mask_range,
981 					rule->config->defs[n].size,
982 					end->level + 1,
983 					&end);
984 				break;
985 
986 			case RTE_ACL_FIELD_TYPE_MASK:
987 			{
988 				/*
989 				 * set msb for the size of the field and
990 				 * all higher bits.
991 				 */
992 				uint64_t mask;
993 				mask = RTE_ACL_MASKLEN_TO_BITMASK(
994 					fld->mask_range.u64,
995 					rule->config->defs[n].size);
996 
997 				/* gen a mini-trie for this field */
998 				merge = acl_gen_mask_trie(context,
999 					&fld->value,
1000 					(char *)&mask,
1001 					rule->config->defs[n].size,
1002 					end->level + 1,
1003 					&end);
1004 			}
1005 			break;
1006 
1007 			case RTE_ACL_FIELD_TYPE_RANGE:
1008 				merge = acl_gen_range_trie(context,
1009 					&rule->f->field[field_index].value,
1010 					&rule->f->field[field_index].mask_range,
1011 					rule->config->defs[n].size,
1012 					end->level + 1,
1013 					&end);
1014 				break;
1015 
1016 			default:
1017 				RTE_LOG(ERR, ACL,
1018 					"Error in rule[%u] type - %hhu\n",
1019 					rule->f->data.userdata,
1020 					rule->config->defs[n].type);
1021 				return NULL;
1022 			}
1023 
1024 			/* merge this field on to the end of the rule */
1025 			if (acl_merge_trie(context, end_prev, merge, 0,
1026 					NULL) != 0) {
1027 				return NULL;
1028 			}
1029 		}
1030 
1031 		end->match_flag = ++context->num_build_rules;
1032 
1033 		/*
1034 		 * Setup the results for this rule.
1035 		 * The result and priority of each category.
1036 		 */
1037 		if (end->mrt == NULL)
1038 			end->mrt = acl_build_alloc(context, 1,
1039 				sizeof(*end->mrt));
1040 
1041 		for (m = context->cfg.num_categories; 0 != m--; ) {
1042 			if (rule->f->data.category_mask & (1U << m)) {
1043 				end->mrt->results[m] = rule->f->data.userdata;
1044 				end->mrt->priority[m] = rule->f->data.priority;
1045 			} else {
1046 				end->mrt->results[m] = 0;
1047 				end->mrt->priority[m] = 0;
1048 			}
1049 		}
1050 
1051 		node_count = context->num_nodes;
1052 		(*count)++;
1053 
1054 		/* merge this rule into the trie */
1055 		if (acl_merge_trie(context, trie, root, 0, NULL))
1056 			return NULL;
1057 
1058 		node_count = context->num_nodes - node_count;
1059 		if (node_count > context->cur_node_max) {
1060 			*last = prev;
1061 			return trie;
1062 		}
1063 
1064 		prev = rule;
1065 		rule = rule->next;
1066 	}
1067 
1068 	*last = NULL;
1069 	return trie;
1070 }
1071 
1072 static void
1073 acl_calc_wildness(struct rte_acl_build_rule *head,
1074 	const struct rte_acl_config *config)
1075 {
1076 	uint32_t n;
1077 	struct rte_acl_build_rule *rule;
1078 
1079 	for (rule = head; rule != NULL; rule = rule->next) {
1080 
1081 		for (n = 0; n < config->num_fields; n++) {
1082 
1083 			double wild = 0;
1084 			uint32_t bit_len = CHAR_BIT * config->defs[n].size;
1085 			uint64_t msk_val = RTE_LEN2MASK(bit_len,
1086 				typeof(msk_val));
1087 			double size = bit_len;
1088 			int field_index = config->defs[n].field_index;
1089 			const struct rte_acl_field *fld = rule->f->field +
1090 				field_index;
1091 
1092 			switch (rule->config->defs[n].type) {
1093 			case RTE_ACL_FIELD_TYPE_BITMASK:
1094 				wild = (size - rte_popcount64(
1095 					fld->mask_range.u64 & msk_val)) /
1096 					size;
1097 				break;
1098 
1099 			case RTE_ACL_FIELD_TYPE_MASK:
1100 				wild = (size - fld->mask_range.u32) / size;
1101 				break;
1102 
1103 			case RTE_ACL_FIELD_TYPE_RANGE:
1104 				wild = (fld->mask_range.u64 & msk_val) -
1105 					(fld->value.u64 & msk_val);
1106 				wild = wild / msk_val;
1107 				break;
1108 			}
1109 
1110 			rule->wildness[field_index] = (uint32_t)(wild * 100);
1111 		}
1112 	}
1113 }
1114 
1115 static void
1116 acl_rule_stats(struct rte_acl_build_rule *head, struct rte_acl_config *config)
1117 {
1118 	struct rte_acl_build_rule *rule;
1119 	uint32_t n, m, fields_deactivated = 0;
1120 	uint32_t start = 0, deactivate = 0;
1121 	int tally[RTE_ACL_MAX_LEVELS][TALLY_NUM];
1122 
1123 	memset(tally, 0, sizeof(tally));
1124 
1125 	for (rule = head; rule != NULL; rule = rule->next) {
1126 
1127 		for (n = 0; n < config->num_fields; n++) {
1128 			uint32_t field_index = config->defs[n].field_index;
1129 
1130 			tally[n][TALLY_0]++;
1131 			for (m = 1; m < RTE_DIM(wild_limits); m++) {
1132 				if (rule->wildness[field_index] >=
1133 						wild_limits[m])
1134 					tally[n][m]++;
1135 			}
1136 		}
1137 
1138 		for (n = config->num_fields - 1; n > 0; n--) {
1139 			uint32_t field_index = config->defs[n].field_index;
1140 
1141 			if (rule->wildness[field_index] == 100)
1142 				tally[n][TALLY_DEPTH]++;
1143 			else
1144 				break;
1145 		}
1146 	}
1147 
1148 	/*
1149 	 * Look for any field that is always wild and drop it from the config
1150 	 * Only deactivate if all fields for a given input loop are deactivated.
1151 	 */
1152 	for (n = 1; n < config->num_fields; n++) {
1153 		if (config->defs[n].input_index !=
1154 				config->defs[n - 1].input_index) {
1155 			for (m = start; m < n; m++)
1156 				tally[m][TALLY_DEACTIVATED] = deactivate;
1157 			fields_deactivated += deactivate;
1158 			start = n;
1159 			deactivate = 1;
1160 		}
1161 
1162 		/* if the field is not always completely wild */
1163 		if (tally[n][TALLY_100] != tally[n][TALLY_0])
1164 			deactivate = 0;
1165 	}
1166 
1167 	for (m = start; m < n; m++)
1168 		tally[m][TALLY_DEACTIVATED] = deactivate;
1169 
1170 	fields_deactivated += deactivate;
1171 
1172 	/* remove deactivated fields */
1173 	if (fields_deactivated) {
1174 		uint32_t k, l = 0;
1175 
1176 		for (k = 0; k < config->num_fields; k++) {
1177 			if (tally[k][TALLY_DEACTIVATED] == 0) {
1178 				memmove(&tally[l][0], &tally[k][0],
1179 					TALLY_NUM * sizeof(tally[0][0]));
1180 				memmove(&config->defs[l++],
1181 					&config->defs[k],
1182 					sizeof(struct rte_acl_field_def));
1183 			}
1184 		}
1185 		config->num_fields = l;
1186 	}
1187 }
1188 
1189 static int
1190 rule_cmp_wildness(struct rte_acl_build_rule *r1, struct rte_acl_build_rule *r2)
1191 {
1192 	uint32_t n;
1193 
1194 	for (n = 1; n < r1->config->num_fields; n++) {
1195 		int field_index = r1->config->defs[n].field_index;
1196 
1197 		if (r1->wildness[field_index] != r2->wildness[field_index])
1198 			return r1->wildness[field_index] -
1199 				r2->wildness[field_index];
1200 	}
1201 	return 0;
1202 }
1203 
1204 /*
1205  * Split the rte_acl_build_rule list into two lists.
1206  */
1207 static void
1208 rule_list_split(struct rte_acl_build_rule *source,
1209 	struct rte_acl_build_rule **list_a,
1210 	struct rte_acl_build_rule **list_b)
1211 {
1212 	struct rte_acl_build_rule *fast;
1213 	struct rte_acl_build_rule *slow;
1214 
1215 	if (source == NULL || source->next == NULL) {
1216 		/* length < 2 cases */
1217 		*list_a = source;
1218 		*list_b = NULL;
1219 	} else {
1220 		slow = source;
1221 		fast = source->next;
1222 		/* Advance 'fast' two nodes, and advance 'slow' one node */
1223 		while (fast != NULL) {
1224 			fast = fast->next;
1225 			if (fast != NULL) {
1226 				slow = slow->next;
1227 				fast = fast->next;
1228 			}
1229 		}
1230 		/* 'slow' is before the midpoint in the list, so split it in two
1231 		   at that point. */
1232 		*list_a = source;
1233 		*list_b = slow->next;
1234 		slow->next = NULL;
1235 	}
1236 }
1237 
1238 /*
1239  * Merge two sorted lists.
1240  */
1241 static struct rte_acl_build_rule *
1242 rule_list_sorted_merge(struct rte_acl_build_rule *a,
1243 	struct rte_acl_build_rule *b)
1244 {
1245 	struct rte_acl_build_rule *result = NULL;
1246 	struct rte_acl_build_rule **last_next = &result;
1247 
1248 	while (1) {
1249 		if (a == NULL) {
1250 			*last_next = b;
1251 			break;
1252 		} else if (b == NULL) {
1253 			*last_next = a;
1254 			break;
1255 		}
1256 		if (rule_cmp_wildness(a, b) >= 0) {
1257 			*last_next = a;
1258 			last_next = &a->next;
1259 			a = a->next;
1260 		} else {
1261 			*last_next = b;
1262 			last_next = &b->next;
1263 			b = b->next;
1264 		}
1265 	}
1266 	return result;
1267 }
1268 
1269 /*
1270  * Sort list of rules based on the rules wildness.
1271  * Use recursive mergesort algorithm.
1272  */
1273 static struct rte_acl_build_rule *
1274 sort_rules(struct rte_acl_build_rule *head)
1275 {
1276 	struct rte_acl_build_rule *a;
1277 	struct rte_acl_build_rule *b;
1278 
1279 	/* Base case -- length 0 or 1 */
1280 	if (head == NULL || head->next == NULL)
1281 		return head;
1282 
1283 	/* Split head into 'a' and 'b' sublists */
1284 	rule_list_split(head, &a, &b);
1285 
1286 	/* Recursively sort the sublists */
1287 	a = sort_rules(a);
1288 	b = sort_rules(b);
1289 
1290 	/* answer = merge the two sorted lists together */
1291 	return rule_list_sorted_merge(a, b);
1292 }
1293 
1294 static uint32_t
1295 acl_build_index(const struct rte_acl_config *config, uint32_t *data_index)
1296 {
1297 	uint32_t n, m;
1298 	int32_t last_header;
1299 
1300 	m = 0;
1301 	last_header = -1;
1302 
1303 	for (n = 0; n < config->num_fields; n++) {
1304 		if (last_header != config->defs[n].input_index) {
1305 			last_header = config->defs[n].input_index;
1306 			data_index[m++] = config->defs[n].offset;
1307 			if (config->defs[n].size > sizeof(uint32_t))
1308 				data_index[m++] = config->defs[n].offset +
1309 					sizeof(uint32_t);
1310 		}
1311 	}
1312 
1313 	return m;
1314 }
1315 
1316 static struct rte_acl_build_rule *
1317 build_one_trie(struct acl_build_context *context,
1318 	struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES],
1319 	uint32_t n, int32_t node_max)
1320 {
1321 	struct rte_acl_build_rule *last;
1322 	struct rte_acl_config *config;
1323 
1324 	config = rule_sets[n]->config;
1325 
1326 	acl_rule_stats(rule_sets[n], config);
1327 	rule_sets[n] = sort_rules(rule_sets[n]);
1328 
1329 	context->tries[n].type = RTE_ACL_FULL_TRIE;
1330 	context->tries[n].count = 0;
1331 
1332 	context->tries[n].num_data_indexes = acl_build_index(config,
1333 		context->data_indexes[n]);
1334 	context->tries[n].data_index = context->data_indexes[n];
1335 
1336 	context->cur_node_max = node_max;
1337 
1338 	context->bld_tries[n].trie = build_trie(context, rule_sets[n],
1339 		&last, &context->tries[n].count);
1340 
1341 	return last;
1342 }
1343 
1344 static int
1345 acl_build_tries(struct acl_build_context *context,
1346 	struct rte_acl_build_rule *head)
1347 {
1348 	uint32_t n, num_tries;
1349 	struct rte_acl_config *config;
1350 	struct rte_acl_build_rule *last;
1351 	struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES];
1352 
1353 	config = head->config;
1354 	rule_sets[0] = head;
1355 
1356 	/* initialize tries */
1357 	for (n = 0; n < RTE_DIM(context->tries); n++) {
1358 		context->tries[n].type = RTE_ACL_UNUSED_TRIE;
1359 		context->bld_tries[n].trie = NULL;
1360 		context->tries[n].count = 0;
1361 	}
1362 
1363 	context->tries[0].type = RTE_ACL_FULL_TRIE;
1364 
1365 	/* calc wildness of each field of each rule */
1366 	acl_calc_wildness(head, config);
1367 
1368 	for (n = 0;; n = num_tries) {
1369 
1370 		num_tries = n + 1;
1371 
1372 		last = build_one_trie(context, rule_sets, n, context->node_max);
1373 		if (context->bld_tries[n].trie == NULL) {
1374 			RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1375 			return -ENOMEM;
1376 		}
1377 
1378 		/* Build of the last trie completed. */
1379 		if (last == NULL)
1380 			break;
1381 
1382 		if (num_tries == RTE_DIM(context->tries)) {
1383 			RTE_LOG(ERR, ACL,
1384 				"Exceeded max number of tries: %u\n",
1385 				num_tries);
1386 			return -ENOMEM;
1387 		}
1388 
1389 		/* Trie is getting too big, split remaining rule set. */
1390 		rule_sets[num_tries] = last->next;
1391 		last->next = NULL;
1392 		acl_free_node(context, context->bld_tries[n].trie);
1393 
1394 		/* Create a new copy of config for remaining rules. */
1395 		config = acl_build_alloc(context, 1, sizeof(*config));
1396 		memcpy(config, rule_sets[n]->config, sizeof(*config));
1397 
1398 		/* Make remaining rules use new config. */
1399 		for (head = rule_sets[num_tries]; head != NULL;
1400 				head = head->next)
1401 			head->config = config;
1402 
1403 		/*
1404 		 * Rebuild the trie for the reduced rule-set.
1405 		 * Don't try to split it any further.
1406 		 */
1407 		last = build_one_trie(context, rule_sets, n, INT32_MAX);
1408 		if (context->bld_tries[n].trie == NULL || last != NULL) {
1409 			RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", n);
1410 			return -ENOMEM;
1411 		}
1412 
1413 	}
1414 
1415 	context->num_tries = num_tries;
1416 	return 0;
1417 }
1418 
1419 static void
1420 acl_build_log(const struct acl_build_context *ctx)
1421 {
1422 	uint32_t n;
1423 
1424 	RTE_LOG(DEBUG, ACL, "Build phase for ACL \"%s\":\n"
1425 		"node limit for tree split: %u\n"
1426 		"nodes created: %u\n"
1427 		"memory consumed: %zu\n",
1428 		ctx->acx->name,
1429 		ctx->node_max,
1430 		ctx->num_nodes,
1431 		ctx->pool.alloc);
1432 
1433 	for (n = 0; n < RTE_DIM(ctx->tries); n++) {
1434 		if (ctx->tries[n].count != 0)
1435 			RTE_LOG(DEBUG, ACL,
1436 				"trie %u: number of rules: %u, indexes: %u\n",
1437 				n, ctx->tries[n].count,
1438 				ctx->tries[n].num_data_indexes);
1439 	}
1440 }
1441 
1442 static int
1443 acl_build_rules(struct acl_build_context *bcx)
1444 {
1445 	struct rte_acl_build_rule *br, *head;
1446 	const struct rte_acl_rule *rule;
1447 	uint32_t *wp;
1448 	uint32_t fn, i, n, num;
1449 	size_t ofs, sz;
1450 
1451 	fn = bcx->cfg.num_fields;
1452 	n = bcx->acx->num_rules;
1453 	ofs = n * sizeof(*br);
1454 	sz = ofs + n * fn * sizeof(*wp);
1455 
1456 	br = tb_alloc(&bcx->pool, sz);
1457 
1458 	wp = (uint32_t *)((uintptr_t)br + ofs);
1459 	num = 0;
1460 	head = NULL;
1461 
1462 	for (i = 0; i != n; i++) {
1463 		rule = (const struct rte_acl_rule *)
1464 			((uintptr_t)bcx->acx->rules + bcx->acx->rule_sz * i);
1465 		if ((rule->data.category_mask & bcx->category_mask) != 0) {
1466 			br[num].next = head;
1467 			br[num].config = &bcx->cfg;
1468 			br[num].f = rule;
1469 			br[num].wildness = wp;
1470 			wp += fn;
1471 			head = br + num;
1472 			num++;
1473 		}
1474 	}
1475 
1476 	bcx->num_rules = num;
1477 	bcx->build_rules = head;
1478 
1479 	return 0;
1480 }
1481 
1482 /*
1483  * Copy data_indexes for each trie into RT location.
1484  */
1485 static void
1486 acl_set_data_indexes(struct rte_acl_ctx *ctx)
1487 {
1488 	uint32_t i, n, ofs;
1489 
1490 	ofs = 0;
1491 	for (i = 0; i != ctx->num_tries; i++) {
1492 		n = ctx->trie[i].num_data_indexes;
1493 		memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index,
1494 			n * sizeof(ctx->data_indexes[0]));
1495 		ctx->trie[i].data_index = ctx->data_indexes + ofs;
1496 		ofs += ACL_MAX_INDEXES;
1497 	}
1498 }
1499 
1500 /*
1501  * Internal routine, performs 'build' phase of trie generation:
1502  * - setups build context.
1503  * - analyzes given set of rules.
1504  * - builds internal tree(s).
1505  */
1506 static int
1507 acl_bld(struct acl_build_context *bcx, struct rte_acl_ctx *ctx,
1508 	const struct rte_acl_config *cfg, uint32_t node_max)
1509 {
1510 	int32_t rc;
1511 
1512 	/* setup build context. */
1513 	memset(bcx, 0, sizeof(*bcx));
1514 	bcx->acx = ctx;
1515 	bcx->pool.alignment = ACL_POOL_ALIGN;
1516 	bcx->pool.min_alloc = ACL_POOL_ALLOC_MIN;
1517 	bcx->cfg = *cfg;
1518 	bcx->category_mask = RTE_LEN2MASK(bcx->cfg.num_categories,
1519 		typeof(bcx->category_mask));
1520 	bcx->node_max = node_max;
1521 
1522 	rc = sigsetjmp(bcx->pool.fail, 0);
1523 
1524 	/* build phase runs out of memory. */
1525 	if (rc != 0) {
1526 		RTE_LOG(ERR, ACL,
1527 			"ACL context: %s, %s() failed with error code: %d\n",
1528 			bcx->acx->name, __func__, rc);
1529 		return rc;
1530 	}
1531 
1532 	/* Create a build rules copy. */
1533 	rc = acl_build_rules(bcx);
1534 	if (rc != 0)
1535 		return rc;
1536 
1537 	/* No rules to build for that context+config */
1538 	if (bcx->build_rules == NULL) {
1539 		rc = -EINVAL;
1540 	} else {
1541 		/* build internal trie representation. */
1542 		rc = acl_build_tries(bcx, bcx->build_rules);
1543 	}
1544 	return rc;
1545 }
1546 
1547 /*
1548  * Check that parameters for acl_build() are valid.
1549  */
1550 static int
1551 acl_check_bld_param(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1552 {
1553 	static const size_t field_sizes[] = {
1554 		sizeof(uint8_t), sizeof(uint16_t),
1555 		sizeof(uint32_t), sizeof(uint64_t),
1556 	};
1557 
1558 	uint32_t i, j;
1559 
1560 	if (ctx == NULL || cfg == NULL || cfg->num_categories == 0 ||
1561 			cfg->num_categories > RTE_ACL_MAX_CATEGORIES ||
1562 			cfg->num_fields == 0 ||
1563 			cfg->num_fields > RTE_ACL_MAX_FIELDS)
1564 		return -EINVAL;
1565 
1566 	for (i = 0; i != cfg->num_fields; i++) {
1567 		if (cfg->defs[i].type > RTE_ACL_FIELD_TYPE_BITMASK) {
1568 			RTE_LOG(ERR, ACL,
1569 			"ACL context: %s, invalid type: %hhu for %u-th field\n",
1570 			ctx->name, cfg->defs[i].type, i);
1571 			return -EINVAL;
1572 		}
1573 		for (j = 0;
1574 				j != RTE_DIM(field_sizes) &&
1575 				cfg->defs[i].size != field_sizes[j];
1576 				j++)
1577 			;
1578 
1579 		if (j == RTE_DIM(field_sizes)) {
1580 			RTE_LOG(ERR, ACL,
1581 			"ACL context: %s, invalid size: %hhu for %u-th field\n",
1582 			ctx->name, cfg->defs[i].size, i);
1583 			return -EINVAL;
1584 		}
1585 	}
1586 
1587 	return 0;
1588 }
1589 
1590 /*
1591  * With current ACL implementation first field in the rule definition
1592  * has always to be one byte long. Though for optimising *classify*
1593  * implementation it might be useful to be able to use 4B reads
1594  * (as we do for rest of the fields).
1595  * This function checks input config to determine is it safe to do 4B
1596  * loads for first ACL field. For that we need to make sure that
1597  * first field in our rule definition doesn't have the biggest offset,
1598  * i.e. we still do have other fields located after the first one.
1599  * Contrary if first field has the largest offset, then it means
1600  * first field can occupy the very last byte in the input data buffer,
1601  * and we have to do single byte load for it.
1602  */
1603 static uint32_t
1604 get_first_load_size(const struct rte_acl_config *cfg)
1605 {
1606 	uint32_t i, max_ofs, ofs;
1607 
1608 	ofs = 0;
1609 	max_ofs = 0;
1610 
1611 	for (i = 0; i != cfg->num_fields; i++) {
1612 		if (cfg->defs[i].field_index == 0)
1613 			ofs = cfg->defs[i].offset;
1614 		else if (max_ofs < cfg->defs[i].offset)
1615 			max_ofs = cfg->defs[i].offset;
1616 	}
1617 
1618 	return (ofs < max_ofs) ? sizeof(uint32_t) : sizeof(uint8_t);
1619 }
1620 
1621 int
1622 rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
1623 {
1624 	int32_t rc;
1625 	uint32_t n;
1626 	size_t max_size;
1627 	struct acl_build_context bcx;
1628 
1629 	rc = acl_check_bld_param(ctx, cfg);
1630 	if (rc != 0)
1631 		return rc;
1632 
1633 	acl_build_reset(ctx);
1634 
1635 	if (cfg->max_size == 0) {
1636 		n = NODE_MIN;
1637 		max_size = SIZE_MAX;
1638 	} else {
1639 		n = NODE_MAX;
1640 		max_size = cfg->max_size;
1641 	}
1642 
1643 	for (rc = -ERANGE; n >= NODE_MIN && rc == -ERANGE; n /= 2) {
1644 
1645 		/* perform build phase. */
1646 		rc = acl_bld(&bcx, ctx, cfg, n);
1647 
1648 		if (rc == 0) {
1649 			/* allocate and fill run-time  structures. */
1650 			rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries,
1651 				bcx.num_tries, bcx.cfg.num_categories,
1652 				ACL_MAX_INDEXES * RTE_DIM(bcx.tries) *
1653 				sizeof(ctx->data_indexes[0]), max_size);
1654 			if (rc == 0) {
1655 				/* set data indexes. */
1656 				acl_set_data_indexes(ctx);
1657 
1658 				/* determine can we always do 4B load */
1659 				ctx->first_load_sz = get_first_load_size(cfg);
1660 
1661 				/* copy in build config. */
1662 				ctx->config = *cfg;
1663 			}
1664 		}
1665 
1666 		acl_build_log(&bcx);
1667 
1668 		/* cleanup after build. */
1669 		tb_free_pool(&bcx.pool);
1670 	}
1671 
1672 	return rc;
1673 }
1674