blob: 4ff7e1bfb6c91f08245a4073777097eb1822b8be [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 Copyright (c) 2014 Cisco and/or its affiliates.
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15*/
16
Chris Luke16bcf7d2016-09-01 14:31:46 -040017/** @cond DOCUMENTATION_IS_IN_BIHASH_DOC_H */
Dave Barachdd3a57f2016-07-27 16:58:51 -040018
Dave Barachc3799992016-08-15 11:12:27 -040019/*
Ed Warnickecb9cada2015-12-08 15:45:58 -070020 * Note: to instantiate the template multiple times in a single file,
21 * #undef __included_bihash_template_h__...
22 */
23#ifndef __included_bihash_template_h__
24#define __included_bihash_template_h__
25
26#include <vppinfra/heap.h>
27#include <vppinfra/format.h>
28#include <vppinfra/pool.h>
Dave Barach30765e72018-02-23 07:45:36 -050029#include <vppinfra/cache.h>
Damjan Marion2a03efe2018-07-20 21:48:59 +020030#include <vppinfra/lock.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070031
32#ifndef BIHASH_TYPE
33#error BIHASH_TYPE not defined
34#endif
35
36#define _bv(a,b) a##b
37#define __bv(a,b) _bv(a,b)
38#define BV(a) __bv(a,BIHASH_TYPE)
39
40#define _bvt(a,b) a##b##_t
41#define __bvt(a,b) _bvt(a,b)
42#define BVT(a) __bvt(a,BIHASH_TYPE)
43
Dave Barachc3799992016-08-15 11:12:27 -040044typedef struct BV (clib_bihash_value)
45{
46 union
47 {
48 BVT (clib_bihash_kv) kvp[BIHASH_KVP_PER_PAGE];
49 struct BV (clib_bihash_value) * next_free;
Ed Warnickecb9cada2015-12-08 15:45:58 -070050 };
Dave Barachc3799992016-08-15 11:12:27 -040051} BVT (clib_bihash_value);
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Dave Barach508498f2018-07-19 12:11:16 -040053#define BIHASH_BUCKET_OFFSET_BITS 36
Dave Barach908a5ea2017-07-14 12:42:21 -040054
Dave Barachc3799992016-08-15 11:12:27 -040055typedef struct
56{
57 union
58 {
59 struct
60 {
Dave Barach508498f2018-07-19 12:11:16 -040061 u64 offset:BIHASH_BUCKET_OFFSET_BITS;
62 u64 lock:1;
Damjan Marion882fcfe2018-07-17 23:01:49 +020063 u64 linear_search:1;
64 u64 log2_pages:8;
65 i64 refcnt:16;
Ed Warnickecb9cada2015-12-08 15:45:58 -070066 };
67 u64 as_u64;
68 };
Dave Barach908a5ea2017-07-14 12:42:21 -040069} BVT (clib_bihash_bucket);
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Damjan Marion882fcfe2018-07-17 23:01:49 +020071STATIC_ASSERT_SIZEOF (BVT (clib_bihash_bucket), sizeof (u64));
Damjan Marion882fcfe2018-07-17 23:01:49 +020072
Dave Barachc3799992016-08-15 11:12:27 -040073typedef struct
74{
75 BVT (clib_bihash_value) * values;
Dave Barach908a5ea2017-07-14 12:42:21 -040076 BVT (clib_bihash_bucket) * buckets;
Dave Barach508498f2018-07-19 12:11:16 -040077 volatile u32 *alloc_lock;
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
Dave Barachc3799992016-08-15 11:12:27 -040079 BVT (clib_bihash_value) ** working_copies;
Dave Barachba7ddfe2017-05-17 20:20:50 -040080 int *working_copy_lengths;
Dave Barach908a5ea2017-07-14 12:42:21 -040081 BVT (clib_bihash_bucket) saved_bucket;
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
83 u32 nbuckets;
84 u32 log2_nbuckets;
Dave Barachc3799992016-08-15 11:12:27 -040085 u8 *name;
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Dave Barachc3799992016-08-15 11:12:27 -040087 BVT (clib_bihash_value) ** freelists;
Dave Barach97f5af02018-02-22 09:48:45 -050088
89 /*
Dave Barach30765e72018-02-23 07:45:36 -050090 * Backing store allocation. Since bihash manages its own
Dave Barach97f5af02018-02-22 09:48:45 -050091 * freelists, we simple dole out memory at alloc_arena_next.
92 */
93 uword alloc_arena;
94 uword alloc_arena_next;
95 uword alloc_arena_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -080097 /**
98 * A custom format function to print the Key and Value of bihash_key instead of default hexdump
99 */
100 format_function_t *fmt_fn;
101
Dave Barachc3799992016-08-15 11:12:27 -0400102} BVT (clib_bihash);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
Dave Barach508498f2018-07-19 12:11:16 -0400104static inline void BV (clib_bihash_alloc_lock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400105{
Dave Barach508498f2018-07-19 12:11:16 -0400106 while (__atomic_test_and_set (h->alloc_lock, __ATOMIC_ACQUIRE))
Damjan Marion2a03efe2018-07-20 21:48:59 +0200107 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400108}
109
Dave Barach508498f2018-07-19 12:11:16 -0400110static inline void BV (clib_bihash_alloc_unlock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400111{
Dave Barach508498f2018-07-19 12:11:16 -0400112 __atomic_clear (h->alloc_lock, __ATOMIC_RELEASE);
Dave Barach908a5ea2017-07-14 12:42:21 -0400113}
114
Dave Barach508498f2018-07-19 12:11:16 -0400115static inline void BV (clib_bihash_lock_bucket) (BVT (clib_bihash_bucket) * b)
Dave Barach908a5ea2017-07-14 12:42:21 -0400116{
Dave Barach508498f2018-07-19 12:11:16 -0400117 BVT (clib_bihash_bucket) unlocked_bucket, locked_bucket;
Dave Barach908a5ea2017-07-14 12:42:21 -0400118
Dave Barach508498f2018-07-19 12:11:16 -0400119 do
120 {
121 locked_bucket.as_u64 = unlocked_bucket.as_u64 = b->as_u64;
122 unlocked_bucket.lock = 0;
123 locked_bucket.lock = 1;
Damjan Marion2a03efe2018-07-20 21:48:59 +0200124 CLIB_PAUSE ();
Dave Barach508498f2018-07-19 12:11:16 -0400125 }
126 while (__atomic_compare_exchange_n (&b->as_u64, &unlocked_bucket.as_u64,
127 locked_bucket.as_u64, 1 /* weak */ ,
128 __ATOMIC_ACQUIRE,
129 __ATOMIC_ACQUIRE) == 0);
Dave Barach858c06f2017-07-21 10:44:27 -0400130}
131
132static inline void BV (clib_bihash_unlock_bucket)
133 (BVT (clib_bihash_bucket) * b)
134{
Dave Barach508498f2018-07-19 12:11:16 -0400135 CLIB_MEMORY_BARRIER ();
136 b->lock = 0;
Dave Barach908a5ea2017-07-14 12:42:21 -0400137}
138
139static inline void *BV (clib_bihash_get_value) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400140 uword offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141{
Dave Barach97f5af02018-02-22 09:48:45 -0500142 u8 *hp = (u8 *) h->alloc_arena;
Dave Barachc3799992016-08-15 11:12:27 -0400143 u8 *vp = hp + offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
145 return (void *) vp;
146}
147
Damjan Marion882fcfe2018-07-17 23:01:49 +0200148static inline int BV (clib_bihash_bucket_is_empty)
149 (BVT (clib_bihash_bucket) * b)
150{
Dave Barach508498f2018-07-19 12:11:16 -0400151 /* Note: applied to locked buckets, test offset */
152 return b->offset == 0;
Damjan Marion882fcfe2018-07-17 23:01:49 +0200153}
154
Dave Barach908a5ea2017-07-14 12:42:21 -0400155static inline uword BV (clib_bihash_get_offset) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400156 void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157{
Dave Barachc3799992016-08-15 11:12:27 -0400158 u8 *hp, *vp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159
Dave Barach97f5af02018-02-22 09:48:45 -0500160 hp = (u8 *) h->alloc_arena;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161 vp = (u8 *) v;
162
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 return vp - hp;
164}
165
Dave Barachc3799992016-08-15 11:12:27 -0400166void BV (clib_bihash_init)
167 (BVT (clib_bihash) * h, char *name, u32 nbuckets, uword memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -0800169void BV (clib_bihash_set_kvp_format_fn) (BVT (clib_bihash) * h,
170 format_function_t * fmt_fn);
171
Dave Barachc3799992016-08-15 11:12:27 -0400172void BV (clib_bihash_free) (BVT (clib_bihash) * h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173
Dave Barachc3799992016-08-15 11:12:27 -0400174int BV (clib_bihash_add_del) (BVT (clib_bihash) * h,
175 BVT (clib_bihash_kv) * add_v, int is_add);
Matus Fabian828d27e2018-08-21 03:15:50 -0700176int BV (clib_bihash_add_or_overwrite_stale) (BVT (clib_bihash) * h,
177 BVT (clib_bihash_kv) * add_v,
178 int (*is_stale_cb) (BVT
179 (clib_bihash_kv)
180 *, void *),
181 void *arg);
Dave Barach908a5ea2017-07-14 12:42:21 -0400182int BV (clib_bihash_search) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400183 BVT (clib_bihash_kv) * search_v,
184 BVT (clib_bihash_kv) * return_v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185
Dave Barachc3799992016-08-15 11:12:27 -0400186void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h,
187 void *callback, void *arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
Dave Barachc3799992016-08-15 11:12:27 -0400189format_function_t BV (format_bihash);
190format_function_t BV (format_bihash_kvp);
Dave Barach908a5ea2017-07-14 12:42:21 -0400191format_function_t BV (format_bihash_lru);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192
Dave Barach30765e72018-02-23 07:45:36 -0500193static inline int BV (clib_bihash_search_inline_with_hash)
194 (BVT (clib_bihash) * h, u64 hash, BVT (clib_bihash_kv) * key_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400197 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400198 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500199 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
Dave Barachc3799992016-08-15 11:12:27 -0400201 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 b = &h->buckets[bucket_index];
203
Damjan Marion882fcfe2018-07-17 23:01:49 +0200204 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 return -1;
206
Dave Barach508498f2018-07-19 12:11:16 -0400207 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400208 {
Dave Barach508498f2018-07-19 12:11:16 -0400209 volatile BVT (clib_bihash_bucket) * bv = b;
210 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200211 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400212 }
213
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 hash >>= h->log2_nbuckets;
215
Dave Barachc3799992016-08-15 11:12:27 -0400216 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400217
Dave Barach5e6b9582016-12-12 15:37:29 -0500218 /* If the bucket has unresolvable collisions, use linear search */
219 limit = BIHASH_KVP_PER_PAGE;
220 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
221 if (PREDICT_FALSE (b->linear_search))
222 limit <<= b->log2_pages;
223
224 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400226 if (BV (clib_bihash_key_compare) (v->kvp[i].key, key_result->key))
Dave Barachc3799992016-08-15 11:12:27 -0400227 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400228 *key_result = v->kvp[i];
Dave Barachc3799992016-08-15 11:12:27 -0400229 return 0;
230 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231 }
232 return -1;
233}
234
Dave Barach30765e72018-02-23 07:45:36 -0500235static inline int BV (clib_bihash_search_inline)
236 (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * key_result)
237{
238 u64 hash;
239
240 hash = BV (clib_bihash_hash) (key_result);
241
242 return BV (clib_bihash_search_inline_with_hash) (h, hash, key_result);
243}
244
245static inline void BV (clib_bihash_prefetch_bucket)
246 (BVT (clib_bihash) * h, u64 hash)
247{
248 u32 bucket_index;
249 BVT (clib_bihash_bucket) * b;
250
251 bucket_index = hash & (h->nbuckets - 1);
252 b = &h->buckets[bucket_index];
253
254 CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, READ);
255}
256
257static inline void BV (clib_bihash_prefetch_data)
258 (BVT (clib_bihash) * h, u64 hash)
259{
260 u32 bucket_index;
261 BVT (clib_bihash_value) * v;
262 BVT (clib_bihash_bucket) * b;
263
264 bucket_index = hash & (h->nbuckets - 1);
265 b = &h->buckets[bucket_index];
266
Damjan Marion882fcfe2018-07-17 23:01:49 +0200267 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Dave Barach30765e72018-02-23 07:45:36 -0500268 return;
269
270 hash >>= h->log2_nbuckets;
271 v = BV (clib_bihash_get_value) (h, b->offset);
272
273 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
274
275 CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, READ);
276}
277
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200278static inline int BV (clib_bihash_search_inline_2_with_hash)
Dave Barach908a5ea2017-07-14 12:42:21 -0400279 (BVT (clib_bihash) * h,
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200280 u64 hash, BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400283 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400284 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500285 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
Dave Barachc3799992016-08-15 11:12:27 -0400287 ASSERT (valuep);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288
Dave Barachc3799992016-08-15 11:12:27 -0400289 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 b = &h->buckets[bucket_index];
291
Damjan Marion882fcfe2018-07-17 23:01:49 +0200292 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 return -1;
294
Dave Barach508498f2018-07-19 12:11:16 -0400295 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400296 {
Dave Barach508498f2018-07-19 12:11:16 -0400297 volatile BVT (clib_bihash_bucket) * bv = b;
298 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200299 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400300 }
301
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302 hash >>= h->log2_nbuckets;
Dave Barachc3799992016-08-15 11:12:27 -0400303 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400304
Dave Barach5e6b9582016-12-12 15:37:29 -0500305 /* If the bucket has unresolvable collisions, use linear search */
306 limit = BIHASH_KVP_PER_PAGE;
307 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
308 if (PREDICT_FALSE (b->linear_search))
309 limit <<= b->log2_pages;
310
311 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312 {
Dave Barachc3799992016-08-15 11:12:27 -0400313 if (BV (clib_bihash_key_compare) (v->kvp[i].key, search_key->key))
314 {
315 *valuep = v->kvp[i];
316 return 0;
317 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 }
319 return -1;
320}
321
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200322static inline int BV (clib_bihash_search_inline_2)
323 (BVT (clib_bihash) * h,
324 BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
325{
326 u64 hash;
327
328 hash = BV (clib_bihash_hash) (search_key);
329
330 return BV (clib_bihash_search_inline_2_with_hash) (h, hash, search_key,
331 valuep);
332}
333
334
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335#endif /* __included_bihash_template_h__ */
Dave Barachdd3a57f2016-07-27 16:58:51 -0400336
Chris Luke16bcf7d2016-09-01 14:31:46 -0400337/** @endcond */
Dave Barachc3799992016-08-15 11:12:27 -0400338
339/*
340 * fd.io coding-style-patch-verification: ON
341 *
342 * Local Variables:
343 * eval: (c-set-style "gnu")
344 * End:
345 */