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