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>
673d85848SStephen Hemminger #include <rte_log.h>
773d85848SStephen Hemminger
899a2dd95SBruce Richardson #include "tb_mem.h"
999a2dd95SBruce Richardson #include "acl.h"
1073d85848SStephen Hemminger #include "acl_log.h"
1199a2dd95SBruce Richardson
1299a2dd95SBruce Richardson #define ACL_POOL_ALIGN 8
1399a2dd95SBruce Richardson #define ACL_POOL_ALLOC_MIN 0x800000
1499a2dd95SBruce Richardson
1599a2dd95SBruce Richardson /* number of pointers per alloc */
1699a2dd95SBruce Richardson #define ACL_PTR_ALLOC 32
1799a2dd95SBruce Richardson
1845109815SKonstantin Ananyev /* account for situation when all fields are 8B long */
1945109815SKonstantin Ananyev #define ACL_MAX_INDEXES (2 * RTE_ACL_MAX_FIELDS)
2045109815SKonstantin Ananyev
2199a2dd95SBruce Richardson /* macros for dividing rule sets heuristics */
2299a2dd95SBruce Richardson #define NODE_MAX 0x4000
2399a2dd95SBruce Richardson #define NODE_MIN 0x800
2499a2dd95SBruce Richardson
2599a2dd95SBruce Richardson /* TALLY are statistics per field */
2699a2dd95SBruce Richardson enum {
2799a2dd95SBruce Richardson TALLY_0 = 0, /* number of rules that are 0% or more wild. */
2899a2dd95SBruce Richardson TALLY_25, /* number of rules that are 25% or more wild. */
2999a2dd95SBruce Richardson TALLY_50,
3099a2dd95SBruce Richardson TALLY_75,
3199a2dd95SBruce Richardson TALLY_100,
3299a2dd95SBruce Richardson TALLY_DEACTIVATED, /* deactivated fields (100% wild in all rules). */
3399a2dd95SBruce Richardson TALLY_DEPTH,
3499a2dd95SBruce Richardson /* number of rules that are 100% wild for this field and higher. */
3599a2dd95SBruce Richardson TALLY_NUM
3699a2dd95SBruce Richardson };
3799a2dd95SBruce Richardson
3899a2dd95SBruce Richardson static const uint32_t wild_limits[TALLY_DEACTIVATED] = {0, 25, 50, 75, 100};
3999a2dd95SBruce Richardson
4099a2dd95SBruce Richardson enum {
4199a2dd95SBruce Richardson ACL_INTERSECT_NONE = 0,
4299a2dd95SBruce Richardson ACL_INTERSECT_A = 1, /* set A is a superset of A and B intersect */
4399a2dd95SBruce Richardson ACL_INTERSECT_B = 2, /* set B is a superset of A and B intersect */
4499a2dd95SBruce Richardson ACL_INTERSECT = 4, /* sets A and B intersect */
4599a2dd95SBruce Richardson };
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson enum {
4899a2dd95SBruce Richardson ACL_PRIORITY_EQUAL = 0,
4999a2dd95SBruce Richardson ACL_PRIORITY_NODE_A = 1,
5099a2dd95SBruce Richardson ACL_PRIORITY_NODE_B = 2,
5199a2dd95SBruce Richardson ACL_PRIORITY_MIXED = 3
5299a2dd95SBruce Richardson };
5399a2dd95SBruce Richardson
5499a2dd95SBruce Richardson
5599a2dd95SBruce Richardson struct acl_mem_block {
5699a2dd95SBruce Richardson uint32_t block_size;
5799a2dd95SBruce Richardson void *mem_ptr;
5899a2dd95SBruce Richardson };
5999a2dd95SBruce Richardson
6099a2dd95SBruce Richardson #define MEM_BLOCK_NUM 16
6199a2dd95SBruce Richardson
6299a2dd95SBruce Richardson /* Single ACL rule, build representation.*/
6399a2dd95SBruce Richardson struct rte_acl_build_rule {
6499a2dd95SBruce Richardson struct rte_acl_build_rule *next;
6599a2dd95SBruce Richardson struct rte_acl_config *config;
6699a2dd95SBruce Richardson /**< configuration for each field in the rule. */
6799a2dd95SBruce Richardson const struct rte_acl_rule *f;
6899a2dd95SBruce Richardson uint32_t *wildness;
6999a2dd95SBruce Richardson };
7099a2dd95SBruce Richardson
7199a2dd95SBruce Richardson /* Context for build phase */
7299a2dd95SBruce Richardson struct acl_build_context {
7399a2dd95SBruce Richardson const struct rte_acl_ctx *acx;
7499a2dd95SBruce Richardson struct rte_acl_build_rule *build_rules;
7599a2dd95SBruce Richardson struct rte_acl_config cfg;
7699a2dd95SBruce Richardson int32_t node_max;
7799a2dd95SBruce Richardson int32_t cur_node_max;
7899a2dd95SBruce Richardson uint32_t node;
7999a2dd95SBruce Richardson uint32_t num_nodes;
8099a2dd95SBruce Richardson uint32_t category_mask;
8199a2dd95SBruce Richardson uint32_t num_rules;
8299a2dd95SBruce Richardson uint32_t node_id;
8399a2dd95SBruce Richardson uint32_t src_mask;
8499a2dd95SBruce Richardson uint32_t num_build_rules;
8599a2dd95SBruce Richardson uint32_t num_tries;
8699a2dd95SBruce Richardson struct tb_mem_pool pool;
8799a2dd95SBruce Richardson struct rte_acl_trie tries[RTE_ACL_MAX_TRIES];
8899a2dd95SBruce Richardson struct rte_acl_bld_trie bld_tries[RTE_ACL_MAX_TRIES];
8945109815SKonstantin Ananyev uint32_t data_indexes[RTE_ACL_MAX_TRIES][ACL_MAX_INDEXES];
9099a2dd95SBruce Richardson
9199a2dd95SBruce Richardson /* memory free lists for nodes and blocks used for node ptrs */
9299a2dd95SBruce Richardson struct acl_mem_block blocks[MEM_BLOCK_NUM];
9399a2dd95SBruce Richardson struct rte_acl_node *node_free_list;
9499a2dd95SBruce Richardson };
9599a2dd95SBruce Richardson
9699a2dd95SBruce Richardson static int acl_merge_trie(struct acl_build_context *context,
9799a2dd95SBruce Richardson struct rte_acl_node *node_a, struct rte_acl_node *node_b,
9899a2dd95SBruce Richardson uint32_t level, struct rte_acl_node **node_c);
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson static void
10199a2dd95SBruce Richardson acl_deref_ptr(struct acl_build_context *context,
10299a2dd95SBruce Richardson struct rte_acl_node *node, int index);
10399a2dd95SBruce Richardson
10499a2dd95SBruce Richardson static void *
acl_build_alloc(struct acl_build_context * context,size_t n,size_t s)10599a2dd95SBruce Richardson acl_build_alloc(struct acl_build_context *context, size_t n, size_t s)
10699a2dd95SBruce Richardson {
10799a2dd95SBruce Richardson uint32_t m;
10899a2dd95SBruce Richardson void *p;
10999a2dd95SBruce Richardson size_t alloc_size = n * s;
11099a2dd95SBruce Richardson
11199a2dd95SBruce Richardson /*
11299a2dd95SBruce Richardson * look for memory in free lists
11399a2dd95SBruce Richardson */
11499a2dd95SBruce Richardson for (m = 0; m < RTE_DIM(context->blocks); m++) {
11599a2dd95SBruce Richardson if (context->blocks[m].block_size ==
11699a2dd95SBruce Richardson alloc_size && context->blocks[m].mem_ptr != NULL) {
11799a2dd95SBruce Richardson p = context->blocks[m].mem_ptr;
11899a2dd95SBruce Richardson context->blocks[m].mem_ptr = *((void **)p);
11999a2dd95SBruce Richardson memset(p, 0, alloc_size);
12099a2dd95SBruce Richardson return p;
12199a2dd95SBruce Richardson }
12299a2dd95SBruce Richardson }
12399a2dd95SBruce Richardson
12499a2dd95SBruce Richardson /*
12599a2dd95SBruce Richardson * return allocation from memory pool
12699a2dd95SBruce Richardson */
12799a2dd95SBruce Richardson p = tb_alloc(&context->pool, alloc_size);
12899a2dd95SBruce Richardson return p;
12999a2dd95SBruce Richardson }
13099a2dd95SBruce Richardson
13199a2dd95SBruce Richardson /*
13299a2dd95SBruce Richardson * Free memory blocks (kept in context for reuse).
13399a2dd95SBruce Richardson */
13499a2dd95SBruce Richardson static void
acl_build_free(struct acl_build_context * context,size_t s,void * p)13599a2dd95SBruce Richardson acl_build_free(struct acl_build_context *context, size_t s, void *p)
13699a2dd95SBruce Richardson {
13799a2dd95SBruce Richardson uint32_t n;
13899a2dd95SBruce Richardson
13999a2dd95SBruce Richardson for (n = 0; n < RTE_DIM(context->blocks); n++) {
14099a2dd95SBruce Richardson if (context->blocks[n].block_size == s) {
14199a2dd95SBruce Richardson *((void **)p) = context->blocks[n].mem_ptr;
14299a2dd95SBruce Richardson context->blocks[n].mem_ptr = p;
14399a2dd95SBruce Richardson return;
14499a2dd95SBruce Richardson }
14599a2dd95SBruce Richardson }
14699a2dd95SBruce Richardson for (n = 0; n < RTE_DIM(context->blocks); n++) {
14799a2dd95SBruce Richardson if (context->blocks[n].block_size == 0) {
14899a2dd95SBruce Richardson context->blocks[n].block_size = s;
14999a2dd95SBruce Richardson *((void **)p) = NULL;
15099a2dd95SBruce Richardson context->blocks[n].mem_ptr = p;
15199a2dd95SBruce Richardson return;
15299a2dd95SBruce Richardson }
15399a2dd95SBruce Richardson }
15499a2dd95SBruce Richardson }
15599a2dd95SBruce Richardson
15699a2dd95SBruce Richardson /*
15799a2dd95SBruce Richardson * Allocate and initialize a new node.
15899a2dd95SBruce Richardson */
15999a2dd95SBruce Richardson static struct rte_acl_node *
acl_alloc_node(struct acl_build_context * context,int level)16099a2dd95SBruce Richardson acl_alloc_node(struct acl_build_context *context, int level)
16199a2dd95SBruce Richardson {
16299a2dd95SBruce Richardson struct rte_acl_node *node;
16399a2dd95SBruce Richardson
16499a2dd95SBruce Richardson if (context->node_free_list != NULL) {
16599a2dd95SBruce Richardson node = context->node_free_list;
16699a2dd95SBruce Richardson context->node_free_list = node->next;
16799a2dd95SBruce Richardson memset(node, 0, sizeof(struct rte_acl_node));
16899a2dd95SBruce Richardson } else {
16999a2dd95SBruce Richardson node = acl_build_alloc(context, sizeof(struct rte_acl_node), 1);
17099a2dd95SBruce Richardson }
17199a2dd95SBruce Richardson
17299a2dd95SBruce Richardson if (node != NULL) {
17399a2dd95SBruce Richardson node->num_ptrs = 0;
17499a2dd95SBruce Richardson node->level = level;
17599a2dd95SBruce Richardson node->node_type = RTE_ACL_NODE_UNDEFINED;
17699a2dd95SBruce Richardson node->node_index = RTE_ACL_NODE_UNDEFINED;
17799a2dd95SBruce Richardson context->num_nodes++;
17899a2dd95SBruce Richardson node->id = context->node_id++;
17999a2dd95SBruce Richardson }
18099a2dd95SBruce Richardson return node;
18199a2dd95SBruce Richardson }
18299a2dd95SBruce Richardson
18399a2dd95SBruce Richardson /*
18499a2dd95SBruce Richardson * Dereference all nodes to which this node points
18599a2dd95SBruce Richardson */
18699a2dd95SBruce Richardson static void
acl_free_node(struct acl_build_context * context,struct rte_acl_node * node)18799a2dd95SBruce Richardson acl_free_node(struct acl_build_context *context,
18899a2dd95SBruce Richardson struct rte_acl_node *node)
18999a2dd95SBruce Richardson {
19099a2dd95SBruce Richardson uint32_t n;
19199a2dd95SBruce Richardson
19299a2dd95SBruce Richardson if (node->prev != NULL)
19399a2dd95SBruce Richardson node->prev->next = NULL;
19499a2dd95SBruce Richardson for (n = 0; n < node->num_ptrs; n++)
19599a2dd95SBruce Richardson acl_deref_ptr(context, node, n);
19699a2dd95SBruce Richardson
19799a2dd95SBruce Richardson /* free mrt if this is a match node */
19899a2dd95SBruce Richardson if (node->mrt != NULL) {
19999a2dd95SBruce Richardson acl_build_free(context, sizeof(struct rte_acl_match_results),
20099a2dd95SBruce Richardson node->mrt);
20199a2dd95SBruce Richardson node->mrt = NULL;
20299a2dd95SBruce Richardson }
20399a2dd95SBruce Richardson
20499a2dd95SBruce Richardson /* free transitions to other nodes */
20599a2dd95SBruce Richardson if (node->ptrs != NULL) {
20699a2dd95SBruce Richardson acl_build_free(context,
20799a2dd95SBruce Richardson node->max_ptrs * sizeof(struct rte_acl_ptr_set),
20899a2dd95SBruce Richardson node->ptrs);
20999a2dd95SBruce Richardson node->ptrs = NULL;
21099a2dd95SBruce Richardson }
21199a2dd95SBruce Richardson
21299a2dd95SBruce Richardson /* put it on the free list */
21399a2dd95SBruce Richardson context->num_nodes--;
21499a2dd95SBruce Richardson node->next = context->node_free_list;
21599a2dd95SBruce Richardson context->node_free_list = node;
21699a2dd95SBruce Richardson }
21799a2dd95SBruce Richardson
21899a2dd95SBruce Richardson
21999a2dd95SBruce Richardson /*
22099a2dd95SBruce Richardson * Include src bitset in dst bitset
22199a2dd95SBruce Richardson */
22299a2dd95SBruce Richardson static void
acl_include(struct rte_acl_bitset * dst,struct rte_acl_bitset * src,bits_t mask)22399a2dd95SBruce Richardson acl_include(struct rte_acl_bitset *dst, struct rte_acl_bitset *src, bits_t mask)
22499a2dd95SBruce Richardson {
22599a2dd95SBruce Richardson uint32_t n;
22699a2dd95SBruce Richardson
22799a2dd95SBruce Richardson for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
22899a2dd95SBruce Richardson dst->bits[n] = (dst->bits[n] & mask) | src->bits[n];
22999a2dd95SBruce Richardson }
23099a2dd95SBruce Richardson
23199a2dd95SBruce Richardson /*
23299a2dd95SBruce Richardson * Set dst to bits of src1 that are not in src2
23399a2dd95SBruce Richardson */
23499a2dd95SBruce Richardson static int
acl_exclude(struct rte_acl_bitset * dst,struct rte_acl_bitset * src1,struct rte_acl_bitset * src2)23599a2dd95SBruce Richardson acl_exclude(struct rte_acl_bitset *dst,
23699a2dd95SBruce Richardson struct rte_acl_bitset *src1,
23799a2dd95SBruce Richardson struct rte_acl_bitset *src2)
23899a2dd95SBruce Richardson {
23999a2dd95SBruce Richardson uint32_t n;
24099a2dd95SBruce Richardson bits_t all_bits = 0;
24199a2dd95SBruce Richardson
24299a2dd95SBruce Richardson for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
24399a2dd95SBruce Richardson dst->bits[n] = src1->bits[n] & ~src2->bits[n];
24499a2dd95SBruce Richardson all_bits |= dst->bits[n];
24599a2dd95SBruce Richardson }
24699a2dd95SBruce Richardson return all_bits != 0;
24799a2dd95SBruce Richardson }
24899a2dd95SBruce Richardson
24999a2dd95SBruce Richardson /*
25099a2dd95SBruce Richardson * Add a pointer (ptr) to a node.
25199a2dd95SBruce Richardson */
25299a2dd95SBruce Richardson 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)25399a2dd95SBruce Richardson acl_add_ptr(struct acl_build_context *context,
25499a2dd95SBruce Richardson struct rte_acl_node *node,
25599a2dd95SBruce Richardson struct rte_acl_node *ptr,
25699a2dd95SBruce Richardson struct rte_acl_bitset *bits)
25799a2dd95SBruce Richardson {
25899a2dd95SBruce Richardson uint32_t n, num_ptrs;
25999a2dd95SBruce Richardson struct rte_acl_ptr_set *ptrs = NULL;
26099a2dd95SBruce Richardson
26199a2dd95SBruce Richardson /*
26299a2dd95SBruce Richardson * If there's already a pointer to the same node, just add to the bitset
26399a2dd95SBruce Richardson */
26499a2dd95SBruce Richardson for (n = 0; n < node->num_ptrs; n++) {
26599a2dd95SBruce Richardson if (node->ptrs[n].ptr != NULL) {
26699a2dd95SBruce Richardson if (node->ptrs[n].ptr == ptr) {
26799a2dd95SBruce Richardson acl_include(&node->ptrs[n].values, bits, -1);
26899a2dd95SBruce Richardson acl_include(&node->values, bits, -1);
26999a2dd95SBruce Richardson return 0;
27099a2dd95SBruce Richardson }
27199a2dd95SBruce Richardson }
27299a2dd95SBruce Richardson }
27399a2dd95SBruce Richardson
27499a2dd95SBruce Richardson /* if there's no room for another pointer, make room */
27599a2dd95SBruce Richardson if (node->num_ptrs >= node->max_ptrs) {
27699a2dd95SBruce Richardson /* add room for more pointers */
27799a2dd95SBruce Richardson num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
27899a2dd95SBruce Richardson ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
27999a2dd95SBruce Richardson
28099a2dd95SBruce Richardson /* copy current points to new memory allocation */
28199a2dd95SBruce Richardson if (node->ptrs != NULL) {
28299a2dd95SBruce Richardson memcpy(ptrs, node->ptrs,
28399a2dd95SBruce Richardson node->num_ptrs * sizeof(*ptrs));
28499a2dd95SBruce Richardson acl_build_free(context, node->max_ptrs * sizeof(*ptrs),
28599a2dd95SBruce Richardson node->ptrs);
28699a2dd95SBruce Richardson }
28799a2dd95SBruce Richardson node->ptrs = ptrs;
28899a2dd95SBruce Richardson node->max_ptrs = num_ptrs;
28999a2dd95SBruce Richardson }
29099a2dd95SBruce Richardson
29199a2dd95SBruce Richardson /* Find available ptr and add a new pointer to this node */
29299a2dd95SBruce Richardson for (n = node->min_add; n < node->max_ptrs; n++) {
29399a2dd95SBruce Richardson if (node->ptrs[n].ptr == NULL) {
29499a2dd95SBruce Richardson node->ptrs[n].ptr = ptr;
29599a2dd95SBruce Richardson acl_include(&node->ptrs[n].values, bits, 0);
29699a2dd95SBruce Richardson acl_include(&node->values, bits, -1);
29799a2dd95SBruce Richardson if (ptr != NULL)
29899a2dd95SBruce Richardson ptr->ref_count++;
29999a2dd95SBruce Richardson if (node->num_ptrs <= n)
30099a2dd95SBruce Richardson node->num_ptrs = n + 1;
30199a2dd95SBruce Richardson return 0;
30299a2dd95SBruce Richardson }
30399a2dd95SBruce Richardson }
30499a2dd95SBruce Richardson
30599a2dd95SBruce Richardson return 0;
30699a2dd95SBruce Richardson }
30799a2dd95SBruce Richardson
30899a2dd95SBruce Richardson /*
30999a2dd95SBruce Richardson * Add a pointer for a range of values
31099a2dd95SBruce Richardson */
31199a2dd95SBruce Richardson 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)31299a2dd95SBruce Richardson acl_add_ptr_range(struct acl_build_context *context,
31399a2dd95SBruce Richardson struct rte_acl_node *root,
31499a2dd95SBruce Richardson struct rte_acl_node *node,
31599a2dd95SBruce Richardson uint8_t low,
31699a2dd95SBruce Richardson uint8_t high)
31799a2dd95SBruce Richardson {
31899a2dd95SBruce Richardson uint32_t n;
31999a2dd95SBruce Richardson struct rte_acl_bitset bitset;
32099a2dd95SBruce Richardson
32199a2dd95SBruce Richardson /* clear the bitset values */
32299a2dd95SBruce Richardson for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
32399a2dd95SBruce Richardson bitset.bits[n] = 0;
32499a2dd95SBruce Richardson
32599a2dd95SBruce Richardson /* for each bit in range, add bit to set */
32699a2dd95SBruce Richardson for (n = 0; n < UINT8_MAX + 1; n++)
32799a2dd95SBruce Richardson if (n >= low && n <= high)
32899a2dd95SBruce Richardson bitset.bits[n / (sizeof(bits_t) * 8)] |=
32999a2dd95SBruce Richardson 1U << (n % (sizeof(bits_t) * CHAR_BIT));
33099a2dd95SBruce Richardson
33199a2dd95SBruce Richardson return acl_add_ptr(context, root, node, &bitset);
33299a2dd95SBruce Richardson }
33399a2dd95SBruce Richardson
33499a2dd95SBruce Richardson /*
33599a2dd95SBruce Richardson * Generate a bitset from a byte value and mask.
33699a2dd95SBruce Richardson */
33799a2dd95SBruce Richardson static int
acl_gen_mask(struct rte_acl_bitset * bitset,uint32_t value,uint32_t mask)33899a2dd95SBruce Richardson acl_gen_mask(struct rte_acl_bitset *bitset, uint32_t value, uint32_t mask)
33999a2dd95SBruce Richardson {
34099a2dd95SBruce Richardson int range = 0;
34199a2dd95SBruce Richardson uint32_t n;
34299a2dd95SBruce Richardson
34399a2dd95SBruce Richardson /* clear the bitset values */
34499a2dd95SBruce Richardson for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++)
34599a2dd95SBruce Richardson bitset->bits[n] = 0;
34699a2dd95SBruce Richardson
34799a2dd95SBruce Richardson /* for each bit in value/mask, add bit to set */
34899a2dd95SBruce Richardson for (n = 0; n < UINT8_MAX + 1; n++) {
34999a2dd95SBruce Richardson if ((n & mask) == value) {
35099a2dd95SBruce Richardson range++;
35199a2dd95SBruce Richardson bitset->bits[n / (sizeof(bits_t) * 8)] |=
35299a2dd95SBruce Richardson 1U << (n % (sizeof(bits_t) * CHAR_BIT));
35399a2dd95SBruce Richardson }
35499a2dd95SBruce Richardson }
35599a2dd95SBruce Richardson return range;
35699a2dd95SBruce Richardson }
35799a2dd95SBruce Richardson
35899a2dd95SBruce Richardson /*
35999a2dd95SBruce Richardson * Determine how A and B intersect.
36099a2dd95SBruce Richardson * Determine if A and/or B are supersets of the intersection.
36199a2dd95SBruce Richardson */
36299a2dd95SBruce Richardson static int
acl_intersect_type(const struct rte_acl_bitset * a_bits,const struct rte_acl_bitset * b_bits,struct rte_acl_bitset * intersect)36399a2dd95SBruce Richardson acl_intersect_type(const struct rte_acl_bitset *a_bits,
36499a2dd95SBruce Richardson const struct rte_acl_bitset *b_bits,
36599a2dd95SBruce Richardson struct rte_acl_bitset *intersect)
36699a2dd95SBruce Richardson {
36799a2dd95SBruce Richardson uint32_t n;
36899a2dd95SBruce Richardson bits_t intersect_bits = 0;
36999a2dd95SBruce Richardson bits_t a_superset = 0;
37099a2dd95SBruce Richardson bits_t b_superset = 0;
37199a2dd95SBruce Richardson
37299a2dd95SBruce Richardson /*
37399a2dd95SBruce Richardson * calculate and store intersection and check if A and/or B have
37499a2dd95SBruce Richardson * bits outside the intersection (superset)
37599a2dd95SBruce Richardson */
37699a2dd95SBruce Richardson for (n = 0; n < RTE_ACL_BIT_SET_SIZE; n++) {
37799a2dd95SBruce Richardson intersect->bits[n] = a_bits->bits[n] & b_bits->bits[n];
37899a2dd95SBruce Richardson a_superset |= a_bits->bits[n] ^ intersect->bits[n];
37999a2dd95SBruce Richardson b_superset |= b_bits->bits[n] ^ intersect->bits[n];
38099a2dd95SBruce Richardson intersect_bits |= intersect->bits[n];
38199a2dd95SBruce Richardson }
38299a2dd95SBruce Richardson
38399a2dd95SBruce Richardson n = (intersect_bits == 0 ? ACL_INTERSECT_NONE : ACL_INTERSECT) |
38499a2dd95SBruce Richardson (b_superset == 0 ? 0 : ACL_INTERSECT_B) |
38599a2dd95SBruce Richardson (a_superset == 0 ? 0 : ACL_INTERSECT_A);
38699a2dd95SBruce Richardson
38799a2dd95SBruce Richardson return n;
38899a2dd95SBruce Richardson }
38999a2dd95SBruce Richardson
39099a2dd95SBruce Richardson /*
39199a2dd95SBruce Richardson * Duplicate a node
39299a2dd95SBruce Richardson */
39399a2dd95SBruce Richardson static struct rte_acl_node *
acl_dup_node(struct acl_build_context * context,struct rte_acl_node * node)39499a2dd95SBruce Richardson acl_dup_node(struct acl_build_context *context, struct rte_acl_node *node)
39599a2dd95SBruce Richardson {
39699a2dd95SBruce Richardson uint32_t n;
39799a2dd95SBruce Richardson struct rte_acl_node *next;
39899a2dd95SBruce Richardson
39999a2dd95SBruce Richardson next = acl_alloc_node(context, node->level);
40099a2dd95SBruce Richardson
40199a2dd95SBruce Richardson /* allocate the pointers */
40299a2dd95SBruce Richardson if (node->num_ptrs > 0) {
40399a2dd95SBruce Richardson next->ptrs = acl_build_alloc(context,
40499a2dd95SBruce Richardson node->max_ptrs,
40599a2dd95SBruce Richardson sizeof(struct rte_acl_ptr_set));
40699a2dd95SBruce Richardson next->max_ptrs = node->max_ptrs;
40799a2dd95SBruce Richardson }
40899a2dd95SBruce Richardson
40999a2dd95SBruce Richardson /* copy over the pointers */
41099a2dd95SBruce Richardson for (n = 0; n < node->num_ptrs; n++) {
41199a2dd95SBruce Richardson if (node->ptrs[n].ptr != NULL) {
41299a2dd95SBruce Richardson next->ptrs[n].ptr = node->ptrs[n].ptr;
41399a2dd95SBruce Richardson next->ptrs[n].ptr->ref_count++;
41499a2dd95SBruce Richardson acl_include(&next->ptrs[n].values,
41599a2dd95SBruce Richardson &node->ptrs[n].values, -1);
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson }
41899a2dd95SBruce Richardson
41999a2dd95SBruce Richardson next->num_ptrs = node->num_ptrs;
42099a2dd95SBruce Richardson
42199a2dd95SBruce Richardson /* copy over node's match results */
42299a2dd95SBruce Richardson if (node->match_flag == 0)
42399a2dd95SBruce Richardson next->match_flag = 0;
42499a2dd95SBruce Richardson else {
42599a2dd95SBruce Richardson next->match_flag = -1;
42699a2dd95SBruce Richardson next->mrt = acl_build_alloc(context, 1, sizeof(*next->mrt));
42799a2dd95SBruce Richardson memcpy(next->mrt, node->mrt, sizeof(*next->mrt));
42899a2dd95SBruce Richardson }
42999a2dd95SBruce Richardson
43099a2dd95SBruce Richardson /* copy over node's bitset */
43199a2dd95SBruce Richardson acl_include(&next->values, &node->values, -1);
43299a2dd95SBruce Richardson
43399a2dd95SBruce Richardson node->next = next;
43499a2dd95SBruce Richardson next->prev = node;
43599a2dd95SBruce Richardson
43699a2dd95SBruce Richardson return next;
43799a2dd95SBruce Richardson }
43899a2dd95SBruce Richardson
43999a2dd95SBruce Richardson /*
44099a2dd95SBruce Richardson * Dereference a pointer from a node
44199a2dd95SBruce Richardson */
44299a2dd95SBruce Richardson static void
acl_deref_ptr(struct acl_build_context * context,struct rte_acl_node * node,int index)44399a2dd95SBruce Richardson acl_deref_ptr(struct acl_build_context *context,
44499a2dd95SBruce Richardson struct rte_acl_node *node, int index)
44599a2dd95SBruce Richardson {
44699a2dd95SBruce Richardson struct rte_acl_node *ref_node;
44799a2dd95SBruce Richardson
44899a2dd95SBruce Richardson /* De-reference the node at the specified pointer */
44999a2dd95SBruce Richardson if (node != NULL && node->ptrs[index].ptr != NULL) {
45099a2dd95SBruce Richardson ref_node = node->ptrs[index].ptr;
45199a2dd95SBruce Richardson ref_node->ref_count--;
45299a2dd95SBruce Richardson if (ref_node->ref_count == 0)
45399a2dd95SBruce Richardson acl_free_node(context, ref_node);
45499a2dd95SBruce Richardson }
45599a2dd95SBruce Richardson }
45699a2dd95SBruce Richardson
45799a2dd95SBruce Richardson /*
45899a2dd95SBruce Richardson * acl_exclude rte_acl_bitset from src and copy remaining pointer to dst
45999a2dd95SBruce Richardson */
46099a2dd95SBruce Richardson 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)46199a2dd95SBruce Richardson acl_copy_ptr(struct acl_build_context *context,
46299a2dd95SBruce Richardson struct rte_acl_node *dst,
46399a2dd95SBruce Richardson struct rte_acl_node *src,
46499a2dd95SBruce Richardson int index,
46599a2dd95SBruce Richardson struct rte_acl_bitset *b_bits)
46699a2dd95SBruce Richardson {
46799a2dd95SBruce Richardson int rc;
46899a2dd95SBruce Richardson struct rte_acl_bitset bits;
46999a2dd95SBruce Richardson
47099a2dd95SBruce Richardson if (b_bits != NULL)
47199a2dd95SBruce Richardson if (!acl_exclude(&bits, &src->ptrs[index].values, b_bits))
47299a2dd95SBruce Richardson return 0;
47399a2dd95SBruce Richardson
47499a2dd95SBruce Richardson rc = acl_add_ptr(context, dst, src->ptrs[index].ptr, &bits);
47599a2dd95SBruce Richardson if (rc < 0)
47699a2dd95SBruce Richardson return rc;
47799a2dd95SBruce Richardson return 1;
47899a2dd95SBruce Richardson }
47999a2dd95SBruce Richardson
48099a2dd95SBruce Richardson /*
48199a2dd95SBruce Richardson * Fill in gaps in ptrs list with the ptr at the end of the list
48299a2dd95SBruce Richardson */
48399a2dd95SBruce Richardson static void
acl_compact_node_ptrs(struct rte_acl_node * node_a)48499a2dd95SBruce Richardson acl_compact_node_ptrs(struct rte_acl_node *node_a)
48599a2dd95SBruce Richardson {
48699a2dd95SBruce Richardson uint32_t n;
48799a2dd95SBruce Richardson int min_add = node_a->min_add;
48899a2dd95SBruce Richardson
48999a2dd95SBruce Richardson while (node_a->num_ptrs > 0 &&
49099a2dd95SBruce Richardson node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
49199a2dd95SBruce Richardson node_a->num_ptrs--;
49299a2dd95SBruce Richardson
49399a2dd95SBruce Richardson for (n = min_add; n + 1 < node_a->num_ptrs; n++) {
49499a2dd95SBruce Richardson
49599a2dd95SBruce Richardson /* if this entry is empty */
49699a2dd95SBruce Richardson if (node_a->ptrs[n].ptr == NULL) {
49799a2dd95SBruce Richardson
49899a2dd95SBruce Richardson /* move the last pointer to this entry */
49999a2dd95SBruce Richardson acl_include(&node_a->ptrs[n].values,
50099a2dd95SBruce Richardson &node_a->ptrs[node_a->num_ptrs - 1].values,
50199a2dd95SBruce Richardson 0);
50299a2dd95SBruce Richardson node_a->ptrs[n].ptr =
50399a2dd95SBruce Richardson node_a->ptrs[node_a->num_ptrs - 1].ptr;
50499a2dd95SBruce Richardson
50599a2dd95SBruce Richardson /*
50699a2dd95SBruce Richardson * mark the end as empty and adjust the number
50799a2dd95SBruce Richardson * of used pointer enum_tries
50899a2dd95SBruce Richardson */
50999a2dd95SBruce Richardson node_a->ptrs[node_a->num_ptrs - 1].ptr = NULL;
51099a2dd95SBruce Richardson while (node_a->num_ptrs > 0 &&
51199a2dd95SBruce Richardson node_a->ptrs[node_a->num_ptrs - 1].ptr == NULL)
51299a2dd95SBruce Richardson node_a->num_ptrs--;
51399a2dd95SBruce Richardson }
51499a2dd95SBruce Richardson }
51599a2dd95SBruce Richardson }
51699a2dd95SBruce Richardson
51799a2dd95SBruce Richardson 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)51899a2dd95SBruce Richardson acl_resolve_leaf(struct acl_build_context *context,
51999a2dd95SBruce Richardson struct rte_acl_node *node_a,
52099a2dd95SBruce Richardson struct rte_acl_node *node_b,
52199a2dd95SBruce Richardson struct rte_acl_node **node_c)
52299a2dd95SBruce Richardson {
52399a2dd95SBruce Richardson uint32_t n;
52499a2dd95SBruce Richardson int combined_priority = ACL_PRIORITY_EQUAL;
52599a2dd95SBruce Richardson
52699a2dd95SBruce Richardson for (n = 0; n < context->cfg.num_categories; n++) {
52799a2dd95SBruce Richardson if (node_a->mrt->priority[n] != node_b->mrt->priority[n]) {
52899a2dd95SBruce Richardson combined_priority |= (node_a->mrt->priority[n] >
52999a2dd95SBruce Richardson node_b->mrt->priority[n]) ?
53099a2dd95SBruce Richardson ACL_PRIORITY_NODE_A : ACL_PRIORITY_NODE_B;
53199a2dd95SBruce Richardson }
53299a2dd95SBruce Richardson }
53399a2dd95SBruce Richardson
53499a2dd95SBruce Richardson /*
53599a2dd95SBruce Richardson * if node a is higher or equal priority for all categories,
53699a2dd95SBruce Richardson * then return node_a.
53799a2dd95SBruce Richardson */
53899a2dd95SBruce Richardson if (combined_priority == ACL_PRIORITY_NODE_A ||
53999a2dd95SBruce Richardson combined_priority == ACL_PRIORITY_EQUAL) {
54099a2dd95SBruce Richardson *node_c = node_a;
54199a2dd95SBruce Richardson return 0;
54299a2dd95SBruce Richardson }
54399a2dd95SBruce Richardson
54499a2dd95SBruce Richardson /*
54599a2dd95SBruce Richardson * if node b is higher or equal priority for all categories,
54699a2dd95SBruce Richardson * then return node_b.
54799a2dd95SBruce Richardson */
54899a2dd95SBruce Richardson if (combined_priority == ACL_PRIORITY_NODE_B) {
54999a2dd95SBruce Richardson *node_c = node_b;
55099a2dd95SBruce Richardson return 0;
55199a2dd95SBruce Richardson }
55299a2dd95SBruce Richardson
55399a2dd95SBruce Richardson /*
55499a2dd95SBruce Richardson * mixed priorities - create a new node with the highest priority
55599a2dd95SBruce Richardson * for each category.
55699a2dd95SBruce Richardson */
55799a2dd95SBruce Richardson
55899a2dd95SBruce Richardson /* force new duplication. */
55999a2dd95SBruce Richardson node_a->next = NULL;
56099a2dd95SBruce Richardson
56199a2dd95SBruce Richardson *node_c = acl_dup_node(context, node_a);
56299a2dd95SBruce Richardson for (n = 0; n < context->cfg.num_categories; n++) {
56399a2dd95SBruce Richardson if ((*node_c)->mrt->priority[n] < node_b->mrt->priority[n]) {
56499a2dd95SBruce Richardson (*node_c)->mrt->priority[n] = node_b->mrt->priority[n];
56599a2dd95SBruce Richardson (*node_c)->mrt->results[n] = node_b->mrt->results[n];
56699a2dd95SBruce Richardson }
56799a2dd95SBruce Richardson }
56899a2dd95SBruce Richardson return 0;
56999a2dd95SBruce Richardson }
57099a2dd95SBruce Richardson
57199a2dd95SBruce Richardson /*
57299a2dd95SBruce Richardson * Merge nodes A and B together,
57399a2dd95SBruce Richardson * returns a node that is the path for the intersection
57499a2dd95SBruce Richardson *
57599a2dd95SBruce Richardson * If match node (leaf on trie)
57699a2dd95SBruce Richardson * For each category
57799a2dd95SBruce Richardson * return node = highest priority result
57899a2dd95SBruce Richardson *
57999a2dd95SBruce Richardson * Create C as a duplicate of A to point to child intersections
58099a2dd95SBruce Richardson * If any pointers in C intersect with any in B
58199a2dd95SBruce Richardson * For each intersection
58299a2dd95SBruce Richardson * merge children
58399a2dd95SBruce Richardson * remove intersection from C pointer
58499a2dd95SBruce Richardson * add a pointer from C to child intersection node
58599a2dd95SBruce Richardson * Compact the pointers in A and B
58699a2dd95SBruce Richardson * Copy any B pointers that are outside of the intersection to C
58799a2dd95SBruce Richardson * If C has no references to the B trie
58899a2dd95SBruce Richardson * free C and return A
58999a2dd95SBruce Richardson * Else If C has no references to the A trie
59099a2dd95SBruce Richardson * free C and return B
59199a2dd95SBruce Richardson * Else
59299a2dd95SBruce Richardson * return C
59399a2dd95SBruce Richardson */
59499a2dd95SBruce Richardson 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)59599a2dd95SBruce Richardson acl_merge_trie(struct acl_build_context *context,
59699a2dd95SBruce Richardson struct rte_acl_node *node_a, struct rte_acl_node *node_b,
59799a2dd95SBruce Richardson uint32_t level, struct rte_acl_node **return_c)
59899a2dd95SBruce Richardson {
59999a2dd95SBruce Richardson uint32_t n, m, ptrs_c, ptrs_b;
60099a2dd95SBruce Richardson uint32_t min_add_c, min_add_b;
60199a2dd95SBruce Richardson int node_intersect_type;
60299a2dd95SBruce Richardson struct rte_acl_bitset node_intersect;
60399a2dd95SBruce Richardson struct rte_acl_node *node_c;
60499a2dd95SBruce Richardson struct rte_acl_node *node_a_next;
60599a2dd95SBruce Richardson int node_b_refs;
60699a2dd95SBruce Richardson int node_a_refs;
60799a2dd95SBruce Richardson
60899a2dd95SBruce Richardson node_c = node_a;
60999a2dd95SBruce Richardson node_a_next = node_a->next;
61099a2dd95SBruce Richardson min_add_c = 0;
61199a2dd95SBruce Richardson min_add_b = 0;
61299a2dd95SBruce Richardson node_a_refs = node_a->num_ptrs;
61399a2dd95SBruce Richardson node_b_refs = 0;
61499a2dd95SBruce Richardson node_intersect_type = 0;
61599a2dd95SBruce Richardson
61699a2dd95SBruce Richardson /* Resolve leaf nodes (matches) */
61799a2dd95SBruce Richardson if (node_a->match_flag != 0) {
61899a2dd95SBruce Richardson acl_resolve_leaf(context, node_a, node_b, return_c);
61999a2dd95SBruce Richardson return 0;
62099a2dd95SBruce Richardson }
62199a2dd95SBruce Richardson
62299a2dd95SBruce Richardson /*
62399a2dd95SBruce Richardson * Create node C as a copy of node A, and do: C = merge(A,B);
62499a2dd95SBruce Richardson * If node A can be used instead (A==C), then later we'll
62599a2dd95SBruce Richardson * destroy C and return A.
62699a2dd95SBruce Richardson */
62799a2dd95SBruce Richardson if (level > 0)
62899a2dd95SBruce Richardson node_c = acl_dup_node(context, node_a);
62999a2dd95SBruce Richardson
63099a2dd95SBruce Richardson /*
63199a2dd95SBruce Richardson * If the two node transitions intersect then merge the transitions.
63299a2dd95SBruce Richardson * Check intersection for entire node (all pointers)
63399a2dd95SBruce Richardson */
63499a2dd95SBruce Richardson node_intersect_type = acl_intersect_type(&node_c->values,
63599a2dd95SBruce Richardson &node_b->values,
63699a2dd95SBruce Richardson &node_intersect);
63799a2dd95SBruce Richardson
63899a2dd95SBruce Richardson if (node_intersect_type & ACL_INTERSECT) {
63999a2dd95SBruce Richardson
64099a2dd95SBruce Richardson min_add_b = node_b->min_add;
64199a2dd95SBruce Richardson node_b->min_add = node_b->num_ptrs;
64299a2dd95SBruce Richardson ptrs_b = node_b->num_ptrs;
64399a2dd95SBruce Richardson
64499a2dd95SBruce Richardson min_add_c = node_c->min_add;
64599a2dd95SBruce Richardson node_c->min_add = node_c->num_ptrs;
64699a2dd95SBruce Richardson ptrs_c = node_c->num_ptrs;
64799a2dd95SBruce Richardson
64899a2dd95SBruce Richardson for (n = 0; n < ptrs_c; n++) {
64999a2dd95SBruce Richardson if (node_c->ptrs[n].ptr == NULL) {
65099a2dd95SBruce Richardson node_a_refs--;
65199a2dd95SBruce Richardson continue;
65299a2dd95SBruce Richardson }
65399a2dd95SBruce Richardson node_c->ptrs[n].ptr->next = NULL;
65499a2dd95SBruce Richardson for (m = 0; m < ptrs_b; m++) {
65599a2dd95SBruce Richardson
65699a2dd95SBruce Richardson struct rte_acl_bitset child_intersect;
65799a2dd95SBruce Richardson int child_intersect_type;
65899a2dd95SBruce Richardson struct rte_acl_node *child_node_c = NULL;
65999a2dd95SBruce Richardson
66099a2dd95SBruce Richardson if (node_b->ptrs[m].ptr == NULL ||
66199a2dd95SBruce Richardson node_c->ptrs[n].ptr ==
66299a2dd95SBruce Richardson node_b->ptrs[m].ptr)
66399a2dd95SBruce Richardson continue;
66499a2dd95SBruce Richardson
66599a2dd95SBruce Richardson child_intersect_type = acl_intersect_type(
66699a2dd95SBruce Richardson &node_c->ptrs[n].values,
66799a2dd95SBruce Richardson &node_b->ptrs[m].values,
66899a2dd95SBruce Richardson &child_intersect);
66999a2dd95SBruce Richardson
67099a2dd95SBruce Richardson if ((child_intersect_type & ACL_INTERSECT) !=
67199a2dd95SBruce Richardson 0) {
67299a2dd95SBruce Richardson if (acl_merge_trie(context,
67399a2dd95SBruce Richardson node_c->ptrs[n].ptr,
67499a2dd95SBruce Richardson node_b->ptrs[m].ptr,
67599a2dd95SBruce Richardson level + 1,
67699a2dd95SBruce Richardson &child_node_c))
67799a2dd95SBruce Richardson return 1;
67899a2dd95SBruce Richardson
67999a2dd95SBruce Richardson if (child_node_c != NULL &&
68099a2dd95SBruce Richardson child_node_c !=
68199a2dd95SBruce Richardson node_c->ptrs[n].ptr) {
68299a2dd95SBruce Richardson
68399a2dd95SBruce Richardson node_b_refs++;
68499a2dd95SBruce Richardson
68599a2dd95SBruce Richardson /*
68699a2dd95SBruce Richardson * Added link from C to
68799a2dd95SBruce Richardson * child_C for all transitions
68899a2dd95SBruce Richardson * in the intersection.
68999a2dd95SBruce Richardson */
69099a2dd95SBruce Richardson acl_add_ptr(context, node_c,
69199a2dd95SBruce Richardson child_node_c,
69299a2dd95SBruce Richardson &child_intersect);
69399a2dd95SBruce Richardson
69499a2dd95SBruce Richardson /*
69599a2dd95SBruce Richardson * inc refs if pointer is not
69699a2dd95SBruce Richardson * to node b.
69799a2dd95SBruce Richardson */
69899a2dd95SBruce Richardson node_a_refs += (child_node_c !=
69999a2dd95SBruce Richardson node_b->ptrs[m].ptr);
70099a2dd95SBruce Richardson
70199a2dd95SBruce Richardson /*
70299a2dd95SBruce Richardson * Remove intersection from C
70399a2dd95SBruce Richardson * pointer.
70499a2dd95SBruce Richardson */
70599a2dd95SBruce Richardson if (!acl_exclude(
70699a2dd95SBruce Richardson &node_c->ptrs[n].values,
70799a2dd95SBruce Richardson &node_c->ptrs[n].values,
70899a2dd95SBruce Richardson &child_intersect)) {
70999a2dd95SBruce Richardson acl_deref_ptr(context,
71099a2dd95SBruce Richardson node_c, n);
71199a2dd95SBruce Richardson node_c->ptrs[n].ptr =
71299a2dd95SBruce Richardson NULL;
71399a2dd95SBruce Richardson node_a_refs--;
71499a2dd95SBruce Richardson }
71599a2dd95SBruce Richardson }
71699a2dd95SBruce Richardson }
71799a2dd95SBruce Richardson }
71899a2dd95SBruce Richardson }
71999a2dd95SBruce Richardson
72099a2dd95SBruce Richardson /* Compact pointers */
72199a2dd95SBruce Richardson node_c->min_add = min_add_c;
72299a2dd95SBruce Richardson acl_compact_node_ptrs(node_c);
72399a2dd95SBruce Richardson node_b->min_add = min_add_b;
72499a2dd95SBruce Richardson acl_compact_node_ptrs(node_b);
72599a2dd95SBruce Richardson }
72699a2dd95SBruce Richardson
72799a2dd95SBruce Richardson /*
72899a2dd95SBruce Richardson * Copy pointers outside of the intersection from B to C
72999a2dd95SBruce Richardson */
73099a2dd95SBruce Richardson if ((node_intersect_type & ACL_INTERSECT_B) != 0) {
73199a2dd95SBruce Richardson node_b_refs++;
73299a2dd95SBruce Richardson for (m = 0; m < node_b->num_ptrs; m++)
73399a2dd95SBruce Richardson if (node_b->ptrs[m].ptr != NULL)
73499a2dd95SBruce Richardson acl_copy_ptr(context, node_c,
73599a2dd95SBruce Richardson node_b, m, &node_intersect);
73699a2dd95SBruce Richardson }
73799a2dd95SBruce Richardson
73899a2dd95SBruce Richardson /*
73999a2dd95SBruce Richardson * Free node C if top of trie is contained in A or B
74099a2dd95SBruce Richardson * if node C is a duplicate of node A &&
74199a2dd95SBruce Richardson * node C was not an existing duplicate
74299a2dd95SBruce Richardson */
74399a2dd95SBruce Richardson if (node_c != node_a && node_c != node_a_next) {
74499a2dd95SBruce Richardson
74599a2dd95SBruce Richardson /*
74699a2dd95SBruce Richardson * if the intersection has no references to the
74799a2dd95SBruce Richardson * B side, then it is contained in A
74899a2dd95SBruce Richardson */
74999a2dd95SBruce Richardson if (node_b_refs == 0) {
75099a2dd95SBruce Richardson acl_free_node(context, node_c);
75199a2dd95SBruce Richardson node_c = node_a;
75299a2dd95SBruce Richardson } else {
75399a2dd95SBruce Richardson /*
75499a2dd95SBruce Richardson * if the intersection has no references to the
75599a2dd95SBruce Richardson * A side, then it is contained in B.
75699a2dd95SBruce Richardson */
75799a2dd95SBruce Richardson if (node_a_refs == 0) {
75899a2dd95SBruce Richardson acl_free_node(context, node_c);
75999a2dd95SBruce Richardson node_c = node_b;
76099a2dd95SBruce Richardson }
76199a2dd95SBruce Richardson }
76299a2dd95SBruce Richardson }
76399a2dd95SBruce Richardson
76499a2dd95SBruce Richardson if (return_c != NULL)
76599a2dd95SBruce Richardson *return_c = node_c;
76699a2dd95SBruce Richardson
76799a2dd95SBruce Richardson if (level == 0)
76899a2dd95SBruce Richardson acl_free_node(context, node_b);
76999a2dd95SBruce Richardson
77099a2dd95SBruce Richardson return 0;
77199a2dd95SBruce Richardson }
77299a2dd95SBruce Richardson
77399a2dd95SBruce Richardson /*
77499a2dd95SBruce Richardson * Reset current runtime fields before next build:
77599a2dd95SBruce Richardson * - free allocated RT memory.
77699a2dd95SBruce Richardson * - reset all RT related fields to zero.
77799a2dd95SBruce Richardson */
77899a2dd95SBruce Richardson static void
acl_build_reset(struct rte_acl_ctx * ctx)77999a2dd95SBruce Richardson acl_build_reset(struct rte_acl_ctx *ctx)
78099a2dd95SBruce Richardson {
78199a2dd95SBruce Richardson rte_free(ctx->mem);
78299a2dd95SBruce Richardson memset(&ctx->num_categories, 0,
78399a2dd95SBruce Richardson sizeof(*ctx) - offsetof(struct rte_acl_ctx, num_categories));
78499a2dd95SBruce Richardson }
78599a2dd95SBruce Richardson
78699a2dd95SBruce Richardson 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)78799a2dd95SBruce Richardson acl_gen_full_range(struct acl_build_context *context, struct rte_acl_node *root,
78899a2dd95SBruce Richardson struct rte_acl_node *end, int size, int level)
78999a2dd95SBruce Richardson {
79099a2dd95SBruce Richardson struct rte_acl_node *node, *prev;
79199a2dd95SBruce Richardson uint32_t n;
79299a2dd95SBruce Richardson
79399a2dd95SBruce Richardson prev = root;
79499a2dd95SBruce Richardson for (n = size - 1; n > 0; n--) {
79599a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
79699a2dd95SBruce Richardson acl_add_ptr_range(context, prev, node, 0, UINT8_MAX);
79799a2dd95SBruce Richardson prev = node;
79899a2dd95SBruce Richardson }
79999a2dd95SBruce Richardson acl_add_ptr_range(context, prev, end, 0, UINT8_MAX);
80099a2dd95SBruce Richardson }
80199a2dd95SBruce Richardson
80299a2dd95SBruce Richardson 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)80399a2dd95SBruce Richardson acl_gen_range_mdl(struct acl_build_context *context, struct rte_acl_node *root,
80499a2dd95SBruce Richardson struct rte_acl_node *end, uint8_t lo, uint8_t hi, int size, int level)
80599a2dd95SBruce Richardson {
80699a2dd95SBruce Richardson struct rte_acl_node *node;
80799a2dd95SBruce Richardson
80899a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
80999a2dd95SBruce Richardson acl_add_ptr_range(context, root, node, lo, hi);
81099a2dd95SBruce Richardson acl_gen_full_range(context, node, end, size - 1, level);
81199a2dd95SBruce Richardson }
81299a2dd95SBruce Richardson
81399a2dd95SBruce Richardson 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)81499a2dd95SBruce Richardson acl_gen_range_low(struct acl_build_context *context, struct rte_acl_node *root,
81599a2dd95SBruce Richardson struct rte_acl_node *end, const uint8_t *lo, int size, int level)
81699a2dd95SBruce Richardson {
81799a2dd95SBruce Richardson struct rte_acl_node *node;
81899a2dd95SBruce Richardson uint32_t n;
81999a2dd95SBruce Richardson
82099a2dd95SBruce Richardson n = size - 1;
82199a2dd95SBruce Richardson if (n == 0) {
82299a2dd95SBruce Richardson acl_add_ptr_range(context, root, end, lo[0], UINT8_MAX);
82399a2dd95SBruce Richardson return;
82499a2dd95SBruce Richardson }
82599a2dd95SBruce Richardson
82699a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
82799a2dd95SBruce Richardson acl_add_ptr_range(context, root, node, lo[n], lo[n]);
82899a2dd95SBruce Richardson
82999a2dd95SBruce Richardson /* generate lower-bound sub-trie */
83099a2dd95SBruce Richardson acl_gen_range_low(context, node, end, lo, n, level);
83199a2dd95SBruce Richardson
83299a2dd95SBruce Richardson /* generate middle sub-trie */
83399a2dd95SBruce Richardson if (n > 1 && lo[n - 1] != UINT8_MAX)
83499a2dd95SBruce Richardson acl_gen_range_mdl(context, node, end, lo[n - 1] + 1, UINT8_MAX,
83599a2dd95SBruce Richardson n, level);
83699a2dd95SBruce Richardson }
83799a2dd95SBruce Richardson
83899a2dd95SBruce Richardson 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)83999a2dd95SBruce Richardson acl_gen_range_high(struct acl_build_context *context, struct rte_acl_node *root,
84099a2dd95SBruce Richardson struct rte_acl_node *end, const uint8_t *hi, int size, int level)
84199a2dd95SBruce Richardson {
84299a2dd95SBruce Richardson struct rte_acl_node *node;
84399a2dd95SBruce Richardson uint32_t n;
84499a2dd95SBruce Richardson
84599a2dd95SBruce Richardson n = size - 1;
84699a2dd95SBruce Richardson if (n == 0) {
84799a2dd95SBruce Richardson acl_add_ptr_range(context, root, end, 0, hi[0]);
84899a2dd95SBruce Richardson return;
84999a2dd95SBruce Richardson }
85099a2dd95SBruce Richardson
85199a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
85299a2dd95SBruce Richardson acl_add_ptr_range(context, root, node, hi[n], hi[n]);
85399a2dd95SBruce Richardson
85499a2dd95SBruce Richardson /* generate upper-bound sub-trie */
85599a2dd95SBruce Richardson acl_gen_range_high(context, node, end, hi, n, level);
85699a2dd95SBruce Richardson
85799a2dd95SBruce Richardson /* generate middle sub-trie */
85899a2dd95SBruce Richardson if (n > 1 && hi[n - 1] != 0)
85999a2dd95SBruce Richardson acl_gen_range_mdl(context, node, end, 0, hi[n - 1] - 1,
86099a2dd95SBruce Richardson n, level);
86199a2dd95SBruce Richardson }
86299a2dd95SBruce Richardson
86399a2dd95SBruce Richardson 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)86499a2dd95SBruce Richardson acl_gen_range_trie(struct acl_build_context *context,
86599a2dd95SBruce Richardson const void *min, const void *max,
86699a2dd95SBruce Richardson int size, int level, struct rte_acl_node **pend)
86799a2dd95SBruce Richardson {
86899a2dd95SBruce Richardson int32_t k, n;
86999a2dd95SBruce Richardson uint8_t hi_ff, lo_00;
87099a2dd95SBruce Richardson struct rte_acl_node *node, *prev, *root;
87199a2dd95SBruce Richardson const uint8_t *lo;
87299a2dd95SBruce Richardson const uint8_t *hi;
87399a2dd95SBruce Richardson
87499a2dd95SBruce Richardson lo = min;
87599a2dd95SBruce Richardson hi = max;
87699a2dd95SBruce Richardson
87799a2dd95SBruce Richardson *pend = acl_alloc_node(context, level + size);
87899a2dd95SBruce Richardson root = acl_alloc_node(context, level++);
87999a2dd95SBruce Richardson prev = root;
88099a2dd95SBruce Richardson
88199a2dd95SBruce Richardson /* build common sub-trie till possible */
88299a2dd95SBruce Richardson for (n = size - 1; n > 0 && lo[n] == hi[n]; n--) {
88399a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
88499a2dd95SBruce Richardson acl_add_ptr_range(context, prev, node, lo[n], hi[n]);
88599a2dd95SBruce Richardson prev = node;
88699a2dd95SBruce Richardson }
88799a2dd95SBruce Richardson
88899a2dd95SBruce Richardson /* no branch needed, just one sub-trie */
88999a2dd95SBruce Richardson if (n == 0) {
89099a2dd95SBruce Richardson acl_add_ptr_range(context, prev, *pend, lo[0], hi[0]);
89199a2dd95SBruce Richardson return root;
89299a2dd95SBruce Richardson }
89399a2dd95SBruce Richardson
8947be78d02SJosh Soref /* gather information about divergent paths */
89599a2dd95SBruce Richardson lo_00 = 0;
89699a2dd95SBruce Richardson hi_ff = UINT8_MAX;
89799a2dd95SBruce Richardson for (k = n - 1; k >= 0; k--) {
89899a2dd95SBruce Richardson hi_ff &= hi[k];
89999a2dd95SBruce Richardson lo_00 |= lo[k];
90099a2dd95SBruce Richardson }
90199a2dd95SBruce Richardson
90299a2dd95SBruce Richardson /* generate left (lower-bound) sub-trie */
90399a2dd95SBruce Richardson if (lo_00 != 0)
90499a2dd95SBruce Richardson acl_gen_range_low(context, prev, *pend, lo, n + 1, level);
90599a2dd95SBruce Richardson
90699a2dd95SBruce Richardson /* generate right (upper-bound) sub-trie */
90799a2dd95SBruce Richardson if (hi_ff != UINT8_MAX)
90899a2dd95SBruce Richardson acl_gen_range_high(context, prev, *pend, hi, n + 1, level);
90999a2dd95SBruce Richardson
91099a2dd95SBruce Richardson /* generate sub-trie in the middle */
91199a2dd95SBruce Richardson if (lo[n] + 1 != hi[n] || lo_00 == 0 || hi_ff == UINT8_MAX) {
91299a2dd95SBruce Richardson lo_00 = lo[n] + (lo_00 != 0);
91399a2dd95SBruce Richardson hi_ff = hi[n] - (hi_ff != UINT8_MAX);
91499a2dd95SBruce Richardson acl_gen_range_mdl(context, prev, *pend, lo_00, hi_ff,
91599a2dd95SBruce Richardson n + 1, level);
91699a2dd95SBruce Richardson }
91799a2dd95SBruce Richardson
91899a2dd95SBruce Richardson return root;
91999a2dd95SBruce Richardson }
92099a2dd95SBruce Richardson
92199a2dd95SBruce Richardson 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)92299a2dd95SBruce Richardson acl_gen_mask_trie(struct acl_build_context *context,
92399a2dd95SBruce Richardson const void *value, const void *mask,
92499a2dd95SBruce Richardson int size, int level, struct rte_acl_node **pend)
92599a2dd95SBruce Richardson {
92699a2dd95SBruce Richardson int32_t n;
92799a2dd95SBruce Richardson struct rte_acl_node *root;
92899a2dd95SBruce Richardson struct rte_acl_node *node, *prev;
92999a2dd95SBruce Richardson struct rte_acl_bitset bits;
93099a2dd95SBruce Richardson const uint8_t *val = value;
93199a2dd95SBruce Richardson const uint8_t *msk = mask;
93299a2dd95SBruce Richardson
93399a2dd95SBruce Richardson root = acl_alloc_node(context, level++);
93499a2dd95SBruce Richardson prev = root;
93599a2dd95SBruce Richardson
93699a2dd95SBruce Richardson for (n = size - 1; n >= 0; n--) {
93799a2dd95SBruce Richardson node = acl_alloc_node(context, level++);
93899a2dd95SBruce Richardson acl_gen_mask(&bits, val[n] & msk[n], msk[n]);
93999a2dd95SBruce Richardson acl_add_ptr(context, prev, node, &bits);
94099a2dd95SBruce Richardson prev = node;
94199a2dd95SBruce Richardson }
94299a2dd95SBruce Richardson
94399a2dd95SBruce Richardson *pend = prev;
94499a2dd95SBruce Richardson return root;
94599a2dd95SBruce Richardson }
94699a2dd95SBruce Richardson
94799a2dd95SBruce Richardson 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)94899a2dd95SBruce Richardson build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head,
94999a2dd95SBruce Richardson struct rte_acl_build_rule **last, uint32_t *count)
95099a2dd95SBruce Richardson {
95199a2dd95SBruce Richardson uint32_t n, m;
95299a2dd95SBruce Richardson int field_index, node_count;
95399a2dd95SBruce Richardson struct rte_acl_node *trie;
95499a2dd95SBruce Richardson struct rte_acl_build_rule *prev, *rule;
95599a2dd95SBruce Richardson struct rte_acl_node *end, *merge, *root, *end_prev;
95699a2dd95SBruce Richardson const struct rte_acl_field *fld;
95799a2dd95SBruce Richardson
95899a2dd95SBruce Richardson prev = head;
95999a2dd95SBruce Richardson rule = head;
96099a2dd95SBruce Richardson *last = prev;
96199a2dd95SBruce Richardson
96299a2dd95SBruce Richardson trie = acl_alloc_node(context, 0);
96399a2dd95SBruce Richardson
96499a2dd95SBruce Richardson while (rule != NULL) {
96599a2dd95SBruce Richardson
96699a2dd95SBruce Richardson root = acl_alloc_node(context, 0);
96799a2dd95SBruce Richardson
96899a2dd95SBruce Richardson root->ref_count = 1;
96999a2dd95SBruce Richardson end = root;
97099a2dd95SBruce Richardson
97199a2dd95SBruce Richardson for (n = 0; n < rule->config->num_fields; n++) {
97299a2dd95SBruce Richardson
97399a2dd95SBruce Richardson field_index = rule->config->defs[n].field_index;
97499a2dd95SBruce Richardson fld = rule->f->field + field_index;
97599a2dd95SBruce Richardson end_prev = end;
97699a2dd95SBruce Richardson
97799a2dd95SBruce Richardson /* build a mini-trie for this field */
97899a2dd95SBruce Richardson switch (rule->config->defs[n].type) {
97999a2dd95SBruce Richardson
98099a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_BITMASK:
98199a2dd95SBruce Richardson merge = acl_gen_mask_trie(context,
98299a2dd95SBruce Richardson &fld->value,
98399a2dd95SBruce Richardson &fld->mask_range,
98499a2dd95SBruce Richardson rule->config->defs[n].size,
98599a2dd95SBruce Richardson end->level + 1,
98699a2dd95SBruce Richardson &end);
98799a2dd95SBruce Richardson break;
98899a2dd95SBruce Richardson
98999a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_MASK:
99099a2dd95SBruce Richardson {
99199a2dd95SBruce Richardson /*
99299a2dd95SBruce Richardson * set msb for the size of the field and
99399a2dd95SBruce Richardson * all higher bits.
99499a2dd95SBruce Richardson */
99599a2dd95SBruce Richardson uint64_t mask;
99699a2dd95SBruce Richardson mask = RTE_ACL_MASKLEN_TO_BITMASK(
99745109815SKonstantin Ananyev fld->mask_range.u64,
99899a2dd95SBruce Richardson rule->config->defs[n].size);
99999a2dd95SBruce Richardson
100099a2dd95SBruce Richardson /* gen a mini-trie for this field */
100199a2dd95SBruce Richardson merge = acl_gen_mask_trie(context,
100299a2dd95SBruce Richardson &fld->value,
100399a2dd95SBruce Richardson (char *)&mask,
100499a2dd95SBruce Richardson rule->config->defs[n].size,
100599a2dd95SBruce Richardson end->level + 1,
100699a2dd95SBruce Richardson &end);
100799a2dd95SBruce Richardson }
100899a2dd95SBruce Richardson break;
100999a2dd95SBruce Richardson
101099a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_RANGE:
101199a2dd95SBruce Richardson merge = acl_gen_range_trie(context,
101299a2dd95SBruce Richardson &rule->f->field[field_index].value,
101399a2dd95SBruce Richardson &rule->f->field[field_index].mask_range,
101499a2dd95SBruce Richardson rule->config->defs[n].size,
101599a2dd95SBruce Richardson end->level + 1,
101699a2dd95SBruce Richardson &end);
101799a2dd95SBruce Richardson break;
101899a2dd95SBruce Richardson
101999a2dd95SBruce Richardson default:
1020*ae67895bSDavid Marchand ACL_LOG(ERR,
1021*ae67895bSDavid Marchand "Error in rule[%u] type - %hhu",
102299a2dd95SBruce Richardson rule->f->data.userdata,
102399a2dd95SBruce Richardson rule->config->defs[n].type);
102499a2dd95SBruce Richardson return NULL;
102599a2dd95SBruce Richardson }
102699a2dd95SBruce Richardson
102799a2dd95SBruce Richardson /* merge this field on to the end of the rule */
102899a2dd95SBruce Richardson if (acl_merge_trie(context, end_prev, merge, 0,
102999a2dd95SBruce Richardson NULL) != 0) {
103099a2dd95SBruce Richardson return NULL;
103199a2dd95SBruce Richardson }
103299a2dd95SBruce Richardson }
103399a2dd95SBruce Richardson
103499a2dd95SBruce Richardson end->match_flag = ++context->num_build_rules;
103599a2dd95SBruce Richardson
103699a2dd95SBruce Richardson /*
103799a2dd95SBruce Richardson * Setup the results for this rule.
103899a2dd95SBruce Richardson * The result and priority of each category.
103999a2dd95SBruce Richardson */
104099a2dd95SBruce Richardson if (end->mrt == NULL)
104199a2dd95SBruce Richardson end->mrt = acl_build_alloc(context, 1,
104299a2dd95SBruce Richardson sizeof(*end->mrt));
104399a2dd95SBruce Richardson
104499a2dd95SBruce Richardson for (m = context->cfg.num_categories; 0 != m--; ) {
104599a2dd95SBruce Richardson if (rule->f->data.category_mask & (1U << m)) {
104699a2dd95SBruce Richardson end->mrt->results[m] = rule->f->data.userdata;
104799a2dd95SBruce Richardson end->mrt->priority[m] = rule->f->data.priority;
104899a2dd95SBruce Richardson } else {
104999a2dd95SBruce Richardson end->mrt->results[m] = 0;
105099a2dd95SBruce Richardson end->mrt->priority[m] = 0;
105199a2dd95SBruce Richardson }
105299a2dd95SBruce Richardson }
105399a2dd95SBruce Richardson
105499a2dd95SBruce Richardson node_count = context->num_nodes;
105599a2dd95SBruce Richardson (*count)++;
105699a2dd95SBruce Richardson
105799a2dd95SBruce Richardson /* merge this rule into the trie */
105899a2dd95SBruce Richardson if (acl_merge_trie(context, trie, root, 0, NULL))
105999a2dd95SBruce Richardson return NULL;
106099a2dd95SBruce Richardson
106199a2dd95SBruce Richardson node_count = context->num_nodes - node_count;
106299a2dd95SBruce Richardson if (node_count > context->cur_node_max) {
106399a2dd95SBruce Richardson *last = prev;
106499a2dd95SBruce Richardson return trie;
106599a2dd95SBruce Richardson }
106699a2dd95SBruce Richardson
106799a2dd95SBruce Richardson prev = rule;
106899a2dd95SBruce Richardson rule = rule->next;
106999a2dd95SBruce Richardson }
107099a2dd95SBruce Richardson
107199a2dd95SBruce Richardson *last = NULL;
107299a2dd95SBruce Richardson return trie;
107399a2dd95SBruce Richardson }
107499a2dd95SBruce Richardson
107599a2dd95SBruce Richardson static void
acl_calc_wildness(struct rte_acl_build_rule * head,const struct rte_acl_config * config)107699a2dd95SBruce Richardson acl_calc_wildness(struct rte_acl_build_rule *head,
107799a2dd95SBruce Richardson const struct rte_acl_config *config)
107899a2dd95SBruce Richardson {
107999a2dd95SBruce Richardson uint32_t n;
108099a2dd95SBruce Richardson struct rte_acl_build_rule *rule;
108199a2dd95SBruce Richardson
108299a2dd95SBruce Richardson for (rule = head; rule != NULL; rule = rule->next) {
108399a2dd95SBruce Richardson
108499a2dd95SBruce Richardson for (n = 0; n < config->num_fields; n++) {
108599a2dd95SBruce Richardson
108699a2dd95SBruce Richardson double wild = 0;
108799a2dd95SBruce Richardson uint32_t bit_len = CHAR_BIT * config->defs[n].size;
108899a2dd95SBruce Richardson uint64_t msk_val = RTE_LEN2MASK(bit_len,
108999a2dd95SBruce Richardson typeof(msk_val));
109099a2dd95SBruce Richardson double size = bit_len;
109199a2dd95SBruce Richardson int field_index = config->defs[n].field_index;
109299a2dd95SBruce Richardson const struct rte_acl_field *fld = rule->f->field +
109399a2dd95SBruce Richardson field_index;
109499a2dd95SBruce Richardson
109599a2dd95SBruce Richardson switch (rule->config->defs[n].type) {
109699a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_BITMASK:
10973d4e27fdSDavid Marchand wild = (size - rte_popcount64(
109899a2dd95SBruce Richardson fld->mask_range.u64 & msk_val)) /
109999a2dd95SBruce Richardson size;
110099a2dd95SBruce Richardson break;
110199a2dd95SBruce Richardson
110299a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_MASK:
110399a2dd95SBruce Richardson wild = (size - fld->mask_range.u32) / size;
110499a2dd95SBruce Richardson break;
110599a2dd95SBruce Richardson
110699a2dd95SBruce Richardson case RTE_ACL_FIELD_TYPE_RANGE:
110799a2dd95SBruce Richardson wild = (fld->mask_range.u64 & msk_val) -
110899a2dd95SBruce Richardson (fld->value.u64 & msk_val);
110999a2dd95SBruce Richardson wild = wild / msk_val;
111099a2dd95SBruce Richardson break;
111199a2dd95SBruce Richardson }
111299a2dd95SBruce Richardson
111399a2dd95SBruce Richardson rule->wildness[field_index] = (uint32_t)(wild * 100);
111499a2dd95SBruce Richardson }
111599a2dd95SBruce Richardson }
111699a2dd95SBruce Richardson }
111799a2dd95SBruce Richardson
111899a2dd95SBruce Richardson static void
acl_rule_stats(struct rte_acl_build_rule * head,struct rte_acl_config * config)111999a2dd95SBruce Richardson acl_rule_stats(struct rte_acl_build_rule *head, struct rte_acl_config *config)
112099a2dd95SBruce Richardson {
112199a2dd95SBruce Richardson struct rte_acl_build_rule *rule;
112299a2dd95SBruce Richardson uint32_t n, m, fields_deactivated = 0;
112399a2dd95SBruce Richardson uint32_t start = 0, deactivate = 0;
112499a2dd95SBruce Richardson int tally[RTE_ACL_MAX_LEVELS][TALLY_NUM];
112599a2dd95SBruce Richardson
112699a2dd95SBruce Richardson memset(tally, 0, sizeof(tally));
112799a2dd95SBruce Richardson
112899a2dd95SBruce Richardson for (rule = head; rule != NULL; rule = rule->next) {
112999a2dd95SBruce Richardson
113099a2dd95SBruce Richardson for (n = 0; n < config->num_fields; n++) {
113199a2dd95SBruce Richardson uint32_t field_index = config->defs[n].field_index;
113299a2dd95SBruce Richardson
113399a2dd95SBruce Richardson tally[n][TALLY_0]++;
113499a2dd95SBruce Richardson for (m = 1; m < RTE_DIM(wild_limits); m++) {
113599a2dd95SBruce Richardson if (rule->wildness[field_index] >=
113699a2dd95SBruce Richardson wild_limits[m])
113799a2dd95SBruce Richardson tally[n][m]++;
113899a2dd95SBruce Richardson }
113999a2dd95SBruce Richardson }
114099a2dd95SBruce Richardson
114199a2dd95SBruce Richardson for (n = config->num_fields - 1; n > 0; n--) {
114299a2dd95SBruce Richardson uint32_t field_index = config->defs[n].field_index;
114399a2dd95SBruce Richardson
114499a2dd95SBruce Richardson if (rule->wildness[field_index] == 100)
114599a2dd95SBruce Richardson tally[n][TALLY_DEPTH]++;
114699a2dd95SBruce Richardson else
114799a2dd95SBruce Richardson break;
114899a2dd95SBruce Richardson }
114999a2dd95SBruce Richardson }
115099a2dd95SBruce Richardson
115199a2dd95SBruce Richardson /*
115299a2dd95SBruce Richardson * Look for any field that is always wild and drop it from the config
115399a2dd95SBruce Richardson * Only deactivate if all fields for a given input loop are deactivated.
115499a2dd95SBruce Richardson */
115599a2dd95SBruce Richardson for (n = 1; n < config->num_fields; n++) {
115699a2dd95SBruce Richardson if (config->defs[n].input_index !=
115799a2dd95SBruce Richardson config->defs[n - 1].input_index) {
115899a2dd95SBruce Richardson for (m = start; m < n; m++)
115999a2dd95SBruce Richardson tally[m][TALLY_DEACTIVATED] = deactivate;
116099a2dd95SBruce Richardson fields_deactivated += deactivate;
116199a2dd95SBruce Richardson start = n;
116299a2dd95SBruce Richardson deactivate = 1;
116399a2dd95SBruce Richardson }
116499a2dd95SBruce Richardson
116599a2dd95SBruce Richardson /* if the field is not always completely wild */
116699a2dd95SBruce Richardson if (tally[n][TALLY_100] != tally[n][TALLY_0])
116799a2dd95SBruce Richardson deactivate = 0;
116899a2dd95SBruce Richardson }
116999a2dd95SBruce Richardson
117099a2dd95SBruce Richardson for (m = start; m < n; m++)
117199a2dd95SBruce Richardson tally[m][TALLY_DEACTIVATED] = deactivate;
117299a2dd95SBruce Richardson
117399a2dd95SBruce Richardson fields_deactivated += deactivate;
117499a2dd95SBruce Richardson
117599a2dd95SBruce Richardson /* remove deactivated fields */
117699a2dd95SBruce Richardson if (fields_deactivated) {
117799a2dd95SBruce Richardson uint32_t k, l = 0;
117899a2dd95SBruce Richardson
117999a2dd95SBruce Richardson for (k = 0; k < config->num_fields; k++) {
118099a2dd95SBruce Richardson if (tally[k][TALLY_DEACTIVATED] == 0) {
118199a2dd95SBruce Richardson memmove(&tally[l][0], &tally[k][0],
118299a2dd95SBruce Richardson TALLY_NUM * sizeof(tally[0][0]));
118399a2dd95SBruce Richardson memmove(&config->defs[l++],
118499a2dd95SBruce Richardson &config->defs[k],
118599a2dd95SBruce Richardson sizeof(struct rte_acl_field_def));
118699a2dd95SBruce Richardson }
118799a2dd95SBruce Richardson }
118899a2dd95SBruce Richardson config->num_fields = l;
118999a2dd95SBruce Richardson }
119099a2dd95SBruce Richardson }
119199a2dd95SBruce Richardson
119299a2dd95SBruce Richardson static int
rule_cmp_wildness(struct rte_acl_build_rule * r1,struct rte_acl_build_rule * r2)119399a2dd95SBruce Richardson rule_cmp_wildness(struct rte_acl_build_rule *r1, struct rte_acl_build_rule *r2)
119499a2dd95SBruce Richardson {
119599a2dd95SBruce Richardson uint32_t n;
119699a2dd95SBruce Richardson
119799a2dd95SBruce Richardson for (n = 1; n < r1->config->num_fields; n++) {
119899a2dd95SBruce Richardson int field_index = r1->config->defs[n].field_index;
119999a2dd95SBruce Richardson
120099a2dd95SBruce Richardson if (r1->wildness[field_index] != r2->wildness[field_index])
120199a2dd95SBruce Richardson return r1->wildness[field_index] -
120299a2dd95SBruce Richardson r2->wildness[field_index];
120399a2dd95SBruce Richardson }
120499a2dd95SBruce Richardson return 0;
120599a2dd95SBruce Richardson }
120699a2dd95SBruce Richardson
120799a2dd95SBruce Richardson /*
120899a2dd95SBruce Richardson * Split the rte_acl_build_rule list into two lists.
120999a2dd95SBruce Richardson */
121099a2dd95SBruce Richardson 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)121199a2dd95SBruce Richardson rule_list_split(struct rte_acl_build_rule *source,
121299a2dd95SBruce Richardson struct rte_acl_build_rule **list_a,
121399a2dd95SBruce Richardson struct rte_acl_build_rule **list_b)
121499a2dd95SBruce Richardson {
121599a2dd95SBruce Richardson struct rte_acl_build_rule *fast;
121699a2dd95SBruce Richardson struct rte_acl_build_rule *slow;
121799a2dd95SBruce Richardson
121899a2dd95SBruce Richardson if (source == NULL || source->next == NULL) {
121999a2dd95SBruce Richardson /* length < 2 cases */
122099a2dd95SBruce Richardson *list_a = source;
122199a2dd95SBruce Richardson *list_b = NULL;
122299a2dd95SBruce Richardson } else {
122399a2dd95SBruce Richardson slow = source;
122499a2dd95SBruce Richardson fast = source->next;
122599a2dd95SBruce Richardson /* Advance 'fast' two nodes, and advance 'slow' one node */
122699a2dd95SBruce Richardson while (fast != NULL) {
122799a2dd95SBruce Richardson fast = fast->next;
122899a2dd95SBruce Richardson if (fast != NULL) {
122999a2dd95SBruce Richardson slow = slow->next;
123099a2dd95SBruce Richardson fast = fast->next;
123199a2dd95SBruce Richardson }
123299a2dd95SBruce Richardson }
123399a2dd95SBruce Richardson /* 'slow' is before the midpoint in the list, so split it in two
123499a2dd95SBruce Richardson at that point. */
123599a2dd95SBruce Richardson *list_a = source;
123699a2dd95SBruce Richardson *list_b = slow->next;
123799a2dd95SBruce Richardson slow->next = NULL;
123899a2dd95SBruce Richardson }
123999a2dd95SBruce Richardson }
124099a2dd95SBruce Richardson
124199a2dd95SBruce Richardson /*
124299a2dd95SBruce Richardson * Merge two sorted lists.
124399a2dd95SBruce Richardson */
124499a2dd95SBruce Richardson static struct rte_acl_build_rule *
rule_list_sorted_merge(struct rte_acl_build_rule * a,struct rte_acl_build_rule * b)124599a2dd95SBruce Richardson rule_list_sorted_merge(struct rte_acl_build_rule *a,
124699a2dd95SBruce Richardson struct rte_acl_build_rule *b)
124799a2dd95SBruce Richardson {
124899a2dd95SBruce Richardson struct rte_acl_build_rule *result = NULL;
124999a2dd95SBruce Richardson struct rte_acl_build_rule **last_next = &result;
125099a2dd95SBruce Richardson
125199a2dd95SBruce Richardson while (1) {
125299a2dd95SBruce Richardson if (a == NULL) {
125399a2dd95SBruce Richardson *last_next = b;
125499a2dd95SBruce Richardson break;
125599a2dd95SBruce Richardson } else if (b == NULL) {
125699a2dd95SBruce Richardson *last_next = a;
125799a2dd95SBruce Richardson break;
125899a2dd95SBruce Richardson }
125999a2dd95SBruce Richardson if (rule_cmp_wildness(a, b) >= 0) {
126099a2dd95SBruce Richardson *last_next = a;
126199a2dd95SBruce Richardson last_next = &a->next;
126299a2dd95SBruce Richardson a = a->next;
126399a2dd95SBruce Richardson } else {
126499a2dd95SBruce Richardson *last_next = b;
126599a2dd95SBruce Richardson last_next = &b->next;
126699a2dd95SBruce Richardson b = b->next;
126799a2dd95SBruce Richardson }
126899a2dd95SBruce Richardson }
126999a2dd95SBruce Richardson return result;
127099a2dd95SBruce Richardson }
127199a2dd95SBruce Richardson
127299a2dd95SBruce Richardson /*
127399a2dd95SBruce Richardson * Sort list of rules based on the rules wildness.
127499a2dd95SBruce Richardson * Use recursive mergesort algorithm.
127599a2dd95SBruce Richardson */
127699a2dd95SBruce Richardson static struct rte_acl_build_rule *
sort_rules(struct rte_acl_build_rule * head)127799a2dd95SBruce Richardson sort_rules(struct rte_acl_build_rule *head)
127899a2dd95SBruce Richardson {
127999a2dd95SBruce Richardson struct rte_acl_build_rule *a;
128099a2dd95SBruce Richardson struct rte_acl_build_rule *b;
128199a2dd95SBruce Richardson
128299a2dd95SBruce Richardson /* Base case -- length 0 or 1 */
128399a2dd95SBruce Richardson if (head == NULL || head->next == NULL)
128499a2dd95SBruce Richardson return head;
128599a2dd95SBruce Richardson
128699a2dd95SBruce Richardson /* Split head into 'a' and 'b' sublists */
128799a2dd95SBruce Richardson rule_list_split(head, &a, &b);
128899a2dd95SBruce Richardson
128999a2dd95SBruce Richardson /* Recursively sort the sublists */
129099a2dd95SBruce Richardson a = sort_rules(a);
129199a2dd95SBruce Richardson b = sort_rules(b);
129299a2dd95SBruce Richardson
129399a2dd95SBruce Richardson /* answer = merge the two sorted lists together */
129499a2dd95SBruce Richardson return rule_list_sorted_merge(a, b);
129599a2dd95SBruce Richardson }
129699a2dd95SBruce Richardson
129799a2dd95SBruce Richardson static uint32_t
acl_build_index(const struct rte_acl_config * config,uint32_t * data_index)129899a2dd95SBruce Richardson acl_build_index(const struct rte_acl_config *config, uint32_t *data_index)
129999a2dd95SBruce Richardson {
130099a2dd95SBruce Richardson uint32_t n, m;
130199a2dd95SBruce Richardson int32_t last_header;
130299a2dd95SBruce Richardson
130399a2dd95SBruce Richardson m = 0;
130499a2dd95SBruce Richardson last_header = -1;
130599a2dd95SBruce Richardson
130699a2dd95SBruce Richardson for (n = 0; n < config->num_fields; n++) {
130799a2dd95SBruce Richardson if (last_header != config->defs[n].input_index) {
130899a2dd95SBruce Richardson last_header = config->defs[n].input_index;
130999a2dd95SBruce Richardson data_index[m++] = config->defs[n].offset;
131045109815SKonstantin Ananyev if (config->defs[n].size > sizeof(uint32_t))
131145109815SKonstantin Ananyev data_index[m++] = config->defs[n].offset +
131245109815SKonstantin Ananyev sizeof(uint32_t);
131399a2dd95SBruce Richardson }
131499a2dd95SBruce Richardson }
131599a2dd95SBruce Richardson
131699a2dd95SBruce Richardson return m;
131799a2dd95SBruce Richardson }
131899a2dd95SBruce Richardson
131999a2dd95SBruce Richardson 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)132099a2dd95SBruce Richardson build_one_trie(struct acl_build_context *context,
132199a2dd95SBruce Richardson struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES],
132299a2dd95SBruce Richardson uint32_t n, int32_t node_max)
132399a2dd95SBruce Richardson {
132499a2dd95SBruce Richardson struct rte_acl_build_rule *last;
132599a2dd95SBruce Richardson struct rte_acl_config *config;
132699a2dd95SBruce Richardson
132799a2dd95SBruce Richardson config = rule_sets[n]->config;
132899a2dd95SBruce Richardson
132999a2dd95SBruce Richardson acl_rule_stats(rule_sets[n], config);
133099a2dd95SBruce Richardson rule_sets[n] = sort_rules(rule_sets[n]);
133199a2dd95SBruce Richardson
133299a2dd95SBruce Richardson context->tries[n].type = RTE_ACL_FULL_TRIE;
133399a2dd95SBruce Richardson context->tries[n].count = 0;
133499a2dd95SBruce Richardson
133599a2dd95SBruce Richardson context->tries[n].num_data_indexes = acl_build_index(config,
133699a2dd95SBruce Richardson context->data_indexes[n]);
133799a2dd95SBruce Richardson context->tries[n].data_index = context->data_indexes[n];
133899a2dd95SBruce Richardson
133999a2dd95SBruce Richardson context->cur_node_max = node_max;
134099a2dd95SBruce Richardson
134199a2dd95SBruce Richardson context->bld_tries[n].trie = build_trie(context, rule_sets[n],
134299a2dd95SBruce Richardson &last, &context->tries[n].count);
134399a2dd95SBruce Richardson
134499a2dd95SBruce Richardson return last;
134599a2dd95SBruce Richardson }
134699a2dd95SBruce Richardson
134799a2dd95SBruce Richardson static int
acl_build_tries(struct acl_build_context * context,struct rte_acl_build_rule * head)134899a2dd95SBruce Richardson acl_build_tries(struct acl_build_context *context,
134999a2dd95SBruce Richardson struct rte_acl_build_rule *head)
135099a2dd95SBruce Richardson {
135199a2dd95SBruce Richardson uint32_t n, num_tries;
135299a2dd95SBruce Richardson struct rte_acl_config *config;
135399a2dd95SBruce Richardson struct rte_acl_build_rule *last;
135499a2dd95SBruce Richardson struct rte_acl_build_rule *rule_sets[RTE_ACL_MAX_TRIES];
135599a2dd95SBruce Richardson
135699a2dd95SBruce Richardson config = head->config;
135799a2dd95SBruce Richardson rule_sets[0] = head;
135899a2dd95SBruce Richardson
135999a2dd95SBruce Richardson /* initialize tries */
136099a2dd95SBruce Richardson for (n = 0; n < RTE_DIM(context->tries); n++) {
136199a2dd95SBruce Richardson context->tries[n].type = RTE_ACL_UNUSED_TRIE;
136299a2dd95SBruce Richardson context->bld_tries[n].trie = NULL;
136399a2dd95SBruce Richardson context->tries[n].count = 0;
136499a2dd95SBruce Richardson }
136599a2dd95SBruce Richardson
136699a2dd95SBruce Richardson context->tries[0].type = RTE_ACL_FULL_TRIE;
136799a2dd95SBruce Richardson
136899a2dd95SBruce Richardson /* calc wildness of each field of each rule */
136999a2dd95SBruce Richardson acl_calc_wildness(head, config);
137099a2dd95SBruce Richardson
137199a2dd95SBruce Richardson for (n = 0;; n = num_tries) {
137299a2dd95SBruce Richardson
137399a2dd95SBruce Richardson num_tries = n + 1;
137499a2dd95SBruce Richardson
137599a2dd95SBruce Richardson last = build_one_trie(context, rule_sets, n, context->node_max);
137699a2dd95SBruce Richardson if (context->bld_tries[n].trie == NULL) {
1377*ae67895bSDavid Marchand ACL_LOG(ERR, "Build of %u-th trie failed", n);
137899a2dd95SBruce Richardson return -ENOMEM;
137999a2dd95SBruce Richardson }
138099a2dd95SBruce Richardson
138199a2dd95SBruce Richardson /* Build of the last trie completed. */
138299a2dd95SBruce Richardson if (last == NULL)
138399a2dd95SBruce Richardson break;
138499a2dd95SBruce Richardson
138599a2dd95SBruce Richardson if (num_tries == RTE_DIM(context->tries)) {
1386*ae67895bSDavid Marchand ACL_LOG(ERR,
1387*ae67895bSDavid Marchand "Exceeded max number of tries: %u",
138899a2dd95SBruce Richardson num_tries);
138999a2dd95SBruce Richardson return -ENOMEM;
139099a2dd95SBruce Richardson }
139199a2dd95SBruce Richardson
139299a2dd95SBruce Richardson /* Trie is getting too big, split remaining rule set. */
139399a2dd95SBruce Richardson rule_sets[num_tries] = last->next;
139499a2dd95SBruce Richardson last->next = NULL;
139599a2dd95SBruce Richardson acl_free_node(context, context->bld_tries[n].trie);
139699a2dd95SBruce Richardson
139799a2dd95SBruce Richardson /* Create a new copy of config for remaining rules. */
139899a2dd95SBruce Richardson config = acl_build_alloc(context, 1, sizeof(*config));
139999a2dd95SBruce Richardson memcpy(config, rule_sets[n]->config, sizeof(*config));
140099a2dd95SBruce Richardson
140199a2dd95SBruce Richardson /* Make remaining rules use new config. */
140299a2dd95SBruce Richardson for (head = rule_sets[num_tries]; head != NULL;
140399a2dd95SBruce Richardson head = head->next)
140499a2dd95SBruce Richardson head->config = config;
140599a2dd95SBruce Richardson
140699a2dd95SBruce Richardson /*
140799a2dd95SBruce Richardson * Rebuild the trie for the reduced rule-set.
140899a2dd95SBruce Richardson * Don't try to split it any further.
140999a2dd95SBruce Richardson */
141099a2dd95SBruce Richardson last = build_one_trie(context, rule_sets, n, INT32_MAX);
141199a2dd95SBruce Richardson if (context->bld_tries[n].trie == NULL || last != NULL) {
1412*ae67895bSDavid Marchand ACL_LOG(ERR, "Build of %u-th trie failed", n);
141399a2dd95SBruce Richardson return -ENOMEM;
141499a2dd95SBruce Richardson }
141599a2dd95SBruce Richardson
141699a2dd95SBruce Richardson }
141799a2dd95SBruce Richardson
141899a2dd95SBruce Richardson context->num_tries = num_tries;
141999a2dd95SBruce Richardson return 0;
142099a2dd95SBruce Richardson }
142199a2dd95SBruce Richardson
142299a2dd95SBruce Richardson static void
acl_build_log(const struct acl_build_context * ctx)142399a2dd95SBruce Richardson acl_build_log(const struct acl_build_context *ctx)
142499a2dd95SBruce Richardson {
142599a2dd95SBruce Richardson uint32_t n;
142699a2dd95SBruce Richardson
142799a2dd95SBruce Richardson RTE_LOG(DEBUG, ACL, "Build phase for ACL \"%s\":\n"
142899a2dd95SBruce Richardson "node limit for tree split: %u\n"
142999a2dd95SBruce Richardson "nodes created: %u\n"
143099a2dd95SBruce Richardson "memory consumed: %zu\n",
143199a2dd95SBruce Richardson ctx->acx->name,
143299a2dd95SBruce Richardson ctx->node_max,
143399a2dd95SBruce Richardson ctx->num_nodes,
143499a2dd95SBruce Richardson ctx->pool.alloc);
143599a2dd95SBruce Richardson
143699a2dd95SBruce Richardson for (n = 0; n < RTE_DIM(ctx->tries); n++) {
143799a2dd95SBruce Richardson if (ctx->tries[n].count != 0)
1438*ae67895bSDavid Marchand ACL_LOG(DEBUG,
1439*ae67895bSDavid Marchand "trie %u: number of rules: %u, indexes: %u",
144099a2dd95SBruce Richardson n, ctx->tries[n].count,
144199a2dd95SBruce Richardson ctx->tries[n].num_data_indexes);
144299a2dd95SBruce Richardson }
144399a2dd95SBruce Richardson }
144499a2dd95SBruce Richardson
144599a2dd95SBruce Richardson static int
acl_build_rules(struct acl_build_context * bcx)144699a2dd95SBruce Richardson acl_build_rules(struct acl_build_context *bcx)
144799a2dd95SBruce Richardson {
144899a2dd95SBruce Richardson struct rte_acl_build_rule *br, *head;
144999a2dd95SBruce Richardson const struct rte_acl_rule *rule;
145099a2dd95SBruce Richardson uint32_t *wp;
145199a2dd95SBruce Richardson uint32_t fn, i, n, num;
145299a2dd95SBruce Richardson size_t ofs, sz;
145399a2dd95SBruce Richardson
145499a2dd95SBruce Richardson fn = bcx->cfg.num_fields;
145599a2dd95SBruce Richardson n = bcx->acx->num_rules;
145699a2dd95SBruce Richardson ofs = n * sizeof(*br);
145799a2dd95SBruce Richardson sz = ofs + n * fn * sizeof(*wp);
145899a2dd95SBruce Richardson
145999a2dd95SBruce Richardson br = tb_alloc(&bcx->pool, sz);
146099a2dd95SBruce Richardson
146199a2dd95SBruce Richardson wp = (uint32_t *)((uintptr_t)br + ofs);
146299a2dd95SBruce Richardson num = 0;
146399a2dd95SBruce Richardson head = NULL;
146499a2dd95SBruce Richardson
146599a2dd95SBruce Richardson for (i = 0; i != n; i++) {
146699a2dd95SBruce Richardson rule = (const struct rte_acl_rule *)
146799a2dd95SBruce Richardson ((uintptr_t)bcx->acx->rules + bcx->acx->rule_sz * i);
146899a2dd95SBruce Richardson if ((rule->data.category_mask & bcx->category_mask) != 0) {
146999a2dd95SBruce Richardson br[num].next = head;
147099a2dd95SBruce Richardson br[num].config = &bcx->cfg;
147199a2dd95SBruce Richardson br[num].f = rule;
147299a2dd95SBruce Richardson br[num].wildness = wp;
147399a2dd95SBruce Richardson wp += fn;
147499a2dd95SBruce Richardson head = br + num;
147599a2dd95SBruce Richardson num++;
147699a2dd95SBruce Richardson }
147799a2dd95SBruce Richardson }
147899a2dd95SBruce Richardson
147999a2dd95SBruce Richardson bcx->num_rules = num;
148099a2dd95SBruce Richardson bcx->build_rules = head;
148199a2dd95SBruce Richardson
148299a2dd95SBruce Richardson return 0;
148399a2dd95SBruce Richardson }
148499a2dd95SBruce Richardson
148599a2dd95SBruce Richardson /*
148699a2dd95SBruce Richardson * Copy data_indexes for each trie into RT location.
148799a2dd95SBruce Richardson */
148899a2dd95SBruce Richardson static void
acl_set_data_indexes(struct rte_acl_ctx * ctx)148999a2dd95SBruce Richardson acl_set_data_indexes(struct rte_acl_ctx *ctx)
149099a2dd95SBruce Richardson {
149199a2dd95SBruce Richardson uint32_t i, n, ofs;
149299a2dd95SBruce Richardson
149399a2dd95SBruce Richardson ofs = 0;
149499a2dd95SBruce Richardson for (i = 0; i != ctx->num_tries; i++) {
149599a2dd95SBruce Richardson n = ctx->trie[i].num_data_indexes;
149699a2dd95SBruce Richardson memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index,
149799a2dd95SBruce Richardson n * sizeof(ctx->data_indexes[0]));
149899a2dd95SBruce Richardson ctx->trie[i].data_index = ctx->data_indexes + ofs;
149945109815SKonstantin Ananyev ofs += ACL_MAX_INDEXES;
150099a2dd95SBruce Richardson }
150199a2dd95SBruce Richardson }
150299a2dd95SBruce Richardson
150399a2dd95SBruce Richardson /*
150499a2dd95SBruce Richardson * Internal routine, performs 'build' phase of trie generation:
150599a2dd95SBruce Richardson * - setups build context.
15064a6672c2SStephen Hemminger * - analyzes given set of rules.
150799a2dd95SBruce Richardson * - builds internal tree(s).
150899a2dd95SBruce Richardson */
150999a2dd95SBruce Richardson static int
acl_bld(struct acl_build_context * bcx,struct rte_acl_ctx * ctx,const struct rte_acl_config * cfg,uint32_t node_max)151099a2dd95SBruce Richardson acl_bld(struct acl_build_context *bcx, struct rte_acl_ctx *ctx,
151199a2dd95SBruce Richardson const struct rte_acl_config *cfg, uint32_t node_max)
151299a2dd95SBruce Richardson {
151399a2dd95SBruce Richardson int32_t rc;
151499a2dd95SBruce Richardson
151599a2dd95SBruce Richardson /* setup build context. */
151699a2dd95SBruce Richardson memset(bcx, 0, sizeof(*bcx));
151799a2dd95SBruce Richardson bcx->acx = ctx;
151899a2dd95SBruce Richardson bcx->pool.alignment = ACL_POOL_ALIGN;
151999a2dd95SBruce Richardson bcx->pool.min_alloc = ACL_POOL_ALLOC_MIN;
152099a2dd95SBruce Richardson bcx->cfg = *cfg;
152199a2dd95SBruce Richardson bcx->category_mask = RTE_LEN2MASK(bcx->cfg.num_categories,
152299a2dd95SBruce Richardson typeof(bcx->category_mask));
152399a2dd95SBruce Richardson bcx->node_max = node_max;
152499a2dd95SBruce Richardson
152599a2dd95SBruce Richardson rc = sigsetjmp(bcx->pool.fail, 0);
152699a2dd95SBruce Richardson
152799a2dd95SBruce Richardson /* build phase runs out of memory. */
152899a2dd95SBruce Richardson if (rc != 0) {
1529*ae67895bSDavid Marchand ACL_LOG(ERR,
1530*ae67895bSDavid Marchand "ACL context: %s, %s() failed with error code: %d",
153199a2dd95SBruce Richardson bcx->acx->name, __func__, rc);
153299a2dd95SBruce Richardson return rc;
153399a2dd95SBruce Richardson }
153499a2dd95SBruce Richardson
153599a2dd95SBruce Richardson /* Create a build rules copy. */
153699a2dd95SBruce Richardson rc = acl_build_rules(bcx);
153799a2dd95SBruce Richardson if (rc != 0)
153899a2dd95SBruce Richardson return rc;
153999a2dd95SBruce Richardson
154099a2dd95SBruce Richardson /* No rules to build for that context+config */
154199a2dd95SBruce Richardson if (bcx->build_rules == NULL) {
154299a2dd95SBruce Richardson rc = -EINVAL;
154399a2dd95SBruce Richardson } else {
154499a2dd95SBruce Richardson /* build internal trie representation. */
154599a2dd95SBruce Richardson rc = acl_build_tries(bcx, bcx->build_rules);
154699a2dd95SBruce Richardson }
154799a2dd95SBruce Richardson return rc;
154899a2dd95SBruce Richardson }
154999a2dd95SBruce Richardson
155099a2dd95SBruce Richardson /*
155199a2dd95SBruce Richardson * Check that parameters for acl_build() are valid.
155299a2dd95SBruce Richardson */
155399a2dd95SBruce Richardson static int
acl_check_bld_param(struct rte_acl_ctx * ctx,const struct rte_acl_config * cfg)155499a2dd95SBruce Richardson acl_check_bld_param(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
155599a2dd95SBruce Richardson {
155699a2dd95SBruce Richardson static const size_t field_sizes[] = {
155799a2dd95SBruce Richardson sizeof(uint8_t), sizeof(uint16_t),
155899a2dd95SBruce Richardson sizeof(uint32_t), sizeof(uint64_t),
155999a2dd95SBruce Richardson };
156099a2dd95SBruce Richardson
156199a2dd95SBruce Richardson uint32_t i, j;
156299a2dd95SBruce Richardson
156399a2dd95SBruce Richardson if (ctx == NULL || cfg == NULL || cfg->num_categories == 0 ||
156499a2dd95SBruce Richardson cfg->num_categories > RTE_ACL_MAX_CATEGORIES ||
156599a2dd95SBruce Richardson cfg->num_fields == 0 ||
156699a2dd95SBruce Richardson cfg->num_fields > RTE_ACL_MAX_FIELDS)
156799a2dd95SBruce Richardson return -EINVAL;
156899a2dd95SBruce Richardson
156999a2dd95SBruce Richardson for (i = 0; i != cfg->num_fields; i++) {
157099a2dd95SBruce Richardson if (cfg->defs[i].type > RTE_ACL_FIELD_TYPE_BITMASK) {
1571*ae67895bSDavid Marchand ACL_LOG(ERR,
1572*ae67895bSDavid Marchand "ACL context: %s, invalid type: %hhu for %u-th field",
157399a2dd95SBruce Richardson ctx->name, cfg->defs[i].type, i);
157499a2dd95SBruce Richardson return -EINVAL;
157599a2dd95SBruce Richardson }
157699a2dd95SBruce Richardson for (j = 0;
157799a2dd95SBruce Richardson j != RTE_DIM(field_sizes) &&
157899a2dd95SBruce Richardson cfg->defs[i].size != field_sizes[j];
157999a2dd95SBruce Richardson j++)
158099a2dd95SBruce Richardson ;
158199a2dd95SBruce Richardson
158299a2dd95SBruce Richardson if (j == RTE_DIM(field_sizes)) {
1583*ae67895bSDavid Marchand ACL_LOG(ERR,
1584*ae67895bSDavid Marchand "ACL context: %s, invalid size: %hhu for %u-th field",
158599a2dd95SBruce Richardson ctx->name, cfg->defs[i].size, i);
158699a2dd95SBruce Richardson return -EINVAL;
158799a2dd95SBruce Richardson }
158899a2dd95SBruce Richardson }
158999a2dd95SBruce Richardson
159099a2dd95SBruce Richardson return 0;
159199a2dd95SBruce Richardson }
159299a2dd95SBruce Richardson
159399a2dd95SBruce Richardson /*
159499a2dd95SBruce Richardson * With current ACL implementation first field in the rule definition
159599a2dd95SBruce Richardson * has always to be one byte long. Though for optimising *classify*
159699a2dd95SBruce Richardson * implementation it might be useful to be able to use 4B reads
159799a2dd95SBruce Richardson * (as we do for rest of the fields).
159899a2dd95SBruce Richardson * This function checks input config to determine is it safe to do 4B
159999a2dd95SBruce Richardson * loads for first ACL field. For that we need to make sure that
160099a2dd95SBruce Richardson * first field in our rule definition doesn't have the biggest offset,
160199a2dd95SBruce Richardson * i.e. we still do have other fields located after the first one.
160299a2dd95SBruce Richardson * Contrary if first field has the largest offset, then it means
160399a2dd95SBruce Richardson * first field can occupy the very last byte in the input data buffer,
160499a2dd95SBruce Richardson * and we have to do single byte load for it.
160599a2dd95SBruce Richardson */
160699a2dd95SBruce Richardson static uint32_t
get_first_load_size(const struct rte_acl_config * cfg)160799a2dd95SBruce Richardson get_first_load_size(const struct rte_acl_config *cfg)
160899a2dd95SBruce Richardson {
160999a2dd95SBruce Richardson uint32_t i, max_ofs, ofs;
161099a2dd95SBruce Richardson
161199a2dd95SBruce Richardson ofs = 0;
161299a2dd95SBruce Richardson max_ofs = 0;
161399a2dd95SBruce Richardson
161499a2dd95SBruce Richardson for (i = 0; i != cfg->num_fields; i++) {
161599a2dd95SBruce Richardson if (cfg->defs[i].field_index == 0)
161699a2dd95SBruce Richardson ofs = cfg->defs[i].offset;
161799a2dd95SBruce Richardson else if (max_ofs < cfg->defs[i].offset)
161899a2dd95SBruce Richardson max_ofs = cfg->defs[i].offset;
161999a2dd95SBruce Richardson }
162099a2dd95SBruce Richardson
162199a2dd95SBruce Richardson return (ofs < max_ofs) ? sizeof(uint32_t) : sizeof(uint8_t);
162299a2dd95SBruce Richardson }
162399a2dd95SBruce Richardson
162499a2dd95SBruce Richardson int
rte_acl_build(struct rte_acl_ctx * ctx,const struct rte_acl_config * cfg)162599a2dd95SBruce Richardson rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg)
162699a2dd95SBruce Richardson {
162799a2dd95SBruce Richardson int32_t rc;
162899a2dd95SBruce Richardson uint32_t n;
162999a2dd95SBruce Richardson size_t max_size;
163099a2dd95SBruce Richardson struct acl_build_context bcx;
163199a2dd95SBruce Richardson
163299a2dd95SBruce Richardson rc = acl_check_bld_param(ctx, cfg);
163399a2dd95SBruce Richardson if (rc != 0)
163499a2dd95SBruce Richardson return rc;
163599a2dd95SBruce Richardson
163699a2dd95SBruce Richardson acl_build_reset(ctx);
163799a2dd95SBruce Richardson
163899a2dd95SBruce Richardson if (cfg->max_size == 0) {
163999a2dd95SBruce Richardson n = NODE_MIN;
164099a2dd95SBruce Richardson max_size = SIZE_MAX;
164199a2dd95SBruce Richardson } else {
164299a2dd95SBruce Richardson n = NODE_MAX;
164399a2dd95SBruce Richardson max_size = cfg->max_size;
164499a2dd95SBruce Richardson }
164599a2dd95SBruce Richardson
164699a2dd95SBruce Richardson for (rc = -ERANGE; n >= NODE_MIN && rc == -ERANGE; n /= 2) {
164799a2dd95SBruce Richardson
164899a2dd95SBruce Richardson /* perform build phase. */
164999a2dd95SBruce Richardson rc = acl_bld(&bcx, ctx, cfg, n);
165099a2dd95SBruce Richardson
165199a2dd95SBruce Richardson if (rc == 0) {
165299a2dd95SBruce Richardson /* allocate and fill run-time structures. */
165399a2dd95SBruce Richardson rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries,
165499a2dd95SBruce Richardson bcx.num_tries, bcx.cfg.num_categories,
165545109815SKonstantin Ananyev ACL_MAX_INDEXES * RTE_DIM(bcx.tries) *
165699a2dd95SBruce Richardson sizeof(ctx->data_indexes[0]), max_size);
165799a2dd95SBruce Richardson if (rc == 0) {
165899a2dd95SBruce Richardson /* set data indexes. */
165999a2dd95SBruce Richardson acl_set_data_indexes(ctx);
166099a2dd95SBruce Richardson
166199a2dd95SBruce Richardson /* determine can we always do 4B load */
166299a2dd95SBruce Richardson ctx->first_load_sz = get_first_load_size(cfg);
166399a2dd95SBruce Richardson
166499a2dd95SBruce Richardson /* copy in build config. */
166599a2dd95SBruce Richardson ctx->config = *cfg;
166699a2dd95SBruce Richardson }
166799a2dd95SBruce Richardson }
166899a2dd95SBruce Richardson
166999a2dd95SBruce Richardson acl_build_log(&bcx);
167099a2dd95SBruce Richardson
167199a2dd95SBruce Richardson /* cleanup after build. */
167299a2dd95SBruce Richardson tb_free_pool(&bcx.pool);
167399a2dd95SBruce Richardson }
167499a2dd95SBruce Richardson
167599a2dd95SBruce Richardson return rc;
167699a2dd95SBruce Richardson }
1677