blob: abc7c4ce4a27f4d9dcde6b84bfc7606d6760ec8d [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{
46 memset (p, 0, hash_pair_bytes (h));
47}
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{
52 memset (p->value, ~0, hash_value_bytes (h));
53}
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 *
106 * However the invalid Bytes are discarded within zap64(), whicj is why
107 * this can be silenced safely.
108 */
109static inline u64 __attribute__ ((no_sanitize_address))
Dave Barachc3799992016-08-15 11:12:27 -0400110hash_memory64 (void *p, word n_bytes, u64 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111{
Dave Barachc3799992016-08-15 11:12:27 -0400112 u64 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 u64 a, b, c, n;
114
115 a = b = 0x9e3779b97f4a7c13LL;
116 c = state;
117 n = n_bytes;
118
Dave Barachc3799992016-08-15 11:12:27 -0400119 while (n >= 3 * sizeof (u64))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 {
121 a += clib_mem_unaligned (q + 0, u64);
122 b += clib_mem_unaligned (q + 1, u64);
123 c += clib_mem_unaligned (q + 2, u64);
124 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400125 n -= 3 * sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 q += 3;
127 }
128
129 c += n_bytes;
130 switch (n / sizeof (u64))
131 {
132 case 2:
133 a += clib_mem_unaligned (q + 0, u64);
134 b += clib_mem_unaligned (q + 1, u64);
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100135 if (n % sizeof (u64))
136 c += zap64 (clib_mem_unaligned (q + 2, u64), n % sizeof (u64)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137 break;
138
139 case 1:
140 a += clib_mem_unaligned (q + 0, u64);
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100141 if (n % sizeof (u64))
142 b += zap64 (clib_mem_unaligned (q + 1, u64), n % sizeof (u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143 break;
144
145 case 0:
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100146 if (n % sizeof (u64))
147 a += zap64 (clib_mem_unaligned (q + 0, u64), n % sizeof (u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148 break;
149 }
150
151 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400152
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 return c;
154}
155
156#else /* if uword_bits == 64 */
157
Dave Barachc3799992016-08-15 11:12:27 -0400158static inline u32
159zap32 (u32 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160{
161#define _(n) (((u32) 1 << (u32) (8*(n))) - (u32) 1)
162 static u32 masks_little_endian[] = {
163 0, _(1), _(2), _(3),
164 };
165 static u32 masks_big_endian[] = {
166 0, ~_(3), ~_(2), ~_(1),
167 };
168#undef _
169 if (clib_arch_is_big_endian)
170 return x & masks_big_endian[n];
171 else
172 return x & masks_little_endian[n];
173}
174
Dave Barachc3799992016-08-15 11:12:27 -0400175static inline u32
176hash_memory32 (void *p, word n_bytes, u32 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177{
Dave Barachc3799992016-08-15 11:12:27 -0400178 u32 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 u32 a, b, c, n;
180
181 a = b = 0x9e3779b9;
182 c = state;
183 n = n_bytes;
184
Dave Barachc3799992016-08-15 11:12:27 -0400185 while (n >= 3 * sizeof (u32))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 {
187 a += clib_mem_unaligned (q + 0, u32);
188 b += clib_mem_unaligned (q + 1, u32);
189 c += clib_mem_unaligned (q + 2, u32);
190 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400191 n -= 3 * sizeof (u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192 q += 3;
193 }
194
195 c += n_bytes;
196 switch (n / sizeof (u32))
197 {
198 case 2:
199 a += clib_mem_unaligned (q + 0, u32);
200 b += clib_mem_unaligned (q + 1, u32);
201 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400202 c += zap32 (clib_mem_unaligned (q + 2, u32), n % sizeof (u32)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 break;
204
205 case 1:
206 a += clib_mem_unaligned (q + 0, u32);
207 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400208 b += zap32 (clib_mem_unaligned (q + 1, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 break;
210
211 case 0:
212 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400213 a += zap32 (clib_mem_unaligned (q + 0, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 break;
215 }
216
217 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400218
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 return c;
220}
221#endif
222
Dave Barachc3799992016-08-15 11:12:27 -0400223uword
224hash_memory (void *p, word n_bytes, uword state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225{
Dave Barachc3799992016-08-15 11:12:27 -0400226 uword *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
228#if uword_bits == 64
229 return hash_memory64 (q, n_bytes, state);
230#else
231 return hash_memory32 (q, n_bytes, state);
232#endif
233}
234
235#if uword_bits == 64
Dave Barachc3799992016-08-15 11:12:27 -0400236always_inline uword
237hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238{
239 u64 a, b, c;
240
241 a = b = 0x9e3779b97f4a7c13LL;
242 c = 0;
243 a += x;
244 hash_mix64 (a, b, c);
245 return c;
246}
247#else
Dave Barachc3799992016-08-15 11:12:27 -0400248always_inline uword
249hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250{
251 u32 a, b, c;
252
253 a = b = 0x9e3779b9;
254 c = 0;
255 a += x;
256 hash_mix32 (a, b, c);
257 return c;
258}
259#endif
260
261/* Call sum function. Hash code will be sum function value
262 modulo the prime length of the hash table. */
Dave Barachc3799992016-08-15 11:12:27 -0400263always_inline uword
264key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265{
266 uword sum;
267 switch (pointer_to_uword ((void *) h->key_sum))
268 {
269 case KEY_FUNC_NONE:
270 sum = hash_uword (key);
271 break;
272
273 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400274 sum = hash_uword (*uword_to_pointer (key, uword *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275 break;
276
277 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400278 sum = hash_uword (*uword_to_pointer (key, u32 *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279 break;
280
281 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400282 sum = string_key_sum (h, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 break;
284
Ole Troan73710c72018-06-04 22:27:49 +0200285 case KEY_FUNC_MEM:
286 sum = mem_key_sum (h, key);
287 break;
288
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 default:
290 sum = h->key_sum (h, key);
291 break;
292 }
293
294 return sum;
295}
296
Dave Barachc3799992016-08-15 11:12:27 -0400297always_inline uword
298key_equal1 (hash_t * h, uword key1, uword key2, uword e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299{
300 switch (pointer_to_uword ((void *) h->key_equal))
301 {
302 case KEY_FUNC_NONE:
303 break;
304
305 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400306 e =
307 *uword_to_pointer (key1, uword *) == *uword_to_pointer (key2,
308 uword *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309 break;
310
311 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400312 e = *uword_to_pointer (key1, u32 *) == *uword_to_pointer (key2, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313 break;
314
315 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400316 e = string_key_equal (h, key1, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317 break;
318
Ole Troan73710c72018-06-04 22:27:49 +0200319 case KEY_FUNC_MEM:
320 e = mem_key_equal (h, key1, key2);
321 break;
322
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323 default:
324 e = h->key_equal (h, key1, key2);
325 break;
326 }
327 return e;
328}
329
330/* Compares two keys: returns 1 if equal, 0 if not. */
Dave Barachc3799992016-08-15 11:12:27 -0400331always_inline uword
332key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333{
334 uword e = key1 == key2;
335 if (CLIB_DEBUG > 0 && key1 == key2)
336 ASSERT (key_equal1 (h, key1, key2, e));
Dave Barachc3799992016-08-15 11:12:27 -0400337 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 e = key_equal1 (h, key1, key2, e);
339 return e;
340}
341
342static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400343get_indirect (void *v, hash_pair_indirect_t * pi, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344{
Dave Barachc3799992016-08-15 11:12:27 -0400345 hash_t *h = hash_header (v);
346 hash_pair_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347
348 p0 = p1 = pi->pairs;
349 if (h->log2_pair_size > 0)
350 p1 = hash_forward (h, p0, indirect_pair_get_len (pi));
351 else
352 p1 += vec_len (p0);
353
354 while (p0 < p1)
355 {
356 if (key_equal (h, p0->key, key))
357 return (hash_pair_union_t *) p0;
358 p0 = hash_forward1 (h, p0);
359 }
360
361 return (hash_pair_union_t *) 0;
362}
363
364static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400365set_indirect_is_user (void *v, uword i, hash_pair_union_t * p, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366{
Dave Barachc3799992016-08-15 11:12:27 -0400367 hash_t *h = hash_header (v);
368 hash_pair_t *q;
369 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370 uword log2_bytes = 0;
371
372 if (h->log2_pair_size == 0)
373 q = vec_new (hash_pair_t, 2);
374 else
375 {
376 log2_bytes = 1 + hash_pair_log2_bytes (h);
Dave Barach6f6f34f2016-08-08 13:05:31 -0400377 q = clib_mem_alloc (1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 }
Damjan Marionf1213b82016-03-13 02:22:06 +0100379 clib_memcpy (q, &p->direct, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380
381 pi->pairs = q;
382 if (h->log2_pair_size > 0)
383 indirect_pair_set (pi, log2_bytes, 2);
384
385 set_is_user (v, i, 0);
386
387 /* First element is used by existing pair, second will be used by caller. */
388 q = hash_forward1 (h, q);
389 q->key = key;
390 init_pair (h, q);
391 return (hash_pair_union_t *) q;
392}
393
394static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400395set_indirect (void *v, hash_pair_indirect_t * pi, uword key,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 uword * found_key)
397{
Dave Barachc3799992016-08-15 11:12:27 -0400398 hash_t *h = hash_header (v);
399 hash_pair_t *new_pair;
400 hash_pair_union_t *q;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
402 q = get_indirect (v, pi, key);
403 if (q)
404 {
405 *found_key = 1;
406 return q;
407 }
408
409 if (h->log2_pair_size == 0)
410 vec_add2 (pi->pairs, new_pair, 1);
411 else
412 {
413 uword len, new_len, log2_bytes;
414
415 len = indirect_pair_get_len (pi);
416 log2_bytes = indirect_pair_get_log2_bytes (pi);
417
418 new_len = len + 1;
Dave Barach6f6f34f2016-08-08 13:05:31 -0400419 if (new_len * hash_pair_bytes (h) > (1ULL << log2_bytes))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 {
421 pi->pairs = clib_mem_realloc (pi->pairs,
Dave Barachdd522cb2016-08-10 16:56:16 -0400422 1ULL << (log2_bytes + 1),
423 1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 log2_bytes++;
425 }
426
427 indirect_pair_set (pi, log2_bytes, new_len);
428 new_pair = pi->pairs + (len << h->log2_pair_size);
429 }
430 new_pair->key = key;
431 init_pair (h, new_pair);
432 *found_key = 0;
433 return (hash_pair_union_t *) new_pair;
434}
435
Dave Barachc3799992016-08-15 11:12:27 -0400436static void
437unset_indirect (void *v, uword i, hash_pair_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700438{
Dave Barachc3799992016-08-15 11:12:27 -0400439 hash_t *h = hash_header (v);
440 hash_pair_union_t *p = get_pair (v, i);
441 hash_pair_t *e;
442 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443 uword len, is_vec;
444
445 is_vec = h->log2_pair_size == 0;
446
Dave Barachc3799992016-08-15 11:12:27 -0400447 ASSERT (!hash_is_user (v, i));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448 len = is_vec ? vec_len (pi->pairs) : indirect_pair_get_len (pi);
449 e = hash_forward (h, pi->pairs, len - 1);
450 ASSERT (q >= pi->pairs && q <= e);
451
452 /* We have two or fewer pairs and we are delete one pair.
453 Make indirect pointer direct and free indirect memory. */
454 if (len <= 2)
455 {
Dave Barachc3799992016-08-15 11:12:27 -0400456 hash_pair_t *r = pi->pairs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
458 if (len == 2)
459 {
Dave Barachc3799992016-08-15 11:12:27 -0400460 clib_memcpy (p, q == r ? hash_forward1 (h, r) : r,
461 hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 set_is_user (v, i, 1);
463 }
464 else
465 zero_pair (h, &p->direct);
466
467 if (is_vec)
468 vec_free (r);
469 else if (r)
470 clib_mem_free (r);
471 }
472 else
473 {
474 /* If deleting a pair we need to keep non-null pairs together. */
475 if (q < e)
Damjan Marionf1213b82016-03-13 02:22:06 +0100476 clib_memcpy (q, e, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477 else
478 zero_pair (h, q);
479 if (is_vec)
480 _vec_len (pi->pairs) -= 1;
481 else
Dave Barachc3799992016-08-15 11:12:27 -0400482 indirect_pair_set (pi, indirect_pair_get_log2_bytes (pi), len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 }
484}
485
Dave Barachc3799992016-08-15 11:12:27 -0400486enum lookup_opcode
487{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 GET = 1,
489 SET = 2,
490 UNSET = 3,
491};
492
Dave Barachc3799992016-08-15 11:12:27 -0400493static hash_pair_t *
494lookup (void *v, uword key, enum lookup_opcode op,
495 void *new_value, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496{
Dave Barachc3799992016-08-15 11:12:27 -0400497 hash_t *h = hash_header (v);
498 hash_pair_union_t *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 uword found_key = 0;
500 uword i;
501
Dave Barachc3799992016-08-15 11:12:27 -0400502 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 return 0;
504
505 i = key_sum (h, key) & (_vec_len (v) - 1);
506 p = get_pair (v, i);
507
508 if (hash_is_user (v, i))
509 {
510 found_key = key_equal (h, p->direct.key, key);
511 if (found_key)
512 {
513 if (op == UNSET)
514 {
515 set_is_user (v, i, 0);
516 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400517 clib_memcpy (old_value, p->direct.value,
518 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 zero_pair (h, &p->direct);
520 }
521 }
522 else
523 {
524 if (op == SET)
525 p = set_indirect_is_user (v, i, p, key);
526 else
527 p = 0;
528 }
529 }
530 else
531 {
Dave Barachc3799992016-08-15 11:12:27 -0400532 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533
534 if (op == SET)
535 {
Dave Barachc3799992016-08-15 11:12:27 -0400536 if (!pi->pairs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 {
538 p->direct.key = key;
539 set_is_user (v, i, 1);
540 }
541 else
542 p = set_indirect (v, pi, key, &found_key);
543 }
544 else
545 {
546 p = get_indirect (v, pi, key);
547 found_key = p != 0;
548 if (found_key && op == UNSET)
549 {
550 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400551 clib_memcpy (old_value, &p->direct.value,
552 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553
554 unset_indirect (v, i, &p->direct);
555
556 /* Nullify p (since it's just been deleted).
Dave Barachc3799992016-08-15 11:12:27 -0400557 Otherwise we might be tempted to play with it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 p = 0;
559 }
560 }
561 }
562
563 if (op == SET && p != 0)
564 {
565 /* Save away old value for caller. */
566 if (old_value && found_key)
Damjan Marionf1213b82016-03-13 02:22:06 +0100567 clib_memcpy (old_value, &p->direct.value, hash_value_bytes (h));
568 clib_memcpy (&p->direct.value, new_value, hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569 }
570
571 if (op == SET)
572 h->elts += !found_key;
573 if (op == UNSET)
574 h->elts -= found_key;
575
576 return &p->direct;
577}
578
579/* Fetch value of key. */
Dave Barachc3799992016-08-15 11:12:27 -0400580uword *
581_hash_get (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582{
Dave Barachc3799992016-08-15 11:12:27 -0400583 hash_t *h = hash_header (v);
584 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585
586 /* Don't even search table if its empty. */
Dave Barachc3799992016-08-15 11:12:27 -0400587 if (!v || h->elts == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588 return 0;
589
590 p = lookup (v, key, GET, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400591 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592 return 0;
593 if (h->log2_pair_size == 0)
594 return &p->key;
595 else
596 return &p->value[0];
597}
598
Dave Barachc3799992016-08-15 11:12:27 -0400599hash_pair_t *
600_hash_get_pair (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700601{
Dave Barachc3799992016-08-15 11:12:27 -0400602 return lookup (v, key, GET, 0, 0);
603}
604
605hash_pair_t *
606hash_next (void *v, hash_next_t * hn)
607{
608 hash_t *h = hash_header (v);
609 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610
611 while (1)
612 {
613 if (hn->i == 0 && hn->j == 0)
614 {
615 /* Save flags. */
616 hn->f = h->flags;
617
618 /* Prevent others from re-sizing hash table. */
619 h->flags |=
Dave Barachc3799992016-08-15 11:12:27 -0400620 (HASH_FLAG_NO_AUTO_GROW
621 | HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_HASH_NEXT_IN_PROGRESS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 }
623 else if (hn->i >= hash_capacity (v))
624 {
625 /* Restore flags. */
626 h->flags = hn->f;
627 memset (hn, 0, sizeof (hn[0]));
628 return 0;
629 }
630
631 p = hash_forward (h, v, hn->i);
632 if (hash_is_user (v, hn->i))
633 {
634 hn->i++;
635 return p;
636 }
637 else
638 {
Dave Barachc3799992016-08-15 11:12:27 -0400639 hash_pair_indirect_t *pi = (void *) p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640 uword n;
641
642 if (h->log2_pair_size > 0)
643 n = indirect_pair_get_len (pi);
644 else
645 n = vec_len (pi->pairs);
646
647 if (hn->j >= n)
648 {
649 hn->i++;
650 hn->j = 0;
651 }
652 else
653 return hash_forward (h, pi->pairs, hn->j++);
654 }
655 }
656}
657
658/* Remove key from table. */
Dave Barachc3799992016-08-15 11:12:27 -0400659void *
660_hash_unset (void *v, uword key, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661{
Dave Barachc3799992016-08-15 11:12:27 -0400662 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663
Dave Barachc3799992016-08-15 11:12:27 -0400664 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665 return v;
666
667 (void) lookup (v, key, UNSET, 0, old_value);
668
669 h = hash_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400670 if (!(h->flags & HASH_FLAG_NO_AUTO_SHRINK))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671 {
672 /* Resize when 1/4 full. */
673 if (h->elts > 32 && 4 * (h->elts + 1) < vec_len (v))
674 v = hash_resize (v, vec_len (v) / 2);
675 }
676
677 return v;
678}
679
Dave Barachc3799992016-08-15 11:12:27 -0400680void *
681_hash_create (uword elts, hash_t * h_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682{
Dave Barachc3799992016-08-15 11:12:27 -0400683 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 uword log2_pair_size;
Dave Barachc3799992016-08-15 11:12:27 -0400685 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686
687 /* Size of hash is power of 2 >= ELTS and larger than
688 number of bits in is_user bitmap elements. */
689 elts = clib_max (elts, BITS (h->is_user[0]));
Dave Barach6f6f34f2016-08-08 13:05:31 -0400690 elts = 1ULL << max_log2 (elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691
692 log2_pair_size = 1;
693 if (h_user)
694 log2_pair_size = h_user->log2_pair_size;
695
Damjan Marion2f25ef32018-05-04 20:45:41 +0200696 v = _vec_resize ((void *) 0,
Dave Barachc3799992016-08-15 11:12:27 -0400697 /* vec len: */ elts,
698 /* data bytes: */
699 (elts << log2_pair_size) * sizeof (hash_pair_t),
700 /* header bytes: */
701 sizeof (h[0]) +
702 (elts / BITS (h->is_user[0])) * sizeof (h->is_user[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703 /* alignment */ sizeof (hash_pair_t));
704 h = hash_header (v);
705
706 if (h_user)
707 h[0] = h_user[0];
708
709 h->log2_pair_size = log2_pair_size;
710 h->elts = 0;
711
712 /* Default flags to never shrinking hash tables.
713 Shrinking tables can cause "jackpot" cases. */
Dave Barachc3799992016-08-15 11:12:27 -0400714 if (!h_user)
715 h->flags = HASH_FLAG_NO_AUTO_SHRINK;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Dave Barachc3799992016-08-15 11:12:27 -0400717 if (!h->format_pair)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718 {
719 h->format_pair = hash_format_pair_default;
720 h->format_pair_arg = 0;
721 }
722
723 return v;
724}
725
Dave Barachc3799992016-08-15 11:12:27 -0400726void *
727_hash_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700728{
Dave Barachc3799992016-08-15 11:12:27 -0400729 hash_t *h = hash_header (v);
730 hash_pair_union_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731 uword i;
732
Dave Barachc3799992016-08-15 11:12:27 -0400733 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 return v;
735
736 /* We zero all freed memory in case user would be tempted to use it. */
737 for (i = 0; i < hash_capacity (v); i++)
738 {
739 if (hash_is_user (v, i))
740 continue;
741 p = get_pair (v, i);
742 if (h->log2_pair_size == 0)
743 vec_free (p->indirect.pairs);
744 else if (p->indirect.pairs)
745 clib_mem_free (p->indirect.pairs);
746 }
747
748 vec_free_header (h);
749
750 return 0;
751}
752
Dave Barachc3799992016-08-15 11:12:27 -0400753static void *
754hash_resize_internal (void *old, uword new_size, uword free_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755{
Dave Barachc3799992016-08-15 11:12:27 -0400756 void *new;
757 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758
759 new = 0;
760 if (new_size > 0)
761 {
Dave Barachc3799992016-08-15 11:12:27 -0400762 hash_t *h = old ? hash_header (old) : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763 new = _hash_create (new_size, h);
Dave Barachc3799992016-08-15 11:12:27 -0400764 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765 hash_foreach_pair (p, old, {
766 new = _hash_set3 (new, p->key, &p->value[0], 0);
767 });
Dave Barachc3799992016-08-15 11:12:27 -0400768 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700769 }
770
771 if (free_old)
772 hash_free (old);
773 return new;
774}
775
Dave Barachc3799992016-08-15 11:12:27 -0400776void *
777hash_resize (void *old, uword new_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778{
Dave Barachc3799992016-08-15 11:12:27 -0400779 return hash_resize_internal (old, new_size, 1);
780}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781
Dave Barachc3799992016-08-15 11:12:27 -0400782void *
783hash_dup (void *old)
784{
785 return hash_resize_internal (old, vec_len (old), 0);
786}
787
788void *
789_hash_set3 (void *v, uword key, void *value, void *old_value)
790{
791 hash_t *h;
792
793 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794 v = hash_create (0, sizeof (uword));
795
796 h = hash_header (v);
797 (void) lookup (v, key, SET, value, old_value);
798
Dave Barachc3799992016-08-15 11:12:27 -0400799 if (!(h->flags & HASH_FLAG_NO_AUTO_GROW))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800 {
801 /* Resize when 3/4 full. */
802 if (4 * (h->elts + 1) > 3 * vec_len (v))
803 v = hash_resize (v, 2 * vec_len (v));
804 }
805
806 return v;
807}
808
Dave Barachc3799992016-08-15 11:12:27 -0400809uword
810vec_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811{
Dave Barachc3799992016-08-15 11:12:27 -0400812 void *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 return hash_memory (v, vec_len (v) * h->user, 0);
814}
815
Dave Barachc3799992016-08-15 11:12:27 -0400816uword
817vec_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818{
Dave Barachc3799992016-08-15 11:12:27 -0400819 void *v1 = uword_to_pointer (key1, void *);
820 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 uword l1 = vec_len (v1);
822 uword l2 = vec_len (v2);
823 return l1 == l2 && 0 == memcmp (v1, v2, l1 * h->user);
824}
825
Dave Barachc3799992016-08-15 11:12:27 -0400826u8 *
827vec_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828{
Dave Barachc3799992016-08-15 11:12:27 -0400829 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
830 void *v = va_arg (*args, void *);
831 hash_pair_t *p = va_arg (*args, hash_pair_t *);
832 hash_t *h = hash_header (v);
833 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834 int i;
835
Dave Barachc3799992016-08-15 11:12:27 -0400836 switch (h->user)
837 {
838 case 1:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 s = format (s, "%v", u);
840 break;
841
Dave Barachc3799992016-08-15 11:12:27 -0400842 case 2:
843 {
844 u16 *w = u;
845 for (i = 0; i < vec_len (w); i++)
846 s = format (s, "0x%x, ", w[i]);
847 break;
848 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849
Dave Barachc3799992016-08-15 11:12:27 -0400850 case 4:
851 {
852 u32 *w = u;
853 for (i = 0; i < vec_len (w); i++)
854 s = format (s, "0x%x, ", w[i]);
855 break;
856 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857
Dave Barachc3799992016-08-15 11:12:27 -0400858 case 8:
859 {
860 u64 *w = u;
861 for (i = 0; i < vec_len (w); i++)
862 s = format (s, "0x%Lx, ", w[i]);
863 break;
864 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865
Dave Barachc3799992016-08-15 11:12:27 -0400866 default:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867 s = format (s, "0x%U", format_hex_bytes, u, vec_len (u) * h->user);
868 break;
Dave Barachc3799992016-08-15 11:12:27 -0400869 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700870
871 if (hash_value_bytes (h) > 0)
872 s = format (s, " -> 0x%wx", p->value[0]);
873
874 return s;
875}
876
Dave Barachc3799992016-08-15 11:12:27 -0400877uword
878mem_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700879{
Dave Barachc3799992016-08-15 11:12:27 -0400880 uword *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881 return hash_memory (v, h->user, 0);
882}
883
Dave Barachc3799992016-08-15 11:12:27 -0400884uword
885mem_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886{
Dave Barachc3799992016-08-15 11:12:27 -0400887 void *v1 = uword_to_pointer (key1, void *);
888 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 return v1 && v2 && 0 == memcmp (v1, v2, h->user);
890}
891
Dave Barachc3799992016-08-15 11:12:27 -0400892uword
893string_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894{
Dave Barachc3799992016-08-15 11:12:27 -0400895 char *v = uword_to_pointer (key, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 return hash_memory (v, strlen (v), 0);
897}
898
Dave Barachc3799992016-08-15 11:12:27 -0400899uword
900string_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700901{
Dave Barachc3799992016-08-15 11:12:27 -0400902 void *v1 = uword_to_pointer (key1, void *);
903 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904 return v1 && v2 && 0 == strcmp (v1, v2);
905}
906
Dave Barachc3799992016-08-15 11:12:27 -0400907u8 *
908string_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700909{
Dave Barachc3799992016-08-15 11:12:27 -0400910 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
911 void *v = va_arg (*args, void *);
912 hash_pair_t *p = va_arg (*args, hash_pair_t *);
913 hash_t *h = hash_header (v);
914 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915
916 s = format (s, "%s", u);
917
918 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400919 s =
920 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
921 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700922
923 return s;
924}
925
Dave Barachc3799992016-08-15 11:12:27 -0400926static u8 *
927hash_format_pair_default (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700928{
Dave Barachc3799992016-08-15 11:12:27 -0400929 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
930 void *v = va_arg (*args, void *);
931 hash_pair_t *p = va_arg (*args, hash_pair_t *);
932 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933
934 s = format (s, "0x%08x", p->key);
935 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400936 s =
937 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
938 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 return s;
940}
941
Dave Barachc3799992016-08-15 11:12:27 -0400942uword
943hash_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944{
945 uword i, bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400946 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947
Dave Barachc3799992016-08-15 11:12:27 -0400948 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949 return 0;
950
951 bytes = vec_capacity (v, hash_header_bytes (v));
952
953 for (i = 0; i < hash_capacity (v); i++)
954 {
Dave Barachc3799992016-08-15 11:12:27 -0400955 if (!hash_is_user (v, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956 {
Dave Barachc3799992016-08-15 11:12:27 -0400957 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958 if (h->log2_pair_size > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400959 bytes += 1 << indirect_pair_get_log2_bytes (&p->indirect);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960 else
961 bytes += vec_capacity (p->indirect.pairs, 0);
962 }
963 }
964 return bytes;
965}
966
Dave Barachc3799992016-08-15 11:12:27 -0400967u8 *
968format_hash (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969{
Dave Barachc3799992016-08-15 11:12:27 -0400970 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 int verbose = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -0400972 hash_pair_t *p;
973 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 uword i;
975
976 s = format (s, "hash %p, %wd elts, capacity %wd, %wd bytes used,\n",
Dave Barachc3799992016-08-15 11:12:27 -0400977 v, hash_elts (v), hash_capacity (v), hash_bytes (v));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978
979 {
Dave Barachc3799992016-08-15 11:12:27 -0400980 uword *occupancy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981
982 /* Count number of buckets with each occupancy. */
983 for (i = 0; i < hash_capacity (v); i++)
984 {
985 uword j;
986
987 if (hash_is_user (v, i))
988 {
989 j = 1;
990 }
991 else
992 {
Dave Barachc3799992016-08-15 11:12:27 -0400993 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994 if (h->log2_pair_size > 0)
995 j = indirect_pair_get_len (&p->indirect);
996 else
997 j = vec_len (p->indirect.pairs);
998 }
999
1000 vec_validate (occupancy, j);
1001 occupancy[j]++;
1002 }
1003
1004 s = format (s, " profile ");
1005 for (i = 0; i < vec_len (occupancy); i++)
1006 s = format (s, "%wd%c", occupancy[i],
1007 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1008
1009 s = format (s, " lookup # of compares: ");
1010 for (i = 1; i < vec_len (occupancy); i++)
1011 s = format (s, "%wd: .%03d%c", i,
1012 (1000 * i * occupancy[i]) / hash_elts (v),
1013 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1014
1015 vec_free (occupancy);
1016 }
1017
1018 if (verbose)
1019 {
Dave Barachc3799992016-08-15 11:12:27 -04001020 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 hash_foreach_pair (p, v, {
1022 s = format (s, " %U\n", h->format_pair, h->format_pair_arg, v, p);
1023 });
Dave Barachc3799992016-08-15 11:12:27 -04001024 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025 }
1026
1027 return s;
1028}
1029
1030static uword
1031unformat_hash_string_internal (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -04001032 va_list * va, int is_vec)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033{
Dave Barachc3799992016-08-15 11:12:27 -04001034 uword *hash = va_arg (*va, uword *);
1035 int *result = va_arg (*va, int *);
1036 u8 *string = 0;
1037 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038
Dave Barachc3799992016-08-15 11:12:27 -04001039 if (!unformat (input, is_vec ? "%v%_" : "%s%_", &string))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040 return 0;
1041
1042 p = hash_get_mem (hash, string);
1043 if (p)
1044 *result = *p;
1045
1046 vec_free (string);
1047 return p ? 1 : 0;
1048}
1049
1050uword
1051unformat_hash_vec_string (unformat_input_t * input, va_list * va)
Dave Barachc3799992016-08-15 11:12:27 -04001052{
1053 return unformat_hash_string_internal (input, va, /* is_vec */ 1);
1054}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055
1056uword
1057unformat_hash_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058{
Dave Barachc3799992016-08-15 11:12:27 -04001059 return unformat_hash_string_internal (input, va, /* is_vec */ 0);
1060}
1061
1062clib_error_t *
1063hash_validate (void *v)
1064{
1065 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066 uword i, j;
Dave Barachc3799992016-08-15 11:12:27 -04001067 uword *keys = 0;
1068 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069
1070#define CHECK(x) if ((error = ERROR_ASSERT (x))) goto done;
1071
1072 for (i = 0; i < hash_capacity (v); i++)
1073 {
Dave Barachc3799992016-08-15 11:12:27 -04001074 hash_pair_union_t *pu = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075
1076 if (hash_is_user (v, i))
1077 {
1078 CHECK (pu->direct.key != 0);
1079 vec_add1 (keys, pu->direct.key);
1080 }
1081 else
1082 {
Dave Barachc3799992016-08-15 11:12:27 -04001083 hash_pair_t *p;
1084 hash_pair_indirect_t *pi = &pu->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 uword n;
1086
1087 n = h->log2_pair_size > 0
Dave Barachc3799992016-08-15 11:12:27 -04001088 ? indirect_pair_get_len (pi) : vec_len (pi->pairs);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
1090 for (p = pi->pairs; n-- > 0; p = hash_forward1 (h, p))
1091 {
1092 /* Assert key uniqueness. */
1093 for (j = 0; j < vec_len (keys); j++)
1094 CHECK (keys[j] != p->key);
1095 vec_add1 (keys, p->key);
1096 }
1097 }
1098 }
1099
1100 CHECK (vec_len (keys) == h->elts);
1101
1102 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -04001103done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104 return error;
1105}
Dave Barachc3799992016-08-15 11:12:27 -04001106
1107/*
1108 * fd.io coding-style-patch-verification: ON
1109 *
1110 * Local Variables:
1111 * eval: (c-set-style "gnu")
1112 * End:
1113 */