blob: c556312e64fadee98398a7a0b98473aacb8612ad [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) 2010 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/mhash.h>
39
40always_inline u32
Dave Barachc3799992016-08-15 11:12:27 -040041load_partial_u32 (void *d, uword n)
Ed Warnickecb9cada2015-12-08 15:45:58 -070042{
43 if (n == 4)
44 return ((u32 *) d)[0];
45 if (n == 3)
46 return ((u16 *) d)[0] | (((u8 *) d)[2] << 16);
47 if (n == 2)
48 return ((u16 *) d)[0];
49 if (n == 1)
50 return ((u8 *) d)[0];
51 ASSERT (0);
52 return 0;
53}
54
55always_inline u32
Dave Barachc3799992016-08-15 11:12:27 -040056mhash_key_sum_inline (void *data, uword n_data_bytes, u32 seed)
Ed Warnickecb9cada2015-12-08 15:45:58 -070057{
Dave Barachc3799992016-08-15 11:12:27 -040058 u32 *d32 = data;
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 u32 a, b, c, n_left;
60
61 a = b = c = seed;
62 n_left = n_data_bytes;
63 a ^= n_data_bytes;
64
65 while (n_left > 12)
66 {
67 a += d32[0];
68 b += d32[1];
69 c += d32[2];
70 hash_v3_mix32 (a, b, c);
71 n_left -= 12;
72 d32 += 3;
73 }
74
75 if (n_left > 8)
76 {
77 c += load_partial_u32 (d32 + 2, n_left - 8);
78 n_left = 8;
79 }
80 if (n_left > 4)
81 {
82 b += load_partial_u32 (d32 + 1, n_left - 4);
83 n_left = 4;
84 }
85 if (n_left > 0)
86 a += load_partial_u32 (d32 + 0, n_left - 0);
87
88 hash_v3_finalize32 (a, b, c);
89
90 return c;
91}
92
93#define foreach_mhash_key_size \
94 _ (2) _ (3) _ (4) _ (5) _ (6) _ (7) \
95 _ (8) _ (12) _ (16) _ (20) \
96 _ (24) _ (28) _ (32) _ (36) \
97 _ (40) _ (44) _ (48) _ (52) \
98 _ (56) _ (60) _ (64)
99
100#define _(N_KEY_BYTES) \
101 static uword \
102 mhash_key_sum_##N_KEY_BYTES (hash_t * h, uword key) \
103 { \
104 mhash_t * hv = uword_to_pointer (h->user, mhash_t *); \
105 return mhash_key_sum_inline (mhash_key_to_mem (hv, key), \
106 (N_KEY_BYTES), \
107 hv->hash_seed); \
108 } \
109 \
110 static uword \
111 mhash_key_equal_##N_KEY_BYTES (hash_t * h, uword key1, uword key2) \
112 { \
113 mhash_t * hv = uword_to_pointer (h->user, mhash_t *); \
114 void * k1 = mhash_key_to_mem (hv, key1); \
115 void * k2 = mhash_key_to_mem (hv, key2); \
116 return ! memcmp (k1, k2, (N_KEY_BYTES)); \
117 }
118
119foreach_mhash_key_size
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120#undef _
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121static uword
122mhash_key_sum_c_string (hash_t * h, uword key)
123{
Dave Barachc3799992016-08-15 11:12:27 -0400124 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
125 void *k = mhash_key_to_mem (hv, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 return mhash_key_sum_inline (k, strlen (k), hv->hash_seed);
127}
128
129static uword
130mhash_key_equal_c_string (hash_t * h, uword key1, uword key2)
131{
Dave Barachc3799992016-08-15 11:12:27 -0400132 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
133 void *k1 = mhash_key_to_mem (hv, key1);
134 void *k2 = mhash_key_to_mem (hv, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 return strcmp (k1, k2) == 0;
136}
137
138static uword
139mhash_key_sum_vec_string (hash_t * h, uword key)
140{
Dave Barachc3799992016-08-15 11:12:27 -0400141 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
142 void *k = mhash_key_to_mem (hv, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143 return mhash_key_sum_inline (k, vec_len (k), hv->hash_seed);
144}
145
146static uword
147mhash_key_equal_vec_string (hash_t * h, uword key1, uword key2)
148{
Dave Barachc3799992016-08-15 11:12:27 -0400149 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
150 void *k1 = mhash_key_to_mem (hv, key1);
151 void *k2 = mhash_key_to_mem (hv, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152 return vec_len (k1) == vec_len (k2) && memcmp (k1, k2, vec_len (k1)) == 0;
153}
154
155/* The CLIB hash user pointer must always point to a valid mhash_t.
156 Now, the address of mhash_t can change (think vec_resize).
157 So we must always be careful that it points to the correct
158 address. */
159always_inline void
160mhash_sanitize_hash_user (mhash_t * mh)
161{
Dave Barachc3799992016-08-15 11:12:27 -0400162 uword *hash = mh->hash;
163 hash_t *h = hash_header (hash);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 h->user = pointer_to_uword (mh);
165}
166
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200167__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400168mhash_init (mhash_t * h, uword n_value_bytes, uword n_key_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169{
Dave Barachc3799992016-08-15 11:12:27 -0400170 static struct
171 {
172 hash_key_sum_function_t *key_sum;
173 hash_key_equal_function_t *key_equal;
174 } t[] =
175 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176#define _(N_KEY_BYTES) \
177 [N_KEY_BYTES] = { \
178 .key_sum = mhash_key_sum_##N_KEY_BYTES, \
179 .key_equal = mhash_key_equal_##N_KEY_BYTES, \
180 },
181
182 foreach_mhash_key_size
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183#undef _
Dave Barachc3799992016-08-15 11:12:27 -0400184 [MHASH_C_STRING_KEY] =
185 {
186 .key_sum = mhash_key_sum_c_string,.key_equal = mhash_key_equal_c_string,},
187 [MHASH_VEC_STRING_KEY] =
188 {
189 .key_sum = mhash_key_sum_vec_string,.key_equal =
190 mhash_key_equal_vec_string,},};
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
192 if (mhash_key_vector_is_heap (h))
193 heap_free (h->key_vector_or_heap);
194 else
195 vec_free (h->key_vector_or_heap);
196 vec_free (h->key_vector_free_indices);
197 {
198 int i;
199 for (i = 0; i < vec_len (h->key_tmps); i++)
200 vec_free (h->key_tmps[i]);
201 }
202 vec_free (h->key_tmps);
203 hash_free (h->hash);
204
Dave Barachb7b92992018-10-17 10:38:51 -0400205 clib_memset (h, 0, sizeof (h[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 h->n_key_bytes = n_key_bytes;
207
Dave Barach2180bac2019-05-10 15:25:10 -0400208 vec_validate (h->key_tmps, os_get_nthreads () - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
210 ASSERT (n_key_bytes < ARRAY_LEN (t));
Dave Barachc3799992016-08-15 11:12:27 -0400211 h->hash = hash_create2 ( /* elts */ 0,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 /* user */ pointer_to_uword (h),
213 /* value_bytes */ n_value_bytes,
Dave Barachc3799992016-08-15 11:12:27 -0400214 t[n_key_bytes].key_sum, t[n_key_bytes].key_equal,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 /* format pair/arg */
216 0, 0);
217}
218
Dave Barachc3799992016-08-15 11:12:27 -0400219static uword
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200220mhash_set_tmp_key (mhash_t * h, const void *key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221{
Dave Barachc3799992016-08-15 11:12:27 -0400222 u8 *key_tmp;
Damjan Marionf55f9b82017-05-10 21:06:28 +0200223 int my_cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225 key_tmp = h->key_tmps[my_cpu];
226
227 vec_reset_length (key_tmp);
228
229 if (mhash_key_vector_is_heap (h))
230 {
231 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
232
233 if (is_c_string)
234 vec_add (key_tmp, key, strlen (key) + 1);
235 else
236 vec_add (key_tmp, key, vec_len (key));
237 }
238 else
239 vec_add (key_tmp, key, h->n_key_bytes);
240
241 h->key_tmps[my_cpu] = key_tmp;
242
243 return ~0;
244}
245
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200246__clib_export hash_pair_t *
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200247mhash_get_pair (mhash_t * h, const void *key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248{
249 uword ikey;
250 mhash_sanitize_hash_user (h);
251 ikey = mhash_set_tmp_key (h, key);
252 return hash_get_pair (h->hash, ikey);
253}
254
Dave Barachc3799992016-08-15 11:12:27 -0400255typedef struct
256{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 u32 heap_handle;
258
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700259 /* Must coincide with vec_header. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 vec_header_t vec;
261} mhash_string_key_t;
262
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200263__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400264mhash_set_mem (mhash_t * h, void *key, uword * new_value, uword * old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265{
Dave Barachc3799992016-08-15 11:12:27 -0400266 u8 *k;
267 uword ikey, i, l = 0, n_key_bytes, old_n_elts, key_alloc_from_free_list = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268
269 mhash_sanitize_hash_user (h);
270
271 if (mhash_key_vector_is_heap (h))
272 {
Dave Barachc3799992016-08-15 11:12:27 -0400273 mhash_string_key_t *sk;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
275 uword handle;
276
277 n_key_bytes = is_c_string ? (strlen (key) + 1) : vec_len (key);
Dave Barachc3799992016-08-15 11:12:27 -0400278 i =
279 heap_alloc (h->key_vector_or_heap, n_key_bytes + sizeof (sk[0]),
280 handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281
282 sk = (void *) (h->key_vector_or_heap + i);
283 sk->heap_handle = handle;
284 sk->vec.len = n_key_bytes;
Dave Barach178cf492018-11-13 16:34:13 -0500285 clib_memcpy_fast (sk->vec.vector_data, key, n_key_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
287 /* Advance key past vector header. */
288 i += sizeof (sk[0]);
289 }
290 else
291 {
Dave Barachc3799992016-08-15 11:12:27 -0400292 key_alloc_from_free_list = (l =
293 vec_len (h->key_vector_free_indices)) > 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294 if (key_alloc_from_free_list)
295 {
296 i = h->key_vector_free_indices[l - 1];
297 k = vec_elt_at_index (h->key_vector_or_heap, i);
298 _vec_len (h->key_vector_free_indices) = l - 1;
299 }
300 else
301 {
302 vec_add2 (h->key_vector_or_heap, k, h->n_key_bytes);
303 i = k - h->key_vector_or_heap;
304 }
305
306 n_key_bytes = h->n_key_bytes;
Dave Barach178cf492018-11-13 16:34:13 -0500307 clib_memcpy_fast (k, key, n_key_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308 }
309 ikey = i;
310
311 old_n_elts = hash_elts (h->hash);
312 h->hash = _hash_set3 (h->hash, ikey, new_value, old_value);
313
314 /* If element already existed remove duplicate key. */
315 if (hash_elts (h->hash) == old_n_elts)
316 {
Dave Barachc3799992016-08-15 11:12:27 -0400317 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
319 /* Fetch old key for return value. */
320 p = hash_get_pair (h->hash, ikey);
321 ikey = p->key;
322
323 /* Remove duplicate key. */
324 if (mhash_key_vector_is_heap (h))
325 {
Dave Barachc3799992016-08-15 11:12:27 -0400326 mhash_string_key_t *sk;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327 sk = (void *) (h->key_vector_or_heap + i - sizeof (sk[0]));
328 heap_dealloc (h->key_vector_or_heap, sk->heap_handle);
329 }
330 else
331 {
332 if (key_alloc_from_free_list)
333 {
334 h->key_vector_free_indices[l] = i;
335 _vec_len (h->key_vector_free_indices) = l + 1;
336 }
337 else
338 _vec_len (h->key_vector_or_heap) -= h->n_key_bytes;
339 }
340 }
341
342 return ikey;
343}
344
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200345__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400346mhash_unset (mhash_t * h, void *key, uword * old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347{
Dave Barachc3799992016-08-15 11:12:27 -0400348 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 uword i;
350
351 mhash_sanitize_hash_user (h);
352 i = mhash_set_tmp_key (h, key);
353
354 p = hash_get_pair (h->hash, i);
Dave Barachc3799992016-08-15 11:12:27 -0400355 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356 return 0;
357
358 ASSERT (p->key != ~0);
359 i = p->key;
360
361 if (mhash_key_vector_is_heap (h))
362 {
Dave Barachc3799992016-08-15 11:12:27 -0400363 mhash_string_key_t *sk;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 sk = (void *) (h->key_vector_or_heap + i) - sizeof (sk[0]);
365 heap_dealloc (h->key_vector_or_heap, sk->heap_handle);
366 }
367 else
368 vec_add1 (h->key_vector_free_indices, i);
369
370 hash_unset3 (h->hash, i, old_value);
371 return 1;
372}
373
Dave Barachc3799992016-08-15 11:12:27 -0400374u8 *
375format_mhash_key (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376{
Dave Barachc3799992016-08-15 11:12:27 -0400377 mhash_t *h = va_arg (*va, mhash_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 u32 ki = va_arg (*va, u32);
Dave Barachc3799992016-08-15 11:12:27 -0400379 void *k = mhash_key_to_mem (h, ki);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380
381 if (mhash_key_vector_is_heap (h))
382 {
383 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
384 u32 l = is_c_string ? strlen (k) : vec_len (k);
385 vec_add (s, k, l);
386 }
387 else if (h->format_key)
388 s = format (s, "%U", h->format_key, k);
389 else
390 s = format (s, "%U", format_hex_bytes, k, h->n_key_bytes);
391
392 return s;
393}
Dave Barachc3799992016-08-15 11:12:27 -0400394
395/*
396 * fd.io coding-style-patch-verification: ON
397 *
398 * Local Variables:
399 * eval: (c-set-style "gnu")
400 * End:
401 */