blob: 79103b6d3f48eb0826bff64d782e164600e69040 [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
285 default:
286 sum = h->key_sum (h, key);
287 break;
288 }
289
290 return sum;
291}
292
Dave Barachc3799992016-08-15 11:12:27 -0400293always_inline uword
294key_equal1 (hash_t * h, uword key1, uword key2, uword e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295{
296 switch (pointer_to_uword ((void *) h->key_equal))
297 {
298 case KEY_FUNC_NONE:
299 break;
300
301 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400302 e =
303 *uword_to_pointer (key1, uword *) == *uword_to_pointer (key2,
304 uword *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305 break;
306
307 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400308 e = *uword_to_pointer (key1, u32 *) == *uword_to_pointer (key2, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309 break;
310
311 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400312 e = string_key_equal (h, key1, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313 break;
314
315 default:
316 e = h->key_equal (h, key1, key2);
317 break;
318 }
319 return e;
320}
321
322/* Compares two keys: returns 1 if equal, 0 if not. */
Dave Barachc3799992016-08-15 11:12:27 -0400323always_inline uword
324key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325{
326 uword e = key1 == key2;
327 if (CLIB_DEBUG > 0 && key1 == key2)
328 ASSERT (key_equal1 (h, key1, key2, e));
Dave Barachc3799992016-08-15 11:12:27 -0400329 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 e = key_equal1 (h, key1, key2, e);
331 return e;
332}
333
334static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400335get_indirect (void *v, hash_pair_indirect_t * pi, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700336{
Dave Barachc3799992016-08-15 11:12:27 -0400337 hash_t *h = hash_header (v);
338 hash_pair_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
340 p0 = p1 = pi->pairs;
341 if (h->log2_pair_size > 0)
342 p1 = hash_forward (h, p0, indirect_pair_get_len (pi));
343 else
344 p1 += vec_len (p0);
345
346 while (p0 < p1)
347 {
348 if (key_equal (h, p0->key, key))
349 return (hash_pair_union_t *) p0;
350 p0 = hash_forward1 (h, p0);
351 }
352
353 return (hash_pair_union_t *) 0;
354}
355
356static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400357set_indirect_is_user (void *v, uword i, hash_pair_union_t * p, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358{
Dave Barachc3799992016-08-15 11:12:27 -0400359 hash_t *h = hash_header (v);
360 hash_pair_t *q;
361 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 uword log2_bytes = 0;
363
364 if (h->log2_pair_size == 0)
365 q = vec_new (hash_pair_t, 2);
366 else
367 {
368 log2_bytes = 1 + hash_pair_log2_bytes (h);
Dave Barach6f6f34f2016-08-08 13:05:31 -0400369 q = clib_mem_alloc (1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370 }
Damjan Marionf1213b82016-03-13 02:22:06 +0100371 clib_memcpy (q, &p->direct, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372
373 pi->pairs = q;
374 if (h->log2_pair_size > 0)
375 indirect_pair_set (pi, log2_bytes, 2);
376
377 set_is_user (v, i, 0);
378
379 /* First element is used by existing pair, second will be used by caller. */
380 q = hash_forward1 (h, q);
381 q->key = key;
382 init_pair (h, q);
383 return (hash_pair_union_t *) q;
384}
385
386static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400387set_indirect (void *v, hash_pair_indirect_t * pi, uword key,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 uword * found_key)
389{
Dave Barachc3799992016-08-15 11:12:27 -0400390 hash_t *h = hash_header (v);
391 hash_pair_t *new_pair;
392 hash_pair_union_t *q;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393
394 q = get_indirect (v, pi, key);
395 if (q)
396 {
397 *found_key = 1;
398 return q;
399 }
400
401 if (h->log2_pair_size == 0)
402 vec_add2 (pi->pairs, new_pair, 1);
403 else
404 {
405 uword len, new_len, log2_bytes;
406
407 len = indirect_pair_get_len (pi);
408 log2_bytes = indirect_pair_get_log2_bytes (pi);
409
410 new_len = len + 1;
Dave Barach6f6f34f2016-08-08 13:05:31 -0400411 if (new_len * hash_pair_bytes (h) > (1ULL << log2_bytes))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 {
413 pi->pairs = clib_mem_realloc (pi->pairs,
Dave Barachdd522cb2016-08-10 16:56:16 -0400414 1ULL << (log2_bytes + 1),
415 1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416 log2_bytes++;
417 }
418
419 indirect_pair_set (pi, log2_bytes, new_len);
420 new_pair = pi->pairs + (len << h->log2_pair_size);
421 }
422 new_pair->key = key;
423 init_pair (h, new_pair);
424 *found_key = 0;
425 return (hash_pair_union_t *) new_pair;
426}
427
Dave Barachc3799992016-08-15 11:12:27 -0400428static void
429unset_indirect (void *v, uword i, hash_pair_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430{
Dave Barachc3799992016-08-15 11:12:27 -0400431 hash_t *h = hash_header (v);
432 hash_pair_union_t *p = get_pair (v, i);
433 hash_pair_t *e;
434 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435 uword len, is_vec;
436
437 is_vec = h->log2_pair_size == 0;
438
Dave Barachc3799992016-08-15 11:12:27 -0400439 ASSERT (!hash_is_user (v, i));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700440 len = is_vec ? vec_len (pi->pairs) : indirect_pair_get_len (pi);
441 e = hash_forward (h, pi->pairs, len - 1);
442 ASSERT (q >= pi->pairs && q <= e);
443
444 /* We have two or fewer pairs and we are delete one pair.
445 Make indirect pointer direct and free indirect memory. */
446 if (len <= 2)
447 {
Dave Barachc3799992016-08-15 11:12:27 -0400448 hash_pair_t *r = pi->pairs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449
450 if (len == 2)
451 {
Dave Barachc3799992016-08-15 11:12:27 -0400452 clib_memcpy (p, q == r ? hash_forward1 (h, r) : r,
453 hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454 set_is_user (v, i, 1);
455 }
456 else
457 zero_pair (h, &p->direct);
458
459 if (is_vec)
460 vec_free (r);
461 else if (r)
462 clib_mem_free (r);
463 }
464 else
465 {
466 /* If deleting a pair we need to keep non-null pairs together. */
467 if (q < e)
Damjan Marionf1213b82016-03-13 02:22:06 +0100468 clib_memcpy (q, e, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 else
470 zero_pair (h, q);
471 if (is_vec)
472 _vec_len (pi->pairs) -= 1;
473 else
Dave Barachc3799992016-08-15 11:12:27 -0400474 indirect_pair_set (pi, indirect_pair_get_log2_bytes (pi), len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475 }
476}
477
Dave Barachc3799992016-08-15 11:12:27 -0400478enum lookup_opcode
479{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480 GET = 1,
481 SET = 2,
482 UNSET = 3,
483};
484
Dave Barachc3799992016-08-15 11:12:27 -0400485static hash_pair_t *
486lookup (void *v, uword key, enum lookup_opcode op,
487 void *new_value, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488{
Dave Barachc3799992016-08-15 11:12:27 -0400489 hash_t *h = hash_header (v);
490 hash_pair_union_t *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 uword found_key = 0;
492 uword i;
493
Dave Barachc3799992016-08-15 11:12:27 -0400494 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495 return 0;
496
497 i = key_sum (h, key) & (_vec_len (v) - 1);
498 p = get_pair (v, i);
499
500 if (hash_is_user (v, i))
501 {
502 found_key = key_equal (h, p->direct.key, key);
503 if (found_key)
504 {
505 if (op == UNSET)
506 {
507 set_is_user (v, i, 0);
508 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400509 clib_memcpy (old_value, p->direct.value,
510 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511 zero_pair (h, &p->direct);
512 }
513 }
514 else
515 {
516 if (op == SET)
517 p = set_indirect_is_user (v, i, p, key);
518 else
519 p = 0;
520 }
521 }
522 else
523 {
Dave Barachc3799992016-08-15 11:12:27 -0400524 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525
526 if (op == SET)
527 {
Dave Barachc3799992016-08-15 11:12:27 -0400528 if (!pi->pairs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 {
530 p->direct.key = key;
531 set_is_user (v, i, 1);
532 }
533 else
534 p = set_indirect (v, pi, key, &found_key);
535 }
536 else
537 {
538 p = get_indirect (v, pi, key);
539 found_key = p != 0;
540 if (found_key && op == UNSET)
541 {
542 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400543 clib_memcpy (old_value, &p->direct.value,
544 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545
546 unset_indirect (v, i, &p->direct);
547
548 /* Nullify p (since it's just been deleted).
Dave Barachc3799992016-08-15 11:12:27 -0400549 Otherwise we might be tempted to play with it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550 p = 0;
551 }
552 }
553 }
554
555 if (op == SET && p != 0)
556 {
557 /* Save away old value for caller. */
558 if (old_value && found_key)
Damjan Marionf1213b82016-03-13 02:22:06 +0100559 clib_memcpy (old_value, &p->direct.value, hash_value_bytes (h));
560 clib_memcpy (&p->direct.value, new_value, hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561 }
562
563 if (op == SET)
564 h->elts += !found_key;
565 if (op == UNSET)
566 h->elts -= found_key;
567
568 return &p->direct;
569}
570
571/* Fetch value of key. */
Dave Barachc3799992016-08-15 11:12:27 -0400572uword *
573_hash_get (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700574{
Dave Barachc3799992016-08-15 11:12:27 -0400575 hash_t *h = hash_header (v);
576 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577
578 /* Don't even search table if its empty. */
Dave Barachc3799992016-08-15 11:12:27 -0400579 if (!v || h->elts == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580 return 0;
581
582 p = lookup (v, key, GET, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400583 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584 return 0;
585 if (h->log2_pair_size == 0)
586 return &p->key;
587 else
588 return &p->value[0];
589}
590
Dave Barachc3799992016-08-15 11:12:27 -0400591hash_pair_t *
592_hash_get_pair (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700593{
Dave Barachc3799992016-08-15 11:12:27 -0400594 return lookup (v, key, GET, 0, 0);
595}
596
597hash_pair_t *
598hash_next (void *v, hash_next_t * hn)
599{
600 hash_t *h = hash_header (v);
601 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602
603 while (1)
604 {
605 if (hn->i == 0 && hn->j == 0)
606 {
607 /* Save flags. */
608 hn->f = h->flags;
609
610 /* Prevent others from re-sizing hash table. */
611 h->flags |=
Dave Barachc3799992016-08-15 11:12:27 -0400612 (HASH_FLAG_NO_AUTO_GROW
613 | HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_HASH_NEXT_IN_PROGRESS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614 }
615 else if (hn->i >= hash_capacity (v))
616 {
617 /* Restore flags. */
618 h->flags = hn->f;
619 memset (hn, 0, sizeof (hn[0]));
620 return 0;
621 }
622
623 p = hash_forward (h, v, hn->i);
624 if (hash_is_user (v, hn->i))
625 {
626 hn->i++;
627 return p;
628 }
629 else
630 {
Dave Barachc3799992016-08-15 11:12:27 -0400631 hash_pair_indirect_t *pi = (void *) p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 uword n;
633
634 if (h->log2_pair_size > 0)
635 n = indirect_pair_get_len (pi);
636 else
637 n = vec_len (pi->pairs);
638
639 if (hn->j >= n)
640 {
641 hn->i++;
642 hn->j = 0;
643 }
644 else
645 return hash_forward (h, pi->pairs, hn->j++);
646 }
647 }
648}
649
650/* Remove key from table. */
Dave Barachc3799992016-08-15 11:12:27 -0400651void *
652_hash_unset (void *v, uword key, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653{
Dave Barachc3799992016-08-15 11:12:27 -0400654 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655
Dave Barachc3799992016-08-15 11:12:27 -0400656 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657 return v;
658
659 (void) lookup (v, key, UNSET, 0, old_value);
660
661 h = hash_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400662 if (!(h->flags & HASH_FLAG_NO_AUTO_SHRINK))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663 {
664 /* Resize when 1/4 full. */
665 if (h->elts > 32 && 4 * (h->elts + 1) < vec_len (v))
666 v = hash_resize (v, vec_len (v) / 2);
667 }
668
669 return v;
670}
671
Dave Barachc3799992016-08-15 11:12:27 -0400672void *
673_hash_create (uword elts, hash_t * h_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674{
Dave Barachc3799992016-08-15 11:12:27 -0400675 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 uword log2_pair_size;
Dave Barachc3799992016-08-15 11:12:27 -0400677 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700678
679 /* Size of hash is power of 2 >= ELTS and larger than
680 number of bits in is_user bitmap elements. */
681 elts = clib_max (elts, BITS (h->is_user[0]));
Dave Barach6f6f34f2016-08-08 13:05:31 -0400682 elts = 1ULL << max_log2 (elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683
684 log2_pair_size = 1;
685 if (h_user)
686 log2_pair_size = h_user->log2_pair_size;
687
Damjan Marion2f25ef32018-05-04 20:45:41 +0200688 v = _vec_resize ((void *) 0,
Dave Barachc3799992016-08-15 11:12:27 -0400689 /* vec len: */ elts,
690 /* data bytes: */
691 (elts << log2_pair_size) * sizeof (hash_pair_t),
692 /* header bytes: */
693 sizeof (h[0]) +
694 (elts / BITS (h->is_user[0])) * sizeof (h->is_user[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 /* alignment */ sizeof (hash_pair_t));
696 h = hash_header (v);
697
698 if (h_user)
699 h[0] = h_user[0];
700
701 h->log2_pair_size = log2_pair_size;
702 h->elts = 0;
703
704 /* Default flags to never shrinking hash tables.
705 Shrinking tables can cause "jackpot" cases. */
Dave Barachc3799992016-08-15 11:12:27 -0400706 if (!h_user)
707 h->flags = HASH_FLAG_NO_AUTO_SHRINK;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708
Dave Barachc3799992016-08-15 11:12:27 -0400709 if (!h->format_pair)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710 {
711 h->format_pair = hash_format_pair_default;
712 h->format_pair_arg = 0;
713 }
714
715 return v;
716}
717
Dave Barachc3799992016-08-15 11:12:27 -0400718void *
719_hash_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720{
Dave Barachc3799992016-08-15 11:12:27 -0400721 hash_t *h = hash_header (v);
722 hash_pair_union_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723 uword i;
724
Dave Barachc3799992016-08-15 11:12:27 -0400725 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 return v;
727
728 /* We zero all freed memory in case user would be tempted to use it. */
729 for (i = 0; i < hash_capacity (v); i++)
730 {
731 if (hash_is_user (v, i))
732 continue;
733 p = get_pair (v, i);
734 if (h->log2_pair_size == 0)
735 vec_free (p->indirect.pairs);
736 else if (p->indirect.pairs)
737 clib_mem_free (p->indirect.pairs);
738 }
739
740 vec_free_header (h);
741
742 return 0;
743}
744
Dave Barachc3799992016-08-15 11:12:27 -0400745static void *
746hash_resize_internal (void *old, uword new_size, uword free_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747{
Dave Barachc3799992016-08-15 11:12:27 -0400748 void *new;
749 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750
751 new = 0;
752 if (new_size > 0)
753 {
Dave Barachc3799992016-08-15 11:12:27 -0400754 hash_t *h = old ? hash_header (old) : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755 new = _hash_create (new_size, h);
Dave Barachc3799992016-08-15 11:12:27 -0400756 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757 hash_foreach_pair (p, old, {
758 new = _hash_set3 (new, p->key, &p->value[0], 0);
759 });
Dave Barachc3799992016-08-15 11:12:27 -0400760 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700761 }
762
763 if (free_old)
764 hash_free (old);
765 return new;
766}
767
Dave Barachc3799992016-08-15 11:12:27 -0400768void *
769hash_resize (void *old, uword new_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700770{
Dave Barachc3799992016-08-15 11:12:27 -0400771 return hash_resize_internal (old, new_size, 1);
772}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773
Dave Barachc3799992016-08-15 11:12:27 -0400774void *
775hash_dup (void *old)
776{
777 return hash_resize_internal (old, vec_len (old), 0);
778}
779
780void *
781_hash_set3 (void *v, uword key, void *value, void *old_value)
782{
783 hash_t *h;
784
785 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 v = hash_create (0, sizeof (uword));
787
788 h = hash_header (v);
789 (void) lookup (v, key, SET, value, old_value);
790
Dave Barachc3799992016-08-15 11:12:27 -0400791 if (!(h->flags & HASH_FLAG_NO_AUTO_GROW))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792 {
793 /* Resize when 3/4 full. */
794 if (4 * (h->elts + 1) > 3 * vec_len (v))
795 v = hash_resize (v, 2 * vec_len (v));
796 }
797
798 return v;
799}
800
Dave Barachc3799992016-08-15 11:12:27 -0400801uword
802vec_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803{
Dave Barachc3799992016-08-15 11:12:27 -0400804 void *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805 return hash_memory (v, vec_len (v) * h->user, 0);
806}
807
Dave Barachc3799992016-08-15 11:12:27 -0400808uword
809vec_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810{
Dave Barachc3799992016-08-15 11:12:27 -0400811 void *v1 = uword_to_pointer (key1, void *);
812 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 uword l1 = vec_len (v1);
814 uword l2 = vec_len (v2);
815 return l1 == l2 && 0 == memcmp (v1, v2, l1 * h->user);
816}
817
Dave Barachc3799992016-08-15 11:12:27 -0400818u8 *
819vec_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820{
Dave Barachc3799992016-08-15 11:12:27 -0400821 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
822 void *v = va_arg (*args, void *);
823 hash_pair_t *p = va_arg (*args, hash_pair_t *);
824 hash_t *h = hash_header (v);
825 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826 int i;
827
Dave Barachc3799992016-08-15 11:12:27 -0400828 switch (h->user)
829 {
830 case 1:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700831 s = format (s, "%v", u);
832 break;
833
Dave Barachc3799992016-08-15 11:12:27 -0400834 case 2:
835 {
836 u16 *w = u;
837 for (i = 0; i < vec_len (w); i++)
838 s = format (s, "0x%x, ", w[i]);
839 break;
840 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841
Dave Barachc3799992016-08-15 11:12:27 -0400842 case 4:
843 {
844 u32 *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 8:
851 {
852 u64 *w = u;
853 for (i = 0; i < vec_len (w); i++)
854 s = format (s, "0x%Lx, ", w[i]);
855 break;
856 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857
Dave Barachc3799992016-08-15 11:12:27 -0400858 default:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859 s = format (s, "0x%U", format_hex_bytes, u, vec_len (u) * h->user);
860 break;
Dave Barachc3799992016-08-15 11:12:27 -0400861 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862
863 if (hash_value_bytes (h) > 0)
864 s = format (s, " -> 0x%wx", p->value[0]);
865
866 return s;
867}
868
Dave Barachc3799992016-08-15 11:12:27 -0400869uword
870mem_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700871{
Dave Barachc3799992016-08-15 11:12:27 -0400872 uword *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873 return hash_memory (v, h->user, 0);
874}
875
Dave Barachc3799992016-08-15 11:12:27 -0400876uword
877mem_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700878{
Dave Barachc3799992016-08-15 11:12:27 -0400879 void *v1 = uword_to_pointer (key1, void *);
880 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881 return v1 && v2 && 0 == memcmp (v1, v2, h->user);
882}
883
Dave Barachc3799992016-08-15 11:12:27 -0400884uword
885string_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886{
Dave Barachc3799992016-08-15 11:12:27 -0400887 char *v = uword_to_pointer (key, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888 return hash_memory (v, strlen (v), 0);
889}
890
Dave Barachc3799992016-08-15 11:12:27 -0400891uword
892string_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893{
Dave Barachc3799992016-08-15 11:12:27 -0400894 void *v1 = uword_to_pointer (key1, void *);
895 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 return v1 && v2 && 0 == strcmp (v1, v2);
897}
898
Dave Barachc3799992016-08-15 11:12:27 -0400899u8 *
900string_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700901{
Dave Barachc3799992016-08-15 11:12:27 -0400902 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
903 void *v = va_arg (*args, void *);
904 hash_pair_t *p = va_arg (*args, hash_pair_t *);
905 hash_t *h = hash_header (v);
906 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907
908 s = format (s, "%s", u);
909
910 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400911 s =
912 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
913 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914
915 return s;
916}
917
Dave Barachc3799992016-08-15 11:12:27 -0400918static u8 *
919hash_format_pair_default (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920{
Dave Barachc3799992016-08-15 11:12:27 -0400921 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
922 void *v = va_arg (*args, void *);
923 hash_pair_t *p = va_arg (*args, hash_pair_t *);
924 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700925
926 s = format (s, "0x%08x", p->key);
927 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400928 s =
929 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
930 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 return s;
932}
933
Dave Barachc3799992016-08-15 11:12:27 -0400934uword
935hash_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936{
937 uword i, bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400938 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939
Dave Barachc3799992016-08-15 11:12:27 -0400940 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941 return 0;
942
943 bytes = vec_capacity (v, hash_header_bytes (v));
944
945 for (i = 0; i < hash_capacity (v); i++)
946 {
Dave Barachc3799992016-08-15 11:12:27 -0400947 if (!hash_is_user (v, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948 {
Dave Barachc3799992016-08-15 11:12:27 -0400949 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950 if (h->log2_pair_size > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400951 bytes += 1 << indirect_pair_get_log2_bytes (&p->indirect);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952 else
953 bytes += vec_capacity (p->indirect.pairs, 0);
954 }
955 }
956 return bytes;
957}
958
Dave Barachc3799992016-08-15 11:12:27 -0400959u8 *
960format_hash (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961{
Dave Barachc3799992016-08-15 11:12:27 -0400962 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 int verbose = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -0400964 hash_pair_t *p;
965 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966 uword i;
967
968 s = format (s, "hash %p, %wd elts, capacity %wd, %wd bytes used,\n",
Dave Barachc3799992016-08-15 11:12:27 -0400969 v, hash_elts (v), hash_capacity (v), hash_bytes (v));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970
971 {
Dave Barachc3799992016-08-15 11:12:27 -0400972 uword *occupancy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973
974 /* Count number of buckets with each occupancy. */
975 for (i = 0; i < hash_capacity (v); i++)
976 {
977 uword j;
978
979 if (hash_is_user (v, i))
980 {
981 j = 1;
982 }
983 else
984 {
Dave Barachc3799992016-08-15 11:12:27 -0400985 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986 if (h->log2_pair_size > 0)
987 j = indirect_pair_get_len (&p->indirect);
988 else
989 j = vec_len (p->indirect.pairs);
990 }
991
992 vec_validate (occupancy, j);
993 occupancy[j]++;
994 }
995
996 s = format (s, " profile ");
997 for (i = 0; i < vec_len (occupancy); i++)
998 s = format (s, "%wd%c", occupancy[i],
999 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1000
1001 s = format (s, " lookup # of compares: ");
1002 for (i = 1; i < vec_len (occupancy); i++)
1003 s = format (s, "%wd: .%03d%c", i,
1004 (1000 * i * occupancy[i]) / hash_elts (v),
1005 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1006
1007 vec_free (occupancy);
1008 }
1009
1010 if (verbose)
1011 {
Dave Barachc3799992016-08-15 11:12:27 -04001012 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 hash_foreach_pair (p, v, {
1014 s = format (s, " %U\n", h->format_pair, h->format_pair_arg, v, p);
1015 });
Dave Barachc3799992016-08-15 11:12:27 -04001016 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017 }
1018
1019 return s;
1020}
1021
1022static uword
1023unformat_hash_string_internal (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -04001024 va_list * va, int is_vec)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025{
Dave Barachc3799992016-08-15 11:12:27 -04001026 uword *hash = va_arg (*va, uword *);
1027 int *result = va_arg (*va, int *);
1028 u8 *string = 0;
1029 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030
Dave Barachc3799992016-08-15 11:12:27 -04001031 if (!unformat (input, is_vec ? "%v%_" : "%s%_", &string))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032 return 0;
1033
1034 p = hash_get_mem (hash, string);
1035 if (p)
1036 *result = *p;
1037
1038 vec_free (string);
1039 return p ? 1 : 0;
1040}
1041
1042uword
1043unformat_hash_vec_string (unformat_input_t * input, va_list * va)
Dave Barachc3799992016-08-15 11:12:27 -04001044{
1045 return unformat_hash_string_internal (input, va, /* is_vec */ 1);
1046}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047
1048uword
1049unformat_hash_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050{
Dave Barachc3799992016-08-15 11:12:27 -04001051 return unformat_hash_string_internal (input, va, /* is_vec */ 0);
1052}
1053
1054clib_error_t *
1055hash_validate (void *v)
1056{
1057 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058 uword i, j;
Dave Barachc3799992016-08-15 11:12:27 -04001059 uword *keys = 0;
1060 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061
1062#define CHECK(x) if ((error = ERROR_ASSERT (x))) goto done;
1063
1064 for (i = 0; i < hash_capacity (v); i++)
1065 {
Dave Barachc3799992016-08-15 11:12:27 -04001066 hash_pair_union_t *pu = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067
1068 if (hash_is_user (v, i))
1069 {
1070 CHECK (pu->direct.key != 0);
1071 vec_add1 (keys, pu->direct.key);
1072 }
1073 else
1074 {
Dave Barachc3799992016-08-15 11:12:27 -04001075 hash_pair_t *p;
1076 hash_pair_indirect_t *pi = &pu->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 uword n;
1078
1079 n = h->log2_pair_size > 0
Dave Barachc3799992016-08-15 11:12:27 -04001080 ? indirect_pair_get_len (pi) : vec_len (pi->pairs);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081
1082 for (p = pi->pairs; n-- > 0; p = hash_forward1 (h, p))
1083 {
1084 /* Assert key uniqueness. */
1085 for (j = 0; j < vec_len (keys); j++)
1086 CHECK (keys[j] != p->key);
1087 vec_add1 (keys, p->key);
1088 }
1089 }
1090 }
1091
1092 CHECK (vec_len (keys) == h->elts);
1093
1094 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -04001095done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 return error;
1097}
Dave Barachc3799992016-08-15 11:12:27 -04001098
1099/*
1100 * fd.io coding-style-patch-verification: ON
1101 *
1102 * Local Variables:
1103 * eval: (c-set-style "gnu")
1104 * End:
1105 */