199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2016-2017 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson #include <stdio.h> 599a2dd95SBruce Richardson #include <string.h> 699a2dd95SBruce Richardson #include <stdint.h> 772b452c5SDmitry Kozlyuk #include <stdlib.h> 899a2dd95SBruce Richardson #include <inttypes.h> 999a2dd95SBruce Richardson #include <errno.h> 1099a2dd95SBruce Richardson #include <sys/queue.h> 1199a2dd95SBruce Richardson 128f9c9288SStephen Hemminger #include <rte_cpuflags.h> 1399a2dd95SBruce Richardson #include <rte_string_fns.h> 1499a2dd95SBruce Richardson #include <rte_log.h> 1599a2dd95SBruce Richardson #include <rte_eal_memconfig.h> 1699a2dd95SBruce Richardson #include <rte_errno.h> 1799a2dd95SBruce Richardson #include <rte_malloc.h> 1899a2dd95SBruce Richardson #include <rte_prefetch.h> 1999a2dd95SBruce Richardson #include <rte_branch_prediction.h> 2099a2dd95SBruce Richardson #include <rte_memcpy.h> 2199a2dd95SBruce Richardson #include <rte_ring.h> 2299a2dd95SBruce Richardson #include <rte_jhash.h> 2399a2dd95SBruce Richardson #include <rte_hash_crc.h> 2499a2dd95SBruce Richardson #include <rte_tailq.h> 2599a2dd95SBruce Richardson 2699a2dd95SBruce Richardson #include "rte_efd.h" 2799a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) 2899a2dd95SBruce Richardson #elif defined(RTE_ARCH_ARM64) 2999a2dd95SBruce Richardson #include "rte_efd_arm64.h" 3099a2dd95SBruce Richardson #endif 3199a2dd95SBruce Richardson 32de863b4eSStephen Hemminger RTE_LOG_REGISTER_DEFAULT(efd_logtype, INFO); 33de863b4eSStephen Hemminger #define RTE_LOGTYPE_EFD efd_logtype 3497433132SDavid Marchand #define EFD_LOG(level, ...) \ 3597433132SDavid Marchand RTE_LOG_LINE(level, EFD, "" __VA_ARGS__) 36de863b4eSStephen Hemminger 3799a2dd95SBruce Richardson #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len)) 3899a2dd95SBruce Richardson /** Hash function used to determine chunk_id and bin_id for a group */ 3999a2dd95SBruce Richardson #define EFD_HASH(key, table) \ 4099a2dd95SBruce Richardson (uint32_t)(rte_jhash(key, table->key_len, 0xbc9f1d34)) 4199a2dd95SBruce Richardson /** Hash function used as constant component of perfect hash search */ 4299a2dd95SBruce Richardson #define EFD_HASHFUNCA(key, table) \ 4399a2dd95SBruce Richardson (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d35)) 4499a2dd95SBruce Richardson /** Hash function used as multiplicative component of perfect hash search */ 4599a2dd95SBruce Richardson #define EFD_HASHFUNCB(key, table) \ 4699a2dd95SBruce Richardson (uint32_t)(rte_hash_crc(key, table->key_len, 0xbc9f1d36)) 4799a2dd95SBruce Richardson 4899a2dd95SBruce Richardson /************************************************************************* 4999a2dd95SBruce Richardson * Fixed constants 5099a2dd95SBruce Richardson *************************************************************************/ 5199a2dd95SBruce Richardson 5299a2dd95SBruce Richardson /* These parameters are fixed by the efd_bin_to_group balancing table */ 5399a2dd95SBruce Richardson #define EFD_CHUNK_NUM_GROUPS (64) 5499a2dd95SBruce Richardson #define EFD_CHUNK_NUM_BINS (256) 5599a2dd95SBruce Richardson #define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS \ 5699a2dd95SBruce Richardson (EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS) 5799a2dd95SBruce Richardson 5899a2dd95SBruce Richardson /* 5999a2dd95SBruce Richardson * Target number of rules that each chunk is created to handle. 6099a2dd95SBruce Richardson * Used when initially allocating the table 6199a2dd95SBruce Richardson */ 6299a2dd95SBruce Richardson #define EFD_TARGET_CHUNK_NUM_RULES \ 6399a2dd95SBruce Richardson (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES) 6499a2dd95SBruce Richardson /* 6599a2dd95SBruce Richardson * Max number of rules that each chunk is created to handle. 6699a2dd95SBruce Richardson * Used when initially allocating the table 6799a2dd95SBruce Richardson */ 6899a2dd95SBruce Richardson #define EFD_TARGET_CHUNK_MAX_NUM_RULES \ 6999a2dd95SBruce Richardson (EFD_CHUNK_NUM_GROUPS * EFD_MAX_GROUP_NUM_RULES) 7099a2dd95SBruce Richardson 7199a2dd95SBruce Richardson /** This is fixed based on the bin_to_group permutation array */ 7299a2dd95SBruce Richardson #define EFD_MAX_GROUP_NUM_BINS (16) 7399a2dd95SBruce Richardson 7499a2dd95SBruce Richardson /** 7599a2dd95SBruce Richardson * The end of the chunks array needs some extra padding to ensure 7699a2dd95SBruce Richardson * that vectorization over-reads on the last online chunk stay within 7799a2dd95SBruce Richardson allocated memory 7899a2dd95SBruce Richardson */ 7999a2dd95SBruce Richardson #define EFD_NUM_CHUNK_PADDING_BYTES (256) 8099a2dd95SBruce Richardson 8199a2dd95SBruce Richardson /* All different internal lookup functions */ 8299a2dd95SBruce Richardson enum efd_lookup_internal_function { 8399a2dd95SBruce Richardson EFD_LOOKUP_SCALAR = 0, 8499a2dd95SBruce Richardson EFD_LOOKUP_AVX2, 8599a2dd95SBruce Richardson EFD_LOOKUP_NEON, 8699a2dd95SBruce Richardson EFD_LOOKUP_NUM 8799a2dd95SBruce Richardson }; 8899a2dd95SBruce Richardson 8999a2dd95SBruce Richardson TAILQ_HEAD(rte_efd_list, rte_tailq_entry); 9099a2dd95SBruce Richardson 9199a2dd95SBruce Richardson static struct rte_tailq_elem rte_efd_tailq = { 9299a2dd95SBruce Richardson .name = "RTE_EFD", 9399a2dd95SBruce Richardson }; 9499a2dd95SBruce Richardson EAL_REGISTER_TAILQ(rte_efd_tailq); 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson /** Internal permutation array used to shuffle bins into pseudorandom groups */ 9799a2dd95SBruce Richardson const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = { 9899a2dd95SBruce Richardson { 9999a2dd95SBruce Richardson 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 10099a2dd95SBruce Richardson 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 10199a2dd95SBruce Richardson 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 10299a2dd95SBruce Richardson 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 10399a2dd95SBruce Richardson 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 10499a2dd95SBruce Richardson 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 10599a2dd95SBruce Richardson 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 10699a2dd95SBruce Richardson 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 10799a2dd95SBruce Richardson 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 10899a2dd95SBruce Richardson 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 10999a2dd95SBruce Richardson 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 11099a2dd95SBruce Richardson 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 11199a2dd95SBruce Richardson 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 11299a2dd95SBruce Richardson 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 11399a2dd95SBruce Richardson 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 11499a2dd95SBruce Richardson 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63 11599a2dd95SBruce Richardson }, 11699a2dd95SBruce Richardson { 11799a2dd95SBruce Richardson 34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5, 11899a2dd95SBruce Richardson 44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6, 11999a2dd95SBruce Richardson 46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7, 12099a2dd95SBruce Richardson 1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34, 12199a2dd95SBruce Richardson 6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18, 12299a2dd95SBruce Richardson 51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27, 12399a2dd95SBruce Richardson 54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55, 12499a2dd95SBruce Richardson 45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41, 12599a2dd95SBruce Richardson 13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43, 12699a2dd95SBruce Richardson 56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13, 12799a2dd95SBruce Richardson 2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27, 12899a2dd95SBruce Richardson 22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39, 12999a2dd95SBruce Richardson 0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42, 13099a2dd95SBruce Richardson 53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10, 13199a2dd95SBruce Richardson 63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30, 13299a2dd95SBruce Richardson 49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50 13399a2dd95SBruce Richardson }, 13499a2dd95SBruce Richardson { 13599a2dd95SBruce Richardson 32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54, 13699a2dd95SBruce Richardson 55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1, 13799a2dd95SBruce Richardson 40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22, 13899a2dd95SBruce Richardson 41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38, 13999a2dd95SBruce Richardson 13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51, 14099a2dd95SBruce Richardson 38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30, 14199a2dd95SBruce Richardson 5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9, 14299a2dd95SBruce Richardson 24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28, 14399a2dd95SBruce Richardson 25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21, 14499a2dd95SBruce Richardson 57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8, 14599a2dd95SBruce Richardson 13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57, 14699a2dd95SBruce Richardson 33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23, 14799a2dd95SBruce Richardson 8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60, 14899a2dd95SBruce Richardson 18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4, 14999a2dd95SBruce Richardson 47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23, 15099a2dd95SBruce Richardson 6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0 15199a2dd95SBruce Richardson }, 15299a2dd95SBruce Richardson { 15399a2dd95SBruce Richardson 29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0, 15499a2dd95SBruce Richardson 59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26, 15599a2dd95SBruce Richardson 35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54, 15699a2dd95SBruce Richardson 13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18, 15799a2dd95SBruce Richardson 55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50, 15899a2dd95SBruce Richardson 17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4, 15999a2dd95SBruce Richardson 14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41, 16099a2dd95SBruce Richardson 39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47, 16199a2dd95SBruce Richardson 55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51, 16299a2dd95SBruce Richardson 31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11, 16399a2dd95SBruce Richardson 27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2, 16499a2dd95SBruce Richardson 47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50, 16599a2dd95SBruce Richardson 29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52, 16699a2dd95SBruce Richardson 35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42, 16799a2dd95SBruce Richardson 38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20, 16899a2dd95SBruce Richardson 24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52 16999a2dd95SBruce Richardson }, 17099a2dd95SBruce Richardson }; 17199a2dd95SBruce Richardson 17299a2dd95SBruce Richardson /************************************************************************* 17399a2dd95SBruce Richardson * Offline region structures 17499a2dd95SBruce Richardson *************************************************************************/ 17599a2dd95SBruce Richardson 17699a2dd95SBruce Richardson /** Online group containing number of rules, values, keys and their bins 17799a2dd95SBruce Richardson * for EFD_MAX_GROUP_NUM_RULES rules. 17899a2dd95SBruce Richardson */ 17999a2dd95SBruce Richardson struct efd_offline_group_rules { 18099a2dd95SBruce Richardson uint32_t num_rules; 18199a2dd95SBruce Richardson /**< Sum of the number of rules in all bins assigned to this group. */ 18299a2dd95SBruce Richardson 18399a2dd95SBruce Richardson uint32_t key_idx[EFD_MAX_GROUP_NUM_RULES]; 18499a2dd95SBruce Richardson /**< Array with all keys of the group. */ 18599a2dd95SBruce Richardson efd_value_t value[EFD_MAX_GROUP_NUM_RULES]; 18699a2dd95SBruce Richardson /**< Array with all values of the keys of the group. */ 18799a2dd95SBruce Richardson 18899a2dd95SBruce Richardson uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES]; 18999a2dd95SBruce Richardson /**< Stores the bin for each corresponding key to 19099a2dd95SBruce Richardson * avoid having to recompute it 19199a2dd95SBruce Richardson */ 19299a2dd95SBruce Richardson }; 19399a2dd95SBruce Richardson 19499a2dd95SBruce Richardson /** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules. 19599a2dd95SBruce Richardson * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk. 19699a2dd95SBruce Richardson */ 19799a2dd95SBruce Richardson struct efd_offline_chunk_rules { 19899a2dd95SBruce Richardson uint16_t num_rules; 19999a2dd95SBruce Richardson /**< Number of rules in the entire chunk; 20099a2dd95SBruce Richardson * used to detect unbalanced groups 20199a2dd95SBruce Richardson */ 20299a2dd95SBruce Richardson 20399a2dd95SBruce Richardson struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS]; 20499a2dd95SBruce Richardson /**< Array of all groups in the chunk. */ 20599a2dd95SBruce Richardson }; 20699a2dd95SBruce Richardson 20799a2dd95SBruce Richardson /************************************************************************* 20899a2dd95SBruce Richardson * Online region structures 20999a2dd95SBruce Richardson *************************************************************************/ 21099a2dd95SBruce Richardson 21199a2dd95SBruce Richardson /** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */ 21299a2dd95SBruce Richardson struct efd_online_group_entry { 21399a2dd95SBruce Richardson efd_hashfunc_t hash_idx[RTE_EFD_VALUE_NUM_BITS]; 21499a2dd95SBruce Richardson efd_lookuptbl_t lookup_table[RTE_EFD_VALUE_NUM_BITS]; 215*1887f919SBruce Richardson }; 21699a2dd95SBruce Richardson 21799a2dd95SBruce Richardson /** 21899a2dd95SBruce Richardson * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules. 21999a2dd95SBruce Richardson * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk. 22099a2dd95SBruce Richardson */ 22199a2dd95SBruce Richardson struct efd_online_chunk { 22299a2dd95SBruce Richardson uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8]; 22399a2dd95SBruce Richardson /**< This is a packed indirection index into the 'groups' array. 22499a2dd95SBruce Richardson * Each byte contains four two-bit values which index into 22599a2dd95SBruce Richardson * the efd_bin_to_group array. 22699a2dd95SBruce Richardson * The efd_bin_to_group array returns the index into the groups array 22799a2dd95SBruce Richardson */ 22899a2dd95SBruce Richardson 22999a2dd95SBruce Richardson struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS]; 23099a2dd95SBruce Richardson /**< Array of all the groups in the chunk. */ 231*1887f919SBruce Richardson }; 23299a2dd95SBruce Richardson 23399a2dd95SBruce Richardson /** 23499a2dd95SBruce Richardson * EFD table structure 23599a2dd95SBruce Richardson */ 23699a2dd95SBruce Richardson struct rte_efd_table { 23799a2dd95SBruce Richardson char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */ 23899a2dd95SBruce Richardson 23999a2dd95SBruce Richardson uint32_t key_len; /**< Length of the key stored offline */ 24099a2dd95SBruce Richardson 24199a2dd95SBruce Richardson uint32_t max_num_rules; 24299a2dd95SBruce Richardson /**< Static maximum number of entries the table was constructed to hold. */ 24399a2dd95SBruce Richardson 24499a2dd95SBruce Richardson uint32_t num_rules; 24599a2dd95SBruce Richardson /**< Number of entries currently in the table . */ 24699a2dd95SBruce Richardson 24799a2dd95SBruce Richardson uint32_t num_chunks; 24899a2dd95SBruce Richardson /**< Number of chunks in the table needed to support num_rules. */ 24999a2dd95SBruce Richardson 25099a2dd95SBruce Richardson uint32_t num_chunks_shift; 25199a2dd95SBruce Richardson /**< Bits to shift to get chunk id, instead of dividing by num_chunk. */ 25299a2dd95SBruce Richardson 25399a2dd95SBruce Richardson enum efd_lookup_internal_function lookup_fn; 25499a2dd95SBruce Richardson /**< Indicates which lookup function to use. */ 25599a2dd95SBruce Richardson 25699a2dd95SBruce Richardson struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES]; 25799a2dd95SBruce Richardson /**< Dynamic array of size num_chunks of chunk records. */ 25899a2dd95SBruce Richardson 25999a2dd95SBruce Richardson struct efd_offline_chunk_rules *offline_chunks; 26099a2dd95SBruce Richardson /**< Dynamic array of size num_chunks of key-value pairs. */ 26199a2dd95SBruce Richardson 26299a2dd95SBruce Richardson struct rte_ring *free_slots; 26399a2dd95SBruce Richardson /**< Ring that stores all indexes of the free slots in the key table */ 26499a2dd95SBruce Richardson 26599a2dd95SBruce Richardson uint8_t *keys; /**< Dynamic array of size max_num_rules of keys */ 26699a2dd95SBruce Richardson }; 26799a2dd95SBruce Richardson 26899a2dd95SBruce Richardson /** 26999a2dd95SBruce Richardson * Computes the chunk ID for a given key hash 27099a2dd95SBruce Richardson * 27199a2dd95SBruce Richardson * @param table 27299a2dd95SBruce Richardson * EFD table to reference 27399a2dd95SBruce Richardson * @param hashed_key 27499a2dd95SBruce Richardson * 32-bit key hash returned by EFD_HASH 27599a2dd95SBruce Richardson * 27699a2dd95SBruce Richardson * @return 27799a2dd95SBruce Richardson * chunk ID containing this key hash 27899a2dd95SBruce Richardson */ 27999a2dd95SBruce Richardson static inline uint32_t 28099a2dd95SBruce Richardson efd_get_chunk_id(const struct rte_efd_table * const table, 28199a2dd95SBruce Richardson const uint32_t hashed_key) 28299a2dd95SBruce Richardson { 28399a2dd95SBruce Richardson return hashed_key & (table->num_chunks - 1); 28499a2dd95SBruce Richardson } 28599a2dd95SBruce Richardson 28699a2dd95SBruce Richardson /** 28799a2dd95SBruce Richardson * Computes the bin ID for a given key hash 28899a2dd95SBruce Richardson * 28999a2dd95SBruce Richardson * @param table 29099a2dd95SBruce Richardson * EFD table to reference 29199a2dd95SBruce Richardson * @param hashed_key 29299a2dd95SBruce Richardson * 32-bit key hash returned by EFD_HASH 29399a2dd95SBruce Richardson * 29499a2dd95SBruce Richardson * @return bin ID containing this key hash 29599a2dd95SBruce Richardson */ 29699a2dd95SBruce Richardson static inline uint32_t 29799a2dd95SBruce Richardson efd_get_bin_id(const struct rte_efd_table * const table, 29899a2dd95SBruce Richardson const uint32_t hashed_key) 29999a2dd95SBruce Richardson { 30099a2dd95SBruce Richardson return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1); 30199a2dd95SBruce Richardson } 30299a2dd95SBruce Richardson 30399a2dd95SBruce Richardson /** 30499a2dd95SBruce Richardson * Looks up the current permutation choice for a particular bin in the online table 30599a2dd95SBruce Richardson * 30699a2dd95SBruce Richardson * @param table 30799a2dd95SBruce Richardson * EFD table to reference 30899a2dd95SBruce Richardson * @param socket_id 30999a2dd95SBruce Richardson * Socket ID to use to look up existing values (ideally caller's socket id) 31099a2dd95SBruce Richardson * @param chunk_id 31199a2dd95SBruce Richardson * Chunk ID of bin to look up 31299a2dd95SBruce Richardson * @param bin_id 31399a2dd95SBruce Richardson * Bin ID to look up 31499a2dd95SBruce Richardson * 31599a2dd95SBruce Richardson * @return 31699a2dd95SBruce Richardson * Currently active permutation choice in the online table 31799a2dd95SBruce Richardson */ 31899a2dd95SBruce Richardson static inline uint8_t 31999a2dd95SBruce Richardson efd_get_choice(const struct rte_efd_table * const table, 32099a2dd95SBruce Richardson const unsigned int socket_id, const uint32_t chunk_id, 32199a2dd95SBruce Richardson const uint32_t bin_id) 32299a2dd95SBruce Richardson { 32399a2dd95SBruce Richardson struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id]; 32499a2dd95SBruce Richardson 32599a2dd95SBruce Richardson /* 32699a2dd95SBruce Richardson * Grab the chunk (byte) that contains the choices 32799a2dd95SBruce Richardson * for four neighboring bins. 32899a2dd95SBruce Richardson */ 32999a2dd95SBruce Richardson uint8_t choice_chunk = 33099a2dd95SBruce Richardson chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS]; 33199a2dd95SBruce Richardson 33299a2dd95SBruce Richardson /* 33399a2dd95SBruce Richardson * Compute the offset into the chunk that contains 33499a2dd95SBruce Richardson * the group_id lookup position 33599a2dd95SBruce Richardson */ 33699a2dd95SBruce Richardson int offset = (bin_id & 0x3) * 2; 33799a2dd95SBruce Richardson 33899a2dd95SBruce Richardson /* Extract from the byte just the desired lookup position */ 33999a2dd95SBruce Richardson return (uint8_t) ((choice_chunk >> offset) & 0x3); 34099a2dd95SBruce Richardson } 34199a2dd95SBruce Richardson 34299a2dd95SBruce Richardson /** 34399a2dd95SBruce Richardson * Compute the chunk_id and bin_id for a given key 34499a2dd95SBruce Richardson * 34599a2dd95SBruce Richardson * @param table 34699a2dd95SBruce Richardson * EFD table to reference 34799a2dd95SBruce Richardson * @param key 34899a2dd95SBruce Richardson * Key to hash and find location of 34999a2dd95SBruce Richardson * @param chunk_id 35099a2dd95SBruce Richardson * Computed chunk ID 35199a2dd95SBruce Richardson * @param bin_id 35299a2dd95SBruce Richardson * Computed bin ID 35399a2dd95SBruce Richardson */ 35499a2dd95SBruce Richardson static inline void 35599a2dd95SBruce Richardson efd_compute_ids(const struct rte_efd_table * const table, 35699a2dd95SBruce Richardson const void *key, uint32_t * const chunk_id, uint32_t * const bin_id) 35799a2dd95SBruce Richardson { 35899a2dd95SBruce Richardson /* Compute the position of the entry in the hash table */ 35999a2dd95SBruce Richardson uint32_t h = EFD_HASH(key, table); 36099a2dd95SBruce Richardson 36199a2dd95SBruce Richardson /* Compute the chunk_id where that entry can be found */ 36299a2dd95SBruce Richardson *chunk_id = efd_get_chunk_id(table, h); 36399a2dd95SBruce Richardson 36499a2dd95SBruce Richardson /* 36599a2dd95SBruce Richardson * Compute the bin within that chunk where the entry 36699a2dd95SBruce Richardson * can be found (0 - 255) 36799a2dd95SBruce Richardson */ 36899a2dd95SBruce Richardson *bin_id = efd_get_bin_id(table, h); 36999a2dd95SBruce Richardson } 37099a2dd95SBruce Richardson 37199a2dd95SBruce Richardson /** 37299a2dd95SBruce Richardson * Search for a hash function for a group that satisfies all group results 37399a2dd95SBruce Richardson */ 37499a2dd95SBruce Richardson static inline int 37599a2dd95SBruce Richardson efd_search_hash(struct rte_efd_table * const table, 37699a2dd95SBruce Richardson const struct efd_offline_group_rules * const off_group, 37799a2dd95SBruce Richardson struct efd_online_group_entry * const on_group) 37899a2dd95SBruce Richardson { 37999a2dd95SBruce Richardson efd_hashfunc_t hash_idx; 38099a2dd95SBruce Richardson efd_hashfunc_t start_hash_idx[RTE_EFD_VALUE_NUM_BITS]; 38199a2dd95SBruce Richardson efd_lookuptbl_t start_lookup_table[RTE_EFD_VALUE_NUM_BITS]; 38299a2dd95SBruce Richardson 38399a2dd95SBruce Richardson uint32_t i, j, rule_id; 38499a2dd95SBruce Richardson uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES]; 38599a2dd95SBruce Richardson uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES]; 38699a2dd95SBruce Richardson uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES]; 38799a2dd95SBruce Richardson 38899a2dd95SBruce Richardson 38999a2dd95SBruce Richardson rte_prefetch0(off_group->value); 39099a2dd95SBruce Richardson 39199a2dd95SBruce Richardson /* 39299a2dd95SBruce Richardson * Prepopulate the hash_val tables by running the two hash functions 39399a2dd95SBruce Richardson * for each provided rule 39499a2dd95SBruce Richardson */ 39599a2dd95SBruce Richardson for (i = 0; i < off_group->num_rules; i++) { 39699a2dd95SBruce Richardson void *key_stored = EFD_KEY(off_group->key_idx[i], table); 39799a2dd95SBruce Richardson hash_val_b[i] = EFD_HASHFUNCB(key_stored, table); 39899a2dd95SBruce Richardson hash_val_a[i] = EFD_HASHFUNCA(key_stored, table); 39999a2dd95SBruce Richardson } 40099a2dd95SBruce Richardson 40199a2dd95SBruce Richardson for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) { 40299a2dd95SBruce Richardson hash_idx = on_group->hash_idx[i]; 40399a2dd95SBruce Richardson start_hash_idx[i] = hash_idx; 40499a2dd95SBruce Richardson start_lookup_table[i] = on_group->lookup_table[i]; 40599a2dd95SBruce Richardson 40699a2dd95SBruce Richardson do { 40799a2dd95SBruce Richardson efd_lookuptbl_t lookup_table = 0; 40899a2dd95SBruce Richardson efd_lookuptbl_t lookup_table_complement = 0; 40999a2dd95SBruce Richardson 41099a2dd95SBruce Richardson for (rule_id = 0; rule_id < off_group->num_rules; rule_id++) 41199a2dd95SBruce Richardson hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx * 41299a2dd95SBruce Richardson hash_val_b[rule_id]); 41399a2dd95SBruce Richardson 41499a2dd95SBruce Richardson /* 41599a2dd95SBruce Richardson * The goal here is to find a hash function for this 41699a2dd95SBruce Richardson * particular bit entry that meets the following criteria: 41799a2dd95SBruce Richardson * The most significant bits of the hash result define a 41899a2dd95SBruce Richardson * shift into the lookup table where the bit will be stored 41999a2dd95SBruce Richardson */ 42099a2dd95SBruce Richardson 42199a2dd95SBruce Richardson /* Iterate over each provided rule */ 42299a2dd95SBruce Richardson for (rule_id = 0; rule_id < off_group->num_rules; 42399a2dd95SBruce Richardson rule_id++) { 42499a2dd95SBruce Richardson /* 42599a2dd95SBruce Richardson * Use the few most significant bits (number based on 42699a2dd95SBruce Richardson * EFD_LOOKUPTBL_SIZE) to see what position the 42799a2dd95SBruce Richardson * expected bit should be set in the lookup_table 42899a2dd95SBruce Richardson */ 42999a2dd95SBruce Richardson uint32_t bucket_idx = hash_val[rule_id] >> 43099a2dd95SBruce Richardson EFD_LOOKUPTBL_SHIFT; 43199a2dd95SBruce Richardson 43299a2dd95SBruce Richardson /* 43399a2dd95SBruce Richardson * Get the current bit of interest. 43499a2dd95SBruce Richardson * This only find an appropriate hash function 43599a2dd95SBruce Richardson * for one bit at a time of the rule 43699a2dd95SBruce Richardson */ 43799a2dd95SBruce Richardson efd_lookuptbl_t expected = 43899a2dd95SBruce Richardson (off_group->value[rule_id] >> i) & 0x1; 43999a2dd95SBruce Richardson 44099a2dd95SBruce Richardson /* 44199a2dd95SBruce Richardson * Add the expected bit (if set) to a map 44299a2dd95SBruce Richardson * (lookup_table). Also set its complement 44399a2dd95SBruce Richardson * in lookup_table_complement 44499a2dd95SBruce Richardson */ 44599a2dd95SBruce Richardson lookup_table |= expected << bucket_idx; 44699a2dd95SBruce Richardson lookup_table_complement |= (1 - expected) 44799a2dd95SBruce Richardson << bucket_idx; 44899a2dd95SBruce Richardson 44999a2dd95SBruce Richardson /* 45099a2dd95SBruce Richardson * If ever the hash function of two different 45199a2dd95SBruce Richardson * elements result in different values at the 45299a2dd95SBruce Richardson * same location in the lookup_table, 45399a2dd95SBruce Richardson * the current hash_idx is not valid. 45499a2dd95SBruce Richardson */ 45599a2dd95SBruce Richardson if (lookup_table & lookup_table_complement) 45699a2dd95SBruce Richardson break; 45799a2dd95SBruce Richardson } 45899a2dd95SBruce Richardson 45999a2dd95SBruce Richardson /* 46099a2dd95SBruce Richardson * Check if the previous loop completed without 46199a2dd95SBruce Richardson * breaking early 46299a2dd95SBruce Richardson */ 46399a2dd95SBruce Richardson if (rule_id == off_group->num_rules) { 46499a2dd95SBruce Richardson /* 46599a2dd95SBruce Richardson * Current hash function worked, store it 46699a2dd95SBruce Richardson * for the current group 46799a2dd95SBruce Richardson */ 46899a2dd95SBruce Richardson on_group->hash_idx[i] = hash_idx; 46999a2dd95SBruce Richardson on_group->lookup_table[i] = lookup_table; 47099a2dd95SBruce Richardson 47199a2dd95SBruce Richardson /* 47299a2dd95SBruce Richardson * Make sure that the hash function has changed 47399a2dd95SBruce Richardson * from the starting value 47499a2dd95SBruce Richardson */ 47599a2dd95SBruce Richardson hash_idx = start_hash_idx[i] + 1; 47699a2dd95SBruce Richardson break; 47799a2dd95SBruce Richardson } 47899a2dd95SBruce Richardson hash_idx++; 47999a2dd95SBruce Richardson 48099a2dd95SBruce Richardson } while (hash_idx != start_hash_idx[i]); 48199a2dd95SBruce Richardson 48299a2dd95SBruce Richardson /* Failed to find perfect hash for this group */ 48399a2dd95SBruce Richardson if (hash_idx == start_hash_idx[i]) { 48499a2dd95SBruce Richardson /* 48599a2dd95SBruce Richardson * Restore previous hash_idx and lookup_table 48699a2dd95SBruce Richardson * for all value bits 48799a2dd95SBruce Richardson */ 48899a2dd95SBruce Richardson for (j = 0; j < i; j++) { 48999a2dd95SBruce Richardson on_group->hash_idx[j] = start_hash_idx[j]; 49099a2dd95SBruce Richardson on_group->lookup_table[j] = start_lookup_table[j]; 49199a2dd95SBruce Richardson } 49299a2dd95SBruce Richardson return 1; 49399a2dd95SBruce Richardson } 49499a2dd95SBruce Richardson } 49599a2dd95SBruce Richardson 49699a2dd95SBruce Richardson return 0; 49799a2dd95SBruce Richardson } 49899a2dd95SBruce Richardson 49999a2dd95SBruce Richardson struct rte_efd_table * 50099a2dd95SBruce Richardson rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, 5018751a7e9SPablo de Lara uint64_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket) 50299a2dd95SBruce Richardson { 50399a2dd95SBruce Richardson struct rte_efd_table *table = NULL; 50499a2dd95SBruce Richardson uint8_t *key_array = NULL; 50599a2dd95SBruce Richardson uint32_t num_chunks, num_chunks_shift; 50699a2dd95SBruce Richardson uint8_t socket_id; 50799a2dd95SBruce Richardson struct rte_efd_list *efd_list = NULL; 50899a2dd95SBruce Richardson struct rte_tailq_entry *te; 50999a2dd95SBruce Richardson uint64_t offline_table_size; 51099a2dd95SBruce Richardson char ring_name[RTE_RING_NAMESIZE]; 51199a2dd95SBruce Richardson struct rte_ring *r = NULL; 51299a2dd95SBruce Richardson unsigned int i; 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list); 51599a2dd95SBruce Richardson 51699a2dd95SBruce Richardson if (online_cpu_socket_bitmask == 0) { 517ae67895bSDavid Marchand EFD_LOG(ERR, "At least one CPU socket must be enabled " 518ae67895bSDavid Marchand "in the bitmask"); 51999a2dd95SBruce Richardson return NULL; 52099a2dd95SBruce Richardson } 52199a2dd95SBruce Richardson 52299a2dd95SBruce Richardson if (max_num_rules == 0) { 523ae67895bSDavid Marchand EFD_LOG(ERR, "Max num rules must be higher than 0"); 52499a2dd95SBruce Richardson return NULL; 52599a2dd95SBruce Richardson } 52699a2dd95SBruce Richardson 52799a2dd95SBruce Richardson /* 52899a2dd95SBruce Richardson * Compute the minimum number of chunks (smallest power of 2) 52999a2dd95SBruce Richardson * that can hold all of the rules 53099a2dd95SBruce Richardson */ 53199a2dd95SBruce Richardson if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0) 53299a2dd95SBruce Richardson num_chunks = rte_align32pow2(max_num_rules / 53399a2dd95SBruce Richardson EFD_TARGET_CHUNK_NUM_RULES); 53499a2dd95SBruce Richardson else 53599a2dd95SBruce Richardson num_chunks = rte_align32pow2((max_num_rules / 53699a2dd95SBruce Richardson EFD_TARGET_CHUNK_NUM_RULES) + 1); 53799a2dd95SBruce Richardson 53899a2dd95SBruce Richardson num_chunks_shift = rte_bsf32(num_chunks); 53999a2dd95SBruce Richardson 54099a2dd95SBruce Richardson rte_mcfg_tailq_write_lock(); 54199a2dd95SBruce Richardson 54299a2dd95SBruce Richardson /* 54399a2dd95SBruce Richardson * Guarantee there's no existing: this is normally already checked 54499a2dd95SBruce Richardson * by ring creation above 54599a2dd95SBruce Richardson */ 54699a2dd95SBruce Richardson TAILQ_FOREACH(te, efd_list, next) 54799a2dd95SBruce Richardson { 54899a2dd95SBruce Richardson table = (struct rte_efd_table *) te->data; 54999a2dd95SBruce Richardson if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0) 55099a2dd95SBruce Richardson break; 55199a2dd95SBruce Richardson } 55299a2dd95SBruce Richardson 55399a2dd95SBruce Richardson table = NULL; 55499a2dd95SBruce Richardson if (te != NULL) { 55599a2dd95SBruce Richardson rte_errno = EEXIST; 55699a2dd95SBruce Richardson te = NULL; 55799a2dd95SBruce Richardson goto error_unlock_exit; 55899a2dd95SBruce Richardson } 55999a2dd95SBruce Richardson 56099a2dd95SBruce Richardson te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0); 56199a2dd95SBruce Richardson if (te == NULL) { 562ae67895bSDavid Marchand EFD_LOG(ERR, "tailq entry allocation failed"); 56399a2dd95SBruce Richardson goto error_unlock_exit; 56499a2dd95SBruce Richardson } 56599a2dd95SBruce Richardson 56699a2dd95SBruce Richardson /* Create a new EFD table management structure */ 56799a2dd95SBruce Richardson table = rte_zmalloc_socket(NULL, 56899a2dd95SBruce Richardson sizeof(struct rte_efd_table), 56999a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, 57099a2dd95SBruce Richardson offline_cpu_socket); 57199a2dd95SBruce Richardson if (table == NULL) { 572ae67895bSDavid Marchand EFD_LOG(ERR, "Allocating EFD table management structure" 573ae67895bSDavid Marchand " on socket %u failed", 57499a2dd95SBruce Richardson offline_cpu_socket); 57599a2dd95SBruce Richardson goto error_unlock_exit; 57699a2dd95SBruce Richardson } 57799a2dd95SBruce Richardson 57899a2dd95SBruce Richardson 579ae67895bSDavid Marchand EFD_LOG(DEBUG, "Allocated EFD table management structure " 580ae67895bSDavid Marchand "on socket %u", offline_cpu_socket); 58199a2dd95SBruce Richardson 58299a2dd95SBruce Richardson table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_MAX_NUM_RULES; 58399a2dd95SBruce Richardson table->num_rules = 0; 58499a2dd95SBruce Richardson table->num_chunks = num_chunks; 58599a2dd95SBruce Richardson table->num_chunks_shift = num_chunks_shift; 58699a2dd95SBruce Richardson table->key_len = key_len; 58799a2dd95SBruce Richardson 58899a2dd95SBruce Richardson /* key_array */ 58999a2dd95SBruce Richardson key_array = rte_zmalloc_socket(NULL, 59099a2dd95SBruce Richardson table->max_num_rules * table->key_len, 59199a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, 59299a2dd95SBruce Richardson offline_cpu_socket); 59399a2dd95SBruce Richardson if (key_array == NULL) { 594ae67895bSDavid Marchand EFD_LOG(ERR, "Allocating key array" 595ae67895bSDavid Marchand " on socket %u failed", 59699a2dd95SBruce Richardson offline_cpu_socket); 59799a2dd95SBruce Richardson goto error_unlock_exit; 59899a2dd95SBruce Richardson } 59999a2dd95SBruce Richardson table->keys = key_array; 60099a2dd95SBruce Richardson strlcpy(table->name, name, sizeof(table->name)); 60199a2dd95SBruce Richardson 602ae67895bSDavid Marchand EFD_LOG(DEBUG, "Creating an EFD table with %u chunks," 603ae67895bSDavid Marchand " which potentially supports %u entries", 60499a2dd95SBruce Richardson num_chunks, table->max_num_rules); 60599a2dd95SBruce Richardson 60699a2dd95SBruce Richardson /* Make sure all the allocatable table pointers are NULL initially */ 60799a2dd95SBruce Richardson for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) 60899a2dd95SBruce Richardson table->chunks[socket_id] = NULL; 60999a2dd95SBruce Richardson table->offline_chunks = NULL; 61099a2dd95SBruce Richardson 61199a2dd95SBruce Richardson /* 61299a2dd95SBruce Richardson * Allocate one online table per socket specified 61399a2dd95SBruce Richardson * in the user-supplied bitmask 61499a2dd95SBruce Richardson */ 61599a2dd95SBruce Richardson uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) + 61699a2dd95SBruce Richardson EFD_NUM_CHUNK_PADDING_BYTES; 61799a2dd95SBruce Richardson 61899a2dd95SBruce Richardson for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) { 61999a2dd95SBruce Richardson if ((online_cpu_socket_bitmask >> socket_id) & 0x01) { 62099a2dd95SBruce Richardson /* 62199a2dd95SBruce Richardson * Allocate all of the EFD table chunks (the online portion) 62299a2dd95SBruce Richardson * as a continuous block 62399a2dd95SBruce Richardson */ 62499a2dd95SBruce Richardson table->chunks[socket_id] = 62599a2dd95SBruce Richardson rte_zmalloc_socket( 62699a2dd95SBruce Richardson NULL, 62799a2dd95SBruce Richardson online_table_size, 62899a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, 62999a2dd95SBruce Richardson socket_id); 63099a2dd95SBruce Richardson if (table->chunks[socket_id] == NULL) { 631ae67895bSDavid Marchand EFD_LOG(ERR, 63299a2dd95SBruce Richardson "Allocating EFD online table on " 633ae67895bSDavid Marchand "socket %u failed", 63499a2dd95SBruce Richardson socket_id); 63599a2dd95SBruce Richardson goto error_unlock_exit; 63699a2dd95SBruce Richardson } 637ae67895bSDavid Marchand EFD_LOG(DEBUG, 63899a2dd95SBruce Richardson "Allocated EFD online table of size " 639ae67895bSDavid Marchand "%"PRIu64" bytes (%.2f MB) on socket %u", 64099a2dd95SBruce Richardson online_table_size, 64199a2dd95SBruce Richardson (float) online_table_size / 64299a2dd95SBruce Richardson (1024.0F * 1024.0F), 64399a2dd95SBruce Richardson socket_id); 64499a2dd95SBruce Richardson } 64599a2dd95SBruce Richardson } 64699a2dd95SBruce Richardson 64799a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) 64899a2dd95SBruce Richardson /* 64999a2dd95SBruce Richardson * For less than 4 bits, scalar function performs better 65099a2dd95SBruce Richardson * than vectorised version 65199a2dd95SBruce Richardson */ 65299a2dd95SBruce Richardson if (RTE_EFD_VALUE_NUM_BITS > 3 65399a2dd95SBruce Richardson && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) 65499a2dd95SBruce Richardson && rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256) 65599a2dd95SBruce Richardson table->lookup_fn = EFD_LOOKUP_AVX2; 65699a2dd95SBruce Richardson else 65799a2dd95SBruce Richardson #endif 65899a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM64) 65999a2dd95SBruce Richardson /* 66099a2dd95SBruce Richardson * For less than or equal to 16 bits, scalar function performs better 66199a2dd95SBruce Richardson * than vectorised version 66299a2dd95SBruce Richardson */ 66399a2dd95SBruce Richardson if (RTE_EFD_VALUE_NUM_BITS > 16 && 66499a2dd95SBruce Richardson rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) && 66599a2dd95SBruce Richardson rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128) 66699a2dd95SBruce Richardson table->lookup_fn = EFD_LOOKUP_NEON; 66799a2dd95SBruce Richardson else 66899a2dd95SBruce Richardson #endif 66999a2dd95SBruce Richardson table->lookup_fn = EFD_LOOKUP_SCALAR; 67099a2dd95SBruce Richardson 67199a2dd95SBruce Richardson /* 67299a2dd95SBruce Richardson * Allocate the EFD table offline portion (with the actual rules 67399a2dd95SBruce Richardson * mapping keys to values) as a continuous block. 67499a2dd95SBruce Richardson * This could be several gigabytes of memory. 67599a2dd95SBruce Richardson */ 67699a2dd95SBruce Richardson offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules); 67799a2dd95SBruce Richardson table->offline_chunks = 67899a2dd95SBruce Richardson rte_zmalloc_socket(NULL, 67999a2dd95SBruce Richardson offline_table_size, 68099a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, 68199a2dd95SBruce Richardson offline_cpu_socket); 68299a2dd95SBruce Richardson if (table->offline_chunks == NULL) { 683ae67895bSDavid Marchand EFD_LOG(ERR, "Allocating EFD offline table on socket %u " 684ae67895bSDavid Marchand "failed", offline_cpu_socket); 68599a2dd95SBruce Richardson goto error_unlock_exit; 68699a2dd95SBruce Richardson } 68799a2dd95SBruce Richardson 688ae67895bSDavid Marchand EFD_LOG(DEBUG, 68999a2dd95SBruce Richardson "Allocated EFD offline table of size %"PRIu64" bytes " 690ae67895bSDavid Marchand " (%.2f MB) on socket %u", offline_table_size, 69199a2dd95SBruce Richardson (float) offline_table_size / (1024.0F * 1024.0F), 69299a2dd95SBruce Richardson offline_cpu_socket); 69399a2dd95SBruce Richardson 69499a2dd95SBruce Richardson te->data = (void *) table; 69599a2dd95SBruce Richardson TAILQ_INSERT_TAIL(efd_list, te, next); 69699a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 69799a2dd95SBruce Richardson 69899a2dd95SBruce Richardson snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name); 69999a2dd95SBruce Richardson /* Create ring (Dummy slot index is not enqueued) */ 70099a2dd95SBruce Richardson r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules), 70199a2dd95SBruce Richardson offline_cpu_socket, 0); 70299a2dd95SBruce Richardson if (r == NULL) { 703ae67895bSDavid Marchand EFD_LOG(ERR, "memory allocation failed"); 70499a2dd95SBruce Richardson rte_efd_free(table); 70599a2dd95SBruce Richardson return NULL; 70699a2dd95SBruce Richardson } 70799a2dd95SBruce Richardson 70899a2dd95SBruce Richardson /* Populate free slots ring. Entry zero is reserved for key misses. */ 70999a2dd95SBruce Richardson for (i = 0; i < table->max_num_rules; i++) 71099a2dd95SBruce Richardson rte_ring_sp_enqueue(r, (void *) ((uintptr_t) i)); 71199a2dd95SBruce Richardson 71299a2dd95SBruce Richardson table->free_slots = r; 71399a2dd95SBruce Richardson return table; 71499a2dd95SBruce Richardson 71599a2dd95SBruce Richardson error_unlock_exit: 71699a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 71799a2dd95SBruce Richardson rte_free(te); 71899a2dd95SBruce Richardson rte_efd_free(table); 71999a2dd95SBruce Richardson 72099a2dd95SBruce Richardson return NULL; 72199a2dd95SBruce Richardson } 72299a2dd95SBruce Richardson 72399a2dd95SBruce Richardson struct rte_efd_table * 72499a2dd95SBruce Richardson rte_efd_find_existing(const char *name) 72599a2dd95SBruce Richardson { 72699a2dd95SBruce Richardson struct rte_efd_table *table = NULL; 72799a2dd95SBruce Richardson struct rte_tailq_entry *te; 72899a2dd95SBruce Richardson struct rte_efd_list *efd_list; 72999a2dd95SBruce Richardson 73099a2dd95SBruce Richardson efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list); 73199a2dd95SBruce Richardson 73299a2dd95SBruce Richardson rte_mcfg_tailq_read_lock(); 73399a2dd95SBruce Richardson 73499a2dd95SBruce Richardson TAILQ_FOREACH(te, efd_list, next) 73599a2dd95SBruce Richardson { 73699a2dd95SBruce Richardson table = (struct rte_efd_table *) te->data; 73799a2dd95SBruce Richardson if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0) 73899a2dd95SBruce Richardson break; 73999a2dd95SBruce Richardson } 74099a2dd95SBruce Richardson rte_mcfg_tailq_read_unlock(); 74199a2dd95SBruce Richardson 74299a2dd95SBruce Richardson if (te == NULL) { 74399a2dd95SBruce Richardson rte_errno = ENOENT; 74499a2dd95SBruce Richardson return NULL; 74599a2dd95SBruce Richardson } 74699a2dd95SBruce Richardson return table; 74799a2dd95SBruce Richardson } 74899a2dd95SBruce Richardson 74999a2dd95SBruce Richardson void 75099a2dd95SBruce Richardson rte_efd_free(struct rte_efd_table *table) 75199a2dd95SBruce Richardson { 75299a2dd95SBruce Richardson uint8_t socket_id; 75399a2dd95SBruce Richardson struct rte_efd_list *efd_list; 75499a2dd95SBruce Richardson struct rte_tailq_entry *te, *temp; 75599a2dd95SBruce Richardson 75699a2dd95SBruce Richardson if (table == NULL) 75799a2dd95SBruce Richardson return; 75899a2dd95SBruce Richardson 75999a2dd95SBruce Richardson for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) 76099a2dd95SBruce Richardson rte_free(table->chunks[socket_id]); 76199a2dd95SBruce Richardson 76299a2dd95SBruce Richardson efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list); 76399a2dd95SBruce Richardson rte_mcfg_tailq_write_lock(); 76499a2dd95SBruce Richardson 765f1f6ebc0SWilliam Tu RTE_TAILQ_FOREACH_SAFE(te, efd_list, next, temp) { 76699a2dd95SBruce Richardson if (te->data == (void *) table) { 76799a2dd95SBruce Richardson TAILQ_REMOVE(efd_list, te, next); 76899a2dd95SBruce Richardson rte_free(te); 76999a2dd95SBruce Richardson break; 77099a2dd95SBruce Richardson } 77199a2dd95SBruce Richardson } 77299a2dd95SBruce Richardson 77399a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 77499a2dd95SBruce Richardson rte_ring_free(table->free_slots); 77599a2dd95SBruce Richardson rte_free(table->offline_chunks); 77699a2dd95SBruce Richardson rte_free(table->keys); 77799a2dd95SBruce Richardson rte_free(table); 77899a2dd95SBruce Richardson } 77999a2dd95SBruce Richardson 78099a2dd95SBruce Richardson /** 78199a2dd95SBruce Richardson * Applies a previously computed table entry to the specified table for all 78299a2dd95SBruce Richardson * socket-local copies of the online table. 78399a2dd95SBruce Richardson * Intended to apply an update for only a single change 78499a2dd95SBruce Richardson * to a key/value pair at a time 78599a2dd95SBruce Richardson * 78699a2dd95SBruce Richardson * @param table 78799a2dd95SBruce Richardson * EFD table to reference 78899a2dd95SBruce Richardson * @param socket_id 78999a2dd95SBruce Richardson * Socket ID to use to lookup existing values (ideally caller's socket id) 79099a2dd95SBruce Richardson * @param chunk_id 79199a2dd95SBruce Richardson * Chunk index to update 79299a2dd95SBruce Richardson * @param group_id 79399a2dd95SBruce Richardson * Group index to update 79499a2dd95SBruce Richardson * @param bin_id 79599a2dd95SBruce Richardson * Bin within the group that this update affects 79699a2dd95SBruce Richardson * @param new_bin_choice 79799a2dd95SBruce Richardson * Newly chosen permutation which this bin should use - only lower 2 bits 79899a2dd95SBruce Richardson * @param new_group_entry 79999a2dd95SBruce Richardson * Previously computed updated chunk/group entry 80099a2dd95SBruce Richardson */ 80199a2dd95SBruce Richardson static inline void 80299a2dd95SBruce Richardson efd_apply_update(struct rte_efd_table * const table, const unsigned int socket_id, 80399a2dd95SBruce Richardson const uint32_t chunk_id, const uint32_t group_id, 80499a2dd95SBruce Richardson const uint32_t bin_id, const uint8_t new_bin_choice, 80599a2dd95SBruce Richardson const struct efd_online_group_entry * const new_group_entry) 80699a2dd95SBruce Richardson { 80799a2dd95SBruce Richardson int i; 80899a2dd95SBruce Richardson struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id]; 80999a2dd95SBruce Richardson uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS; 81099a2dd95SBruce Richardson 81199a2dd95SBruce Richardson /* 81299a2dd95SBruce Richardson * Grab the current byte that contains the choices 81399a2dd95SBruce Richardson * for four neighboring bins 81499a2dd95SBruce Richardson */ 81599a2dd95SBruce Richardson uint8_t choice_chunk = 81699a2dd95SBruce Richardson chunk->bin_choice_list[bin_index]; 81799a2dd95SBruce Richardson 81899a2dd95SBruce Richardson 81999a2dd95SBruce Richardson /* Compute the offset into the chunk that needs to be updated */ 82099a2dd95SBruce Richardson int offset = (bin_id & 0x3) * 2; 82199a2dd95SBruce Richardson 82299a2dd95SBruce Richardson /* Zero the two bits of interest and set them to new_bin_choice */ 82399a2dd95SBruce Richardson choice_chunk = (choice_chunk & (~(0x03 << offset))) 82499a2dd95SBruce Richardson | ((new_bin_choice & 0x03) << offset); 82599a2dd95SBruce Richardson 82699a2dd95SBruce Richardson /* Update the online table with the new data across all sockets */ 82799a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { 82899a2dd95SBruce Richardson if (table->chunks[i] != NULL) { 82999a2dd95SBruce Richardson memcpy(&(table->chunks[i][chunk_id].groups[group_id]), 83099a2dd95SBruce Richardson new_group_entry, 83199a2dd95SBruce Richardson sizeof(struct efd_online_group_entry)); 83299a2dd95SBruce Richardson table->chunks[i][chunk_id].bin_choice_list[bin_index] = 83399a2dd95SBruce Richardson choice_chunk; 83499a2dd95SBruce Richardson } 83599a2dd95SBruce Richardson } 83699a2dd95SBruce Richardson } 83799a2dd95SBruce Richardson 83899a2dd95SBruce Richardson /* 83999a2dd95SBruce Richardson * Move the bin from prev group to the new group 84099a2dd95SBruce Richardson */ 84199a2dd95SBruce Richardson static inline void 84299a2dd95SBruce Richardson move_groups(uint32_t bin_id, uint8_t bin_size, 84399a2dd95SBruce Richardson struct efd_offline_group_rules *new_group, 84499a2dd95SBruce Richardson struct efd_offline_group_rules * const current_group) 84599a2dd95SBruce Richardson { 84699a2dd95SBruce Richardson 84799a2dd95SBruce Richardson uint8_t empty_idx = 0; 84899a2dd95SBruce Richardson unsigned int i; 84999a2dd95SBruce Richardson 85099a2dd95SBruce Richardson if (new_group == current_group) 85199a2dd95SBruce Richardson return; 85299a2dd95SBruce Richardson 85399a2dd95SBruce Richardson for (i = 0; i < current_group->num_rules; i++) { 85499a2dd95SBruce Richardson /* 85599a2dd95SBruce Richardson * Move keys that belong to the same bin 85699a2dd95SBruce Richardson * to the new group 85799a2dd95SBruce Richardson */ 85899a2dd95SBruce Richardson if (current_group->bin_id[i] == bin_id) { 85999a2dd95SBruce Richardson new_group->key_idx[new_group->num_rules] = 86099a2dd95SBruce Richardson current_group->key_idx[i]; 86199a2dd95SBruce Richardson new_group->value[new_group->num_rules] = 86299a2dd95SBruce Richardson current_group->value[i]; 86399a2dd95SBruce Richardson new_group->bin_id[new_group->num_rules] = 86499a2dd95SBruce Richardson current_group->bin_id[i]; 86599a2dd95SBruce Richardson new_group->num_rules++; 86699a2dd95SBruce Richardson } else { 86799a2dd95SBruce Richardson if (i != empty_idx) { 86899a2dd95SBruce Richardson /* 86999a2dd95SBruce Richardson * Need to move this key towards 87099a2dd95SBruce Richardson * the top of the array 87199a2dd95SBruce Richardson */ 87299a2dd95SBruce Richardson current_group->key_idx[empty_idx] = 87399a2dd95SBruce Richardson current_group->key_idx[i]; 87499a2dd95SBruce Richardson current_group->value[empty_idx] = 87599a2dd95SBruce Richardson current_group->value[i]; 87699a2dd95SBruce Richardson current_group->bin_id[empty_idx] = 87799a2dd95SBruce Richardson current_group->bin_id[i]; 87899a2dd95SBruce Richardson } 87999a2dd95SBruce Richardson empty_idx++; 88099a2dd95SBruce Richardson } 88199a2dd95SBruce Richardson 88299a2dd95SBruce Richardson } 88399a2dd95SBruce Richardson current_group->num_rules -= bin_size; 88499a2dd95SBruce Richardson } 88599a2dd95SBruce Richardson 88699a2dd95SBruce Richardson /* 88799a2dd95SBruce Richardson * Revert group/s to their previous state before 88899a2dd95SBruce Richardson * trying to insert/add a new key 88999a2dd95SBruce Richardson */ 89099a2dd95SBruce Richardson static inline void 89199a2dd95SBruce Richardson revert_groups(struct efd_offline_group_rules *previous_group, 89299a2dd95SBruce Richardson struct efd_offline_group_rules *current_group, uint8_t bin_size) 89399a2dd95SBruce Richardson { 89499a2dd95SBruce Richardson unsigned int i; 89599a2dd95SBruce Richardson 89699a2dd95SBruce Richardson if (current_group == previous_group) 89799a2dd95SBruce Richardson return; 89899a2dd95SBruce Richardson 89999a2dd95SBruce Richardson /* Move keys back to previous group */ 90099a2dd95SBruce Richardson for (i = current_group->num_rules - bin_size; 90199a2dd95SBruce Richardson i < current_group->num_rules; i++) { 90299a2dd95SBruce Richardson previous_group->key_idx[previous_group->num_rules] = 90399a2dd95SBruce Richardson current_group->key_idx[i]; 90499a2dd95SBruce Richardson previous_group->value[previous_group->num_rules] = 90599a2dd95SBruce Richardson current_group->value[i]; 90699a2dd95SBruce Richardson previous_group->bin_id[previous_group->num_rules] = 90799a2dd95SBruce Richardson current_group->bin_id[i]; 90899a2dd95SBruce Richardson previous_group->num_rules++; 90999a2dd95SBruce Richardson } 91099a2dd95SBruce Richardson 91199a2dd95SBruce Richardson /* 91299a2dd95SBruce Richardson * Decrease number of rules after the move 91399a2dd95SBruce Richardson * in the new group 91499a2dd95SBruce Richardson */ 91599a2dd95SBruce Richardson current_group->num_rules -= bin_size; 91699a2dd95SBruce Richardson } 91799a2dd95SBruce Richardson 91899a2dd95SBruce Richardson /** 91999a2dd95SBruce Richardson * Computes an updated table entry where the supplied key points to a new host. 92099a2dd95SBruce Richardson * If no entry exists, one is inserted. 92199a2dd95SBruce Richardson * 92299a2dd95SBruce Richardson * This function does NOT modify the online table(s) 92399a2dd95SBruce Richardson * This function DOES modify the offline table 92499a2dd95SBruce Richardson * 92599a2dd95SBruce Richardson * @param table 92699a2dd95SBruce Richardson * EFD table to reference 92799a2dd95SBruce Richardson * @param socket_id 92899a2dd95SBruce Richardson * Socket ID to use to lookup existing values (ideally caller's socket id) 92999a2dd95SBruce Richardson * @param key 93099a2dd95SBruce Richardson * Key to insert 93199a2dd95SBruce Richardson * @param value 93299a2dd95SBruce Richardson * Value to associate with key 93399a2dd95SBruce Richardson * @param chunk_id 93499a2dd95SBruce Richardson * Chunk ID of the chunk that was modified 93599a2dd95SBruce Richardson * @param group_id 93699a2dd95SBruce Richardson * Group ID of the group that was modified 93799a2dd95SBruce Richardson * @param bin_id 93899a2dd95SBruce Richardson * Bin ID that was modified 93999a2dd95SBruce Richardson * @param new_bin_choice 94099a2dd95SBruce Richardson * Newly chosen permutation which this bin will use 94199a2dd95SBruce Richardson * @param entry 94299a2dd95SBruce Richardson * Newly computed online entry to apply later with efd_apply_update 94399a2dd95SBruce Richardson * 94499a2dd95SBruce Richardson * @return 94599a2dd95SBruce Richardson * RTE_EFD_UPDATE_WARN_GROUP_FULL 94699a2dd95SBruce Richardson * Operation is insert, and the last available space in the 94799a2dd95SBruce Richardson * key's group was just used. Future inserts may fail as groups fill up. 94899a2dd95SBruce Richardson * This operation was still successful, and entry contains a valid update 94999a2dd95SBruce Richardson * RTE_EFD_UPDATE_FAILED 95099a2dd95SBruce Richardson * Either the EFD failed to find a suitable perfect hash or the group was full 95199a2dd95SBruce Richardson * This is a fatal error, and the table is now in an indeterminate state 95299a2dd95SBruce Richardson * RTE_EFD_UPDATE_NO_CHANGE 95399a2dd95SBruce Richardson * Operation resulted in no change to the table (same value already exists) 95499a2dd95SBruce Richardson * 0 95599a2dd95SBruce Richardson * Insert or update was successful, and the new efd_online_group_entry 95699a2dd95SBruce Richardson * is stored in *entry 95799a2dd95SBruce Richardson * 95899a2dd95SBruce Richardson * @warning 95999a2dd95SBruce Richardson * Note that entry will be UNCHANGED if the update has no effect, and thus any 96099a2dd95SBruce Richardson * subsequent use of the entry content will likely be invalid 96199a2dd95SBruce Richardson */ 96299a2dd95SBruce Richardson static inline int 96399a2dd95SBruce Richardson efd_compute_update(struct rte_efd_table * const table, 96499a2dd95SBruce Richardson const unsigned int socket_id, const void *key, 96599a2dd95SBruce Richardson const efd_value_t value, uint32_t * const chunk_id, 96699a2dd95SBruce Richardson uint32_t * const group_id, uint32_t * const bin_id, 96799a2dd95SBruce Richardson uint8_t * const new_bin_choice, 96899a2dd95SBruce Richardson struct efd_online_group_entry * const entry) 96999a2dd95SBruce Richardson { 97099a2dd95SBruce Richardson unsigned int i; 97199a2dd95SBruce Richardson int ret; 97299a2dd95SBruce Richardson uint32_t new_idx; 97399a2dd95SBruce Richardson void *new_k, *slot_id = NULL; 97499a2dd95SBruce Richardson int status = EXIT_SUCCESS; 97599a2dd95SBruce Richardson unsigned int found = 0; 97699a2dd95SBruce Richardson 97799a2dd95SBruce Richardson efd_compute_ids(table, key, chunk_id, bin_id); 97899a2dd95SBruce Richardson 97999a2dd95SBruce Richardson struct efd_offline_chunk_rules * const chunk = 98099a2dd95SBruce Richardson &table->offline_chunks[*chunk_id]; 98199a2dd95SBruce Richardson struct efd_offline_group_rules *new_group; 98299a2dd95SBruce Richardson 98399a2dd95SBruce Richardson uint8_t current_choice = efd_get_choice(table, socket_id, 98499a2dd95SBruce Richardson *chunk_id, *bin_id); 98599a2dd95SBruce Richardson uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id]; 98699a2dd95SBruce Richardson struct efd_offline_group_rules * const current_group = 98799a2dd95SBruce Richardson &chunk->group_rules[current_group_id]; 98899a2dd95SBruce Richardson uint8_t bin_size = 0; 98999a2dd95SBruce Richardson uint8_t key_changed_index = 0; 99099a2dd95SBruce Richardson efd_value_t key_changed_previous_value = 0; 99199a2dd95SBruce Richardson uint32_t key_idx_previous = 0; 99299a2dd95SBruce Richardson 99399a2dd95SBruce Richardson /* Scan the current group and see if the key is already present */ 99499a2dd95SBruce Richardson for (i = 0; i < current_group->num_rules; i++) { 99599a2dd95SBruce Richardson if (current_group->bin_id[i] == *bin_id) 99699a2dd95SBruce Richardson bin_size++; 99799a2dd95SBruce Richardson else 99899a2dd95SBruce Richardson continue; 99999a2dd95SBruce Richardson 100099a2dd95SBruce Richardson void *key_stored = EFD_KEY(current_group->key_idx[i], table); 100199a2dd95SBruce Richardson if (found == 0 && unlikely(memcmp(key_stored, key, 100299a2dd95SBruce Richardson table->key_len) == 0)) { 100399a2dd95SBruce Richardson /* Key is already present */ 100499a2dd95SBruce Richardson 100599a2dd95SBruce Richardson /* 100699a2dd95SBruce Richardson * If previous value is same as new value, 100799a2dd95SBruce Richardson * no additional work is required 100899a2dd95SBruce Richardson */ 100999a2dd95SBruce Richardson if (current_group->value[i] == value) 101099a2dd95SBruce Richardson return RTE_EFD_UPDATE_NO_CHANGE; 101199a2dd95SBruce Richardson 101299a2dd95SBruce Richardson key_idx_previous = current_group->key_idx[i]; 101399a2dd95SBruce Richardson key_changed_previous_value = current_group->value[i]; 101499a2dd95SBruce Richardson key_changed_index = i; 101599a2dd95SBruce Richardson current_group->value[i] = value; 101699a2dd95SBruce Richardson found = 1; 101799a2dd95SBruce Richardson } 101899a2dd95SBruce Richardson } 101999a2dd95SBruce Richardson 102099a2dd95SBruce Richardson if (found == 0) { 102199a2dd95SBruce Richardson /* Key does not exist. Insert the rule into the bin/group */ 102299a2dd95SBruce Richardson if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) { 1023ae67895bSDavid Marchand EFD_LOG(ERR, 102499a2dd95SBruce Richardson "Fatal: No room remaining for insert into " 1025ae67895bSDavid Marchand "chunk %u group %u bin %u", 102699a2dd95SBruce Richardson *chunk_id, 102799a2dd95SBruce Richardson current_group_id, *bin_id); 102899a2dd95SBruce Richardson return RTE_EFD_UPDATE_FAILED; 102999a2dd95SBruce Richardson } 103099a2dd95SBruce Richardson 103199a2dd95SBruce Richardson if (unlikely(current_group->num_rules == 103299a2dd95SBruce Richardson (EFD_MAX_GROUP_NUM_RULES - 1))) { 1033ae67895bSDavid Marchand EFD_LOG(INFO, "Warn: Insert into last " 103499a2dd95SBruce Richardson "available slot in chunk %u " 1035ae67895bSDavid Marchand "group %u bin %u", *chunk_id, 103699a2dd95SBruce Richardson current_group_id, *bin_id); 103799a2dd95SBruce Richardson status = RTE_EFD_UPDATE_WARN_GROUP_FULL; 103899a2dd95SBruce Richardson } 103999a2dd95SBruce Richardson 104099a2dd95SBruce Richardson if (rte_ring_sc_dequeue(table->free_slots, &slot_id) != 0) 104199a2dd95SBruce Richardson return RTE_EFD_UPDATE_FAILED; 104299a2dd95SBruce Richardson 104399a2dd95SBruce Richardson new_k = RTE_PTR_ADD(table->keys, (uintptr_t) slot_id * 104499a2dd95SBruce Richardson table->key_len); 104599a2dd95SBruce Richardson rte_prefetch0(new_k); 104699a2dd95SBruce Richardson new_idx = (uint32_t) ((uintptr_t) slot_id); 104799a2dd95SBruce Richardson 104899a2dd95SBruce Richardson rte_memcpy(EFD_KEY(new_idx, table), key, table->key_len); 104999a2dd95SBruce Richardson current_group->key_idx[current_group->num_rules] = new_idx; 105099a2dd95SBruce Richardson current_group->value[current_group->num_rules] = value; 105199a2dd95SBruce Richardson current_group->bin_id[current_group->num_rules] = *bin_id; 105299a2dd95SBruce Richardson current_group->num_rules++; 105399a2dd95SBruce Richardson table->num_rules++; 105499a2dd95SBruce Richardson bin_size++; 105599a2dd95SBruce Richardson } else { 105699a2dd95SBruce Richardson uint32_t last = current_group->num_rules - 1; 105799a2dd95SBruce Richardson /* Swap the key with the last key inserted*/ 105899a2dd95SBruce Richardson current_group->key_idx[key_changed_index] = 105999a2dd95SBruce Richardson current_group->key_idx[last]; 106099a2dd95SBruce Richardson current_group->value[key_changed_index] = 106199a2dd95SBruce Richardson current_group->value[last]; 106299a2dd95SBruce Richardson current_group->bin_id[key_changed_index] = 106399a2dd95SBruce Richardson current_group->bin_id[last]; 106499a2dd95SBruce Richardson 106599a2dd95SBruce Richardson /* 106699a2dd95SBruce Richardson * Key to be updated will always be available 106799a2dd95SBruce Richardson * at the end of the group 106899a2dd95SBruce Richardson */ 106999a2dd95SBruce Richardson current_group->key_idx[last] = key_idx_previous; 107099a2dd95SBruce Richardson current_group->value[last] = value; 107199a2dd95SBruce Richardson current_group->bin_id[last] = *bin_id; 107299a2dd95SBruce Richardson } 107399a2dd95SBruce Richardson 107499a2dd95SBruce Richardson *new_bin_choice = current_choice; 107599a2dd95SBruce Richardson *group_id = current_group_id; 107699a2dd95SBruce Richardson new_group = current_group; 107799a2dd95SBruce Richardson 107899a2dd95SBruce Richardson /* Group need to be rebalanced when it starts to get loaded */ 107999a2dd95SBruce Richardson if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) { 108099a2dd95SBruce Richardson 108199a2dd95SBruce Richardson /* 108299a2dd95SBruce Richardson * Subtract the number of entries in the bin from 108399a2dd95SBruce Richardson * the original group 108499a2dd95SBruce Richardson */ 108599a2dd95SBruce Richardson current_group->num_rules -= bin_size; 108699a2dd95SBruce Richardson 108799a2dd95SBruce Richardson /* 108899a2dd95SBruce Richardson * Figure out which of the available groups that this bin 108999a2dd95SBruce Richardson * can map to is the smallest (using the current group 109099a2dd95SBruce Richardson * as baseline) 109199a2dd95SBruce Richardson */ 109299a2dd95SBruce Richardson uint8_t smallest_choice = current_choice; 109399a2dd95SBruce Richardson uint8_t smallest_size = current_group->num_rules; 109499a2dd95SBruce Richardson uint32_t smallest_group_id = current_group_id; 109599a2dd95SBruce Richardson unsigned char choice; 109699a2dd95SBruce Richardson 109799a2dd95SBruce Richardson for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS; 109899a2dd95SBruce Richardson choice++) { 109999a2dd95SBruce Richardson uint32_t test_group_id = 110099a2dd95SBruce Richardson efd_bin_to_group[choice][*bin_id]; 110199a2dd95SBruce Richardson uint32_t num_rules = 110299a2dd95SBruce Richardson chunk->group_rules[test_group_id].num_rules; 110399a2dd95SBruce Richardson if (num_rules < smallest_size) { 110499a2dd95SBruce Richardson smallest_choice = choice; 110599a2dd95SBruce Richardson smallest_size = num_rules; 110699a2dd95SBruce Richardson smallest_group_id = test_group_id; 110799a2dd95SBruce Richardson } 110899a2dd95SBruce Richardson } 110999a2dd95SBruce Richardson 111099a2dd95SBruce Richardson *new_bin_choice = smallest_choice; 111199a2dd95SBruce Richardson *group_id = smallest_group_id; 111299a2dd95SBruce Richardson new_group = &chunk->group_rules[smallest_group_id]; 111399a2dd95SBruce Richardson current_group->num_rules += bin_size; 111499a2dd95SBruce Richardson 111599a2dd95SBruce Richardson } 111699a2dd95SBruce Richardson 111799a2dd95SBruce Richardson uint8_t choice = 0; 111899a2dd95SBruce Richardson for (;;) { 111999a2dd95SBruce Richardson if (current_group != new_group && 112099a2dd95SBruce Richardson new_group->num_rules + bin_size > 112199a2dd95SBruce Richardson EFD_MAX_GROUP_NUM_RULES) { 1122ae67895bSDavid Marchand EFD_LOG(DEBUG, 112399a2dd95SBruce Richardson "Unable to move_groups to dest group " 112499a2dd95SBruce Richardson "containing %u entries." 1125ae67895bSDavid Marchand "bin_size:%u choice:%02x", 112699a2dd95SBruce Richardson new_group->num_rules, bin_size, 112799a2dd95SBruce Richardson choice - 1); 112899a2dd95SBruce Richardson goto next_choice; 112999a2dd95SBruce Richardson } 113099a2dd95SBruce Richardson move_groups(*bin_id, bin_size, new_group, current_group); 113199a2dd95SBruce Richardson /* 113299a2dd95SBruce Richardson * Recompute the hash function for the modified group, 113399a2dd95SBruce Richardson * and return it to the caller 113499a2dd95SBruce Richardson */ 113599a2dd95SBruce Richardson ret = efd_search_hash(table, new_group, entry); 113699a2dd95SBruce Richardson 113799a2dd95SBruce Richardson if (!ret) 113899a2dd95SBruce Richardson return status; 113999a2dd95SBruce Richardson 1140ae67895bSDavid Marchand EFD_LOG(DEBUG, 114199a2dd95SBruce Richardson "Failed to find perfect hash for group " 1142ae67895bSDavid Marchand "containing %u entries. bin_size:%u choice:%02x", 114399a2dd95SBruce Richardson new_group->num_rules, bin_size, choice - 1); 114499a2dd95SBruce Richardson /* Restore groups modified to their previous state */ 114599a2dd95SBruce Richardson revert_groups(current_group, new_group, bin_size); 114699a2dd95SBruce Richardson 114799a2dd95SBruce Richardson next_choice: 114899a2dd95SBruce Richardson if (choice == EFD_CHUNK_NUM_BIN_TO_GROUP_SETS) 114999a2dd95SBruce Richardson break; 115099a2dd95SBruce Richardson *new_bin_choice = choice; 115199a2dd95SBruce Richardson *group_id = efd_bin_to_group[choice][*bin_id]; 115299a2dd95SBruce Richardson new_group = &chunk->group_rules[*group_id]; 115399a2dd95SBruce Richardson choice++; 115499a2dd95SBruce Richardson } 115599a2dd95SBruce Richardson 115699a2dd95SBruce Richardson if (!found) { 115799a2dd95SBruce Richardson current_group->num_rules--; 115899a2dd95SBruce Richardson table->num_rules--; 115999a2dd95SBruce Richardson } else 116099a2dd95SBruce Richardson current_group->value[current_group->num_rules - 1] = 116199a2dd95SBruce Richardson key_changed_previous_value; 116299a2dd95SBruce Richardson return RTE_EFD_UPDATE_FAILED; 116399a2dd95SBruce Richardson } 116499a2dd95SBruce Richardson 116599a2dd95SBruce Richardson int 116699a2dd95SBruce Richardson rte_efd_update(struct rte_efd_table * const table, const unsigned int socket_id, 116799a2dd95SBruce Richardson const void *key, const efd_value_t value) 116899a2dd95SBruce Richardson { 116999a2dd95SBruce Richardson uint32_t chunk_id = 0, group_id = 0, bin_id = 0; 117099a2dd95SBruce Richardson uint8_t new_bin_choice = 0; 1171ecda2c40SPablo de Lara struct efd_online_group_entry entry = {{0}}; 117299a2dd95SBruce Richardson 117399a2dd95SBruce Richardson int status = efd_compute_update(table, socket_id, key, value, 117499a2dd95SBruce Richardson &chunk_id, &group_id, &bin_id, 117599a2dd95SBruce Richardson &new_bin_choice, &entry); 117699a2dd95SBruce Richardson 117799a2dd95SBruce Richardson if (status == RTE_EFD_UPDATE_NO_CHANGE) 117899a2dd95SBruce Richardson return EXIT_SUCCESS; 117999a2dd95SBruce Richardson 118099a2dd95SBruce Richardson if (status == RTE_EFD_UPDATE_FAILED) 118199a2dd95SBruce Richardson return status; 118299a2dd95SBruce Richardson 118399a2dd95SBruce Richardson efd_apply_update(table, socket_id, chunk_id, group_id, bin_id, 118499a2dd95SBruce Richardson new_bin_choice, &entry); 118599a2dd95SBruce Richardson return status; 118699a2dd95SBruce Richardson } 118799a2dd95SBruce Richardson 118899a2dd95SBruce Richardson int 118999a2dd95SBruce Richardson rte_efd_delete(struct rte_efd_table * const table, const unsigned int socket_id, 119099a2dd95SBruce Richardson const void *key, efd_value_t * const prev_value) 119199a2dd95SBruce Richardson { 119299a2dd95SBruce Richardson unsigned int i; 119399a2dd95SBruce Richardson uint32_t chunk_id, bin_id; 119499a2dd95SBruce Richardson uint8_t not_found = 1; 119599a2dd95SBruce Richardson 119699a2dd95SBruce Richardson efd_compute_ids(table, key, &chunk_id, &bin_id); 119799a2dd95SBruce Richardson 119899a2dd95SBruce Richardson struct efd_offline_chunk_rules * const chunk = 119999a2dd95SBruce Richardson &table->offline_chunks[chunk_id]; 120099a2dd95SBruce Richardson 120199a2dd95SBruce Richardson uint8_t current_choice = efd_get_choice(table, socket_id, 120299a2dd95SBruce Richardson chunk_id, bin_id); 120399a2dd95SBruce Richardson uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id]; 120499a2dd95SBruce Richardson struct efd_offline_group_rules * const current_group = 120599a2dd95SBruce Richardson &chunk->group_rules[current_group_id]; 120699a2dd95SBruce Richardson 120799a2dd95SBruce Richardson /* 120899a2dd95SBruce Richardson * Search the current group for the specified key. 120999a2dd95SBruce Richardson * If it exists, remove it and re-pack the other values 121099a2dd95SBruce Richardson */ 121199a2dd95SBruce Richardson for (i = 0; i < current_group->num_rules; i++) { 121299a2dd95SBruce Richardson if (not_found) { 121399a2dd95SBruce Richardson /* Found key that needs to be removed */ 121499a2dd95SBruce Richardson if (memcmp(EFD_KEY(current_group->key_idx[i], table), 121599a2dd95SBruce Richardson key, table->key_len) == 0) { 121699a2dd95SBruce Richardson /* Store previous value if requested by caller */ 121799a2dd95SBruce Richardson if (prev_value != NULL) 121899a2dd95SBruce Richardson *prev_value = current_group->value[i]; 121999a2dd95SBruce Richardson 122099a2dd95SBruce Richardson not_found = 0; 122199a2dd95SBruce Richardson rte_ring_sp_enqueue(table->free_slots, 122299a2dd95SBruce Richardson (void *)((uintptr_t)current_group->key_idx[i])); 122399a2dd95SBruce Richardson } 122499a2dd95SBruce Richardson } else { 122599a2dd95SBruce Richardson /* 122699a2dd95SBruce Richardson * If the desired key has been found, 122799a2dd95SBruce Richardson * need to shift other values up one 122899a2dd95SBruce Richardson */ 122999a2dd95SBruce Richardson 123099a2dd95SBruce Richardson /* Need to shift this entry back up one index */ 123199a2dd95SBruce Richardson current_group->key_idx[i - 1] = current_group->key_idx[i]; 123299a2dd95SBruce Richardson current_group->value[i - 1] = current_group->value[i]; 123399a2dd95SBruce Richardson current_group->bin_id[i - 1] = current_group->bin_id[i]; 123499a2dd95SBruce Richardson } 123599a2dd95SBruce Richardson } 123699a2dd95SBruce Richardson 123799a2dd95SBruce Richardson if (not_found == 0) { 123899a2dd95SBruce Richardson table->num_rules--; 123999a2dd95SBruce Richardson current_group->num_rules--; 124099a2dd95SBruce Richardson } 124199a2dd95SBruce Richardson 124299a2dd95SBruce Richardson return not_found; 124399a2dd95SBruce Richardson } 124499a2dd95SBruce Richardson 124599a2dd95SBruce Richardson static inline efd_value_t 124699a2dd95SBruce Richardson efd_lookup_internal_scalar(const efd_hashfunc_t *group_hash_idx, 124799a2dd95SBruce Richardson const efd_lookuptbl_t *group_lookup_table, 124899a2dd95SBruce Richardson const uint32_t hash_val_a, const uint32_t hash_val_b) 124999a2dd95SBruce Richardson { 125099a2dd95SBruce Richardson efd_value_t value = 0; 125199a2dd95SBruce Richardson uint32_t i; 125299a2dd95SBruce Richardson 125399a2dd95SBruce Richardson for (i = 0; i < RTE_EFD_VALUE_NUM_BITS; i++) { 125499a2dd95SBruce Richardson value <<= 1; 125599a2dd95SBruce Richardson uint32_t h = hash_val_a + (hash_val_b * 125699a2dd95SBruce Richardson group_hash_idx[RTE_EFD_VALUE_NUM_BITS - i - 1]); 125799a2dd95SBruce Richardson uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT; 125899a2dd95SBruce Richardson value |= (group_lookup_table[ 125999a2dd95SBruce Richardson RTE_EFD_VALUE_NUM_BITS - i - 1] >> 126099a2dd95SBruce Richardson bucket_idx) & 0x1; 126199a2dd95SBruce Richardson } 126299a2dd95SBruce Richardson 126399a2dd95SBruce Richardson return value; 126499a2dd95SBruce Richardson } 126599a2dd95SBruce Richardson 126699a2dd95SBruce Richardson 126799a2dd95SBruce Richardson static inline efd_value_t 126899a2dd95SBruce Richardson efd_lookup_internal(const struct efd_online_group_entry * const group, 126999a2dd95SBruce Richardson const uint32_t hash_val_a, const uint32_t hash_val_b, 127099a2dd95SBruce Richardson enum efd_lookup_internal_function lookup_fn) 127199a2dd95SBruce Richardson { 127299a2dd95SBruce Richardson efd_value_t value = 0; 127399a2dd95SBruce Richardson 127499a2dd95SBruce Richardson switch (lookup_fn) { 127599a2dd95SBruce Richardson 127699a2dd95SBruce Richardson #if defined(RTE_ARCH_X86) && defined(CC_SUPPORT_AVX2) 127799a2dd95SBruce Richardson case EFD_LOOKUP_AVX2: 127899a2dd95SBruce Richardson return efd_lookup_internal_avx2(group->hash_idx, 127999a2dd95SBruce Richardson group->lookup_table, 128099a2dd95SBruce Richardson hash_val_a, 128199a2dd95SBruce Richardson hash_val_b); 128299a2dd95SBruce Richardson break; 128399a2dd95SBruce Richardson #endif 128499a2dd95SBruce Richardson #if defined(RTE_ARCH_ARM64) 128599a2dd95SBruce Richardson case EFD_LOOKUP_NEON: 128699a2dd95SBruce Richardson return efd_lookup_internal_neon(group->hash_idx, 128799a2dd95SBruce Richardson group->lookup_table, 128899a2dd95SBruce Richardson hash_val_a, 128999a2dd95SBruce Richardson hash_val_b); 129099a2dd95SBruce Richardson break; 129199a2dd95SBruce Richardson #endif 129299a2dd95SBruce Richardson case EFD_LOOKUP_SCALAR: 129399a2dd95SBruce Richardson /* Fall-through */ 129499a2dd95SBruce Richardson default: 129599a2dd95SBruce Richardson return efd_lookup_internal_scalar(group->hash_idx, 129699a2dd95SBruce Richardson group->lookup_table, 129799a2dd95SBruce Richardson hash_val_a, 129899a2dd95SBruce Richardson hash_val_b); 129999a2dd95SBruce Richardson } 130099a2dd95SBruce Richardson 130199a2dd95SBruce Richardson return value; 130299a2dd95SBruce Richardson } 130399a2dd95SBruce Richardson 130499a2dd95SBruce Richardson efd_value_t 130599a2dd95SBruce Richardson rte_efd_lookup(const struct rte_efd_table * const table, 130699a2dd95SBruce Richardson const unsigned int socket_id, const void *key) 130799a2dd95SBruce Richardson { 130899a2dd95SBruce Richardson uint32_t chunk_id, group_id, bin_id; 130999a2dd95SBruce Richardson uint8_t bin_choice; 131099a2dd95SBruce Richardson const struct efd_online_group_entry *group; 131199a2dd95SBruce Richardson const struct efd_online_chunk * const chunks = table->chunks[socket_id]; 131299a2dd95SBruce Richardson 131399a2dd95SBruce Richardson /* Determine the chunk and group location for the given key */ 131499a2dd95SBruce Richardson efd_compute_ids(table, key, &chunk_id, &bin_id); 131599a2dd95SBruce Richardson bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id); 131699a2dd95SBruce Richardson group_id = efd_bin_to_group[bin_choice][bin_id]; 131799a2dd95SBruce Richardson group = &chunks[chunk_id].groups[group_id]; 131899a2dd95SBruce Richardson 131999a2dd95SBruce Richardson return efd_lookup_internal(group, 132099a2dd95SBruce Richardson EFD_HASHFUNCA(key, table), 132199a2dd95SBruce Richardson EFD_HASHFUNCB(key, table), 132299a2dd95SBruce Richardson table->lookup_fn); 132399a2dd95SBruce Richardson } 132499a2dd95SBruce Richardson 132599a2dd95SBruce Richardson void rte_efd_lookup_bulk(const struct rte_efd_table * const table, 132699a2dd95SBruce Richardson const unsigned int socket_id, const int num_keys, 132799a2dd95SBruce Richardson const void **key_list, efd_value_t * const value_list) 132899a2dd95SBruce Richardson { 132999a2dd95SBruce Richardson int i; 133099a2dd95SBruce Richardson uint32_t chunk_id_list[RTE_EFD_BURST_MAX]; 133199a2dd95SBruce Richardson uint32_t bin_id_list[RTE_EFD_BURST_MAX]; 133299a2dd95SBruce Richardson uint8_t bin_choice_list[RTE_EFD_BURST_MAX]; 133399a2dd95SBruce Richardson uint32_t group_id_list[RTE_EFD_BURST_MAX]; 133499a2dd95SBruce Richardson struct efd_online_group_entry *group; 133599a2dd95SBruce Richardson 133699a2dd95SBruce Richardson struct efd_online_chunk *chunks = table->chunks[socket_id]; 133799a2dd95SBruce Richardson 133899a2dd95SBruce Richardson for (i = 0; i < num_keys; i++) { 133999a2dd95SBruce Richardson efd_compute_ids(table, key_list[i], &chunk_id_list[i], 134099a2dd95SBruce Richardson &bin_id_list[i]); 134199a2dd95SBruce Richardson rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list); 134299a2dd95SBruce Richardson } 134399a2dd95SBruce Richardson 134499a2dd95SBruce Richardson for (i = 0; i < num_keys; i++) { 134599a2dd95SBruce Richardson bin_choice_list[i] = efd_get_choice(table, socket_id, 134699a2dd95SBruce Richardson chunk_id_list[i], bin_id_list[i]); 134799a2dd95SBruce Richardson group_id_list[i] = 134899a2dd95SBruce Richardson efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]]; 134999a2dd95SBruce Richardson group = &chunks[chunk_id_list[i]].groups[group_id_list[i]]; 135099a2dd95SBruce Richardson rte_prefetch0(group); 135199a2dd95SBruce Richardson } 135299a2dd95SBruce Richardson 135399a2dd95SBruce Richardson for (i = 0; i < num_keys; i++) { 135499a2dd95SBruce Richardson group = &chunks[chunk_id_list[i]].groups[group_id_list[i]]; 135599a2dd95SBruce Richardson value_list[i] = efd_lookup_internal(group, 135699a2dd95SBruce Richardson EFD_HASHFUNCA(key_list[i], table), 135799a2dd95SBruce Richardson EFD_HASHFUNCB(key_list[i], table), 135899a2dd95SBruce Richardson table->lookup_fn); 135999a2dd95SBruce Richardson } 136099a2dd95SBruce Richardson } 1361