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> 6*73d85848SStephen Hemminger #include <rte_log.h> 7*73d85848SStephen Hemminger 899a2dd95SBruce Richardson #include "tb_mem.h" 999a2dd95SBruce Richardson #include "acl.h" 10*73d85848SStephen 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 * 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 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 * 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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: 102099a2dd95SBruce Richardson RTE_LOG(ERR, ACL, 102199a2dd95SBruce Richardson "Error in rule[%u] type - %hhu\n", 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 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 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 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 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 * 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 * 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 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 * 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 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) { 137799a2dd95SBruce Richardson RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", 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)) { 138699a2dd95SBruce Richardson RTE_LOG(ERR, ACL, 138799a2dd95SBruce Richardson "Exceeded max number of tries: %u\n", 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) { 141299a2dd95SBruce Richardson RTE_LOG(ERR, ACL, "Build of %u-th trie failed\n", 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 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) 143899a2dd95SBruce Richardson RTE_LOG(DEBUG, ACL, 143999a2dd95SBruce Richardson "trie %u: number of rules: %u, indexes: %u\n", 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 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 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 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) { 152999a2dd95SBruce Richardson RTE_LOG(ERR, ACL, 153099a2dd95SBruce Richardson "ACL context: %s, %s() failed with error code: %d\n", 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 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) { 157199a2dd95SBruce Richardson RTE_LOG(ERR, ACL, 157299a2dd95SBruce Richardson "ACL context: %s, invalid type: %hhu for %u-th field\n", 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)) { 158399a2dd95SBruce Richardson RTE_LOG(ERR, ACL, 158499a2dd95SBruce Richardson "ACL context: %s, invalid size: %hhu for %u-th field\n", 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 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 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