blob: 6115b0cffd6cb575c672f754d74d1b9de4ecb03f [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001-2005 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#include <vppinfra/hash.h>
39#include <vppinfra/error.h>
40#include <vppinfra/mem.h>
41#include <vppinfra/byte_order.h> /* for clib_arch_is_big_endian */
42
Dave Barachc3799992016-08-15 11:12:27 -040043always_inline void
44zero_pair (hash_t * h, hash_pair_t * p)
45{
Dave Barachb7b92992018-10-17 10:38:51 -040046 clib_memset (p, 0, hash_pair_bytes (h));
Dave Barachc3799992016-08-15 11:12:27 -040047}
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barachc3799992016-08-15 11:12:27 -040049always_inline void
50init_pair (hash_t * h, hash_pair_t * p)
51{
Dave Barachb7b92992018-10-17 10:38:51 -040052 clib_memset (p->value, ~0, hash_value_bytes (h));
Dave Barachc3799992016-08-15 11:12:27 -040053}
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
55always_inline hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -040056get_pair (void *v, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -070057{
Dave Barachc3799992016-08-15 11:12:27 -040058 hash_t *h = hash_header (v);
59 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070060 ASSERT (i < vec_len (v));
61 p = v;
62 p += i << h->log2_pair_size;
63 return (hash_pair_union_t *) p;
64}
65
Dave Barachc3799992016-08-15 11:12:27 -040066always_inline void
67set_is_user (void *v, uword i, uword is_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barachc3799992016-08-15 11:12:27 -040069 hash_t *h = hash_header (v);
70 uword i0 = i / BITS (h->is_user[0]);
71 uword i1 = (uword) 1 << (i % BITS (h->is_user[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 if (is_user)
73 h->is_user[i0] |= i1;
74 else
75 h->is_user[i0] &= ~i1;
76}
77
Dave Barachc3799992016-08-15 11:12:27 -040078static u8 *hash_format_pair_default (u8 * s, va_list * args);
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80#if uword_bits == 64
81
Dave Barachc3799992016-08-15 11:12:27 -040082static inline u64
Gabriel Gannec5c2bb32017-11-03 10:30:45 +010083zap64 (u64 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -070084{
Gabriel Gannec5c2bb32017-11-03 10:30:45 +010085#define _(n) (((u64) 1 << (u64) (8*(n))) - (u64) 1)
86 static u64 masks_little_endian[] = {
87 0, _(1), _(2), _(3), _(4), _(5), _(6), _(7),
88 };
89 static u64 masks_big_endian[] = {
90 0, ~_(7), ~_(6), ~_(5), ~_(4), ~_(3), ~_(2), ~_(1),
91 };
92#undef _
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 if (clib_arch_is_big_endian)
Gabriel Gannec5c2bb32017-11-03 10:30:45 +010094 return x & masks_big_endian[n];
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 else
Gabriel Gannec5c2bb32017-11-03 10:30:45 +010096 return x & masks_little_endian[n];
Ed Warnickecb9cada2015-12-08 15:45:58 -070097}
98
Gabriel Gannec5c2bb32017-11-03 10:30:45 +010099/**
100 * make address-sanitizer skip this:
101 * clib_mem_unaligned + zap64 casts its input as u64, computes a mask
102 * according to the input length, and returns the casted maked value.
103 * Therefore all the 8 Bytes of the u64 are systematically read, which
104 * rightfully causes address-sanitizer to raise an error on smaller inputs.
105 *
Dave Barach7e2cea32019-10-09 12:57:13 -0400106 * However the invalid Bytes are discarded within zap64(), which is why
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100107 * this can be silenced safely.
Dave Barach7e2cea32019-10-09 12:57:13 -0400108 *
109 * The above is true *unless* the extra bytes cross a page boundary
110 * into unmapped or no-access space, hence the boundary crossing check.
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100111 */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200112static inline u64
Dave Barachc3799992016-08-15 11:12:27 -0400113hash_memory64 (void *p, word n_bytes, u64 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114{
Dave Barachc3799992016-08-15 11:12:27 -0400115 u64 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 u64 a, b, c, n;
Dave Barach7e2cea32019-10-09 12:57:13 -0400117 int page_boundary_crossing;
118 u64 start_addr, end_addr;
119 union
120 {
121 u8 as_u8[8];
122 u64 as_u64;
123 } tmp;
124
125 /*
126 * If the request crosses a 4k boundary, it's not OK to assume
127 * that the zap64 game is safe. 4k is the minimum known page size.
128 */
129 start_addr = (u64) p;
130 end_addr = start_addr + n_bytes + 7;
131 page_boundary_crossing = (start_addr >> 12) != (end_addr >> 12);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132
133 a = b = 0x9e3779b97f4a7c13LL;
134 c = state;
135 n = n_bytes;
136
Dave Barachc3799992016-08-15 11:12:27 -0400137 while (n >= 3 * sizeof (u64))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 {
139 a += clib_mem_unaligned (q + 0, u64);
140 b += clib_mem_unaligned (q + 1, u64);
141 c += clib_mem_unaligned (q + 2, u64);
142 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400143 n -= 3 * sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144 q += 3;
145 }
146
147 c += n_bytes;
148 switch (n / sizeof (u64))
149 {
150 case 2:
151 a += clib_mem_unaligned (q + 0, u64);
152 b += clib_mem_unaligned (q + 1, u64);
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100153 if (n % sizeof (u64))
Dave Barach7e2cea32019-10-09 12:57:13 -0400154 {
155 if (PREDICT_TRUE (page_boundary_crossing == 0))
156 c +=
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200157 zap64 (CLIB_MEM_OVERFLOW
158 (clib_mem_unaligned (q + 2, u64), q + 2, sizeof (u64)),
159 n % sizeof (u64)) << 8;
Dave Barach7e2cea32019-10-09 12:57:13 -0400160 else
161 {
162 clib_memcpy_fast (tmp.as_u8, q + 2, n % sizeof (u64));
163 c += zap64 (tmp.as_u64, n % sizeof (u64)) << 8;
164 }
165 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 break;
167
168 case 1:
169 a += clib_mem_unaligned (q + 0, u64);
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100170 if (n % sizeof (u64))
Dave Barach7e2cea32019-10-09 12:57:13 -0400171 {
172 if (PREDICT_TRUE (page_boundary_crossing == 0))
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200173 b +=
174 zap64 (CLIB_MEM_OVERFLOW
175 (clib_mem_unaligned (q + 1, u64), q + 1, sizeof (u64)),
176 n % sizeof (u64));
Dave Barach7e2cea32019-10-09 12:57:13 -0400177 else
178 {
179 clib_memcpy_fast (tmp.as_u8, q + 1, n % sizeof (u64));
180 b += zap64 (tmp.as_u64, n % sizeof (u64));
181 }
182 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 break;
184
185 case 0:
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100186 if (n % sizeof (u64))
Dave Barach7e2cea32019-10-09 12:57:13 -0400187 {
188 if (PREDICT_TRUE (page_boundary_crossing == 0))
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200189 a +=
190 zap64 (CLIB_MEM_OVERFLOW
191 (clib_mem_unaligned (q + 0, u64), q + 0, sizeof (u64)),
192 n % sizeof (u64));
Dave Barach7e2cea32019-10-09 12:57:13 -0400193 else
194 {
195 clib_memcpy_fast (tmp.as_u8, q, n % sizeof (u64));
196 a += zap64 (tmp.as_u64, n % sizeof (u64));
197 }
198 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 break;
200 }
201
202 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400203
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 return c;
205}
206
207#else /* if uword_bits == 64 */
208
Dave Barachc3799992016-08-15 11:12:27 -0400209static inline u32
210zap32 (u32 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211{
212#define _(n) (((u32) 1 << (u32) (8*(n))) - (u32) 1)
213 static u32 masks_little_endian[] = {
214 0, _(1), _(2), _(3),
215 };
216 static u32 masks_big_endian[] = {
217 0, ~_(3), ~_(2), ~_(1),
218 };
219#undef _
220 if (clib_arch_is_big_endian)
221 return x & masks_big_endian[n];
222 else
223 return x & masks_little_endian[n];
224}
225
Dave Barachc3799992016-08-15 11:12:27 -0400226static inline u32
227hash_memory32 (void *p, word n_bytes, u32 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228{
Dave Barachc3799992016-08-15 11:12:27 -0400229 u32 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230 u32 a, b, c, n;
231
232 a = b = 0x9e3779b9;
233 c = state;
234 n = n_bytes;
235
Dave Barachc3799992016-08-15 11:12:27 -0400236 while (n >= 3 * sizeof (u32))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 {
238 a += clib_mem_unaligned (q + 0, u32);
239 b += clib_mem_unaligned (q + 1, u32);
240 c += clib_mem_unaligned (q + 2, u32);
241 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400242 n -= 3 * sizeof (u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 q += 3;
244 }
245
246 c += n_bytes;
247 switch (n / sizeof (u32))
248 {
249 case 2:
250 a += clib_mem_unaligned (q + 0, u32);
251 b += clib_mem_unaligned (q + 1, u32);
252 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400253 c += zap32 (clib_mem_unaligned (q + 2, u32), n % sizeof (u32)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 break;
255
256 case 1:
257 a += clib_mem_unaligned (q + 0, u32);
258 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400259 b += zap32 (clib_mem_unaligned (q + 1, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 break;
261
262 case 0:
263 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400264 a += zap32 (clib_mem_unaligned (q + 0, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265 break;
266 }
267
268 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400269
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 return c;
271}
272#endif
273
Dave Barachc3799992016-08-15 11:12:27 -0400274uword
275hash_memory (void *p, word n_bytes, uword state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276{
Dave Barachc3799992016-08-15 11:12:27 -0400277 uword *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278
279#if uword_bits == 64
280 return hash_memory64 (q, n_bytes, state);
281#else
282 return hash_memory32 (q, n_bytes, state);
283#endif
284}
285
286#if uword_bits == 64
Dave Barachc3799992016-08-15 11:12:27 -0400287always_inline uword
288hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289{
290 u64 a, b, c;
291
292 a = b = 0x9e3779b97f4a7c13LL;
293 c = 0;
294 a += x;
295 hash_mix64 (a, b, c);
296 return c;
297}
298#else
Dave Barachc3799992016-08-15 11:12:27 -0400299always_inline uword
300hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301{
302 u32 a, b, c;
303
304 a = b = 0x9e3779b9;
305 c = 0;
306 a += x;
307 hash_mix32 (a, b, c);
308 return c;
309}
310#endif
311
312/* Call sum function. Hash code will be sum function value
313 modulo the prime length of the hash table. */
Dave Barachc3799992016-08-15 11:12:27 -0400314always_inline uword
315key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316{
317 uword sum;
318 switch (pointer_to_uword ((void *) h->key_sum))
319 {
320 case KEY_FUNC_NONE:
321 sum = hash_uword (key);
322 break;
323
324 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400325 sum = hash_uword (*uword_to_pointer (key, uword *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326 break;
327
328 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400329 sum = hash_uword (*uword_to_pointer (key, u32 *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 break;
331
332 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400333 sum = string_key_sum (h, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 break;
335
Ole Troan73710c72018-06-04 22:27:49 +0200336 case KEY_FUNC_MEM:
337 sum = mem_key_sum (h, key);
338 break;
339
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340 default:
341 sum = h->key_sum (h, key);
342 break;
343 }
344
345 return sum;
346}
347
Dave Barachc3799992016-08-15 11:12:27 -0400348always_inline uword
349key_equal1 (hash_t * h, uword key1, uword key2, uword e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350{
351 switch (pointer_to_uword ((void *) h->key_equal))
352 {
353 case KEY_FUNC_NONE:
354 break;
355
356 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400357 e =
358 *uword_to_pointer (key1, uword *) == *uword_to_pointer (key2,
359 uword *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 break;
361
362 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400363 e = *uword_to_pointer (key1, u32 *) == *uword_to_pointer (key2, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 break;
365
366 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400367 e = string_key_equal (h, key1, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 break;
369
Ole Troan73710c72018-06-04 22:27:49 +0200370 case KEY_FUNC_MEM:
371 e = mem_key_equal (h, key1, key2);
372 break;
373
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374 default:
375 e = h->key_equal (h, key1, key2);
376 break;
377 }
378 return e;
379}
380
381/* Compares two keys: returns 1 if equal, 0 if not. */
Dave Barachc3799992016-08-15 11:12:27 -0400382always_inline uword
383key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384{
385 uword e = key1 == key2;
386 if (CLIB_DEBUG > 0 && key1 == key2)
387 ASSERT (key_equal1 (h, key1, key2, e));
Dave Barachc3799992016-08-15 11:12:27 -0400388 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389 e = key_equal1 (h, key1, key2, e);
390 return e;
391}
392
393static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400394get_indirect (void *v, hash_pair_indirect_t * pi, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395{
Dave Barachc3799992016-08-15 11:12:27 -0400396 hash_t *h = hash_header (v);
397 hash_pair_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398
399 p0 = p1 = pi->pairs;
400 if (h->log2_pair_size > 0)
401 p1 = hash_forward (h, p0, indirect_pair_get_len (pi));
402 else
403 p1 += vec_len (p0);
404
405 while (p0 < p1)
406 {
407 if (key_equal (h, p0->key, key))
408 return (hash_pair_union_t *) p0;
409 p0 = hash_forward1 (h, p0);
410 }
411
412 return (hash_pair_union_t *) 0;
413}
414
415static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400416set_indirect_is_user (void *v, uword i, hash_pair_union_t * p, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417{
Dave Barachc3799992016-08-15 11:12:27 -0400418 hash_t *h = hash_header (v);
419 hash_pair_t *q;
420 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 uword log2_bytes = 0;
422
423 if (h->log2_pair_size == 0)
424 q = vec_new (hash_pair_t, 2);
425 else
426 {
427 log2_bytes = 1 + hash_pair_log2_bytes (h);
Dave Barach6f6f34f2016-08-08 13:05:31 -0400428 q = clib_mem_alloc (1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429 }
Dave Barach178cf492018-11-13 16:34:13 -0500430 clib_memcpy_fast (q, &p->direct, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431
432 pi->pairs = q;
433 if (h->log2_pair_size > 0)
434 indirect_pair_set (pi, log2_bytes, 2);
435
436 set_is_user (v, i, 0);
437
438 /* First element is used by existing pair, second will be used by caller. */
439 q = hash_forward1 (h, q);
440 q->key = key;
441 init_pair (h, q);
442 return (hash_pair_union_t *) q;
443}
444
445static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400446set_indirect (void *v, hash_pair_indirect_t * pi, uword key,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 uword * found_key)
448{
Dave Barachc3799992016-08-15 11:12:27 -0400449 hash_t *h = hash_header (v);
450 hash_pair_t *new_pair;
451 hash_pair_union_t *q;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452
453 q = get_indirect (v, pi, key);
454 if (q)
455 {
456 *found_key = 1;
457 return q;
458 }
459
460 if (h->log2_pair_size == 0)
461 vec_add2 (pi->pairs, new_pair, 1);
462 else
463 {
464 uword len, new_len, log2_bytes;
465
466 len = indirect_pair_get_len (pi);
467 log2_bytes = indirect_pair_get_log2_bytes (pi);
468
469 new_len = len + 1;
Dave Barach6f6f34f2016-08-08 13:05:31 -0400470 if (new_len * hash_pair_bytes (h) > (1ULL << log2_bytes))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 {
472 pi->pairs = clib_mem_realloc (pi->pairs,
Dave Barachdd522cb2016-08-10 16:56:16 -0400473 1ULL << (log2_bytes + 1),
474 1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475 log2_bytes++;
476 }
477
478 indirect_pair_set (pi, log2_bytes, new_len);
479 new_pair = pi->pairs + (len << h->log2_pair_size);
480 }
481 new_pair->key = key;
482 init_pair (h, new_pair);
483 *found_key = 0;
484 return (hash_pair_union_t *) new_pair;
485}
486
Dave Barachc3799992016-08-15 11:12:27 -0400487static void
488unset_indirect (void *v, uword i, hash_pair_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489{
Dave Barachc3799992016-08-15 11:12:27 -0400490 hash_t *h = hash_header (v);
491 hash_pair_union_t *p = get_pair (v, i);
492 hash_pair_t *e;
493 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 uword len, is_vec;
495
496 is_vec = h->log2_pair_size == 0;
497
Dave Barachc3799992016-08-15 11:12:27 -0400498 ASSERT (!hash_is_user (v, i));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 len = is_vec ? vec_len (pi->pairs) : indirect_pair_get_len (pi);
500 e = hash_forward (h, pi->pairs, len - 1);
501 ASSERT (q >= pi->pairs && q <= e);
502
503 /* We have two or fewer pairs and we are delete one pair.
504 Make indirect pointer direct and free indirect memory. */
505 if (len <= 2)
506 {
Dave Barachc3799992016-08-15 11:12:27 -0400507 hash_pair_t *r = pi->pairs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
509 if (len == 2)
510 {
Dave Barach178cf492018-11-13 16:34:13 -0500511 clib_memcpy_fast (p, q == r ? hash_forward1 (h, r) : r,
512 hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513 set_is_user (v, i, 1);
514 }
515 else
516 zero_pair (h, &p->direct);
517
518 if (is_vec)
519 vec_free (r);
520 else if (r)
521 clib_mem_free (r);
522 }
523 else
524 {
525 /* If deleting a pair we need to keep non-null pairs together. */
526 if (q < e)
Dave Barach178cf492018-11-13 16:34:13 -0500527 clib_memcpy_fast (q, e, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528 else
529 zero_pair (h, q);
530 if (is_vec)
531 _vec_len (pi->pairs) -= 1;
532 else
Dave Barachc3799992016-08-15 11:12:27 -0400533 indirect_pair_set (pi, indirect_pair_get_log2_bytes (pi), len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 }
535}
536
Dave Barachc3799992016-08-15 11:12:27 -0400537enum lookup_opcode
538{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539 GET = 1,
540 SET = 2,
541 UNSET = 3,
542};
543
Dave Barachc3799992016-08-15 11:12:27 -0400544static hash_pair_t *
545lookup (void *v, uword key, enum lookup_opcode op,
546 void *new_value, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547{
Dave Barachc3799992016-08-15 11:12:27 -0400548 hash_t *h = hash_header (v);
549 hash_pair_union_t *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550 uword found_key = 0;
551 uword i;
552
Dave Barachc3799992016-08-15 11:12:27 -0400553 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 return 0;
555
556 i = key_sum (h, key) & (_vec_len (v) - 1);
557 p = get_pair (v, i);
558
559 if (hash_is_user (v, i))
560 {
561 found_key = key_equal (h, p->direct.key, key);
562 if (found_key)
563 {
564 if (op == UNSET)
565 {
566 set_is_user (v, i, 0);
567 if (old_value)
Dave Barach178cf492018-11-13 16:34:13 -0500568 clib_memcpy_fast (old_value, p->direct.value,
569 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570 zero_pair (h, &p->direct);
571 }
572 }
573 else
574 {
575 if (op == SET)
576 p = set_indirect_is_user (v, i, p, key);
577 else
578 p = 0;
579 }
580 }
581 else
582 {
Dave Barachc3799992016-08-15 11:12:27 -0400583 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584
585 if (op == SET)
586 {
Dave Barachc3799992016-08-15 11:12:27 -0400587 if (!pi->pairs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588 {
589 p->direct.key = key;
590 set_is_user (v, i, 1);
591 }
592 else
593 p = set_indirect (v, pi, key, &found_key);
594 }
595 else
596 {
597 p = get_indirect (v, pi, key);
598 found_key = p != 0;
599 if (found_key && op == UNSET)
600 {
601 if (old_value)
Dave Barach178cf492018-11-13 16:34:13 -0500602 clib_memcpy_fast (old_value, &p->direct.value,
603 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604
605 unset_indirect (v, i, &p->direct);
606
607 /* Nullify p (since it's just been deleted).
Dave Barachc3799992016-08-15 11:12:27 -0400608 Otherwise we might be tempted to play with it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609 p = 0;
610 }
611 }
612 }
613
614 if (op == SET && p != 0)
615 {
616 /* Save away old value for caller. */
617 if (old_value && found_key)
Dave Barach178cf492018-11-13 16:34:13 -0500618 clib_memcpy_fast (old_value, &p->direct.value, hash_value_bytes (h));
619 clib_memcpy_fast (&p->direct.value, new_value, hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620 }
621
622 if (op == SET)
623 h->elts += !found_key;
624 if (op == UNSET)
625 h->elts -= found_key;
626
627 return &p->direct;
628}
629
630/* Fetch value of key. */
Dave Barachc3799992016-08-15 11:12:27 -0400631uword *
632_hash_get (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633{
Dave Barachc3799992016-08-15 11:12:27 -0400634 hash_t *h = hash_header (v);
635 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636
637 /* Don't even search table if its empty. */
Dave Barachc3799992016-08-15 11:12:27 -0400638 if (!v || h->elts == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 return 0;
640
641 p = lookup (v, key, GET, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400642 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 return 0;
644 if (h->log2_pair_size == 0)
645 return &p->key;
646 else
647 return &p->value[0];
648}
649
Dave Barachc3799992016-08-15 11:12:27 -0400650hash_pair_t *
651_hash_get_pair (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652{
Dave Barachc3799992016-08-15 11:12:27 -0400653 return lookup (v, key, GET, 0, 0);
654}
655
656hash_pair_t *
657hash_next (void *v, hash_next_t * hn)
658{
659 hash_t *h = hash_header (v);
660 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661
662 while (1)
663 {
664 if (hn->i == 0 && hn->j == 0)
665 {
666 /* Save flags. */
667 hn->f = h->flags;
668
669 /* Prevent others from re-sizing hash table. */
670 h->flags |=
Dave Barachc3799992016-08-15 11:12:27 -0400671 (HASH_FLAG_NO_AUTO_GROW
672 | HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_HASH_NEXT_IN_PROGRESS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 }
674 else if (hn->i >= hash_capacity (v))
675 {
676 /* Restore flags. */
677 h->flags = hn->f;
Dave Barachb7b92992018-10-17 10:38:51 -0400678 clib_memset (hn, 0, sizeof (hn[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679 return 0;
680 }
681
682 p = hash_forward (h, v, hn->i);
683 if (hash_is_user (v, hn->i))
684 {
685 hn->i++;
686 return p;
687 }
688 else
689 {
Dave Barachc3799992016-08-15 11:12:27 -0400690 hash_pair_indirect_t *pi = (void *) p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 uword n;
692
693 if (h->log2_pair_size > 0)
694 n = indirect_pair_get_len (pi);
695 else
696 n = vec_len (pi->pairs);
697
698 if (hn->j >= n)
699 {
700 hn->i++;
701 hn->j = 0;
702 }
703 else
704 return hash_forward (h, pi->pairs, hn->j++);
705 }
706 }
707}
708
709/* Remove key from table. */
Dave Barachc3799992016-08-15 11:12:27 -0400710void *
711_hash_unset (void *v, uword key, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700712{
Dave Barachc3799992016-08-15 11:12:27 -0400713 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714
Dave Barachc3799992016-08-15 11:12:27 -0400715 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716 return v;
717
718 (void) lookup (v, key, UNSET, 0, old_value);
719
720 h = hash_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400721 if (!(h->flags & HASH_FLAG_NO_AUTO_SHRINK))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 {
723 /* Resize when 1/4 full. */
724 if (h->elts > 32 && 4 * (h->elts + 1) < vec_len (v))
725 v = hash_resize (v, vec_len (v) / 2);
726 }
727
728 return v;
729}
730
Dave Barachc3799992016-08-15 11:12:27 -0400731void *
732_hash_create (uword elts, hash_t * h_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733{
Dave Barachc3799992016-08-15 11:12:27 -0400734 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 uword log2_pair_size;
Dave Barachc3799992016-08-15 11:12:27 -0400736 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737
738 /* Size of hash is power of 2 >= ELTS and larger than
739 number of bits in is_user bitmap elements. */
740 elts = clib_max (elts, BITS (h->is_user[0]));
Dave Barach6f6f34f2016-08-08 13:05:31 -0400741 elts = 1ULL << max_log2 (elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742
743 log2_pair_size = 1;
744 if (h_user)
745 log2_pair_size = h_user->log2_pair_size;
746
Damjan Marion2f25ef32018-05-04 20:45:41 +0200747 v = _vec_resize ((void *) 0,
Dave Barachc3799992016-08-15 11:12:27 -0400748 /* vec len: */ elts,
749 /* data bytes: */
750 (elts << log2_pair_size) * sizeof (hash_pair_t),
751 /* header bytes: */
752 sizeof (h[0]) +
753 (elts / BITS (h->is_user[0])) * sizeof (h->is_user[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754 /* alignment */ sizeof (hash_pair_t));
755 h = hash_header (v);
756
757 if (h_user)
758 h[0] = h_user[0];
759
760 h->log2_pair_size = log2_pair_size;
761 h->elts = 0;
762
763 /* Default flags to never shrinking hash tables.
764 Shrinking tables can cause "jackpot" cases. */
Dave Barachc3799992016-08-15 11:12:27 -0400765 if (!h_user)
766 h->flags = HASH_FLAG_NO_AUTO_SHRINK;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
Dave Barachc3799992016-08-15 11:12:27 -0400768 if (!h->format_pair)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700769 {
770 h->format_pair = hash_format_pair_default;
771 h->format_pair_arg = 0;
772 }
773
774 return v;
775}
776
Dave Barachc3799992016-08-15 11:12:27 -0400777void *
778_hash_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700779{
Dave Barachc3799992016-08-15 11:12:27 -0400780 hash_t *h = hash_header (v);
781 hash_pair_union_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 uword i;
783
Dave Barachc3799992016-08-15 11:12:27 -0400784 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785 return v;
786
787 /* We zero all freed memory in case user would be tempted to use it. */
788 for (i = 0; i < hash_capacity (v); i++)
789 {
790 if (hash_is_user (v, i))
791 continue;
792 p = get_pair (v, i);
793 if (h->log2_pair_size == 0)
794 vec_free (p->indirect.pairs);
795 else if (p->indirect.pairs)
796 clib_mem_free (p->indirect.pairs);
797 }
798
799 vec_free_header (h);
800
801 return 0;
802}
803
Dave Barachc3799992016-08-15 11:12:27 -0400804static void *
805hash_resize_internal (void *old, uword new_size, uword free_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806{
Dave Barachc3799992016-08-15 11:12:27 -0400807 void *new;
808 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809
810 new = 0;
811 if (new_size > 0)
812 {
Dave Barachc3799992016-08-15 11:12:27 -0400813 hash_t *h = old ? hash_header (old) : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 new = _hash_create (new_size, h);
Dave Barachc3799992016-08-15 11:12:27 -0400815 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 hash_foreach_pair (p, old, {
817 new = _hash_set3 (new, p->key, &p->value[0], 0);
818 });
Dave Barachc3799992016-08-15 11:12:27 -0400819 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820 }
821
822 if (free_old)
823 hash_free (old);
824 return new;
825}
826
Dave Barachc3799992016-08-15 11:12:27 -0400827void *
828hash_resize (void *old, uword new_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829{
Dave Barachc3799992016-08-15 11:12:27 -0400830 return hash_resize_internal (old, new_size, 1);
831}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832
Dave Barachc3799992016-08-15 11:12:27 -0400833void *
834hash_dup (void *old)
835{
836 return hash_resize_internal (old, vec_len (old), 0);
837}
838
839void *
840_hash_set3 (void *v, uword key, void *value, void *old_value)
841{
842 hash_t *h;
843
844 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700845 v = hash_create (0, sizeof (uword));
846
847 h = hash_header (v);
848 (void) lookup (v, key, SET, value, old_value);
849
Dave Barachc3799992016-08-15 11:12:27 -0400850 if (!(h->flags & HASH_FLAG_NO_AUTO_GROW))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851 {
852 /* Resize when 3/4 full. */
853 if (4 * (h->elts + 1) > 3 * vec_len (v))
854 v = hash_resize (v, 2 * vec_len (v));
855 }
856
857 return v;
858}
859
Dave Barachc3799992016-08-15 11:12:27 -0400860uword
861vec_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862{
Dave Barachc3799992016-08-15 11:12:27 -0400863 void *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700864 return hash_memory (v, vec_len (v) * h->user, 0);
865}
866
Dave Barachc3799992016-08-15 11:12:27 -0400867uword
868vec_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869{
Dave Barachc3799992016-08-15 11:12:27 -0400870 void *v1 = uword_to_pointer (key1, void *);
871 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872 uword l1 = vec_len (v1);
873 uword l2 = vec_len (v2);
874 return l1 == l2 && 0 == memcmp (v1, v2, l1 * h->user);
875}
876
Dave Barachc3799992016-08-15 11:12:27 -0400877u8 *
878vec_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700879{
Dave Barachc3799992016-08-15 11:12:27 -0400880 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
881 void *v = va_arg (*args, void *);
882 hash_pair_t *p = va_arg (*args, hash_pair_t *);
883 hash_t *h = hash_header (v);
884 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885 int i;
886
Dave Barachc3799992016-08-15 11:12:27 -0400887 switch (h->user)
888 {
889 case 1:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700890 s = format (s, "%v", u);
891 break;
892
Dave Barachc3799992016-08-15 11:12:27 -0400893 case 2:
894 {
895 u16 *w = u;
896 for (i = 0; i < vec_len (w); i++)
897 s = format (s, "0x%x, ", w[i]);
898 break;
899 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900
Dave Barachc3799992016-08-15 11:12:27 -0400901 case 4:
902 {
903 u32 *w = u;
904 for (i = 0; i < vec_len (w); i++)
905 s = format (s, "0x%x, ", w[i]);
906 break;
907 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908
Dave Barachc3799992016-08-15 11:12:27 -0400909 case 8:
910 {
911 u64 *w = u;
912 for (i = 0; i < vec_len (w); i++)
913 s = format (s, "0x%Lx, ", w[i]);
914 break;
915 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916
Dave Barachc3799992016-08-15 11:12:27 -0400917 default:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918 s = format (s, "0x%U", format_hex_bytes, u, vec_len (u) * h->user);
919 break;
Dave Barachc3799992016-08-15 11:12:27 -0400920 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921
922 if (hash_value_bytes (h) > 0)
923 s = format (s, " -> 0x%wx", p->value[0]);
924
925 return s;
926}
927
Dave Barachc3799992016-08-15 11:12:27 -0400928uword
929mem_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700930{
Dave Barachc3799992016-08-15 11:12:27 -0400931 uword *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932 return hash_memory (v, h->user, 0);
933}
934
Dave Barachc3799992016-08-15 11:12:27 -0400935uword
936mem_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937{
Dave Barachc3799992016-08-15 11:12:27 -0400938 void *v1 = uword_to_pointer (key1, void *);
939 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 return v1 && v2 && 0 == memcmp (v1, v2, h->user);
941}
942
Dave Barachc3799992016-08-15 11:12:27 -0400943uword
944string_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945{
Dave Barachc3799992016-08-15 11:12:27 -0400946 char *v = uword_to_pointer (key, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947 return hash_memory (v, strlen (v), 0);
948}
949
Dave Barachc3799992016-08-15 11:12:27 -0400950uword
951string_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952{
Dave Barachc3799992016-08-15 11:12:27 -0400953 void *v1 = uword_to_pointer (key1, void *);
954 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955 return v1 && v2 && 0 == strcmp (v1, v2);
956}
957
Dave Barachc3799992016-08-15 11:12:27 -0400958u8 *
959string_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960{
Dave Barachc3799992016-08-15 11:12:27 -0400961 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
962 void *v = va_arg (*args, void *);
963 hash_pair_t *p = va_arg (*args, hash_pair_t *);
964 hash_t *h = hash_header (v);
965 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 s = format (s, "%s", u);
968
969 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400970 s =
971 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
972 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973
974 return s;
975}
976
Dave Barachc3799992016-08-15 11:12:27 -0400977static u8 *
978hash_format_pair_default (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979{
Dave Barachc3799992016-08-15 11:12:27 -0400980 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
981 void *v = va_arg (*args, void *);
982 hash_pair_t *p = va_arg (*args, hash_pair_t *);
983 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984
985 s = format (s, "0x%08x", p->key);
986 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400987 s =
988 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
989 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990 return s;
991}
992
Dave Barachc3799992016-08-15 11:12:27 -0400993uword
994hash_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995{
996 uword i, bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400997 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998
Dave Barachc3799992016-08-15 11:12:27 -0400999 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001000 return 0;
1001
1002 bytes = vec_capacity (v, hash_header_bytes (v));
1003
1004 for (i = 0; i < hash_capacity (v); i++)
1005 {
Dave Barachc3799992016-08-15 11:12:27 -04001006 if (!hash_is_user (v, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 {
Dave Barachc3799992016-08-15 11:12:27 -04001008 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009 if (h->log2_pair_size > 0)
Dave Barachc3799992016-08-15 11:12:27 -04001010 bytes += 1 << indirect_pair_get_log2_bytes (&p->indirect);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011 else
1012 bytes += vec_capacity (p->indirect.pairs, 0);
1013 }
1014 }
1015 return bytes;
1016}
1017
Dave Barachc3799992016-08-15 11:12:27 -04001018u8 *
1019format_hash (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020{
Dave Barachc3799992016-08-15 11:12:27 -04001021 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001022 int verbose = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -04001023 hash_pair_t *p;
1024 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025 uword i;
1026
1027 s = format (s, "hash %p, %wd elts, capacity %wd, %wd bytes used,\n",
Dave Barachc3799992016-08-15 11:12:27 -04001028 v, hash_elts (v), hash_capacity (v), hash_bytes (v));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029
1030 {
Dave Barachc3799992016-08-15 11:12:27 -04001031 uword *occupancy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032
1033 /* Count number of buckets with each occupancy. */
1034 for (i = 0; i < hash_capacity (v); i++)
1035 {
1036 uword j;
1037
1038 if (hash_is_user (v, i))
1039 {
1040 j = 1;
1041 }
1042 else
1043 {
Dave Barachc3799992016-08-15 11:12:27 -04001044 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045 if (h->log2_pair_size > 0)
1046 j = indirect_pair_get_len (&p->indirect);
1047 else
1048 j = vec_len (p->indirect.pairs);
1049 }
1050
1051 vec_validate (occupancy, j);
1052 occupancy[j]++;
1053 }
1054
1055 s = format (s, " profile ");
1056 for (i = 0; i < vec_len (occupancy); i++)
1057 s = format (s, "%wd%c", occupancy[i],
1058 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1059
1060 s = format (s, " lookup # of compares: ");
1061 for (i = 1; i < vec_len (occupancy); i++)
1062 s = format (s, "%wd: .%03d%c", i,
1063 (1000 * i * occupancy[i]) / hash_elts (v),
1064 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1065
1066 vec_free (occupancy);
1067 }
1068
1069 if (verbose)
1070 {
Dave Barachc3799992016-08-15 11:12:27 -04001071 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 hash_foreach_pair (p, v, {
1073 s = format (s, " %U\n", h->format_pair, h->format_pair_arg, v, p);
1074 });
Dave Barachc3799992016-08-15 11:12:27 -04001075 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 }
1077
1078 return s;
1079}
1080
1081static uword
1082unformat_hash_string_internal (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -04001083 va_list * va, int is_vec)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084{
Dave Barachc3799992016-08-15 11:12:27 -04001085 uword *hash = va_arg (*va, uword *);
1086 int *result = va_arg (*va, int *);
1087 u8 *string = 0;
1088 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
Dave Barachc3799992016-08-15 11:12:27 -04001090 if (!unformat (input, is_vec ? "%v%_" : "%s%_", &string))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 return 0;
1092
1093 p = hash_get_mem (hash, string);
1094 if (p)
1095 *result = *p;
1096
1097 vec_free (string);
1098 return p ? 1 : 0;
1099}
1100
1101uword
1102unformat_hash_vec_string (unformat_input_t * input, va_list * va)
Dave Barachc3799992016-08-15 11:12:27 -04001103{
1104 return unformat_hash_string_internal (input, va, /* is_vec */ 1);
1105}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106
1107uword
1108unformat_hash_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109{
Dave Barachc3799992016-08-15 11:12:27 -04001110 return unformat_hash_string_internal (input, va, /* is_vec */ 0);
1111}
1112
1113clib_error_t *
1114hash_validate (void *v)
1115{
1116 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117 uword i, j;
Dave Barachc3799992016-08-15 11:12:27 -04001118 uword *keys = 0;
1119 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
1121#define CHECK(x) if ((error = ERROR_ASSERT (x))) goto done;
1122
1123 for (i = 0; i < hash_capacity (v); i++)
1124 {
Dave Barachc3799992016-08-15 11:12:27 -04001125 hash_pair_union_t *pu = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126
1127 if (hash_is_user (v, i))
1128 {
1129 CHECK (pu->direct.key != 0);
1130 vec_add1 (keys, pu->direct.key);
1131 }
1132 else
1133 {
Dave Barachc3799992016-08-15 11:12:27 -04001134 hash_pair_t *p;
1135 hash_pair_indirect_t *pi = &pu->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136 uword n;
1137
1138 n = h->log2_pair_size > 0
Dave Barachc3799992016-08-15 11:12:27 -04001139 ? indirect_pair_get_len (pi) : vec_len (pi->pairs);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140
1141 for (p = pi->pairs; n-- > 0; p = hash_forward1 (h, p))
1142 {
1143 /* Assert key uniqueness. */
1144 for (j = 0; j < vec_len (keys); j++)
1145 CHECK (keys[j] != p->key);
1146 vec_add1 (keys, p->key);
1147 }
1148 }
1149 }
1150
1151 CHECK (vec_len (keys) == h->elts);
1152
1153 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -04001154done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155 return error;
1156}
Dave Barachc3799992016-08-15 11:12:27 -04001157
1158/*
1159 * fd.io coding-style-patch-verification: ON
1160 *
1161 * Local Variables:
1162 * eval: (c-set-style "gnu")
1163 * End:
1164 */