blob: 9bf4737cd84db4a826700b54e7db4f12c71c26f9 [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 Barach908a5ea2017-07-14 12:42:21 -040087 u64 cache_hits;
88 u64 cache_misses;
89
Dave Barachc3799992016-08-15 11:12:27 -040090 BVT (clib_bihash_value) ** freelists;
Dave Barach97f5af02018-02-22 09:48:45 -050091
92 /*
Dave Barach30765e72018-02-23 07:45:36 -050093 * Backing store allocation. Since bihash manages its own
Dave Barach97f5af02018-02-22 09:48:45 -050094 * freelists, we simple dole out memory at alloc_arena_next.
95 */
96 uword alloc_arena;
97 uword alloc_arena_next;
98 uword alloc_arena_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -0800100 /**
101 * A custom format function to print the Key and Value of bihash_key instead of default hexdump
102 */
103 format_function_t *fmt_fn;
104
Dave Barachc3799992016-08-15 11:12:27 -0400105} BVT (clib_bihash);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
Dave Barach508498f2018-07-19 12:11:16 -0400107static inline void BV (clib_bihash_alloc_lock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400108{
Dave Barach508498f2018-07-19 12:11:16 -0400109 while (__atomic_test_and_set (h->alloc_lock, __ATOMIC_ACQUIRE))
Damjan Marion2a03efe2018-07-20 21:48:59 +0200110 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400111}
112
Dave Barach508498f2018-07-19 12:11:16 -0400113static inline void BV (clib_bihash_alloc_unlock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400114{
Dave Barach508498f2018-07-19 12:11:16 -0400115 __atomic_clear (h->alloc_lock, __ATOMIC_RELEASE);
Dave Barach908a5ea2017-07-14 12:42:21 -0400116}
117
Dave Barach508498f2018-07-19 12:11:16 -0400118static inline void BV (clib_bihash_lock_bucket) (BVT (clib_bihash_bucket) * b)
Dave Barach908a5ea2017-07-14 12:42:21 -0400119{
Dave Barach508498f2018-07-19 12:11:16 -0400120 BVT (clib_bihash_bucket) unlocked_bucket, locked_bucket;
Dave Barach908a5ea2017-07-14 12:42:21 -0400121
Dave Barach508498f2018-07-19 12:11:16 -0400122 do
123 {
124 locked_bucket.as_u64 = unlocked_bucket.as_u64 = b->as_u64;
125 unlocked_bucket.lock = 0;
126 locked_bucket.lock = 1;
Damjan Marion2a03efe2018-07-20 21:48:59 +0200127 CLIB_PAUSE ();
Dave Barach508498f2018-07-19 12:11:16 -0400128 }
129 while (__atomic_compare_exchange_n (&b->as_u64, &unlocked_bucket.as_u64,
130 locked_bucket.as_u64, 1 /* weak */ ,
131 __ATOMIC_ACQUIRE,
132 __ATOMIC_ACQUIRE) == 0);
Dave Barach858c06f2017-07-21 10:44:27 -0400133}
134
135static inline void BV (clib_bihash_unlock_bucket)
136 (BVT (clib_bihash_bucket) * b)
137{
Dave Barach508498f2018-07-19 12:11:16 -0400138 CLIB_MEMORY_BARRIER ();
139 b->lock = 0;
Dave Barach908a5ea2017-07-14 12:42:21 -0400140}
141
142static inline void *BV (clib_bihash_get_value) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400143 uword offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144{
Dave Barach97f5af02018-02-22 09:48:45 -0500145 u8 *hp = (u8 *) h->alloc_arena;
Dave Barachc3799992016-08-15 11:12:27 -0400146 u8 *vp = hp + offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147
148 return (void *) vp;
149}
150
Damjan Marion882fcfe2018-07-17 23:01:49 +0200151static inline int BV (clib_bihash_bucket_is_empty)
152 (BVT (clib_bihash_bucket) * b)
153{
Dave Barach508498f2018-07-19 12:11:16 -0400154 /* Note: applied to locked buckets, test offset */
155 return b->offset == 0;
Damjan Marion882fcfe2018-07-17 23:01:49 +0200156}
157
Dave Barach908a5ea2017-07-14 12:42:21 -0400158static inline uword BV (clib_bihash_get_offset) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400159 void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160{
Dave Barachc3799992016-08-15 11:12:27 -0400161 u8 *hp, *vp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Dave Barach97f5af02018-02-22 09:48:45 -0500163 hp = (u8 *) h->alloc_arena;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 vp = (u8 *) v;
165
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 return vp - hp;
167}
168
Dave Barachc3799992016-08-15 11:12:27 -0400169void BV (clib_bihash_init)
170 (BVT (clib_bihash) * h, char *name, u32 nbuckets, uword memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -0800172void BV (clib_bihash_set_kvp_format_fn) (BVT (clib_bihash) * h,
173 format_function_t * fmt_fn);
174
Dave Barachc3799992016-08-15 11:12:27 -0400175void BV (clib_bihash_free) (BVT (clib_bihash) * h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
Dave Barachc3799992016-08-15 11:12:27 -0400177int BV (clib_bihash_add_del) (BVT (clib_bihash) * h,
178 BVT (clib_bihash_kv) * add_v, int is_add);
Dave Barach908a5ea2017-07-14 12:42:21 -0400179int BV (clib_bihash_search) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400180 BVT (clib_bihash_kv) * search_v,
181 BVT (clib_bihash_kv) * return_v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182
Dave Barachc3799992016-08-15 11:12:27 -0400183void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h,
184 void *callback, void *arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185
Dave Barachc3799992016-08-15 11:12:27 -0400186format_function_t BV (format_bihash);
187format_function_t BV (format_bihash_kvp);
Dave Barach908a5ea2017-07-14 12:42:21 -0400188format_function_t BV (format_bihash_lru);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
Dave Barach30765e72018-02-23 07:45:36 -0500190static inline int BV (clib_bihash_search_inline_with_hash)
191 (BVT (clib_bihash) * h, u64 hash, BVT (clib_bihash_kv) * key_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400194 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400195 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500196 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
Dave Barachc3799992016-08-15 11:12:27 -0400198 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 b = &h->buckets[bucket_index];
200
Damjan Marion882fcfe2018-07-17 23:01:49 +0200201 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 return -1;
203
Dave Barach508498f2018-07-19 12:11:16 -0400204 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400205 {
Dave Barach508498f2018-07-19 12:11:16 -0400206 volatile BVT (clib_bihash_bucket) * bv = b;
207 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200208 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400209 }
210
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 hash >>= h->log2_nbuckets;
212
Dave Barachc3799992016-08-15 11:12:27 -0400213 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400214
Dave Barach5e6b9582016-12-12 15:37:29 -0500215 /* If the bucket has unresolvable collisions, use linear search */
216 limit = BIHASH_KVP_PER_PAGE;
217 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
218 if (PREDICT_FALSE (b->linear_search))
219 limit <<= b->log2_pages;
220
221 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400223 if (BV (clib_bihash_key_compare) (v->kvp[i].key, key_result->key))
Dave Barachc3799992016-08-15 11:12:27 -0400224 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400225 *key_result = v->kvp[i];
Dave Barachc3799992016-08-15 11:12:27 -0400226 return 0;
227 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 }
229 return -1;
230}
231
Dave Barach30765e72018-02-23 07:45:36 -0500232static inline int BV (clib_bihash_search_inline)
233 (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * key_result)
234{
235 u64 hash;
236
237 hash = BV (clib_bihash_hash) (key_result);
238
239 return BV (clib_bihash_search_inline_with_hash) (h, hash, key_result);
240}
241
242static inline void BV (clib_bihash_prefetch_bucket)
243 (BVT (clib_bihash) * h, u64 hash)
244{
245 u32 bucket_index;
246 BVT (clib_bihash_bucket) * b;
247
248 bucket_index = hash & (h->nbuckets - 1);
249 b = &h->buckets[bucket_index];
250
251 CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, READ);
252}
253
254static inline void BV (clib_bihash_prefetch_data)
255 (BVT (clib_bihash) * h, u64 hash)
256{
257 u32 bucket_index;
258 BVT (clib_bihash_value) * v;
259 BVT (clib_bihash_bucket) * b;
260
261 bucket_index = hash & (h->nbuckets - 1);
262 b = &h->buckets[bucket_index];
263
Damjan Marion882fcfe2018-07-17 23:01:49 +0200264 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Dave Barach30765e72018-02-23 07:45:36 -0500265 return;
266
267 hash >>= h->log2_nbuckets;
268 v = BV (clib_bihash_get_value) (h, b->offset);
269
270 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
271
272 CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, READ);
273}
274
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200275static inline int BV (clib_bihash_search_inline_2_with_hash)
Dave Barach908a5ea2017-07-14 12:42:21 -0400276 (BVT (clib_bihash) * h,
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200277 u64 hash, BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400280 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400281 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500282 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283
Dave Barachc3799992016-08-15 11:12:27 -0400284 ASSERT (valuep);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285
Dave Barachc3799992016-08-15 11:12:27 -0400286 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 b = &h->buckets[bucket_index];
288
Damjan Marion882fcfe2018-07-17 23:01:49 +0200289 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 return -1;
291
Dave Barach508498f2018-07-19 12:11:16 -0400292 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400293 {
Dave Barach508498f2018-07-19 12:11:16 -0400294 volatile BVT (clib_bihash_bucket) * bv = b;
295 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200296 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400297 }
298
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 hash >>= h->log2_nbuckets;
Dave Barachc3799992016-08-15 11:12:27 -0400300 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400301
Dave Barach5e6b9582016-12-12 15:37:29 -0500302 /* If the bucket has unresolvable collisions, use linear search */
303 limit = BIHASH_KVP_PER_PAGE;
304 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
305 if (PREDICT_FALSE (b->linear_search))
306 limit <<= b->log2_pages;
307
308 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309 {
Dave Barachc3799992016-08-15 11:12:27 -0400310 if (BV (clib_bihash_key_compare) (v->kvp[i].key, search_key->key))
311 {
312 *valuep = v->kvp[i];
313 return 0;
314 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 }
316 return -1;
317}
318
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200319static inline int BV (clib_bihash_search_inline_2)
320 (BVT (clib_bihash) * h,
321 BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
322{
323 u64 hash;
324
325 hash = BV (clib_bihash_hash) (search_key);
326
327 return BV (clib_bihash_search_inline_2_with_hash) (h, hash, search_key,
328 valuep);
329}
330
331
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332#endif /* __included_bihash_template_h__ */
Dave Barachdd3a57f2016-07-27 16:58:51 -0400333
Chris Luke16bcf7d2016-09-01 14:31:46 -0400334/** @endcond */
Dave Barachc3799992016-08-15 11:12:27 -0400335
336/*
337 * fd.io coding-style-patch-verification: ON
338 *
339 * Local Variables:
340 * eval: (c-set-style "gnu")
341 * End:
342 */