xref: /dpdk/lib/acl/acl_gen.c (revision ae67895b507bb6af22263c79ba0d5c374b396485)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_acl.h>
699a2dd95SBruce Richardson #include "acl.h"
773d85848SStephen Hemminger #include "acl_log.h"
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson #define	QRANGE_MIN	((uint8_t)INT8_MIN)
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #define	RTE_ACL_VERIFY(exp)	do {                                          \
1299a2dd95SBruce Richardson 	if (!(exp))                                                           \
1399a2dd95SBruce Richardson 		rte_panic("line %d\tassert \"" #exp "\" failed\n", __LINE__); \
1499a2dd95SBruce Richardson } while (0)
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson struct acl_node_counters {
1799a2dd95SBruce Richardson 	int32_t match;
1899a2dd95SBruce Richardson 	int32_t match_used;
1999a2dd95SBruce Richardson 	int32_t single;
2099a2dd95SBruce Richardson 	int32_t quad;
2199a2dd95SBruce Richardson 	int32_t quad_vectors;
2299a2dd95SBruce Richardson 	int32_t dfa;
2399a2dd95SBruce Richardson 	int32_t dfa_gr64;
2499a2dd95SBruce Richardson };
2599a2dd95SBruce Richardson 
2699a2dd95SBruce Richardson struct rte_acl_indices {
2799a2dd95SBruce Richardson 	int32_t dfa_index;
2899a2dd95SBruce Richardson 	int32_t quad_index;
2999a2dd95SBruce Richardson 	int32_t single_index;
3099a2dd95SBruce Richardson 	int32_t match_index;
3199a2dd95SBruce Richardson 	int32_t match_start;
3299a2dd95SBruce Richardson };
3399a2dd95SBruce Richardson 
3499a2dd95SBruce Richardson static void
acl_gen_log_stats(const struct rte_acl_ctx * ctx,const struct acl_node_counters * counts,const struct rte_acl_indices * indices,size_t max_size)3599a2dd95SBruce Richardson acl_gen_log_stats(const struct rte_acl_ctx *ctx,
3699a2dd95SBruce Richardson 	const struct acl_node_counters *counts,
3799a2dd95SBruce Richardson 	const struct rte_acl_indices *indices,
3899a2dd95SBruce Richardson 	size_t max_size)
3999a2dd95SBruce Richardson {
4099a2dd95SBruce Richardson 	RTE_LOG(DEBUG, ACL, "Gen phase for ACL \"%s\":\n"
4199a2dd95SBruce Richardson 		"runtime memory footprint on socket %d:\n"
4299a2dd95SBruce Richardson 		"single nodes/bytes used: %d/%zu\n"
4399a2dd95SBruce Richardson 		"quad nodes/vectors/bytes used: %d/%d/%zu\n"
4499a2dd95SBruce Richardson 		"DFA nodes/group64/bytes used: %d/%d/%zu\n"
4599a2dd95SBruce Richardson 		"match nodes/bytes used: %d/%zu\n"
4699a2dd95SBruce Richardson 		"total: %zu bytes\n"
4799a2dd95SBruce Richardson 		"max limit: %zu bytes\n",
4899a2dd95SBruce Richardson 		ctx->name, ctx->socket_id,
4999a2dd95SBruce Richardson 		counts->single, counts->single * sizeof(uint64_t),
5099a2dd95SBruce Richardson 		counts->quad, counts->quad_vectors,
5199a2dd95SBruce Richardson 		(indices->quad_index - indices->dfa_index) * sizeof(uint64_t),
5299a2dd95SBruce Richardson 		counts->dfa, counts->dfa_gr64,
5399a2dd95SBruce Richardson 		indices->dfa_index * sizeof(uint64_t),
5499a2dd95SBruce Richardson 		counts->match,
5599a2dd95SBruce Richardson 		counts->match * sizeof(struct rte_acl_match_results),
5699a2dd95SBruce Richardson 		ctx->mem_sz,
5799a2dd95SBruce Richardson 		max_size);
5899a2dd95SBruce Richardson }
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson static uint64_t
acl_dfa_gen_idx(const struct rte_acl_node * node,uint32_t index)6199a2dd95SBruce Richardson acl_dfa_gen_idx(const struct rte_acl_node *node, uint32_t index)
6299a2dd95SBruce Richardson {
6399a2dd95SBruce Richardson 	uint64_t idx;
6499a2dd95SBruce Richardson 	uint32_t i;
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson 	idx = 0;
6799a2dd95SBruce Richardson 	for (i = 0; i != RTE_DIM(node->dfa_gr64); i++) {
6899a2dd95SBruce Richardson 		RTE_ACL_VERIFY(node->dfa_gr64[i] < RTE_ACL_DFA_GR64_NUM);
6999a2dd95SBruce Richardson 		RTE_ACL_VERIFY(node->dfa_gr64[i] < node->fanout);
7099a2dd95SBruce Richardson 		idx |= (i - node->dfa_gr64[i]) <<
7199a2dd95SBruce Richardson 			(6 + RTE_ACL_DFA_GR64_BIT * i);
7299a2dd95SBruce Richardson 	}
7399a2dd95SBruce Richardson 
7499a2dd95SBruce Richardson 	return idx << (CHAR_BIT * sizeof(index)) | index | node->node_type;
7599a2dd95SBruce Richardson }
7699a2dd95SBruce Richardson 
7799a2dd95SBruce Richardson static void
acl_dfa_fill_gr64(const struct rte_acl_node * node,const uint64_t src[RTE_ACL_DFA_SIZE],uint64_t dst[RTE_ACL_DFA_SIZE])7899a2dd95SBruce Richardson acl_dfa_fill_gr64(const struct rte_acl_node *node,
7999a2dd95SBruce Richardson 	const uint64_t src[RTE_ACL_DFA_SIZE], uint64_t dst[RTE_ACL_DFA_SIZE])
8099a2dd95SBruce Richardson {
8199a2dd95SBruce Richardson 	uint32_t i;
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 	for (i = 0; i != RTE_DIM(node->dfa_gr64); i++) {
8499a2dd95SBruce Richardson 		memcpy(dst + node->dfa_gr64[i] * RTE_ACL_DFA_GR64_SIZE,
8599a2dd95SBruce Richardson 			src + i * RTE_ACL_DFA_GR64_SIZE,
8699a2dd95SBruce Richardson 			RTE_ACL_DFA_GR64_SIZE * sizeof(dst[0]));
8799a2dd95SBruce Richardson 	}
8899a2dd95SBruce Richardson }
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson static uint32_t
acl_dfa_count_gr64(const uint64_t array_ptr[RTE_ACL_DFA_SIZE],uint8_t gr64[RTE_ACL_DFA_GR64_NUM])9199a2dd95SBruce Richardson acl_dfa_count_gr64(const uint64_t array_ptr[RTE_ACL_DFA_SIZE],
9299a2dd95SBruce Richardson 	uint8_t gr64[RTE_ACL_DFA_GR64_NUM])
9399a2dd95SBruce Richardson {
9499a2dd95SBruce Richardson 	uint32_t i, j, k;
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson 	k = 0;
9799a2dd95SBruce Richardson 	for (i = 0; i != RTE_ACL_DFA_GR64_NUM; i++) {
9899a2dd95SBruce Richardson 		gr64[i] = i;
9999a2dd95SBruce Richardson 		for (j = 0; j != i; j++) {
10099a2dd95SBruce Richardson 			if (memcmp(array_ptr + i * RTE_ACL_DFA_GR64_SIZE,
10199a2dd95SBruce Richardson 					array_ptr + j * RTE_ACL_DFA_GR64_SIZE,
10299a2dd95SBruce Richardson 					RTE_ACL_DFA_GR64_SIZE *
10399a2dd95SBruce Richardson 					sizeof(array_ptr[0])) == 0)
10499a2dd95SBruce Richardson 				break;
10599a2dd95SBruce Richardson 		}
10699a2dd95SBruce Richardson 		gr64[i] = (j != i) ? gr64[j] : k++;
10799a2dd95SBruce Richardson 	}
10899a2dd95SBruce Richardson 
10999a2dd95SBruce Richardson 	return k;
11099a2dd95SBruce Richardson }
11199a2dd95SBruce Richardson 
11299a2dd95SBruce Richardson static uint32_t
acl_node_fill_dfa(const struct rte_acl_node * node,uint64_t dfa[RTE_ACL_DFA_SIZE],uint64_t no_match,int32_t resolved)11399a2dd95SBruce Richardson acl_node_fill_dfa(const struct rte_acl_node *node,
11499a2dd95SBruce Richardson 	uint64_t dfa[RTE_ACL_DFA_SIZE], uint64_t no_match, int32_t resolved)
11599a2dd95SBruce Richardson {
11699a2dd95SBruce Richardson 	uint32_t n, x;
11799a2dd95SBruce Richardson 	uint32_t ranges, last_bit;
11899a2dd95SBruce Richardson 	struct rte_acl_node *child;
11999a2dd95SBruce Richardson 	struct rte_acl_bitset *bits;
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson 	ranges = 0;
12299a2dd95SBruce Richardson 	last_bit = 0;
12399a2dd95SBruce Richardson 
12499a2dd95SBruce Richardson 	for (n = 0; n < RTE_ACL_DFA_SIZE; n++)
12599a2dd95SBruce Richardson 		dfa[n] = no_match;
12699a2dd95SBruce Richardson 
12799a2dd95SBruce Richardson 	for (x = 0; x < node->num_ptrs; x++) {
12899a2dd95SBruce Richardson 
12999a2dd95SBruce Richardson 		child = node->ptrs[x].ptr;
13099a2dd95SBruce Richardson 		if (child == NULL)
13199a2dd95SBruce Richardson 			continue;
13299a2dd95SBruce Richardson 
13399a2dd95SBruce Richardson 		bits = &node->ptrs[x].values;
13499a2dd95SBruce Richardson 		for (n = 0; n < RTE_ACL_DFA_SIZE; n++) {
13599a2dd95SBruce Richardson 
13699a2dd95SBruce Richardson 			if (bits->bits[n / (sizeof(bits_t) * CHAR_BIT)] &
13799a2dd95SBruce Richardson 				(1U << (n % (sizeof(bits_t) * CHAR_BIT)))) {
13899a2dd95SBruce Richardson 
13999a2dd95SBruce Richardson 				dfa[n] = resolved ? child->node_index : x;
14099a2dd95SBruce Richardson 				ranges += (last_bit == 0);
14199a2dd95SBruce Richardson 				last_bit = 1;
14299a2dd95SBruce Richardson 			} else {
14399a2dd95SBruce Richardson 				last_bit = 0;
14499a2dd95SBruce Richardson 			}
14599a2dd95SBruce Richardson 		}
14699a2dd95SBruce Richardson 	}
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	return ranges;
14999a2dd95SBruce Richardson }
15099a2dd95SBruce Richardson 
15199a2dd95SBruce Richardson /*
152d5d13ef9SThomas Monjalon  * Count the number of groups of sequential bits that are either 0 or 1,
153d5d13ef9SThomas Monjalon  * as specified by the zero_one parameter.
154d5d13ef9SThomas Monjalon  * This is used to calculate the number of ranges in a node
155d5d13ef9SThomas Monjalon  * to see if it fits in a quad range node.
15699a2dd95SBruce Richardson  */
15799a2dd95SBruce Richardson static int
acl_count_sequential_groups(struct rte_acl_bitset * bits,int zero_one)15899a2dd95SBruce Richardson acl_count_sequential_groups(struct rte_acl_bitset *bits, int zero_one)
15999a2dd95SBruce Richardson {
16099a2dd95SBruce Richardson 	int n, ranges, last_bit;
16199a2dd95SBruce Richardson 
16299a2dd95SBruce Richardson 	ranges = 0;
16399a2dd95SBruce Richardson 	last_bit = zero_one ^ 1;
16499a2dd95SBruce Richardson 
16599a2dd95SBruce Richardson 	for (n = QRANGE_MIN; n < UINT8_MAX + 1; n++) {
16699a2dd95SBruce Richardson 		if (bits->bits[n / (sizeof(bits_t) * 8)] &
16799a2dd95SBruce Richardson 				(1U << (n % (sizeof(bits_t) * 8)))) {
16899a2dd95SBruce Richardson 			if (zero_one == 1 && last_bit != 1)
16999a2dd95SBruce Richardson 				ranges++;
17099a2dd95SBruce Richardson 			last_bit = 1;
17199a2dd95SBruce Richardson 		} else {
17299a2dd95SBruce Richardson 			if (zero_one == 0 && last_bit != 0)
17399a2dd95SBruce Richardson 				ranges++;
17499a2dd95SBruce Richardson 			last_bit = 0;
17599a2dd95SBruce Richardson 		}
17699a2dd95SBruce Richardson 	}
17799a2dd95SBruce Richardson 	for (n = 0; n < QRANGE_MIN; n++) {
17899a2dd95SBruce Richardson 		if (bits->bits[n / (sizeof(bits_t) * 8)] &
17999a2dd95SBruce Richardson 				(1U << (n % (sizeof(bits_t) * CHAR_BIT)))) {
18099a2dd95SBruce Richardson 			if (zero_one == 1 && last_bit != 1)
18199a2dd95SBruce Richardson 				ranges++;
18299a2dd95SBruce Richardson 			last_bit = 1;
18399a2dd95SBruce Richardson 		} else {
18499a2dd95SBruce Richardson 			if (zero_one == 0 && last_bit != 0)
18599a2dd95SBruce Richardson 				ranges++;
18699a2dd95SBruce Richardson 			last_bit = 0;
18799a2dd95SBruce Richardson 		}
18899a2dd95SBruce Richardson 	}
18999a2dd95SBruce Richardson 
19099a2dd95SBruce Richardson 	return ranges;
19199a2dd95SBruce Richardson }
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson /*
19499a2dd95SBruce Richardson  * Count number of ranges spanned by the node's pointers
19599a2dd95SBruce Richardson  */
19699a2dd95SBruce Richardson static int
acl_count_fanout(struct rte_acl_node * node)19799a2dd95SBruce Richardson acl_count_fanout(struct rte_acl_node *node)
19899a2dd95SBruce Richardson {
19999a2dd95SBruce Richardson 	uint32_t n;
20099a2dd95SBruce Richardson 	int ranges;
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson 	if (node->fanout != 0)
20399a2dd95SBruce Richardson 		return node->fanout;
20499a2dd95SBruce Richardson 
20599a2dd95SBruce Richardson 	ranges = acl_count_sequential_groups(&node->values, 0);
20699a2dd95SBruce Richardson 
20799a2dd95SBruce Richardson 	for (n = 0; n < node->num_ptrs; n++) {
20899a2dd95SBruce Richardson 		if (node->ptrs[n].ptr != NULL)
20999a2dd95SBruce Richardson 			ranges += acl_count_sequential_groups(
21099a2dd95SBruce Richardson 				&node->ptrs[n].values, 1);
21199a2dd95SBruce Richardson 	}
21299a2dd95SBruce Richardson 
21399a2dd95SBruce Richardson 	node->fanout = ranges;
21499a2dd95SBruce Richardson 	return node->fanout;
21599a2dd95SBruce Richardson }
21699a2dd95SBruce Richardson 
21799a2dd95SBruce Richardson /*
21899a2dd95SBruce Richardson  * Determine the type of nodes and count each type
21999a2dd95SBruce Richardson  */
22099a2dd95SBruce Richardson static void
acl_count_trie_types(struct acl_node_counters * counts,struct rte_acl_node * node,uint64_t no_match,int force_dfa)22199a2dd95SBruce Richardson acl_count_trie_types(struct acl_node_counters *counts,
22299a2dd95SBruce Richardson 	struct rte_acl_node *node, uint64_t no_match, int force_dfa)
22399a2dd95SBruce Richardson {
22499a2dd95SBruce Richardson 	uint32_t n;
22599a2dd95SBruce Richardson 	int num_ptrs;
22699a2dd95SBruce Richardson 	uint64_t dfa[RTE_ACL_DFA_SIZE];
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson 	/* skip if this node has been counted */
22999a2dd95SBruce Richardson 	if (node->node_type != (uint32_t)RTE_ACL_NODE_UNDEFINED)
23099a2dd95SBruce Richardson 		return;
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson 	if (node->match_flag != 0 || node->num_ptrs == 0) {
23399a2dd95SBruce Richardson 		counts->match++;
23499a2dd95SBruce Richardson 		node->node_type = RTE_ACL_NODE_MATCH;
23599a2dd95SBruce Richardson 		return;
23699a2dd95SBruce Richardson 	}
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 	num_ptrs = acl_count_fanout(node);
23999a2dd95SBruce Richardson 
24099a2dd95SBruce Richardson 	/* Force type to dfa */
24199a2dd95SBruce Richardson 	if (force_dfa)
24299a2dd95SBruce Richardson 		num_ptrs = RTE_ACL_DFA_SIZE;
24399a2dd95SBruce Richardson 
24499a2dd95SBruce Richardson 	/* determine node type based on number of ranges */
24599a2dd95SBruce Richardson 	if (num_ptrs == 1) {
24699a2dd95SBruce Richardson 		counts->single++;
24799a2dd95SBruce Richardson 		node->node_type = RTE_ACL_NODE_SINGLE;
24899a2dd95SBruce Richardson 	} else if (num_ptrs <= RTE_ACL_QUAD_MAX) {
24999a2dd95SBruce Richardson 		counts->quad++;
25099a2dd95SBruce Richardson 		counts->quad_vectors += node->fanout;
25199a2dd95SBruce Richardson 		node->node_type = RTE_ACL_NODE_QRANGE;
25299a2dd95SBruce Richardson 	} else {
25399a2dd95SBruce Richardson 		counts->dfa++;
25499a2dd95SBruce Richardson 		node->node_type = RTE_ACL_NODE_DFA;
25599a2dd95SBruce Richardson 		if (force_dfa != 0) {
25699a2dd95SBruce Richardson 			/* always expand to a max number of nodes. */
25799a2dd95SBruce Richardson 			for (n = 0; n != RTE_DIM(node->dfa_gr64); n++)
25899a2dd95SBruce Richardson 				node->dfa_gr64[n] = n;
25999a2dd95SBruce Richardson 			node->fanout = n;
26099a2dd95SBruce Richardson 		} else {
26199a2dd95SBruce Richardson 			acl_node_fill_dfa(node, dfa, no_match, 0);
26299a2dd95SBruce Richardson 			node->fanout = acl_dfa_count_gr64(dfa, node->dfa_gr64);
26399a2dd95SBruce Richardson 		}
26499a2dd95SBruce Richardson 		counts->dfa_gr64 += node->fanout;
26599a2dd95SBruce Richardson 	}
26699a2dd95SBruce Richardson 
26799a2dd95SBruce Richardson 	/*
26899a2dd95SBruce Richardson 	 * recursively count the types of all children
26999a2dd95SBruce Richardson 	 */
27099a2dd95SBruce Richardson 	for (n = 0; n < node->num_ptrs; n++) {
27199a2dd95SBruce Richardson 		if (node->ptrs[n].ptr != NULL)
27299a2dd95SBruce Richardson 			acl_count_trie_types(counts, node->ptrs[n].ptr,
27399a2dd95SBruce Richardson 				no_match, 0);
27499a2dd95SBruce Richardson 	}
27599a2dd95SBruce Richardson }
27699a2dd95SBruce Richardson 
27799a2dd95SBruce Richardson static void
acl_add_ptrs(struct rte_acl_node * node,uint64_t * node_array,uint64_t no_match,int resolved)27899a2dd95SBruce Richardson acl_add_ptrs(struct rte_acl_node *node, uint64_t *node_array, uint64_t no_match,
27999a2dd95SBruce Richardson 	int resolved)
28099a2dd95SBruce Richardson {
28199a2dd95SBruce Richardson 	uint32_t x;
28299a2dd95SBruce Richardson 	int32_t m;
28399a2dd95SBruce Richardson 	uint64_t *node_a, index, dfa[RTE_ACL_DFA_SIZE];
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson 	acl_node_fill_dfa(node, dfa, no_match, resolved);
28699a2dd95SBruce Richardson 
28799a2dd95SBruce Richardson 	/*
28899a2dd95SBruce Richardson 	 * Rather than going from 0 to 256, the range count and
28999a2dd95SBruce Richardson 	 * the layout are from 80-ff then 0-7f due to signed compare
29099a2dd95SBruce Richardson 	 * for SSE (cmpgt).
29199a2dd95SBruce Richardson 	 */
29299a2dd95SBruce Richardson 	if (node->node_type == RTE_ACL_NODE_QRANGE) {
29399a2dd95SBruce Richardson 
29499a2dd95SBruce Richardson 		m = 0;
29599a2dd95SBruce Richardson 		node_a = node_array;
29699a2dd95SBruce Richardson 		index = dfa[QRANGE_MIN];
29799a2dd95SBruce Richardson 		*node_a++ = index;
29899a2dd95SBruce Richardson 
29999a2dd95SBruce Richardson 		for (x = QRANGE_MIN + 1; x < UINT8_MAX + 1; x++) {
30099a2dd95SBruce Richardson 			if (dfa[x] != index) {
30199a2dd95SBruce Richardson 				index = dfa[x];
30299a2dd95SBruce Richardson 				*node_a++ = index;
30399a2dd95SBruce Richardson 				node->transitions[m++] = (uint8_t)(x - 1);
30499a2dd95SBruce Richardson 			}
30599a2dd95SBruce Richardson 		}
30699a2dd95SBruce Richardson 
30799a2dd95SBruce Richardson 		for (x = 0; x < INT8_MAX + 1; x++) {
30899a2dd95SBruce Richardson 			if (dfa[x] != index) {
30999a2dd95SBruce Richardson 				index = dfa[x];
31099a2dd95SBruce Richardson 				*node_a++ = index;
31199a2dd95SBruce Richardson 				node->transitions[m++] = (uint8_t)(x - 1);
31299a2dd95SBruce Richardson 			}
31399a2dd95SBruce Richardson 		}
31499a2dd95SBruce Richardson 
31599a2dd95SBruce Richardson 		/* fill unused locations with max value - nothing is greater */
31699a2dd95SBruce Richardson 		for (; m < RTE_ACL_QUAD_SIZE; m++)
31799a2dd95SBruce Richardson 			node->transitions[m] = INT8_MAX;
31899a2dd95SBruce Richardson 
31999a2dd95SBruce Richardson 		RTE_ACL_VERIFY(m <= RTE_ACL_QUAD_SIZE);
32099a2dd95SBruce Richardson 
32199a2dd95SBruce Richardson 	} else if (node->node_type == RTE_ACL_NODE_DFA && resolved) {
32299a2dd95SBruce Richardson 		acl_dfa_fill_gr64(node, dfa, node_array);
32399a2dd95SBruce Richardson 	}
32499a2dd95SBruce Richardson }
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson /*
32799a2dd95SBruce Richardson  * Routine that allocates space for this node and recursively calls
32899a2dd95SBruce Richardson  * to allocate space for each child. Once all the children are allocated,
32999a2dd95SBruce Richardson  * then resolve all transitions for this node.
33099a2dd95SBruce Richardson  */
33199a2dd95SBruce Richardson static void
acl_gen_node(struct rte_acl_node * node,uint64_t * node_array,uint64_t no_match,struct rte_acl_indices * index,int num_categories)33299a2dd95SBruce Richardson acl_gen_node(struct rte_acl_node *node, uint64_t *node_array,
33399a2dd95SBruce Richardson 	uint64_t no_match, struct rte_acl_indices *index, int num_categories)
33499a2dd95SBruce Richardson {
33599a2dd95SBruce Richardson 	uint32_t n, sz, *qtrp;
33699a2dd95SBruce Richardson 	uint64_t *array_ptr;
33799a2dd95SBruce Richardson 	struct rte_acl_match_results *match;
33899a2dd95SBruce Richardson 
33999a2dd95SBruce Richardson 	if (node->node_index != RTE_ACL_NODE_UNDEFINED)
34099a2dd95SBruce Richardson 		return;
34199a2dd95SBruce Richardson 
34299a2dd95SBruce Richardson 	array_ptr = NULL;
34399a2dd95SBruce Richardson 
34499a2dd95SBruce Richardson 	switch (node->node_type) {
34599a2dd95SBruce Richardson 	case RTE_ACL_NODE_DFA:
34699a2dd95SBruce Richardson 		array_ptr = &node_array[index->dfa_index];
34799a2dd95SBruce Richardson 		node->node_index = acl_dfa_gen_idx(node, index->dfa_index);
34899a2dd95SBruce Richardson 		sz = node->fanout * RTE_ACL_DFA_GR64_SIZE;
34999a2dd95SBruce Richardson 		index->dfa_index += sz;
35099a2dd95SBruce Richardson 		for (n = 0; n < sz; n++)
35199a2dd95SBruce Richardson 			array_ptr[n] = no_match;
35299a2dd95SBruce Richardson 		break;
35399a2dd95SBruce Richardson 	case RTE_ACL_NODE_SINGLE:
35499a2dd95SBruce Richardson 		node->node_index = RTE_ACL_QUAD_SINGLE | index->single_index |
35599a2dd95SBruce Richardson 			node->node_type;
35699a2dd95SBruce Richardson 		array_ptr = &node_array[index->single_index];
35799a2dd95SBruce Richardson 		index->single_index += 1;
35899a2dd95SBruce Richardson 		array_ptr[0] = no_match;
35999a2dd95SBruce Richardson 		break;
36099a2dd95SBruce Richardson 	case RTE_ACL_NODE_QRANGE:
36199a2dd95SBruce Richardson 		array_ptr = &node_array[index->quad_index];
36299a2dd95SBruce Richardson 		acl_add_ptrs(node, array_ptr, no_match, 0);
36399a2dd95SBruce Richardson 		qtrp = (uint32_t *)node->transitions;
36499a2dd95SBruce Richardson 		node->node_index = qtrp[0];
36599a2dd95SBruce Richardson 		node->node_index <<= sizeof(index->quad_index) * CHAR_BIT;
36699a2dd95SBruce Richardson 		node->node_index |= index->quad_index | node->node_type;
36799a2dd95SBruce Richardson 		index->quad_index += node->fanout;
36899a2dd95SBruce Richardson 		break;
36999a2dd95SBruce Richardson 	case RTE_ACL_NODE_MATCH:
37099a2dd95SBruce Richardson 		match = ((struct rte_acl_match_results *)
37199a2dd95SBruce Richardson 			(node_array + index->match_start));
37299a2dd95SBruce Richardson 		for (n = 0; n != RTE_DIM(match->results); n++)
37399a2dd95SBruce Richardson 			RTE_ACL_VERIFY(match->results[0] == 0);
37499a2dd95SBruce Richardson 		memcpy(match + index->match_index, node->mrt,
37599a2dd95SBruce Richardson 			sizeof(*node->mrt));
37699a2dd95SBruce Richardson 		node->node_index = index->match_index | node->node_type;
37799a2dd95SBruce Richardson 		index->match_index += 1;
37899a2dd95SBruce Richardson 		break;
37999a2dd95SBruce Richardson 	case RTE_ACL_NODE_UNDEFINED:
38099a2dd95SBruce Richardson 		RTE_ACL_VERIFY(node->node_type !=
38199a2dd95SBruce Richardson 			(uint32_t)RTE_ACL_NODE_UNDEFINED);
38299a2dd95SBruce Richardson 		break;
38399a2dd95SBruce Richardson 	}
38499a2dd95SBruce Richardson 
38599a2dd95SBruce Richardson 	/* recursively allocate space for all children */
38699a2dd95SBruce Richardson 	for (n = 0; n < node->num_ptrs; n++) {
38799a2dd95SBruce Richardson 		if (node->ptrs[n].ptr != NULL)
38899a2dd95SBruce Richardson 			acl_gen_node(node->ptrs[n].ptr,
38999a2dd95SBruce Richardson 				node_array,
39099a2dd95SBruce Richardson 				no_match,
39199a2dd95SBruce Richardson 				index,
39299a2dd95SBruce Richardson 				num_categories);
39399a2dd95SBruce Richardson 	}
39499a2dd95SBruce Richardson 
39599a2dd95SBruce Richardson 	/* All children are resolved, resolve this node's pointers */
39699a2dd95SBruce Richardson 	switch (node->node_type) {
39799a2dd95SBruce Richardson 	case RTE_ACL_NODE_DFA:
39899a2dd95SBruce Richardson 		acl_add_ptrs(node, array_ptr, no_match, 1);
39999a2dd95SBruce Richardson 		break;
40099a2dd95SBruce Richardson 	case RTE_ACL_NODE_SINGLE:
40199a2dd95SBruce Richardson 		for (n = 0; n < node->num_ptrs; n++) {
40299a2dd95SBruce Richardson 			if (node->ptrs[n].ptr != NULL)
40399a2dd95SBruce Richardson 				array_ptr[0] = node->ptrs[n].ptr->node_index;
40499a2dd95SBruce Richardson 		}
40599a2dd95SBruce Richardson 		break;
40699a2dd95SBruce Richardson 	case RTE_ACL_NODE_QRANGE:
40799a2dd95SBruce Richardson 		acl_add_ptrs(node, array_ptr, no_match, 1);
40899a2dd95SBruce Richardson 		break;
40999a2dd95SBruce Richardson 	case RTE_ACL_NODE_MATCH:
41099a2dd95SBruce Richardson 		break;
41199a2dd95SBruce Richardson 	case RTE_ACL_NODE_UNDEFINED:
41299a2dd95SBruce Richardson 		RTE_ACL_VERIFY(node->node_type !=
41399a2dd95SBruce Richardson 			(uint32_t)RTE_ACL_NODE_UNDEFINED);
41499a2dd95SBruce Richardson 		break;
41599a2dd95SBruce Richardson 	}
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson 
41899a2dd95SBruce Richardson static void
acl_calc_counts_indices(struct acl_node_counters * counts,struct rte_acl_indices * indices,struct rte_acl_bld_trie * node_bld_trie,uint32_t num_tries,uint64_t no_match)41999a2dd95SBruce Richardson acl_calc_counts_indices(struct acl_node_counters *counts,
42099a2dd95SBruce Richardson 	struct rte_acl_indices *indices,
42199a2dd95SBruce Richardson 	struct rte_acl_bld_trie *node_bld_trie, uint32_t num_tries,
42299a2dd95SBruce Richardson 	uint64_t no_match)
42399a2dd95SBruce Richardson {
42499a2dd95SBruce Richardson 	uint32_t n;
42599a2dd95SBruce Richardson 
42699a2dd95SBruce Richardson 	memset(indices, 0, sizeof(*indices));
42799a2dd95SBruce Richardson 	memset(counts, 0, sizeof(*counts));
42899a2dd95SBruce Richardson 
42999a2dd95SBruce Richardson 	/* Get stats on nodes */
43099a2dd95SBruce Richardson 	for (n = 0; n < num_tries; n++) {
43199a2dd95SBruce Richardson 		acl_count_trie_types(counts, node_bld_trie[n].trie,
43299a2dd95SBruce Richardson 			no_match, 1);
43399a2dd95SBruce Richardson 	}
43499a2dd95SBruce Richardson 
43599a2dd95SBruce Richardson 	indices->dfa_index = RTE_ACL_DFA_SIZE + 1;
43699a2dd95SBruce Richardson 	indices->quad_index = indices->dfa_index +
43799a2dd95SBruce Richardson 		counts->dfa_gr64 * RTE_ACL_DFA_GR64_SIZE;
43899a2dd95SBruce Richardson 	indices->single_index = indices->quad_index + counts->quad_vectors;
43999a2dd95SBruce Richardson 	indices->match_start = indices->single_index + counts->single + 1;
44099a2dd95SBruce Richardson 	indices->match_start = RTE_ALIGN(indices->match_start,
44199a2dd95SBruce Richardson 		(XMM_SIZE / sizeof(uint64_t)));
44299a2dd95SBruce Richardson 	indices->match_index = 1;
44399a2dd95SBruce Richardson }
44499a2dd95SBruce Richardson 
44599a2dd95SBruce Richardson /*
44699a2dd95SBruce Richardson  * Generate the runtime structure using build structure
44799a2dd95SBruce Richardson  */
44899a2dd95SBruce Richardson int
rte_acl_gen(struct rte_acl_ctx * ctx,struct rte_acl_trie * trie,struct rte_acl_bld_trie * node_bld_trie,uint32_t num_tries,uint32_t num_categories,uint32_t data_index_sz,size_t max_size)44999a2dd95SBruce Richardson rte_acl_gen(struct rte_acl_ctx *ctx, struct rte_acl_trie *trie,
45099a2dd95SBruce Richardson 	struct rte_acl_bld_trie *node_bld_trie, uint32_t num_tries,
45199a2dd95SBruce Richardson 	uint32_t num_categories, uint32_t data_index_sz, size_t max_size)
45299a2dd95SBruce Richardson {
45399a2dd95SBruce Richardson 	void *mem;
45499a2dd95SBruce Richardson 	size_t total_size;
45599a2dd95SBruce Richardson 	uint64_t *node_array, no_match;
45699a2dd95SBruce Richardson 	uint32_t n, match_index;
45799a2dd95SBruce Richardson 	struct rte_acl_match_results *match;
45899a2dd95SBruce Richardson 	struct acl_node_counters counts;
45999a2dd95SBruce Richardson 	struct rte_acl_indices indices;
46099a2dd95SBruce Richardson 
46199a2dd95SBruce Richardson 	no_match = RTE_ACL_NODE_MATCH;
46299a2dd95SBruce Richardson 
46399a2dd95SBruce Richardson 	/* Fill counts and indices arrays from the nodes. */
46499a2dd95SBruce Richardson 	acl_calc_counts_indices(&counts, &indices,
46599a2dd95SBruce Richardson 		node_bld_trie, num_tries, no_match);
46699a2dd95SBruce Richardson 
46799a2dd95SBruce Richardson 	/* Allocate runtime memory (align to cache boundary) */
46899a2dd95SBruce Richardson 	total_size = RTE_ALIGN(data_index_sz, RTE_CACHE_LINE_SIZE) +
46999a2dd95SBruce Richardson 		indices.match_start * sizeof(uint64_t) +
47099a2dd95SBruce Richardson 		(counts.match + 1) * sizeof(struct rte_acl_match_results) +
47199a2dd95SBruce Richardson 		XMM_SIZE;
47299a2dd95SBruce Richardson 
47399a2dd95SBruce Richardson 	if (total_size > max_size) {
474*ae67895bSDavid Marchand 		ACL_LOG(DEBUG,
47599a2dd95SBruce Richardson 			"Gen phase for ACL ctx \"%s\" exceeds max_size limit, "
476*ae67895bSDavid Marchand 			"bytes required: %zu, allowed: %zu",
47799a2dd95SBruce Richardson 			ctx->name, total_size, max_size);
47899a2dd95SBruce Richardson 		return -ERANGE;
47999a2dd95SBruce Richardson 	}
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson 	mem = rte_zmalloc_socket(ctx->name, total_size, RTE_CACHE_LINE_SIZE,
48299a2dd95SBruce Richardson 			ctx->socket_id);
48399a2dd95SBruce Richardson 	if (mem == NULL) {
484*ae67895bSDavid Marchand 		ACL_LOG(ERR,
485*ae67895bSDavid Marchand 			"allocation of %zu bytes on socket %d for %s failed",
48699a2dd95SBruce Richardson 			total_size, ctx->socket_id, ctx->name);
48799a2dd95SBruce Richardson 		return -ENOMEM;
48899a2dd95SBruce Richardson 	}
48999a2dd95SBruce Richardson 
49099a2dd95SBruce Richardson 	/* Fill the runtime structure */
49199a2dd95SBruce Richardson 	match_index = indices.match_start;
49299a2dd95SBruce Richardson 	node_array = (uint64_t *)((uintptr_t)mem +
49399a2dd95SBruce Richardson 		RTE_ALIGN(data_index_sz, RTE_CACHE_LINE_SIZE));
49499a2dd95SBruce Richardson 
49599a2dd95SBruce Richardson 	/*
49699a2dd95SBruce Richardson 	 * Setup the NOMATCH node (a SINGLE at the
49799a2dd95SBruce Richardson 	 * highest index, that points to itself)
49899a2dd95SBruce Richardson 	 */
49999a2dd95SBruce Richardson 
50099a2dd95SBruce Richardson 	node_array[RTE_ACL_DFA_SIZE] = RTE_ACL_IDLE_NODE;
50199a2dd95SBruce Richardson 
50299a2dd95SBruce Richardson 	for (n = 0; n < RTE_ACL_DFA_SIZE; n++)
50399a2dd95SBruce Richardson 		node_array[n] = no_match;
50499a2dd95SBruce Richardson 
50599a2dd95SBruce Richardson 	/* NOMATCH result at index 0 */
50699a2dd95SBruce Richardson 	match = ((struct rte_acl_match_results *)(node_array + match_index));
50799a2dd95SBruce Richardson 	memset(match, 0, sizeof(*match));
50899a2dd95SBruce Richardson 
50999a2dd95SBruce Richardson 	for (n = 0; n < num_tries; n++) {
51099a2dd95SBruce Richardson 
51199a2dd95SBruce Richardson 		acl_gen_node(node_bld_trie[n].trie, node_array, no_match,
51299a2dd95SBruce Richardson 			&indices, num_categories);
51399a2dd95SBruce Richardson 
51499a2dd95SBruce Richardson 		if (node_bld_trie[n].trie->node_index == no_match)
51599a2dd95SBruce Richardson 			trie[n].root_index = 0;
51699a2dd95SBruce Richardson 		else
51799a2dd95SBruce Richardson 			trie[n].root_index = node_bld_trie[n].trie->node_index;
51899a2dd95SBruce Richardson 	}
51999a2dd95SBruce Richardson 
52099a2dd95SBruce Richardson 	ctx->mem = mem;
52199a2dd95SBruce Richardson 	ctx->mem_sz = total_size;
52299a2dd95SBruce Richardson 	ctx->data_indexes = mem;
52399a2dd95SBruce Richardson 	ctx->num_tries = num_tries;
52499a2dd95SBruce Richardson 	ctx->num_categories = num_categories;
52599a2dd95SBruce Richardson 	ctx->match_index = match_index;
52699a2dd95SBruce Richardson 	ctx->no_match = no_match;
52799a2dd95SBruce Richardson 	ctx->idle = node_array[RTE_ACL_DFA_SIZE];
52899a2dd95SBruce Richardson 	ctx->trans_table = node_array;
52999a2dd95SBruce Richardson 	memcpy(ctx->trie, trie, sizeof(ctx->trie));
53099a2dd95SBruce Richardson 
53199a2dd95SBruce Richardson 	acl_gen_log_stats(ctx, &counts, &indices, max_size);
53299a2dd95SBruce Richardson 	return 0;
53399a2dd95SBruce Richardson }
534