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