LCOV - code coverage report
Current view: top level - lib/acl - acl_bld.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 538 563 95.6 %
Date: 2025-05-01 17:49:45 Functions: 35 35 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 305 350 87.1 %

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

Generated by: LCOV version 1.14