dpdk/lib/librte_efd/rte_efd.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2016-2017 Intel Corporation
   3 */
   4#include <stdio.h>
   5#include <string.h>
   6#include <stdint.h>
   7#include <inttypes.h>
   8#include <errno.h>
   9#include <stdarg.h>
  10#include <sys/queue.h>
  11
  12#include <rte_string_fns.h>
  13#include <rte_log.h>
  14#include <rte_eal_memconfig.h>
  15#include <rte_errno.h>
  16#include <rte_malloc.h>
  17#include <rte_prefetch.h>
  18#include <rte_branch_prediction.h>
  19#include <rte_memcpy.h>
  20#include <rte_ring.h>
  21#include <rte_jhash.h>
  22#include <rte_hash_crc.h>
  23#include <rte_tailq.h>
  24#include <rte_vect.h>
  25
  26#include "rte_efd.h"
  27#if defined(RTE_ARCH_X86)
  28#include "rte_efd_x86.h"
  29#elif defined(RTE_ARCH_ARM64)
  30#include "rte_efd_arm64.h"
  31#endif
  32
  33#define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len))
  34/** Hash function used to determine chunk_id and bin_id for a group */
  35#define EFD_HASH(key, table) \
  36        (uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34))
  37/** Hash function used as constant component of perfect hash search */
  38#define EFD_HASHFUNCA(key, table) \
  39        (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35))
  40/** Hash function used as multiplicative component of perfect hash search */
  41#define EFD_HASHFUNCB(key, table) \
  42        (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36))
  43
  44/*************************************************************************
  45 * Fixed constants
  46 *************************************************************************/
  47
  48/* These parameters are fixed by the efd_bin_to_group balancing table */
  49#define EFD_CHUNK_NUM_GROUPS (64)
  50#define EFD_CHUNK_NUM_BINS   (256)
  51#define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \
  52        (EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
  53
  54/*
  55 * Target number of rules that each chunk is created to handle.
  56 * Used when initially allocating the table
  57 */
  58#define EFD_TARGET_CHUNK_NUM_RULES  \
  59        (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
  60/*
  61 * Max number of rules that each chunk is created to handle.
  62 * Used when initially allocating the table
  63 */
  64#define EFD_TARGET_CHUNK_MAX_NUM_RULES  \
  65        (EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES)
  66
  67/** This is fixed based on the bin_to_group permutation array */
  68#define EFD_MAX_GROUP_NUM_BINS (16)
  69
  70/**
  71 * The end of the chunks array needs some extra padding to ensure
  72 * that vectorization over-reads on the last online chunk stay within
  73allocated memory
  74 */
  75#define EFD_NUM_CHUNK_PADDING_BYTES (256)
  76
  77/* All different internal lookup functions */
  78enum efd_lookup_internal_function {
  79        EFD_LOOKUP_SCALAR = 0,
  80        EFD_LOOKUP_AVX2,
  81        EFD_LOOKUP_NEON,
  82        EFD_LOOKUP_NUM
  83};
  84
  85TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
  86
  87static struct rte_tailq_elem rte_efd_tailq = {
  88        .name = "RTE_EFD",
  89};
  90EAL_REGISTER_TAILQ(rte_efd_tailq);
  91
  92/** Internal permutation array used to shuffle bins into pseudorandom groups */
  93const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
  94        {
  95                0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
  96                4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
  97                8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
  98                12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
  99                16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
 100                20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
 101                24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
 102                28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
 103                32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
 104                36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
 105                40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
 106                44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
 107                48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
 108                52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
 109                56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
 110                60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
 111        },
 112        {
 113                34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
 114                44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
 115                46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
 116                1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
 117                6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
 118                51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
 119                54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
 120                45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
 121                13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
 122                56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
 123                2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
 124                22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
 125                0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
 126                53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
 127                63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
 128                49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
 129        },
 130        {
 131                32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
 132                55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
 133                40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
 134                41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
 135                13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
 136                38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
 137                5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
 138                24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
 139                25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
 140                57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
 141                13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
 142                33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
 143                8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
 144                18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
 145                47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
 146                6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
 147        },
 148        {
 149                29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
 150                59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
 151                35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
 152                13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
 153                55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
 154                17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
 155                14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
 156                39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
 157                55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
 158                31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
 159                27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
 160                47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
 161                29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
 162                35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
 163                38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
 164                24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
 165        },
 166};
 167
 168/*************************************************************************
 169 * Offline region structures
 170 *************************************************************************/
 171
 172/** Online group containing number of rules, values, keys and their bins
 173 * for EFD_MAX_GROUP_NUM_RULES rules.
 174 */
 175struct efd_offline_group_rules {
 176        uint32_t num_rules;
 177        /**< Sum of the number of rules in all bins assigned to this group. */
 178
 179        uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES];
 180        /**< Array with all keys of the group. */
 181        efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
 182        /**< Array with all values of the keys of the group. */
 183
 184        uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
 185        /**< Stores the bin for each corresponding key to
 186         * avoid having to recompute it
 187         */
 188};
 189
 190/** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
 191 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
 192 */
 193struct efd_offline_chunk_rules {
 194        uint16_t num_rules;
 195        /**< Number of rules in the entire chunk;
 196         * used to detect unbalanced groups
 197         */
 198
 199        struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
 200        /**< Array of all groups in the chunk. */
 201};
 202
 203/*************************************************************************
 204 * Online region structures
 205 *************************************************************************/
 206
 207/** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
 208struct efd_online_group_entry {
 209        efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS];
 210        efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS];
 211} __rte_packed;
 212
 213/**
 214 * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
 215 * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
 216 */
 217struct efd_online_chunk {
 218        uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
 219        /**< This is a packed indirection index into the 'groups' array.
 220         * Each byte contains four two-bit values which index into
 221         * the efd_bin_to_group array.
 222         * The efd_bin_to_group array returns the index into the groups array
 223         */
 224
 225        struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
 226        /**< Array of all the groups in the chunk. */
 227} __rte_packed;
 228
 229/**
 230 * EFD table structure
 231 */
 232struct rte_efd_table {
 233        char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
 234
 235        uint32_t key_len; /**< Length of the key stored offline */
 236
 237        uint32_t max_num_rules;
 238        /**< Static maximum number of entries the table was constructed to hold. */
 239
 240        uint32_t num_rules;
 241        /**< Number of entries currently in the table . */
 242
 243        uint32_t num_chunks;
 244        /**< Number of chunks in the table needed to support num_rules. */
 245
 246        uint32_t num_chunks_shift;
 247        /**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
 248
 249        enum efd_lookup_internal_function lookup_fn;
 250        /**< Indicates which lookup function to use. */
 251
 252        struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
 253        /**< Dynamic array of size num_chunks of chunk records. */
 254
 255        struct efd_offline_chunk_rules *offline_chunks;
 256        /**< Dynamic array of size num_chunks of key-value pairs. */
 257
 258        struct rte_ring *free_slots;
 259        /**< Ring that stores all indexes of the free slots in the key table */
 260
 261        uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */
 262};
 263
 264/**
 265 * Computes the chunk ID for a given key hash
 266 *
 267 * @param table
 268 *   EFD table to reference
 269 * @param hashed_key
 270 *   32-bit key hash returned by EFD_HASH
 271 *
 272 * @return
 273 *   chunk ID containing this key hash
 274 */
 275static inline uint32_t
 276efd_get_chunk_id(const struct rte_efd_table * const table,
 277                const uint32_t hashed_key)
 278{
 279        return hashed_key & (table->num_chunks - 1);
 280}
 281
 282/**
 283 * Computes the bin ID for a given key hash
 284 *
 285 * @param table
 286 *   EFD table to reference
 287 * @param hashed_key
 288 *   32-bit key hash returned by EFD_HASH
 289 *
 290 * @return bin ID containing this key hash
 291 */
 292static inline uint32_t
 293efd_get_bin_id(const struct rte_efd_table * const table,
 294                const uint32_t hashed_key)
 295{
 296        return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
 297}
 298
 299/**
 300 * Looks up the current permutation choice for a particular bin in the online table
 301 *
 302 * @param table
 303 *  EFD table to reference
 304 * @param socket_id
 305 *   Socket ID to use to look up existing values (ideally caller's socket id)
 306 * @param chunk_id
 307 *   Chunk ID of bin to look up
 308 * @param bin_id
 309 *   Bin ID to look up
 310 *
 311 * @return
 312 *   Currently active permutation choice in the online table
 313 */
 314static inline uint8_t
 315efd_get_choice(const struct rte_efd_table * const table,
 316                const unsigned int socket_id, const uint32_t chunk_id,
 317                const uint32_t bin_id)
 318{
 319        struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
 320
 321        /*
 322         * Grab the chunk (byte) that contains the choices
 323         * for four neighboring bins.
 324         */
 325        uint8_t choice_chunk =
 326                        chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
 327
 328        /*
 329         * Compute the offset into the chunk that contains
 330         * the group_id lookup position
 331         */
 332        int offset = (bin_id & 0x3) * 2;
 333
 334        /* Extract from the byte just the desired lookup position */
 335        return (uint8_t) ((choice_chunk >> offset) & 0x3);
 336}
 337
 338/**
 339 * Compute the chunk_id and bin_id for a given key
 340 *
 341 * @param table
 342 *   EFD table to reference
 343 * @param key
 344 *   Key to hash and find location of
 345 * @param chunk_id
 346 *   Computed chunk ID
 347 * @param bin_id
 348 *   Computed bin ID
 349 *
 350 */
 351static inline void
 352efd_compute_ids(const struct rte_efd_table * const table,
 353                const void *key, uint32_t * const chunk_id, uint32_t * const bin_id)
 354{
 355        /* Compute the position of the entry in the hash table */
 356        uint32_t h = EFD_HASH(key, table);
 357
 358        /* Compute the chunk_id where that entry can be found */
 359        *chunk_id = efd_get_chunk_id(table, h);
 360
 361        /*
 362         * Compute the bin within that chunk where the entry
 363         * can be found (0 - 255)
 364         */
 365        *bin_id = efd_get_bin_id(table, h);
 366}
 367
 368/**
 369 * Search for a hash function for a group that satisfies all group results
 370 */
 371static inline int
 372efd_search_hash(struct rte_efd_table * const table,
 373                const struct efd_offline_group_rules * const off_group,
 374                struct efd_online_group_entry * const on_group)
 375{
 376        efd_hashfunc_t hash_idx;
 377        efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS];
 378        efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS];
 379
 380        uint32_t i, j, rule_id;
 381        uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
 382        uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
 383        uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
 384
 385
 386        rte_prefetch0(off_group->value);
 387
 388        /*
 389         * Prepopulate the hash_val tables by running the two hash functions
 390         * for each provided rule
 391         */
 392        for (i = 0; i < off_group->num_rules; i++) {
 393                void *key_stored = EFD_KEY(off_group->key_idx[i], table);
 394                hash_val_b[i] = EFD_HASHFUNCB(key_stored, table);
 395                hash_val_a[i] = EFD_HASHFUNCA(key_stored, table);
 396        }
 397
 398        for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
 399                hash_idx = on_group->hash_idx[i];
 400                start_hash_idx[i] = hash_idx;
 401                start_lookup_table[i] = on_group->lookup_table[i];
 402
 403                do {
 404                        efd_lookuptbl_t lookup_table = 0;
 405                        efd_lookuptbl_t lookup_table_complement = 0;
 406
 407                        for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
 408                                hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
 409                                        hash_val_b[rule_id]);
 410
 411                        /*
 412                         * The goal here is to find a hash function for this
 413                         * particular bit entry that meets the following criteria:
 414                         * The most significant bits of the hash result define a
 415                         * shift into the lookup table where the bit will be stored
 416                         */
 417
 418                        /* Iterate over each provided rule */
 419                        for (rule_id = 0; rule_id < off_group->num_rules;
 420                                        rule_id++) {
 421                                /*
 422                                 * Use the few most significant bits (number based on
 423                                 * EFD_LOOKUPTBL_SIZE) to see what position the
 424                                 * expected bit should be set in the lookup_table
 425                                 */
 426                                uint32_t bucket_idx = hash_val[rule_id] >>
 427                                                EFD_LOOKUPTBL_SHIFT;
 428
 429                                /*
 430                                 * Get the current bit of interest.
 431                                 * This only find an appropriate hash function
 432                                 * for one bit at a time of the rule
 433                                 */
 434                                efd_lookuptbl_t expected =
 435                                                (off_group->value[rule_id] >> i) & 0x1;
 436
 437                                /*
 438                                 * Add the expected bit (if set) to a map
 439                                 * (lookup_table). Also set its complement
 440                                 * in lookup_table_complement
 441                                 */
 442                                lookup_table |= expected << bucket_idx;
 443                                lookup_table_complement |= (1 - expected)
 444                                                << bucket_idx;
 445
 446                                /*
 447                                 * If ever the hash function of two different
 448                                 * elements result in different values at the
 449                                 * same location in the lookup_table,
 450                                 * the current hash_idx is not valid.
 451                                 */
 452                                if (lookup_table & lookup_table_complement)
 453                                        break;
 454                        }
 455
 456                        /*
 457                         * Check if the previous loop completed without
 458                         * breaking early
 459                         */
 460                        if (rule_id == off_group->num_rules) {
 461                                /*
 462                                 * Current hash function worked, store it
 463                                 * for the current group
 464                                 */
 465                                on_group->hash_idx[i] = hash_idx;
 466                                on_group->lookup_table[i] = lookup_table;
 467
 468                                /*
 469                                 * Make sure that the hash function has changed
 470                                 * from the starting value
 471                                 */
 472                                hash_idx = start_hash_idx[i] + 1;
 473                                break;
 474                        }
 475                        hash_idx++;
 476
 477                } while (hash_idx != start_hash_idx[i]);
 478
 479                /* Failed to find perfect hash for this group */
 480                if (hash_idx == start_hash_idx[i]) {
 481                        /*
 482                         * Restore previous hash_idx and lookup_table
 483                         * for all value bits
 484                         */
 485                        for (j = 0; j < i; j++) {
 486                                on_group->hash_idx[j] = start_hash_idx[j];
 487                                on_group->lookup_table[j] = start_lookup_table[j];
 488                        }
 489                        return 1;
 490                }
 491        }
 492
 493        return 0;
 494}
 495
 496struct rte_efd_table *
 497rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len,
 498                uint8_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket)
 499{
 500        struct rte_efd_table *table = NULL;
 501        uint8_t *key_array = NULL;
 502        uint32_t num_chunks, num_chunks_shift;
 503        uint8_t socket_id;
 504        struct rte_efd_list *efd_list = NULL;
 505        struct rte_tailq_entry *te;
 506        uint64_t offline_table_size;
 507        char ring_name[RTE_RING_NAMESIZE];
 508        struct rte_ring *r = NULL;
 509        unsigned int i;
 510
 511        efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
 512
 513        if (online_cpu_socket_bitmask == 0) {
 514                RTE_LOG(ERR, EFD, "At least one CPU socket must be enabled "
 515                                "in the bitmask\n");
 516                return NULL;
 517        }
 518
 519        if (max_num_rules == 0) {
 520                RTE_LOG(ERR, EFD, "Max num rules must be higher than 0\n");
 521                return NULL;
 522        }
 523
 524        /*
 525         * Compute the minimum number of chunks (smallest power of 2)
 526         * that can hold all of the rules
 527         */
 528        if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
 529                num_chunks = rte_align32pow2(max_num_rules /
 530                        EFD_TARGET_CHUNK_NUM_RULES);
 531        else
 532                num_chunks = rte_align32pow2((max_num_rules /
 533                        EFD_TARGET_CHUNK_NUM_RULES) + 1);
 534
 535        num_chunks_shift = rte_bsf32(num_chunks);
 536
 537        rte_mcfg_tailq_write_lock();
 538
 539        /*
 540         * Guarantee there's no existing: this is normally already checked
 541         * by ring creation above
 542         */
 543        TAILQ_FOREACH(te, efd_list, next)
 544        {
 545                table = (struct rte_efd_table *) te->data;
 546                if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
 547                        break;
 548        }
 549
 550        table = NULL;
 551        if (te != NULL) {
 552                rte_errno = EEXIST;
 553                te = NULL;
 554                goto error_unlock_exit;
 555        }
 556
 557        te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
 558        if (te == NULL) {
 559                RTE_LOG(ERR, EFD, "tailq entry allocation failed\n");
 560                goto error_unlock_exit;
 561        }
 562
 563        /* Create a new EFD table management structure */
 564        table = rte_zmalloc_socket(NULL,
 565                        sizeof(struct rte_efd_table),
 566                        RTE_CACHE_LINE_SIZE,
 567                        offline_cpu_socket);
 568        if (table == NULL) {
 569                RTE_LOG(ERR, EFD, "Allocating EFD table management structure"
 570                                " on socket %u failed\n",
 571                                offline_cpu_socket);
 572                goto error_unlock_exit;
 573        }
 574
 575
 576        RTE_LOG(DEBUG, EFD, "Allocated EFD table management structure "
 577                        "on socket %u\n", offline_cpu_socket);
 578
 579        table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES;
 580        table->num_rules = 0;
 581        table->num_chunks = num_chunks;
 582        table->num_chunks_shift = num_chunks_shift;
 583        table->key_len = key_len;
 584
 585        /* key_array */
 586        key_array = rte_zmalloc_socket(NULL,
 587                        table->max_num_rules * table->key_len,
 588                        RTE_CACHE_LINE_SIZE,
 589                        offline_cpu_socket);
 590        if (key_array == NULL) {
 591                RTE_LOG(ERR, EFD, "Allocating key array"
 592                                " on socket %u failed\n",
 593                                offline_cpu_socket);
 594                goto error_unlock_exit;
 595        }
 596        table->keys = key_array;
 597        strlcpy(table->name, name, sizeof(table->name));
 598
 599        RTE_LOG(DEBUG, EFD, "Creating an EFD table with %u chunks,"
 600                        " which potentially supports %u entries\n",
 601                        num_chunks, table->max_num_rules);
 602
 603        /* Make sure all the allocatable table pointers are NULL initially */
 604        for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
 605                table->chunks[socket_id] = NULL;
 606        table->offline_chunks = NULL;
 607
 608        /*
 609         * Allocate one online table per socket specified
 610         * in the user-supplied bitmask
 611         */
 612        uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
 613                        EFD_NUM_CHUNK_PADDING_BYTES;
 614
 615        for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
 616                if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
 617                        /*
 618                         * Allocate all of the EFD table chunks (the online portion)
 619                         * as a continuous block
 620                         */
 621                        table->chunks[socket_id] =
 622                                rte_zmalloc_socket(
 623                                NULL,
 624                                online_table_size,
 625                                RTE_CACHE_LINE_SIZE,
 626                                socket_id);
 627                        if (table->chunks[socket_id] == NULL) {
 628                                RTE_LOG(ERR, EFD,
 629                                                "Allocating EFD online table on "
 630                                                "socket %u failed\n",
 631                                                socket_id);
 632                                goto error_unlock_exit;
 633                        }
 634                        RTE_LOG(DEBUG, EFD,
 635                                        "Allocated EFD online table of size "
 636                                        "%"PRIu64" bytes (%.2f MB) on socket %u\n",
 637                                        online_table_size,
 638                                        (float) online_table_size /
 639                                                (1024.0F * 1024.0F),
 640                                        socket_id);
 641                }
 642        }
 643
 644#if defined(RTE_ARCH_X86)
 645        /*
 646         * For less than 4 bits, scalar function performs better
 647         * than vectorised version
 648         */
 649        if (RTE_EFD_VALUE_NUM_BITS > 3
 650                        && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2)
 651                        && rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
 652                table->lookup_fn = EFD_LOOKUP_AVX2;
 653        else
 654#endif
 655#if defined(RTE_ARCH_ARM64)
 656        /*
 657         * For less than or equal to 16 bits, scalar function performs better
 658         * than vectorised version
 659         */
 660        if (RTE_EFD_VALUE_NUM_BITS > 16 &&
 661            rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) &&
 662                        rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
 663                table->lookup_fn = EFD_LOOKUP_NEON;
 664        else
 665#endif
 666                table->lookup_fn = EFD_LOOKUP_SCALAR;
 667
 668        /*
 669         * Allocate the EFD table offline portion (with the actual rules
 670         * mapping keys to values) as a continuous block.
 671         * This could be several gigabytes of memory.
 672         */
 673        offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
 674        table->offline_chunks =
 675                        rte_zmalloc_socket(NULL,
 676                        offline_table_size,
 677                        RTE_CACHE_LINE_SIZE,
 678                        offline_cpu_socket);
 679        if (table->offline_chunks == NULL) {
 680                RTE_LOG(ERR, EFD, "Allocating EFD offline table on socket %u "
 681                                "failed\n", offline_cpu_socket);
 682                goto error_unlock_exit;
 683        }
 684
 685        RTE_LOG(DEBUG, EFD,
 686                        "Allocated EFD offline table of size %"PRIu64" bytes "
 687                        " (%.2f MB) on socket %u\n", offline_table_size,
 688                        (float) offline_table_size / (1024.0F * 1024.0F),
 689                        offline_cpu_socket);
 690
 691        te->data = (void *) table;
 692        TAILQ_INSERT_TAIL(efd_list, te, next);
 693        rte_mcfg_tailq_write_unlock();
 694
 695        snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name);
 696        /* Create ring (Dummy slot index is not enqueued) */
 697        r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules),
 698                        offline_cpu_socket, 0);
 699        if (r == NULL) {
 700                RTE_LOG(ERR, EFD, "memory allocation failed\n");
 701                rte_efd_free(table);
 702                return NULL;
 703        }
 704
 705        /* Populate free slots ring. Entry zero is reserved for key misses. */
 706        for (i = 0; i < table->max_num_rules; i++)
 707                rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i));
 708
 709        table->free_slots = r;
 710        return table;
 711
 712error_unlock_exit:
 713        rte_mcfg_tailq_write_unlock();
 714        rte_free(te);
 715        rte_efd_free(table);
 716
 717        return NULL;
 718}
 719
 720struct rte_efd_table *
 721rte_efd_find_existing(const char *name)
 722{
 723        struct rte_efd_table *table = NULL;
 724        struct rte_tailq_entry *te;
 725        struct rte_efd_list *efd_list;
 726
 727        efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
 728
 729        rte_mcfg_tailq_read_lock();
 730
 731        TAILQ_FOREACH(te, efd_list, next)
 732        {
 733                table = (struct rte_efd_table *) te->data;
 734                if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
 735                        break;
 736        }
 737        rte_mcfg_tailq_read_unlock();
 738
 739        if (te == NULL) {
 740                rte_errno = ENOENT;
 741                return NULL;
 742        }
 743        return table;
 744}
 745
 746void
 747rte_efd_free(struct rte_efd_table *table)
 748{
 749        uint8_t socket_id;
 750        struct rte_efd_list *efd_list;
 751        struct rte_tailq_entry *te, *temp;
 752
 753        if (table == NULL)
 754                return;
 755
 756        for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
 757                rte_free(table->chunks[socket_id]);
 758
 759        efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
 760        rte_mcfg_tailq_write_lock();
 761
 762        TAILQ_FOREACH_SAFE(te, efd_list, next, temp) {
 763                if (te->data == (void *) table) {
 764                        TAILQ_REMOVE(efd_list, te, next);
 765                        rte_free(te);
 766                        break;
 767                }
 768        }
 769
 770        rte_mcfg_tailq_write_unlock();
 771        rte_ring_free(table->free_slots);
 772        rte_free(table->offline_chunks);
 773        rte_free(table->keys);
 774        rte_free(table);
 775}
 776
 777/**
 778 * Applies a previously computed table entry to the specified table for all
 779 * socket-local copies of the online table.
 780 * Intended to apply an update for only a single change
 781 * to a key/value pair at a time
 782 *
 783 * @param table
 784 *   EFD table to reference
 785 * @param socket_id
 786 *   Socket ID to use to lookup existing values (ideally caller's socket id)
 787 * @param chunk_id
 788 *   Chunk index to update
 789 * @param group_id
 790 *   Group index to update
 791 * @param bin_id
 792 *   Bin within the group that this update affects
 793 * @param new_bin_choice
 794 *   Newly chosen permutation which this bin should use - only lower 2 bits
 795 * @param new_group_entry
 796 *   Previously computed updated chunk/group entry
 797 */
 798static inline void
 799efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id,
 800                const uint32_t chunk_id, const uint32_t group_id,
 801                const uint32_t bin_id, const uint8_t new_bin_choice,
 802                const struct efd_online_group_entry * const new_group_entry)
 803{
 804        int i;
 805        struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
 806        uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
 807
 808        /*
 809         * Grab the current byte that contains the choices
 810         * for four neighboring bins
 811         */
 812        uint8_t choice_chunk =
 813                        chunk->bin_choice_list[bin_index];
 814
 815
 816        /* Compute the offset into the chunk that needs to be updated */
 817        int offset = (bin_id & 0x3) * 2;
 818
 819        /* Zero the two bits of interest and set them to new_bin_choice */
 820        choice_chunk = (choice_chunk & (~(0x03 << offset)))
 821                        | ((new_bin_choice & 0x03) << offset);
 822
 823        /* Update the online table with the new data across all sockets */
 824        for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
 825                if (table->chunks[i] != NULL) {
 826                        memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
 827                                        new_group_entry,
 828                                        sizeof(struct efd_online_group_entry));
 829                        table->chunks[i][chunk_id].bin_choice_list[bin_index] =
 830                                        choice_chunk;
 831                }
 832        }
 833}
 834
 835/*
 836 * Move the bin from prev group to the new group
 837 */
 838static inline void
 839move_groups(uint32_t bin_id, uint8_t bin_size,
 840                struct efd_offline_group_rules *new_group,
 841                struct efd_offline_group_rules * const current_group)
 842{
 843
 844        uint8_t empty_idx = 0;
 845        unsigned int i;
 846
 847        if (new_group == current_group)
 848                return;
 849
 850        for (i = 0; i < current_group->num_rules; i++) {
 851                /*
 852                 * Move keys that belong to the same bin
 853                 * to the new group
 854                 */
 855                if (current_group->bin_id[i] == bin_id) {
 856                        new_group->key_idx[new_group->num_rules] =
 857                                        current_group->key_idx[i];
 858                        new_group->value[new_group->num_rules] =
 859                                        current_group->value[i];
 860                        new_group->bin_id[new_group->num_rules] =
 861                                        current_group->bin_id[i];
 862                        new_group->num_rules++;
 863                } else {
 864                        if (i != empty_idx) {
 865                                /*
 866                                 * Need to move this key towards
 867                                 * the top of the array
 868                                 */
 869                                current_group->key_idx[empty_idx] =
 870                                                current_group->key_idx[i];
 871                                current_group->value[empty_idx] =
 872                                                current_group->value[i];
 873                                current_group->bin_id[empty_idx] =
 874                                                current_group->bin_id[i];
 875                        }
 876                        empty_idx++;
 877                }
 878
 879        }
 880        current_group->num_rules -= bin_size;
 881}
 882
 883/*
 884 * Revert group/s to their previous state before
 885 * trying to insert/add a new key
 886 */
 887static inline void
 888revert_groups(struct efd_offline_group_rules *previous_group,
 889                struct efd_offline_group_rules *current_group, uint8_t bin_size)
 890{
 891        unsigned int i;
 892
 893        if (current_group == previous_group)
 894                return;
 895
 896        /* Move keys back to previous group */
 897        for (i = current_group->num_rules - bin_size;
 898                        i < current_group->num_rules; i++) {
 899                previous_group->key_idx[previous_group->num_rules] =
 900                                current_group->key_idx[i];
 901                previous_group->value[previous_group->num_rules] =
 902                                current_group->value[i];
 903                previous_group->bin_id[previous_group->num_rules] =
 904                                current_group->bin_id[i];
 905                previous_group->num_rules++;
 906        }
 907
 908        /*
 909         * Decrease number of rules after the move
 910         * in the new group
 911         */
 912        current_group->num_rules -= bin_size;
 913}
 914
 915/**
 916 * Computes an updated table entry where the supplied key points to a new host.
 917 * If no entry exists, one is inserted.
 918 *
 919 * This function does NOT modify the online table(s)
 920 * This function DOES modify the offline table
 921 *
 922 * @param table
 923 *   EFD table to reference
 924 * @param socket_id
 925 *   Socket ID to use to lookup existing values (ideally caller's socket id)
 926 * @param key
 927 *   Key to insert
 928 * @param value
 929 *   Value to associate with key
 930 * @param chunk_id
 931 *   Chunk ID of the chunk that was modified
 932 * @param group_id
 933 *   Group ID of the group that was modified
 934 * @param bin_id
 935 *   Bin ID that was modified
 936 * @param new_bin_choice
 937 *   Newly chosen permutation which this bin will use
 938 * @param entry
 939 *   Newly computed online entry to apply later with efd_apply_update
 940 *
 941 * @return
 942 *   RTE_EFD_UPDATE_WARN_GROUP_FULL
 943 *     Operation is insert, and the last available space in the
 944 *     key's group was just used. Future inserts may fail as groups fill up.
 945 *     This operation was still successful, and entry contains a valid update
 946 *   RTE_EFD_UPDATE_FAILED
 947 *     Either the EFD failed to find a suitable perfect hash or the group was full
 948 *     This is a fatal error, and the table is now in an indeterminate state
 949 *   RTE_EFD_UPDATE_NO_CHANGE
 950 *     Operation resulted in no change to the table (same value already exists)
 951 *   0
 952 *     Insert or update was successful, and the new efd_online_group_entry
 953 *     is stored in *entry
 954 *
 955 * @warning
 956 *   Note that entry will be UNCHANGED if the update has no effect, and thus any
 957 *   subsequent use of the entry content will likely be invalid
 958 */
 959static inline int
 960efd_compute_update(struct rte_efd_table * const table,
 961                const unsigned int socket_id, const void *key,
 962                const efd_value_t value, uint32_t * const chunk_id,
 963                uint32_t * const group_id, uint32_t * const bin_id,
 964                uint8_t * const new_bin_choice,
 965                struct efd_online_group_entry * const entry)
 966{
 967        unsigned int i;
 968        int ret;
 969        uint32_t new_idx;
 970        void *new_k, *slot_id = NULL;
 971        int status = EXIT_SUCCESS;
 972        unsigned int found = 0;
 973
 974        efd_compute_ids(table, key, chunk_id, bin_id);
 975
 976        struct efd_offline_chunk_rules * const chunk =
 977                        &table->offline_chunks[*chunk_id];
 978        struct efd_offline_group_rules *new_group;
 979
 980        uint8_t current_choice = efd_get_choice(table, socket_id,
 981                        *chunk_id, *bin_id);
 982        uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
 983        struct efd_offline_group_rules * const current_group =
 984                        &chunk->group_rules[current_group_id];
 985        uint8_t bin_size = 0;
 986        uint8_t key_changed_index = 0;
 987        efd_value_t key_changed_previous_value = 0;
 988        uint32_t key_idx_previous = 0;
 989
 990        /* Scan the current group and see if the key is already present */
 991        for (i = 0; i < current_group->num_rules; i++) {
 992                if (current_group->bin_id[i] == *bin_id)
 993                        bin_size++;
 994                else
 995                        continue;
 996
 997                void *key_stored = EFD_KEY(current_group->key_idx[i], table);
 998                if (found == 0 && unlikely(memcmp(key_stored, key,
 999                                table->key_len) == 0)) {
1000                        /* Key is already present */
1001
1002                        /*
1003                         * If previous value is same as new value,
1004                         * no additional work is required
1005                         */
1006                        if (current_group->value[i] == value)
1007                                return RTE_EFD_UPDATE_NO_CHANGE;
1008
1009                        key_idx_previous = current_group->key_idx[i];
1010                        key_changed_previous_value = current_group->value[i];
1011                        key_changed_index = i;
1012                        current_group->value[i] = value;
1013                        found = 1;
1014                }
1015        }
1016
1017        if (found == 0) {
1018                /* Key does not exist. Insert the rule into the bin/group */
1019                if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
1020                        RTE_LOG(ERR, EFD,
1021                                        "Fatal: No room remaining for insert into "
1022                                        "chunk %u group %u bin %u\n",
1023                                        *chunk_id,
1024                                        current_group_id, *bin_id);
1025                        return RTE_EFD_UPDATE_FAILED;
1026                }
1027
1028                if (unlikely(current_group->num_rules ==
1029                                (EFD_MAX_GROUP_NUM_RULES - 1))) {
1030                        RTE_LOG(INFO, EFD, "Warn: Insert into last "
1031                                        "available slot in chunk %u "
1032                                        "group %u bin %u\n", *chunk_id,
1033                                        current_group_id, *bin_id);
1034                        status = RTE_EFD_UPDATE_WARN_GROUP_FULL;
1035                }
1036
1037                if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0)
1038                        return RTE_EFD_UPDATE_FAILED;
1039
1040                new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id *
1041                                        table->key_len);
1042                rte_prefetch0(new_k);
1043                new_idx = (uint32_t) ((uintptr_t) slot_id);
1044
1045                rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len);
1046                current_group->key_idx[current_group->num_rules] = new_idx;
1047                current_group->value[current_group->num_rules] = value;
1048                current_group->bin_id[current_group->num_rules] = *bin_id;
1049                current_group->num_rules++;
1050                table->num_rules++;
1051                bin_size++;
1052        } else {
1053                uint32_t last = current_group->num_rules - 1;
1054                /* Swap the key with the last key inserted*/
1055                current_group->key_idx[key_changed_index] =
1056                                current_group->key_idx[last];
1057                current_group->value[key_changed_index] =
1058                                current_group->value[last];
1059                current_group->bin_id[key_changed_index] =
1060                                current_group->bin_id[last];
1061
1062                /*
1063                 * Key to be updated will always be available
1064                 * at the end of the group
1065                 */
1066                current_group->key_idx[last] = key_idx_previous;
1067                current_group->value[last] = value;
1068                current_group->bin_id[last] = *bin_id;
1069        }
1070
1071        *new_bin_choice = current_choice;
1072        *group_id = current_group_id;
1073        new_group = current_group;
1074
1075        /* Group need to be rebalanced when it starts to get loaded */
1076        if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
1077
1078                /*
1079                 * Subtract the number of entries in the bin from
1080                 * the original group
1081                 */
1082                current_group->num_rules -= bin_size;
1083
1084                /*
1085                 * Figure out which of the available groups that this bin
1086                 * can map to is the smallest (using the current group
1087                 * as baseline)
1088                 */
1089                uint8_t smallest_choice = current_choice;
1090                uint8_t smallest_size = current_group->num_rules;
1091                uint32_t smallest_group_id = current_group_id;
1092                unsigned char choice;
1093
1094                for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
1095                                choice++) {
1096                        uint32_t test_group_id =
1097                                        efd_bin_to_group[choice][*bin_id];
1098                        uint32_t num_rules =
1099                                        chunk->group_rules[test_group_id].num_rules;
1100                        if (num_rules < smallest_size) {
1101                                smallest_choice = choice;
1102                                smallest_size = num_rules;
1103                                smallest_group_id = test_group_id;
1104                        }
1105                }
1106
1107                *new_bin_choice = smallest_choice;
1108                *group_id = smallest_group_id;
1109                new_group = &chunk->group_rules[smallest_group_id];
1110                current_group->num_rules += bin_size;
1111
1112        }
1113
1114        uint8_t choice = 0;
1115        for (;;) {
1116                if (current_group != new_group &&
1117                                new_group->num_rules + bin_size >
1118                                        EFD_MAX_GROUP_NUM_RULES) {
1119                        RTE_LOG(DEBUG, EFD,
1120                                        "Unable to move_groups to dest group "
1121                                        "containing %u entries."
1122                                        "bin_size:%u choice:%02x\n",
1123                                        new_group->num_rules, bin_size,
1124                                        choice - 1);
1125                        goto next_choice;
1126                }
1127                move_groups(*bin_id, bin_size, new_group, current_group);
1128                /*
1129                 * Recompute the hash function for the modified group,
1130                 * and return it to the caller
1131                 */
1132                ret = efd_search_hash(table, new_group, entry);
1133
1134                if (!ret)
1135                        return status;
1136
1137                RTE_LOG(DEBUG, EFD,
1138                                "Failed to find perfect hash for group "
1139                                "containing %u entries. bin_size:%u choice:%02x\n",
1140                                new_group->num_rules, bin_size, choice - 1);
1141                /* Restore groups modified to their previous state */
1142                revert_groups(current_group, new_group, bin_size);
1143
1144next_choice:
1145                if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS)
1146                        break;
1147                *new_bin_choice = choice;
1148                *group_id = efd_bin_to_group[choice][*bin_id];
1149                new_group = &chunk->group_rules[*group_id];
1150                choice++;
1151        }
1152
1153        if (!found) {
1154                current_group->num_rules--;
1155                table->num_rules--;
1156        } else
1157                current_group->value[current_group->num_rules - 1] =
1158                        key_changed_previous_value;
1159        return RTE_EFD_UPDATE_FAILED;
1160}
1161
1162int
1163rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id,
1164                const void *key, const efd_value_t value)
1165{
1166        uint32_t chunk_id = 0, group_id = 0, bin_id = 0;
1167        uint8_t new_bin_choice = 0;
1168        struct efd_online_group_entry entry;
1169
1170        int status = efd_compute_update(table, socket_id, key, value,
1171                        &chunk_id, &group_id, &bin_id,
1172                        &new_bin_choice, &entry);
1173
1174        if (status == RTE_EFD_UPDATE_NO_CHANGE)
1175                return EXIT_SUCCESS;
1176
1177        if (status == RTE_EFD_UPDATE_FAILED)
1178                return status;
1179
1180        efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
1181                        new_bin_choice, &entry);
1182        return status;
1183}
1184
1185int
1186rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id,
1187                const void *key, efd_value_t * const prev_value)
1188{
1189        unsigned int i;
1190        uint32_t chunk_id, bin_id;
1191        uint8_t not_found = 1;
1192
1193        efd_compute_ids(table, key, &chunk_id, &bin_id);
1194
1195        struct efd_offline_chunk_rules * const chunk =
1196                        &table->offline_chunks[chunk_id];
1197
1198        uint8_t current_choice = efd_get_choice(table, socket_id,
1199                        chunk_id, bin_id);
1200        uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
1201        struct efd_offline_group_rules * const current_group =
1202                        &chunk->group_rules[current_group_id];
1203
1204        /*
1205         * Search the current group for the specified key.
1206         * If it exists, remove it and re-pack the other values
1207         */
1208        for (i = 0; i < current_group->num_rules; i++) {
1209                if (not_found) {
1210                        /* Found key that needs to be removed */
1211                        if (memcmp(EFD_KEY(current_group->key_idx[i], table),
1212                                        key, table->key_len) == 0) {
1213                                /* Store previous value if requested by caller */
1214                                if (prev_value != NULL)
1215                                        *prev_value = current_group->value[i];
1216
1217                                not_found = 0;
1218                                rte_ring_sp_enqueue(table->free_slots,
1219                                        (void *)((uintptr_t)current_group->key_idx[i]));
1220                        }
1221                } else {
1222                        /*
1223                         * If the desired key has been found,
1224                         * need to shift other values up one
1225                         */
1226
1227                        /* Need to shift this entry back up one index */
1228                        current_group->key_idx[i - 1] = current_group->key_idx[i];
1229                        current_group->value[i - 1] = current_group->value[i];
1230                        current_group->bin_id[i - 1] = current_group->bin_id[i];
1231                }
1232        }
1233
1234        if (not_found == 0) {
1235                table->num_rules--;
1236                current_group->num_rules--;
1237        }
1238
1239        return not_found;
1240}
1241
1242static inline efd_value_t
1243efd_lookup_internal_scalar(const efd_hashfunc_t *group_hash_idx,
1244                const efd_lookuptbl_t *group_lookup_table,
1245                const uint32_t hash_val_a, const uint32_t hash_val_b)
1246{
1247        efd_value_t value = 0;
1248        uint32_t i;
1249
1250        for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) {
1251                value <<= 1;
1252                uint32_t h = hash_val_a + (hash_val_b *
1253                        group_hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]);
1254                uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
1255                value |= (group_lookup_table[
1256                                RTE_EFD_VALUE_NUM_BITS - i - 1] >>
1257                                bucket_idx) & 0x1;
1258        }
1259
1260        return value;
1261}
1262
1263
1264static inline efd_value_t
1265efd_lookup_internal(const struct efd_online_group_entry * const group,
1266                const uint32_t hash_val_a, const uint32_t hash_val_b,
1267                enum efd_lookup_internal_function lookup_fn)
1268{
1269        efd_value_t value = 0;
1270
1271        switch (lookup_fn) {
1272
1273#if defined(RTE_ARCH_X86) && defined(CC_SUPPORT_AVX2)
1274        case EFD_LOOKUP_AVX2:
1275                return efd_lookup_internal_avx2(group->hash_idx,
1276                                        group->lookup_table,
1277                                        hash_val_a,
1278                                        hash_val_b);
1279                break;
1280#endif
1281#if defined(RTE_ARCH_ARM64)
1282        case EFD_LOOKUP_NEON:
1283                return efd_lookup_internal_neon(group->hash_idx,
1284                                        group->lookup_table,
1285                                        hash_val_a,
1286                                        hash_val_b);
1287                break;
1288#endif
1289        case EFD_LOOKUP_SCALAR:
1290        /* Fall-through */
1291        default:
1292                return efd_lookup_internal_scalar(group->hash_idx,
1293                                        group->lookup_table,
1294                                        hash_val_a,
1295                                        hash_val_b);
1296        }
1297
1298        return value;
1299}
1300
1301efd_value_t
1302rte_efd_lookup(const struct rte_efd_table * const table,
1303                const unsigned int socket_id, const void *key)
1304{
1305        uint32_t chunk_id, group_id, bin_id;
1306        uint8_t bin_choice;
1307        const struct efd_online_group_entry *group;
1308        const struct efd_online_chunk * const chunks = table->chunks[socket_id];
1309
1310        /* Determine the chunk and group location for the given key */
1311        efd_compute_ids(table, key, &chunk_id, &bin_id);
1312        bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
1313        group_id = efd_bin_to_group[bin_choice][bin_id];
1314        group = &chunks[chunk_id].groups[group_id];
1315
1316        return efd_lookup_internal(group,
1317                        EFD_HASHFUNCA(key, table),
1318                        EFD_HASHFUNCB(key, table),
1319                        table->lookup_fn);
1320}
1321
1322void rte_efd_lookup_bulk(const struct rte_efd_table * const table,
1323                const unsigned int socket_id, const int num_keys,
1324                const void **key_list, efd_value_t * const value_list)
1325{
1326        int i;
1327        uint32_t chunk_id_list[RTE_EFD_BURST_MAX];
1328        uint32_t bin_id_list[RTE_EFD_BURST_MAX];
1329        uint8_t bin_choice_list[RTE_EFD_BURST_MAX];
1330        uint32_t group_id_list[RTE_EFD_BURST_MAX];
1331        struct efd_online_group_entry *group;
1332
1333        struct efd_online_chunk *chunks = table->chunks[socket_id];
1334
1335        for (i = 0; i < num_keys; i++) {
1336                efd_compute_ids(table, key_list[i], &chunk_id_list[i],
1337                                &bin_id_list[i]);
1338                rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
1339        }
1340
1341        for (i = 0; i < num_keys; i++) {
1342                bin_choice_list[i] = efd_get_choice(table, socket_id,
1343                                chunk_id_list[i], bin_id_list[i]);
1344                group_id_list[i] =
1345                                efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
1346                group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1347                rte_prefetch0(group);
1348        }
1349
1350        for (i = 0; i < num_keys; i++) {
1351                group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
1352                value_list[i] = efd_lookup_internal(group,
1353                                EFD_HASHFUNCA(key_list[i], table),
1354                                EFD_HASHFUNCB(key_list[i], table),
1355                                table->lookup_fn);
1356        }
1357}
1358