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