blob: c7774bb87ef9b4625733e26d00c571e7f4173512 [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))
BenoƮt Ganne96856242021-09-08 15:36:56 +0200156 {
157 CLIB_MEM_OVERFLOW_PUSH (q + 2, sizeof (u64));
158 c += zap64 (clib_mem_unaligned (q + 2, u64), n % sizeof (u64))
159 << 8;
160 CLIB_MEM_OVERFLOW_POP ();
161 }
Dave Barach7e2cea32019-10-09 12:57:13 -0400162 else
163 {
164 clib_memcpy_fast (tmp.as_u8, q + 2, n % sizeof (u64));
165 c += zap64 (tmp.as_u64, n % sizeof (u64)) << 8;
166 }
167 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168 break;
169
170 case 1:
171 a += clib_mem_unaligned (q + 0, u64);
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100172 if (n % sizeof (u64))
Dave Barach7e2cea32019-10-09 12:57:13 -0400173 {
174 if (PREDICT_TRUE (page_boundary_crossing == 0))
BenoƮt Ganne96856242021-09-08 15:36:56 +0200175 {
176 CLIB_MEM_OVERFLOW_PUSH (q + 1, sizeof (u64));
177 b += zap64 (clib_mem_unaligned (q + 1, u64), n % sizeof (u64));
178 CLIB_MEM_OVERFLOW_POP ();
179 }
Dave Barach7e2cea32019-10-09 12:57:13 -0400180 else
181 {
182 clib_memcpy_fast (tmp.as_u8, q + 1, n % sizeof (u64));
183 b += zap64 (tmp.as_u64, n % sizeof (u64));
184 }
185 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 break;
187
188 case 0:
Gabriel Gannec5c2bb32017-11-03 10:30:45 +0100189 if (n % sizeof (u64))
Dave Barach7e2cea32019-10-09 12:57:13 -0400190 {
191 if (PREDICT_TRUE (page_boundary_crossing == 0))
BenoƮt Ganne96856242021-09-08 15:36:56 +0200192 {
193 CLIB_MEM_OVERFLOW_PUSH (q + 0, sizeof (u64));
194 a += zap64 (clib_mem_unaligned (q + 0, u64), n % sizeof (u64));
195 CLIB_MEM_OVERFLOW_POP ();
196 }
Dave Barach7e2cea32019-10-09 12:57:13 -0400197 else
198 {
199 clib_memcpy_fast (tmp.as_u8, q, n % sizeof (u64));
200 a += zap64 (tmp.as_u64, n % sizeof (u64));
201 }
202 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 break;
204 }
205
206 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400207
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 return c;
209}
210
211#else /* if uword_bits == 64 */
212
Dave Barachc3799992016-08-15 11:12:27 -0400213static inline u32
214zap32 (u32 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215{
216#define _(n) (((u32) 1 << (u32) (8*(n))) - (u32) 1)
217 static u32 masks_little_endian[] = {
218 0, _(1), _(2), _(3),
219 };
220 static u32 masks_big_endian[] = {
221 0, ~_(3), ~_(2), ~_(1),
222 };
223#undef _
224 if (clib_arch_is_big_endian)
225 return x & masks_big_endian[n];
226 else
227 return x & masks_little_endian[n];
228}
229
Dave Barachc3799992016-08-15 11:12:27 -0400230static inline u32
231hash_memory32 (void *p, word n_bytes, u32 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232{
Dave Barachc3799992016-08-15 11:12:27 -0400233 u32 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 u32 a, b, c, n;
235
236 a = b = 0x9e3779b9;
237 c = state;
238 n = n_bytes;
239
Dave Barachc3799992016-08-15 11:12:27 -0400240 while (n >= 3 * sizeof (u32))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 {
242 a += clib_mem_unaligned (q + 0, u32);
243 b += clib_mem_unaligned (q + 1, u32);
244 c += clib_mem_unaligned (q + 2, u32);
245 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400246 n -= 3 * sizeof (u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 q += 3;
248 }
249
250 c += n_bytes;
251 switch (n / sizeof (u32))
252 {
253 case 2:
254 a += clib_mem_unaligned (q + 0, u32);
255 b += clib_mem_unaligned (q + 1, u32);
256 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400257 c += zap32 (clib_mem_unaligned (q + 2, u32), n % sizeof (u32)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258 break;
259
260 case 1:
261 a += clib_mem_unaligned (q + 0, u32);
262 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400263 b += zap32 (clib_mem_unaligned (q + 1, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 break;
265
266 case 0:
267 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400268 a += zap32 (clib_mem_unaligned (q + 0, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 break;
270 }
271
272 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400273
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 return c;
275}
276#endif
277
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200278__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400279hash_memory (void *p, word n_bytes, uword state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280{
Dave Barachc3799992016-08-15 11:12:27 -0400281 uword *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282
283#if uword_bits == 64
284 return hash_memory64 (q, n_bytes, state);
285#else
286 return hash_memory32 (q, n_bytes, state);
287#endif
288}
289
290#if uword_bits == 64
Dave Barachc3799992016-08-15 11:12:27 -0400291always_inline uword
292hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293{
294 u64 a, b, c;
295
296 a = b = 0x9e3779b97f4a7c13LL;
297 c = 0;
298 a += x;
299 hash_mix64 (a, b, c);
300 return c;
301}
302#else
Dave Barachc3799992016-08-15 11:12:27 -0400303always_inline uword
304hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305{
306 u32 a, b, c;
307
308 a = b = 0x9e3779b9;
309 c = 0;
310 a += x;
311 hash_mix32 (a, b, c);
312 return c;
313}
314#endif
315
316/* Call sum function. Hash code will be sum function value
317 modulo the prime length of the hash table. */
Dave Barachc3799992016-08-15 11:12:27 -0400318always_inline uword
319key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320{
321 uword sum;
322 switch (pointer_to_uword ((void *) h->key_sum))
323 {
324 case KEY_FUNC_NONE:
325 sum = hash_uword (key);
326 break;
327
328 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400329 sum = hash_uword (*uword_to_pointer (key, uword *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 break;
331
332 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400333 sum = hash_uword (*uword_to_pointer (key, u32 *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 break;
335
336 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400337 sum = string_key_sum (h, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 break;
339
Ole Troan73710c72018-06-04 22:27:49 +0200340 case KEY_FUNC_MEM:
341 sum = mem_key_sum (h, key);
342 break;
343
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344 default:
345 sum = h->key_sum (h, key);
346 break;
347 }
348
349 return sum;
350}
351
Dave Barachc3799992016-08-15 11:12:27 -0400352always_inline uword
353key_equal1 (hash_t * h, uword key1, uword key2, uword e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354{
355 switch (pointer_to_uword ((void *) h->key_equal))
356 {
357 case KEY_FUNC_NONE:
358 break;
359
360 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400361 e =
362 *uword_to_pointer (key1, uword *) == *uword_to_pointer (key2,
363 uword *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 break;
365
366 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400367 e = *uword_to_pointer (key1, u32 *) == *uword_to_pointer (key2, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 break;
369
370 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400371 e = string_key_equal (h, key1, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 break;
373
Ole Troan73710c72018-06-04 22:27:49 +0200374 case KEY_FUNC_MEM:
375 e = mem_key_equal (h, key1, key2);
376 break;
377
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 default:
379 e = h->key_equal (h, key1, key2);
380 break;
381 }
382 return e;
383}
384
385/* Compares two keys: returns 1 if equal, 0 if not. */
Dave Barachc3799992016-08-15 11:12:27 -0400386always_inline uword
387key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388{
389 uword e = key1 == key2;
390 if (CLIB_DEBUG > 0 && key1 == key2)
391 ASSERT (key_equal1 (h, key1, key2, e));
Dave Barachc3799992016-08-15 11:12:27 -0400392 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 e = key_equal1 (h, key1, key2, e);
394 return e;
395}
396
397static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400398get_indirect (void *v, hash_pair_indirect_t * pi, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399{
Dave Barachc3799992016-08-15 11:12:27 -0400400 hash_t *h = hash_header (v);
401 hash_pair_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
403 p0 = p1 = pi->pairs;
404 if (h->log2_pair_size > 0)
405 p1 = hash_forward (h, p0, indirect_pair_get_len (pi));
406 else
407 p1 += vec_len (p0);
408
409 while (p0 < p1)
410 {
411 if (key_equal (h, p0->key, key))
412 return (hash_pair_union_t *) p0;
413 p0 = hash_forward1 (h, p0);
414 }
415
416 return (hash_pair_union_t *) 0;
417}
418
419static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400420set_indirect_is_user (void *v, uword i, hash_pair_union_t * p, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421{
Dave Barachc3799992016-08-15 11:12:27 -0400422 hash_t *h = hash_header (v);
423 hash_pair_t *q;
424 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425 uword log2_bytes = 0;
426
427 if (h->log2_pair_size == 0)
428 q = vec_new (hash_pair_t, 2);
429 else
430 {
431 log2_bytes = 1 + hash_pair_log2_bytes (h);
Dave Barach6f6f34f2016-08-08 13:05:31 -0400432 q = clib_mem_alloc (1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433 }
Dave Barach178cf492018-11-13 16:34:13 -0500434 clib_memcpy_fast (q, &p->direct, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
436 pi->pairs = q;
437 if (h->log2_pair_size > 0)
438 indirect_pair_set (pi, log2_bytes, 2);
439
440 set_is_user (v, i, 0);
441
442 /* First element is used by existing pair, second will be used by caller. */
443 q = hash_forward1 (h, q);
444 q->key = key;
445 init_pair (h, q);
446 return (hash_pair_union_t *) q;
447}
448
449static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400450set_indirect (void *v, hash_pair_indirect_t * pi, uword key,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451 uword * found_key)
452{
Dave Barachc3799992016-08-15 11:12:27 -0400453 hash_t *h = hash_header (v);
454 hash_pair_t *new_pair;
455 hash_pair_union_t *q;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456
457 q = get_indirect (v, pi, key);
458 if (q)
459 {
460 *found_key = 1;
461 return q;
462 }
463
464 if (h->log2_pair_size == 0)
465 vec_add2 (pi->pairs, new_pair, 1);
466 else
467 {
468 uword len, new_len, log2_bytes;
469
470 len = indirect_pair_get_len (pi);
471 log2_bytes = indirect_pair_get_log2_bytes (pi);
472
473 new_len = len + 1;
Dave Barach6f6f34f2016-08-08 13:05:31 -0400474 if (new_len * hash_pair_bytes (h) > (1ULL << log2_bytes))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475 {
476 pi->pairs = clib_mem_realloc (pi->pairs,
Dave Barachdd522cb2016-08-10 16:56:16 -0400477 1ULL << (log2_bytes + 1),
478 1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700479 log2_bytes++;
480 }
481
482 indirect_pair_set (pi, log2_bytes, new_len);
483 new_pair = pi->pairs + (len << h->log2_pair_size);
484 }
485 new_pair->key = key;
486 init_pair (h, new_pair);
487 *found_key = 0;
488 return (hash_pair_union_t *) new_pair;
489}
490
Dave Barachc3799992016-08-15 11:12:27 -0400491static void
492unset_indirect (void *v, uword i, hash_pair_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493{
Dave Barachc3799992016-08-15 11:12:27 -0400494 hash_t *h = hash_header (v);
495 hash_pair_union_t *p = get_pair (v, i);
496 hash_pair_t *e;
497 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 uword len, is_vec;
499
500 is_vec = h->log2_pair_size == 0;
501
Dave Barachc3799992016-08-15 11:12:27 -0400502 ASSERT (!hash_is_user (v, i));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 len = is_vec ? vec_len (pi->pairs) : indirect_pair_get_len (pi);
504 e = hash_forward (h, pi->pairs, len - 1);
505 ASSERT (q >= pi->pairs && q <= e);
506
507 /* We have two or fewer pairs and we are delete one pair.
508 Make indirect pointer direct and free indirect memory. */
509 if (len <= 2)
510 {
Dave Barachc3799992016-08-15 11:12:27 -0400511 hash_pair_t *r = pi->pairs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512
513 if (len == 2)
514 {
Dave Barach178cf492018-11-13 16:34:13 -0500515 clib_memcpy_fast (p, q == r ? hash_forward1 (h, r) : r,
516 hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517 set_is_user (v, i, 1);
518 }
519 else
520 zero_pair (h, &p->direct);
521
522 if (is_vec)
523 vec_free (r);
524 else if (r)
525 clib_mem_free (r);
526 }
527 else
528 {
529 /* If deleting a pair we need to keep non-null pairs together. */
530 if (q < e)
Dave Barach178cf492018-11-13 16:34:13 -0500531 clib_memcpy_fast (q, e, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 else
533 zero_pair (h, q);
534 if (is_vec)
535 _vec_len (pi->pairs) -= 1;
536 else
Dave Barachc3799992016-08-15 11:12:27 -0400537 indirect_pair_set (pi, indirect_pair_get_log2_bytes (pi), len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700538 }
539}
540
Dave Barachc3799992016-08-15 11:12:27 -0400541enum lookup_opcode
542{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543 GET = 1,
544 SET = 2,
545 UNSET = 3,
546};
547
Dave Barachc3799992016-08-15 11:12:27 -0400548static hash_pair_t *
549lookup (void *v, uword key, enum lookup_opcode op,
550 void *new_value, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551{
Dave Barachc3799992016-08-15 11:12:27 -0400552 hash_t *h = hash_header (v);
553 hash_pair_union_t *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 uword found_key = 0;
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100555 uword value_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556 uword i;
557
Dave Barachc3799992016-08-15 11:12:27 -0400558 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559 return 0;
560
561 i = key_sum (h, key) & (_vec_len (v) - 1);
562 p = get_pair (v, i);
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100563 value_bytes = hash_value_bytes (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
565 if (hash_is_user (v, i))
566 {
567 found_key = key_equal (h, p->direct.key, key);
568 if (found_key)
569 {
570 if (op == UNSET)
571 {
572 set_is_user (v, i, 0);
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100573 if (old_value && value_bytes)
574 clib_memcpy_fast (old_value, p->direct.value, value_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700575 zero_pair (h, &p->direct);
576 }
577 }
578 else
579 {
580 if (op == SET)
581 p = set_indirect_is_user (v, i, p, key);
582 else
583 p = 0;
584 }
585 }
586 else
587 {
Dave Barachc3799992016-08-15 11:12:27 -0400588 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589
590 if (op == SET)
591 {
Dave Barachc3799992016-08-15 11:12:27 -0400592 if (!pi->pairs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700593 {
594 p->direct.key = key;
595 set_is_user (v, i, 1);
596 }
597 else
598 p = set_indirect (v, pi, key, &found_key);
599 }
600 else
601 {
602 p = get_indirect (v, pi, key);
603 found_key = p != 0;
604 if (found_key && op == UNSET)
605 {
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100606 if (old_value && value_bytes)
607 clib_memcpy_fast (old_value, &p->direct.value, value_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608
609 unset_indirect (v, i, &p->direct);
610
611 /* Nullify p (since it's just been deleted).
Dave Barachc3799992016-08-15 11:12:27 -0400612 Otherwise we might be tempted to play with it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700613 p = 0;
614 }
615 }
616 }
617
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100618 if (op == SET && p != 0 && value_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 {
620 /* Save away old value for caller. */
621 if (old_value && found_key)
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100622 clib_memcpy_fast (old_value, &p->direct.value, value_bytes);
623 clib_memcpy_fast (&p->direct.value, new_value, value_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624 }
625
626 if (op == SET)
627 h->elts += !found_key;
628 if (op == UNSET)
629 h->elts -= found_key;
630
631 return &p->direct;
632}
633
634/* Fetch value of key. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200635__clib_export uword *
Dave Barachc3799992016-08-15 11:12:27 -0400636_hash_get (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637{
Dave Barachc3799992016-08-15 11:12:27 -0400638 hash_t *h = hash_header (v);
639 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
641 /* Don't even search table if its empty. */
Dave Barachc3799992016-08-15 11:12:27 -0400642 if (!v || h->elts == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 return 0;
644
645 p = lookup (v, key, GET, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400646 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647 return 0;
648 if (h->log2_pair_size == 0)
649 return &p->key;
650 else
651 return &p->value[0];
652}
653
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200654__clib_export hash_pair_t *
Dave Barachc3799992016-08-15 11:12:27 -0400655_hash_get_pair (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656{
Dave Barachc3799992016-08-15 11:12:27 -0400657 return lookup (v, key, GET, 0, 0);
658}
659
Damjan Marion4a251d02021-05-06 17:28:12 +0200660__clib_export hash_pair_t *
661hash_next (void *v, hash_next_t *hn)
Dave Barachc3799992016-08-15 11:12:27 -0400662{
663 hash_t *h = hash_header (v);
664 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665
666 while (1)
667 {
668 if (hn->i == 0 && hn->j == 0)
669 {
670 /* Save flags. */
671 hn->f = h->flags;
672
673 /* Prevent others from re-sizing hash table. */
674 h->flags |=
Dave Barachc3799992016-08-15 11:12:27 -0400675 (HASH_FLAG_NO_AUTO_GROW
676 | HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_HASH_NEXT_IN_PROGRESS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 }
678 else if (hn->i >= hash_capacity (v))
679 {
680 /* Restore flags. */
681 h->flags = hn->f;
Dave Barachb7b92992018-10-17 10:38:51 -0400682 clib_memset (hn, 0, sizeof (hn[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683 return 0;
684 }
685
686 p = hash_forward (h, v, hn->i);
687 if (hash_is_user (v, hn->i))
688 {
689 hn->i++;
690 return p;
691 }
692 else
693 {
Dave Barachc3799992016-08-15 11:12:27 -0400694 hash_pair_indirect_t *pi = (void *) p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 uword n;
696
697 if (h->log2_pair_size > 0)
698 n = indirect_pair_get_len (pi);
699 else
700 n = vec_len (pi->pairs);
701
702 if (hn->j >= n)
703 {
704 hn->i++;
705 hn->j = 0;
706 }
707 else
708 return hash_forward (h, pi->pairs, hn->j++);
709 }
710 }
711}
712
713/* Remove key from table. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200714__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400715_hash_unset (void *v, uword key, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716{
Dave Barachc3799992016-08-15 11:12:27 -0400717 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
Dave Barachc3799992016-08-15 11:12:27 -0400719 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720 return v;
721
722 (void) lookup (v, key, UNSET, 0, old_value);
723
724 h = hash_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400725 if (!(h->flags & HASH_FLAG_NO_AUTO_SHRINK))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 {
727 /* Resize when 1/4 full. */
728 if (h->elts > 32 && 4 * (h->elts + 1) < vec_len (v))
729 v = hash_resize (v, vec_len (v) / 2);
730 }
731
732 return v;
733}
734
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200735__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400736_hash_create (uword elts, hash_t * h_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737{
Dave Barachc3799992016-08-15 11:12:27 -0400738 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 uword log2_pair_size;
Dave Barachc3799992016-08-15 11:12:27 -0400740 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741
742 /* Size of hash is power of 2 >= ELTS and larger than
743 number of bits in is_user bitmap elements. */
744 elts = clib_max (elts, BITS (h->is_user[0]));
Dave Barach6f6f34f2016-08-08 13:05:31 -0400745 elts = 1ULL << max_log2 (elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
747 log2_pair_size = 1;
748 if (h_user)
749 log2_pair_size = h_user->log2_pair_size;
750
Damjan Marion2f25ef32018-05-04 20:45:41 +0200751 v = _vec_resize ((void *) 0,
Dave Barachc3799992016-08-15 11:12:27 -0400752 /* vec len: */ elts,
753 /* data bytes: */
754 (elts << log2_pair_size) * sizeof (hash_pair_t),
755 /* header bytes: */
756 sizeof (h[0]) +
757 (elts / BITS (h->is_user[0])) * sizeof (h->is_user[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758 /* alignment */ sizeof (hash_pair_t));
759 h = hash_header (v);
760
761 if (h_user)
762 h[0] = h_user[0];
763
764 h->log2_pair_size = log2_pair_size;
765 h->elts = 0;
766
767 /* Default flags to never shrinking hash tables.
768 Shrinking tables can cause "jackpot" cases. */
Dave Barachc3799992016-08-15 11:12:27 -0400769 if (!h_user)
770 h->flags = HASH_FLAG_NO_AUTO_SHRINK;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700771
Dave Barachc3799992016-08-15 11:12:27 -0400772 if (!h->format_pair)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773 {
774 h->format_pair = hash_format_pair_default;
775 h->format_pair_arg = 0;
776 }
777
778 return v;
779}
780
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200781__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400782_hash_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783{
Dave Barachc3799992016-08-15 11:12:27 -0400784 hash_t *h = hash_header (v);
785 hash_pair_union_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 uword i;
787
Dave Barachc3799992016-08-15 11:12:27 -0400788 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700789 return v;
790
791 /* We zero all freed memory in case user would be tempted to use it. */
792 for (i = 0; i < hash_capacity (v); i++)
793 {
794 if (hash_is_user (v, i))
795 continue;
796 p = get_pair (v, i);
797 if (h->log2_pair_size == 0)
798 vec_free (p->indirect.pairs);
799 else if (p->indirect.pairs)
800 clib_mem_free (p->indirect.pairs);
801 }
802
803 vec_free_header (h);
804
805 return 0;
806}
807
Dave Barachc3799992016-08-15 11:12:27 -0400808static void *
809hash_resize_internal (void *old, uword new_size, uword free_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810{
Dave Barachc3799992016-08-15 11:12:27 -0400811 void *new;
812 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813
814 new = 0;
815 if (new_size > 0)
816 {
Dave Barachc3799992016-08-15 11:12:27 -0400817 hash_t *h = old ? hash_header (old) : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818 new = _hash_create (new_size, h);
Dave Barachc3799992016-08-15 11:12:27 -0400819 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820 hash_foreach_pair (p, old, {
821 new = _hash_set3 (new, p->key, &p->value[0], 0);
822 });
Dave Barachc3799992016-08-15 11:12:27 -0400823 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824 }
825
826 if (free_old)
827 hash_free (old);
828 return new;
829}
830
benkerddb8d652021-12-14 15:31:14 +0000831__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400832hash_resize (void *old, uword new_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700833{
Dave Barachc3799992016-08-15 11:12:27 -0400834 return hash_resize_internal (old, new_size, 1);
835}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700836
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200837__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400838hash_dup (void *old)
839{
840 return hash_resize_internal (old, vec_len (old), 0);
841}
842
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200843__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400844_hash_set3 (void *v, uword key, void *value, void *old_value)
845{
846 hash_t *h;
847
848 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849 v = hash_create (0, sizeof (uword));
850
851 h = hash_header (v);
852 (void) lookup (v, key, SET, value, old_value);
853
Dave Barachc3799992016-08-15 11:12:27 -0400854 if (!(h->flags & HASH_FLAG_NO_AUTO_GROW))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855 {
856 /* Resize when 3/4 full. */
857 if (4 * (h->elts + 1) > 3 * vec_len (v))
858 v = hash_resize (v, 2 * vec_len (v));
859 }
860
861 return v;
862}
863
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200864__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400865vec_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700866{
Dave Barachc3799992016-08-15 11:12:27 -0400867 void *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868 return hash_memory (v, vec_len (v) * h->user, 0);
869}
870
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200871__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400872vec_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873{
Dave Barachc3799992016-08-15 11:12:27 -0400874 void *v1 = uword_to_pointer (key1, void *);
875 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700876 uword l1 = vec_len (v1);
877 uword l2 = vec_len (v2);
878 return l1 == l2 && 0 == memcmp (v1, v2, l1 * h->user);
879}
880
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200881__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400882vec_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700883{
Dave Barachc3799992016-08-15 11:12:27 -0400884 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
885 void *v = va_arg (*args, void *);
886 hash_pair_t *p = va_arg (*args, hash_pair_t *);
887 hash_t *h = hash_header (v);
888 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 int i;
890
Dave Barachc3799992016-08-15 11:12:27 -0400891 switch (h->user)
892 {
893 case 1:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894 s = format (s, "%v", u);
895 break;
896
Dave Barachc3799992016-08-15 11:12:27 -0400897 case 2:
898 {
899 u16 *w = u;
900 for (i = 0; i < vec_len (w); i++)
901 s = format (s, "0x%x, ", w[i]);
902 break;
903 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904
Dave Barachc3799992016-08-15 11:12:27 -0400905 case 4:
906 {
907 u32 *w = u;
908 for (i = 0; i < vec_len (w); i++)
909 s = format (s, "0x%x, ", w[i]);
910 break;
911 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912
Dave Barachc3799992016-08-15 11:12:27 -0400913 case 8:
914 {
915 u64 *w = u;
916 for (i = 0; i < vec_len (w); i++)
917 s = format (s, "0x%Lx, ", w[i]);
918 break;
919 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920
Dave Barachc3799992016-08-15 11:12:27 -0400921 default:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700922 s = format (s, "0x%U", format_hex_bytes, u, vec_len (u) * h->user);
923 break;
Dave Barachc3799992016-08-15 11:12:27 -0400924 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700925
926 if (hash_value_bytes (h) > 0)
927 s = format (s, " -> 0x%wx", p->value[0]);
928
929 return s;
930}
931
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200932__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400933mem_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934{
Dave Barachc3799992016-08-15 11:12:27 -0400935 uword *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936 return hash_memory (v, h->user, 0);
937}
938
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200939__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400940mem_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941{
Dave Barachc3799992016-08-15 11:12:27 -0400942 void *v1 = uword_to_pointer (key1, void *);
943 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944 return v1 && v2 && 0 == memcmp (v1, v2, h->user);
945}
946
Dave Barachc3799992016-08-15 11:12:27 -0400947uword
948string_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949{
Dave Barachc3799992016-08-15 11:12:27 -0400950 char *v = uword_to_pointer (key, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 return hash_memory (v, strlen (v), 0);
952}
953
Dave Barachc3799992016-08-15 11:12:27 -0400954uword
955string_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956{
Dave Barachc3799992016-08-15 11:12:27 -0400957 void *v1 = uword_to_pointer (key1, void *);
958 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959 return v1 && v2 && 0 == strcmp (v1, v2);
960}
961
Dave Barachc3799992016-08-15 11:12:27 -0400962u8 *
963string_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964{
Dave Barachc3799992016-08-15 11:12:27 -0400965 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
966 void *v = va_arg (*args, void *);
967 hash_pair_t *p = va_arg (*args, hash_pair_t *);
968 hash_t *h = hash_header (v);
969 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970
971 s = format (s, "%s", u);
972
973 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400974 s =
975 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
976 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977
978 return s;
979}
980
Dave Barachc3799992016-08-15 11:12:27 -0400981static u8 *
982hash_format_pair_default (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983{
Dave Barachc3799992016-08-15 11:12:27 -0400984 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
985 void *v = va_arg (*args, void *);
986 hash_pair_t *p = va_arg (*args, hash_pair_t *);
987 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988
989 s = format (s, "0x%08x", p->key);
990 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400991 s =
992 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
993 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994 return s;
995}
996
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200997__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400998hash_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700999{
1000 uword i, bytes;
Dave Barachc3799992016-08-15 11:12:27 -04001001 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001002
Dave Barachc3799992016-08-15 11:12:27 -04001003 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001004 return 0;
1005
1006 bytes = vec_capacity (v, hash_header_bytes (v));
1007
1008 for (i = 0; i < hash_capacity (v); i++)
1009 {
Dave Barachc3799992016-08-15 11:12:27 -04001010 if (!hash_is_user (v, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011 {
Dave Barachc3799992016-08-15 11:12:27 -04001012 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 if (h->log2_pair_size > 0)
Dave Barachc3799992016-08-15 11:12:27 -04001014 bytes += 1 << indirect_pair_get_log2_bytes (&p->indirect);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 else
1016 bytes += vec_capacity (p->indirect.pairs, 0);
1017 }
1018 }
1019 return bytes;
1020}
1021
Damjan Marion4a251d02021-05-06 17:28:12 +02001022__clib_export u8 *
1023format_hash (u8 *s, va_list *va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024{
Dave Barachc3799992016-08-15 11:12:27 -04001025 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001026 int verbose = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -04001027 hash_pair_t *p;
1028 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029 uword i;
1030
1031 s = format (s, "hash %p, %wd elts, capacity %wd, %wd bytes used,\n",
Dave Barachc3799992016-08-15 11:12:27 -04001032 v, hash_elts (v), hash_capacity (v), hash_bytes (v));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033
1034 {
Dave Barachc3799992016-08-15 11:12:27 -04001035 uword *occupancy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036
1037 /* Count number of buckets with each occupancy. */
1038 for (i = 0; i < hash_capacity (v); i++)
1039 {
1040 uword j;
1041
1042 if (hash_is_user (v, i))
1043 {
1044 j = 1;
1045 }
1046 else
1047 {
Dave Barachc3799992016-08-15 11:12:27 -04001048 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 if (h->log2_pair_size > 0)
1050 j = indirect_pair_get_len (&p->indirect);
1051 else
1052 j = vec_len (p->indirect.pairs);
1053 }
1054
1055 vec_validate (occupancy, j);
1056 occupancy[j]++;
1057 }
1058
1059 s = format (s, " profile ");
1060 for (i = 0; i < vec_len (occupancy); i++)
1061 s = format (s, "%wd%c", occupancy[i],
1062 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1063
1064 s = format (s, " lookup # of compares: ");
1065 for (i = 1; i < vec_len (occupancy); i++)
1066 s = format (s, "%wd: .%03d%c", i,
1067 (1000 * i * occupancy[i]) / hash_elts (v),
1068 i + 1 == vec_len (occupancy) ? '\n' : ' ');
1069
1070 vec_free (occupancy);
1071 }
1072
1073 if (verbose)
1074 {
Dave Barachc3799992016-08-15 11:12:27 -04001075 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 hash_foreach_pair (p, v, {
1077 s = format (s, " %U\n", h->format_pair, h->format_pair_arg, v, p);
1078 });
Dave Barachc3799992016-08-15 11:12:27 -04001079 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 }
1081
1082 return s;
1083}
1084
1085static uword
1086unformat_hash_string_internal (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -04001087 va_list * va, int is_vec)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088{
Dave Barachc3799992016-08-15 11:12:27 -04001089 uword *hash = va_arg (*va, uword *);
1090 int *result = va_arg (*va, int *);
1091 u8 *string = 0;
1092 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093
Dave Barachc3799992016-08-15 11:12:27 -04001094 if (!unformat (input, is_vec ? "%v%_" : "%s%_", &string))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 return 0;
1096
1097 p = hash_get_mem (hash, string);
1098 if (p)
1099 *result = *p;
1100
1101 vec_free (string);
1102 return p ? 1 : 0;
1103}
1104
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001105__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106unformat_hash_vec_string (unformat_input_t * input, va_list * va)
Dave Barachc3799992016-08-15 11:12:27 -04001107{
1108 return unformat_hash_string_internal (input, va, /* is_vec */ 1);
1109}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001111__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112unformat_hash_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113{
Dave Barachc3799992016-08-15 11:12:27 -04001114 return unformat_hash_string_internal (input, va, /* is_vec */ 0);
1115}
1116
Damjan Marion4a251d02021-05-06 17:28:12 +02001117__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -04001118hash_validate (void *v)
1119{
1120 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121 uword i, j;
Dave Barachc3799992016-08-15 11:12:27 -04001122 uword *keys = 0;
1123 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124
1125#define CHECK(x) if ((error = ERROR_ASSERT (x))) goto done;
1126
1127 for (i = 0; i < hash_capacity (v); i++)
1128 {
Dave Barachc3799992016-08-15 11:12:27 -04001129 hash_pair_union_t *pu = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130
1131 if (hash_is_user (v, i))
1132 {
1133 CHECK (pu->direct.key != 0);
1134 vec_add1 (keys, pu->direct.key);
1135 }
1136 else
1137 {
Dave Barachc3799992016-08-15 11:12:27 -04001138 hash_pair_t *p;
1139 hash_pair_indirect_t *pi = &pu->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140 uword n;
1141
1142 n = h->log2_pair_size > 0
Dave Barachc3799992016-08-15 11:12:27 -04001143 ? indirect_pair_get_len (pi) : vec_len (pi->pairs);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144
1145 for (p = pi->pairs; n-- > 0; p = hash_forward1 (h, p))
1146 {
1147 /* Assert key uniqueness. */
1148 for (j = 0; j < vec_len (keys); j++)
1149 CHECK (keys[j] != p->key);
1150 vec_add1 (keys, p->key);
1151 }
1152 }
1153 }
1154
1155 CHECK (vec_len (keys) == h->elts);
1156
1157 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -04001158done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159 return error;
1160}
Dave Barachc3799992016-08-15 11:12:27 -04001161
1162/*
1163 * fd.io coding-style-patch-verification: ON
1164 *
1165 * Local Variables:
1166 * eval: (c-set-style "gnu")
1167 * End:
1168 */