Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2010-2014 Intel Corporation 3 : : */ 4 : : 5 : : #ifndef _RTE_FBK_HASH_H_ 6 : : #define _RTE_FBK_HASH_H_ 7 : : 8 : : /** 9 : : * @file 10 : : * 11 : : * This is a hash table implementation for four byte keys (fbk). 12 : : * 13 : : * Note that the return value of the add function should always be checked as, 14 : : * if a bucket is full, the key is not added even if there is space in other 15 : : * buckets. This keeps the lookup function very simple and therefore fast. 16 : : */ 17 : : 18 : : #include <stdint.h> 19 : : #include <errno.h> 20 : : 21 : : #include <string.h> 22 : : 23 : : #include <rte_common.h> 24 : : #include <rte_hash_crc.h> 25 : : #include <rte_jhash.h> 26 : : 27 : : #ifdef __cplusplus 28 : : extern "C" { 29 : : #endif 30 : : 31 : : #ifndef RTE_FBK_HASH_INIT_VAL_DEFAULT 32 : : /** Initialising value used when calculating hash. */ 33 : : #define RTE_FBK_HASH_INIT_VAL_DEFAULT 0xFFFFFFFF 34 : : #endif 35 : : 36 : : /** The maximum number of entries in the hash table that is supported. */ 37 : : #define RTE_FBK_HASH_ENTRIES_MAX (1 << 20) 38 : : 39 : : /** The maximum number of entries in each bucket that is supported. */ 40 : : #define RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX 256 41 : : 42 : : /** Maximum size of string for naming the hash. */ 43 : : #define RTE_FBK_HASH_NAMESIZE 32 44 : : 45 : : /** Type of function that can be used for calculating the hash value. */ 46 : : typedef uint32_t (*rte_fbk_hash_fn)(uint32_t key, uint32_t init_val); 47 : : 48 : : /** Parameters used when creating four-byte key hash table. */ 49 : : struct rte_fbk_hash_params { 50 : : const char *name; /**< Name of the hash table. */ 51 : : uint32_t entries; /**< Total number of entries. */ 52 : : uint32_t entries_per_bucket; /**< Number of entries in a bucket. */ 53 : : int socket_id; /**< Socket to allocate memory on. */ 54 : : rte_fbk_hash_fn hash_func; /**< The hash function. */ 55 : : uint32_t init_val; /**< For initialising hash function. */ 56 : : }; 57 : : 58 : : /** Individual entry in the four-byte key hash table. */ 59 : : union rte_fbk_hash_entry { 60 : : uint64_t whole_entry; /**< For accessing entire entry. */ 61 : : struct { 62 : : uint16_t is_entry; /**< Non-zero if entry is active. */ 63 : : uint16_t value; /**< Value returned by lookup. */ 64 : : uint32_t key; /**< Key used to find value. */ 65 : : } entry; /**< For accessing each entry part. */ 66 : : }; 67 : : 68 : : 69 : : /** The four-byte key hash table structure. */ 70 : : struct rte_fbk_hash_table { 71 : : char name[RTE_FBK_HASH_NAMESIZE]; /**< Name of the hash. */ 72 : : uint32_t entries; /**< Total number of entries. */ 73 : : uint32_t entries_per_bucket; /**< Number of entries in a bucket. */ 74 : : uint32_t used_entries; /**< How many entries are used. */ 75 : : uint32_t bucket_mask; /**< To find which bucket the key is in. */ 76 : : uint32_t bucket_shift; /**< Convert bucket to table offset. */ 77 : : rte_fbk_hash_fn hash_func; /**< The hash function. */ 78 : : uint32_t init_val; /**< For initialising hash function. */ 79 : : 80 : : /** A flat table of all buckets. */ 81 : : union rte_fbk_hash_entry t[]; 82 : : }; 83 : : 84 : : /** 85 : : * Find the offset into hash table of the bucket containing a particular key. 86 : : * 87 : : * @param ht 88 : : * Pointer to hash table. 89 : : * @param key 90 : : * Key to calculate bucket for. 91 : : * @return 92 : : * Offset into hash table. 93 : : */ 94 : : static inline uint32_t 95 : : rte_fbk_hash_get_bucket(const struct rte_fbk_hash_table *ht, uint32_t key) 96 : : { 97 : 2097250 : return (ht->hash_func(key, ht->init_val) & ht->bucket_mask) << 98 : 26 : ht->bucket_shift; 99 : : } 100 : : 101 : : /** 102 : : * Add a key to an existing hash table with bucket id. 103 : : * This operation is not multi-thread safe 104 : : * and should only be called from one thread. 105 : : * 106 : : * @param ht 107 : : * Hash table to add the key to. 108 : : * @param key 109 : : * Key to add to the hash table. 110 : : * @param value 111 : : * Value to associate with key. 112 : : * @param bucket 113 : : * Bucket to associate with key. 114 : : * @return 115 : : * 0 if ok, or negative value on error. 116 : : */ 117 : : static inline int 118 : 1048592 : rte_fbk_hash_add_key_with_bucket(struct rte_fbk_hash_table *ht, 119 : : uint32_t key, uint16_t value, uint32_t bucket) 120 : : { 121 : : /* 122 : : * The writing of a new value to the hash table is done as a single 123 : : * 64bit operation. This should help prevent individual entries being 124 : : * corrupted due to race conditions, but it's still possible to 125 : : * overwrite entries that have just been made valid. 126 : : */ 127 : 1048592 : const uint64_t new_entry = ((uint64_t)(key) << 32) | 128 : 1048592 : ((uint64_t)(value) << 16) | 129 : : 1; /* 1 = is_entry bit. */ 130 : : uint32_t i; 131 : : 132 [ + + ]: 5160980 : for (i = 0; i < ht->entries_per_bucket; i++) { 133 : : /* Set entry if unused. */ 134 [ + + ]: 4145171 : if (! ht->t[bucket + i].entry.is_entry) { 135 : 32778 : ht->t[bucket + i].whole_entry = new_entry; 136 : 32778 : ht->used_entries++; 137 : 32778 : return 0; 138 : : } 139 : : /* Change value if key already exists. */ 140 [ + + ]: 4112393 : if (ht->t[bucket + i].entry.key == key) { 141 : 5 : ht->t[bucket + i].entry.value = value; 142 : 5 : return 0; 143 : : } 144 : : } 145 : : 146 : : return -ENOSPC; /* No space in bucket. */ 147 : : } 148 : : 149 : : /** 150 : : * Add a key to an existing hash table. This operation is not multi-thread safe 151 : : * and should only be called from one thread. 152 : : * 153 : : * @param ht 154 : : * Hash table to add the key to. 155 : : * @param key 156 : : * Key to add to the hash table. 157 : : * @param value 158 : : * Value to associate with key. 159 : : * @return 160 : : * 0 if ok, or negative value on error. 161 : : */ 162 : : static inline int 163 : 1048592 : rte_fbk_hash_add_key(struct rte_fbk_hash_table *ht, 164 : : uint32_t key, uint16_t value) 165 : : { 166 : 1048592 : return rte_fbk_hash_add_key_with_bucket(ht, 167 : : key, value, rte_fbk_hash_get_bucket(ht, key)); 168 : : } 169 : : 170 : : /** 171 : : * Remove a key with a given bucket id from an existing hash table. 172 : : * This operation is not multi-thread 173 : : * safe and should only be called from one thread. 174 : : * 175 : : * @param ht 176 : : * Hash table to remove the key from. 177 : : * @param key 178 : : * Key to remove from the hash table. 179 : : * @param bucket 180 : : * Bucket id associate with key. 181 : : * @return 182 : : * 0 if ok, or negative value on error. 183 : : */ 184 : : static inline int 185 : 7 : rte_fbk_hash_delete_key_with_bucket(struct rte_fbk_hash_table *ht, 186 : : uint32_t key, uint32_t bucket) 187 : : { 188 : 7 : uint32_t last_entry = ht->entries_per_bucket - 1; 189 : : uint32_t i, j; 190 : : 191 [ + + ]: 11 : for (i = 0; i < ht->entries_per_bucket; i++) { 192 [ + + ]: 10 : if (ht->t[bucket + i].entry.key == key) { 193 : : /* Find last key in bucket. */ 194 [ + + ]: 24 : for (j = ht->entries_per_bucket - 1; j > i; j-- ) { 195 [ + + ]: 18 : if (! ht->t[bucket + j].entry.is_entry) { 196 : 15 : last_entry = j - 1; 197 : : } 198 : : } 199 : : /* 200 : : * Move the last key to the deleted key's position, and 201 : : * delete the last key. lastEntry and i may be same but 202 : : * it doesn't matter. 203 : : */ 204 : 6 : ht->t[bucket + i].whole_entry = 205 : 6 : ht->t[bucket + last_entry].whole_entry; 206 : 6 : ht->t[bucket + last_entry].whole_entry = 0; 207 : : 208 : 6 : ht->used_entries--; 209 : 6 : return 0; 210 : : } 211 : : } 212 : : 213 : : return -ENOENT; /* Key didn't exist. */ 214 : : } 215 : : 216 : : /** 217 : : * Remove a key from an existing hash table. This operation is not multi-thread 218 : : * safe and should only be called from one thread. 219 : : * 220 : : * @param ht 221 : : * Hash table to remove the key from. 222 : : * @param key 223 : : * Key to remove from the hash table. 224 : : * @return 225 : : * 0 if ok, or negative value on error. 226 : : */ 227 : : static inline int 228 : 7 : rte_fbk_hash_delete_key(struct rte_fbk_hash_table *ht, uint32_t key) 229 : : { 230 : 7 : return rte_fbk_hash_delete_key_with_bucket(ht, 231 : : key, rte_fbk_hash_get_bucket(ht, key)); 232 : : } 233 : : 234 : : /** 235 : : * Find a key in the hash table with a given bucketid. 236 : : * This operation is multi-thread safe. 237 : : * 238 : : * @param ht 239 : : * Hash table to look in. 240 : : * @param key 241 : : * Key to find. 242 : : * @param bucket 243 : : * Bucket associate to the key. 244 : : * @return 245 : : * The value that was associated with the key, or negative value on error. 246 : : */ 247 : : static inline int 248 : : rte_fbk_hash_lookup_with_bucket(const struct rte_fbk_hash_table *ht, 249 : : uint32_t key, uint32_t bucket) 250 : : { 251 : : union rte_fbk_hash_entry current_entry; 252 : : uint32_t i; 253 : : 254 [ + + ]: 30 : for (i = 0; i < ht->entries_per_bucket; i++) { 255 : : /* Single read of entry, which should be atomic. */ 256 : 29 : current_entry.whole_entry = ht->t[bucket + i].whole_entry; 257 [ + + ]: 29 : if (! current_entry.entry.is_entry) { 258 : : return -ENOENT; /* Error once we hit an empty field. */ 259 : : } 260 [ + + ]: 19 : if (current_entry.entry.key == key) { 261 : 15 : return current_entry.entry.value; 262 : : } 263 : : } 264 : : return -ENOENT; /* Key didn't exist. */ 265 : : } 266 : : 267 : : /** 268 : : * Find a key in the hash table. This operation is multi-thread safe. 269 : : * 270 : : * @param ht 271 : : * Hash table to look in. 272 : : * @param key 273 : : * Key to find. 274 : : * @return 275 : : * The value that was associated with the key, or negative value on error. 276 : : */ 277 : : static inline int 278 : 26 : rte_fbk_hash_lookup(const struct rte_fbk_hash_table *ht, uint32_t key) 279 : : { 280 : 26 : return rte_fbk_hash_lookup_with_bucket(ht, 281 : : key, rte_fbk_hash_get_bucket(ht, key)); 282 : : } 283 : : 284 : : /** 285 : : * Delete all entries in a hash table. This operation is not multi-thread 286 : : * safe and should only be called from one thread. 287 : : * 288 : : * @param ht 289 : : * Hash table to delete entries in. 290 : : */ 291 : : static inline void 292 : : rte_fbk_hash_clear_all(struct rte_fbk_hash_table *ht) 293 : : { 294 : 2 : memset(ht->t, 0, sizeof(ht->t[0]) * ht->entries); 295 : 2 : ht->used_entries = 0; 296 : : } 297 : : 298 : : /** 299 : : * Find what fraction of entries are being used. 300 : : * 301 : : * @param ht 302 : : * Hash table to find how many entries are being used in. 303 : : * @return 304 : : * Load factor of the hash table, or negative value on error. 305 : : */ 306 : : static inline double 307 : : rte_fbk_hash_get_load_factor(struct rte_fbk_hash_table *ht) 308 : : { 309 [ - + - + : 3 : return (double)ht->used_entries / (double)ht->entries; - + ] 310 : : } 311 : : 312 : : /** 313 : : * Performs a lookup for an existing hash table, and returns a pointer to 314 : : * the table if found. 315 : : * 316 : : * @param name 317 : : * Name of the hash table to find 318 : : * 319 : : * @return 320 : : * pointer to hash table structure or NULL on error with rte_errno 321 : : * set appropriately. Possible rte_errno values include: 322 : : * - ENOENT - required entry not available to return. 323 : : */ 324 : : struct rte_fbk_hash_table *rte_fbk_hash_find_existing(const char *name); 325 : : 326 : : /** 327 : : * Free all memory used by a hash table. 328 : : * Has no effect on hash tables allocated in memory zones 329 : : * 330 : : * @param ht 331 : : * Hash table to deallocate. 332 : : */ 333 : : void rte_fbk_hash_free(struct rte_fbk_hash_table *ht); 334 : : 335 : : /** 336 : : * Create a new hash table for use with four byte keys. 337 : : * 338 : : * @param params 339 : : * Parameters used in creation of hash table. 340 : : * 341 : : * @return 342 : : * Pointer to hash table structure that is used in future hash table 343 : : * operations, or NULL on error with rte_errno set appropriately. 344 : : * Possible rte_errno error values include: 345 : : * - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure 346 : : * - E_RTE_SECONDARY - function was called from a secondary process instance 347 : : * - EINVAL - invalid parameter value passed to function 348 : : * - ENOSPC - the maximum number of memzones has already been allocated 349 : : * - EEXIST - a memzone with the same name already exists 350 : : * - ENOMEM - no appropriate memory area found in which to create memzone 351 : : */ 352 : : struct rte_fbk_hash_table * 353 : : rte_fbk_hash_create(const struct rte_fbk_hash_params *params) 354 : : __rte_malloc __rte_dealloc(rte_fbk_hash_free, 1); 355 : : 356 : : #ifdef __cplusplus 357 : : } 358 : : #endif 359 : : 360 : : #endif /* _RTE_FBK_HASH_H_ */