ethdev: bring in async queue-based flow rules operations
[dpdk.git] / lib / 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
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24
25 #include <string.h>
26
27 #include <rte_hash_crc.h>
28 #include <rte_jhash.h>
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         return (ht->hash_func(key, ht->init_val) & ht->bucket_mask) <<
97                         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 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         const uint64_t new_entry = ((uint64_t)(key) << 32) |
127                         ((uint64_t)(value) << 16) |
128                         1;  /* 1 = is_entry bit. */
129         uint32_t i;
130
131         for (i = 0; i < ht->entries_per_bucket; i++) {
132                 /* Set entry if unused. */
133                 if (! ht->t[bucket + i].entry.is_entry) {
134                         ht->t[bucket + i].whole_entry = new_entry;
135                         ht->used_entries++;
136                         return 0;
137                 }
138                 /* Change value if key already exists. */
139                 if (ht->t[bucket + i].entry.key == key) {
140                         ht->t[bucket + i].entry.value = value;
141                         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 rte_fbk_hash_add_key(struct rte_fbk_hash_table *ht,
163                         uint32_t key, uint16_t value)
164 {
165         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 rte_fbk_hash_delete_key_with_bucket(struct rte_fbk_hash_table *ht,
185                                         uint32_t key, uint32_t bucket)
186 {
187         uint32_t last_entry = ht->entries_per_bucket - 1;
188         uint32_t i, j;
189
190         for (i = 0; i < ht->entries_per_bucket; i++) {
191                 if (ht->t[bucket + i].entry.key == key) {
192                         /* Find last key in bucket. */
193                         for (j = ht->entries_per_bucket - 1; j > i; j-- ) {
194                                 if (! ht->t[bucket + j].entry.is_entry) {
195                                         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                         ht->t[bucket + i].whole_entry =
204                                         ht->t[bucket + last_entry].whole_entry;
205                         ht->t[bucket + last_entry].whole_entry = 0;
206
207                         ht->used_entries--;
208                         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 rte_fbk_hash_delete_key(struct rte_fbk_hash_table *ht, uint32_t key)
228 {
229         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         for (i = 0; i < ht->entries_per_bucket; i++) {
254                 /* Single read of entry, which should be atomic. */
255                 current_entry.whole_entry = ht->t[bucket + i].whole_entry;
256                 if (! current_entry.entry.is_entry) {
257                         return -ENOENT; /* Error once we hit an empty field. */
258                 }
259                 if (current_entry.entry.key == key) {
260                         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 rte_fbk_hash_lookup(const struct rte_fbk_hash_table *ht, uint32_t key)
278 {
279         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         memset(ht->t, 0, sizeof(ht->t[0]) * ht->entries);
294         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         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_ */