FD.io VPP  v16.06
Vector Packet Processing
mhash.c
Go to the documentation of this file.
1 /*
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 
41 load_partial_u32 (void * d, uword n)
42 {
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 
56 mhash_key_sum_inline (void * data, uword n_data_bytes, u32 seed)
57 {
58  u32 * d32 = data;
59  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 
120 
121 #undef _
122 
123 static uword
125 {
126  mhash_t * hv = uword_to_pointer (h->user, mhash_t *);
127  void * k = mhash_key_to_mem (hv, key);
128  return mhash_key_sum_inline (k, strlen (k), hv->hash_seed);
129 }
130 
131 static uword
133 {
134  mhash_t * hv = uword_to_pointer (h->user, mhash_t *);
135  void * k1 = mhash_key_to_mem (hv, key1);
136  void * k2 = mhash_key_to_mem (hv, key2);
137  return strcmp (k1, k2) == 0;
138 }
139 
140 static uword
142 {
143  mhash_t * hv = uword_to_pointer (h->user, mhash_t *);
144  void * k = mhash_key_to_mem (hv, key);
145  return mhash_key_sum_inline (k, vec_len (k), hv->hash_seed);
146 }
147 
148 static uword
150 {
151  mhash_t * hv = uword_to_pointer (h->user, mhash_t *);
152  void * k1 = mhash_key_to_mem (hv, key1);
153  void * k2 = mhash_key_to_mem (hv, key2);
154  return vec_len (k1) == vec_len (k2) && memcmp (k1, k2, vec_len (k1)) == 0;
155 }
156 
157 /* The CLIB hash user pointer must always point to a valid mhash_t.
158  Now, the address of mhash_t can change (think vec_resize).
159  So we must always be careful that it points to the correct
160  address. */
161 always_inline void
163 {
164  uword * hash = mh->hash;
165  hash_t * h = hash_header (hash);
166  h->user = pointer_to_uword (mh);
167 }
168 
169 void mhash_init (mhash_t * h, uword n_value_bytes, uword n_key_bytes)
170 {
171  static struct {
174  } t[] = {
175 #define _(N_KEY_BYTES) \
176  [N_KEY_BYTES] = { \
177  .key_sum = mhash_key_sum_##N_KEY_BYTES, \
178  .key_equal = mhash_key_equal_##N_KEY_BYTES, \
179  },
180 
182 
183 #undef _
184 
185  [MHASH_C_STRING_KEY] = {
186  .key_sum = mhash_key_sum_c_string,
187  .key_equal = mhash_key_equal_c_string,
188  },
189 
191  .key_sum = mhash_key_sum_vec_string,
192  .key_equal = mhash_key_equal_vec_string,
193  },
194  };
195 
196  if (mhash_key_vector_is_heap (h))
198  else
201  {
202  int i;
203  for (i = 0; i < vec_len (h->key_tmps); i++)
204  vec_free (h->key_tmps[i]);
205  }
206  vec_free (h->key_tmps);
207  hash_free (h->hash);
208 
209  memset (h, 0, sizeof (h[0]));
210  h->n_key_bytes = n_key_bytes;
211 
212 #if 0
213  if (h->n_key_bytes > 0)
214  {
215  vec_validate (h->key_tmp, h->n_key_bytes-1);
216  _vec_len(h->key_tmp) = 0;
217  }
218 #endif
219 
220  ASSERT (n_key_bytes < ARRAY_LEN (t));
221  h->hash = hash_create2 (/* elts */ 0,
222  /* user */ pointer_to_uword (h),
223  /* value_bytes */ n_value_bytes,
224  t[n_key_bytes].key_sum,
225  t[n_key_bytes].key_equal,
226  /* format pair/arg */
227  0, 0);
228 }
229 
230 static uword mhash_set_tmp_key (mhash_t * h, void * key)
231 {
232  u8 * key_tmp;
233  int my_cpu = os_get_cpu_number();
234 
235  vec_validate(h->key_tmps, my_cpu);
236  key_tmp = h->key_tmps[my_cpu];
237 
238  vec_reset_length (key_tmp);
239 
240  if (mhash_key_vector_is_heap (h))
241  {
242  uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
243 
244  if (is_c_string)
245  vec_add (key_tmp, key, strlen (key) + 1);
246  else
247  vec_add (key_tmp, key, vec_len (key));
248  }
249  else
250  vec_add (key_tmp, key, h->n_key_bytes);
251 
252  h->key_tmps[my_cpu] = key_tmp;
253 
254  return ~0;
255 }
256 
257 hash_pair_t * mhash_get_pair (mhash_t * h, void * key)
258 {
259  uword ikey;
261  ikey = mhash_set_tmp_key (h, key);
262  return hash_get_pair (h->hash, ikey);
263 }
264 
265 typedef struct {
267 
268  /* Must conincide with vec_header. */
271 
272 uword mhash_set_mem (mhash_t * h, void * key, uword * new_value, uword * old_value)
273 {
274  u8 * k;
275  uword ikey, i, l=0, n_key_bytes, old_n_elts, key_alloc_from_free_list = 0;
276 
278 
279  if (mhash_key_vector_is_heap (h))
280  {
281  mhash_string_key_t * sk;
282  uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
283  uword handle;
284 
285  n_key_bytes = is_c_string ? (strlen (key) + 1) : vec_len (key);
286  i = heap_alloc (h->key_vector_or_heap, n_key_bytes + sizeof (sk[0]), handle);
287 
288  sk = (void *) (h->key_vector_or_heap + i);
289  sk->heap_handle = handle;
290  sk->vec.len = n_key_bytes;
291  clib_memcpy (sk->vec.vector_data, key, n_key_bytes);
292 
293  /* Advance key past vector header. */
294  i += sizeof (sk[0]);
295  }
296  else
297  {
298  key_alloc_from_free_list = (l = vec_len (h->key_vector_free_indices)) > 0;
299  if (key_alloc_from_free_list)
300  {
301  i = h->key_vector_free_indices[l - 1];
303  _vec_len (h->key_vector_free_indices) = l - 1;
304  }
305  else
306  {
308  i = k - h->key_vector_or_heap;
309  }
310 
311  n_key_bytes = h->n_key_bytes;
312  clib_memcpy (k, key, n_key_bytes);
313  }
314  ikey = i;
315 
316  old_n_elts = hash_elts (h->hash);
317  h->hash = _hash_set3 (h->hash, ikey, new_value, old_value);
318 
319  /* If element already existed remove duplicate key. */
320  if (hash_elts (h->hash) == old_n_elts)
321  {
322  hash_pair_t * p;
323 
324  /* Fetch old key for return value. */
325  p = hash_get_pair (h->hash, ikey);
326  ikey = p->key;
327 
328  /* Remove duplicate key. */
329  if (mhash_key_vector_is_heap (h))
330  {
331  mhash_string_key_t * sk;
332  sk = (void *) (h->key_vector_or_heap + i - sizeof (sk[0]));
334  }
335  else
336  {
337  if (key_alloc_from_free_list)
338  {
339  h->key_vector_free_indices[l] = i;
340  _vec_len (h->key_vector_free_indices) = l + 1;
341  }
342  else
343  _vec_len (h->key_vector_or_heap) -= h->n_key_bytes;
344  }
345  }
346 
347  return ikey;
348 }
349 
350 uword mhash_unset (mhash_t * h, void * key, uword * old_value)
351 {
352  hash_pair_t * p;
353  uword i;
354 
356  i = mhash_set_tmp_key (h, key);
357 
358  p = hash_get_pair (h->hash, i);
359  if (! p)
360  return 0;
361 
362  ASSERT (p->key != ~0);
363  i = p->key;
364 
365  if (mhash_key_vector_is_heap (h))
366  {
367  mhash_string_key_t * sk;
368  sk = (void *) (h->key_vector_or_heap + i) - sizeof (sk[0]);
370  }
371  else
373 
374  hash_unset3 (h->hash, i, old_value);
375  return 1;
376 }
377 
378 u8 * format_mhash_key (u8 * s, va_list * va)
379 {
380  mhash_t * h = va_arg (*va, mhash_t *);
381  u32 ki = va_arg (*va, u32);
382  void * k = mhash_key_to_mem (h, ki);
383 
384  if (mhash_key_vector_is_heap (h))
385  {
386  uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
387  u32 l = is_c_string ? strlen (k) : vec_len (k);
388  vec_add (s, k, l);
389  }
390  else if (h->format_key)
391  s = format (s, "%U", h->format_key, k);
392  else
393  s = format (s, "%U", format_hex_bytes, k, h->n_key_bytes);
394 
395  return s;
396 }
static uword mhash_set_tmp_key(mhash_t *h, void *key)
Definition: mhash.c:230
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
#define foreach_mhash_key_size
Definition: mhash.c:93
Definition: mhash.h:46
any user
Definition: hash.h:85
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
hash_pair_t * mhash_get_pair(mhash_t *h, void *key)
Definition: mhash.c:257
a
Definition: bitmap.h:393
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:350
format_function_t * format_key
Definition: mhash.h:71
always_inline hash_t * hash_header(void *v)
Definition: hash.h:107
always_inline uword key_sum(hash_t *h, uword key)
Definition: hash.c:245
u32 n_key_bytes
Definition: mhash.h:62
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
vec_header_t vec
Definition: mhash.c:269
uword( hash_key_equal_function_t)(struct hash_header *, uword key1, uword key2)
Definition: hash.h:51
always_inline void * mhash_key_to_mem(mhash_t *h, uword key)
Definition: mhash.h:85
#define hash_v3_mix32(a, b, c)
Definition: hash.h:487
#define heap_free(v)
Definition: heap.h:319
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
always_inline uword mhash_key_vector_is_heap(mhash_t *h)
Definition: mhash.h:133
u32 hash_seed
Definition: mhash.h:65
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:557
u8 ** key_tmps
Definition: mhash.h:55
#define always_inline
Definition: clib.h:84
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:79
#define hash_get_pair(h, key)
Definition: hash.h:234
static uword pointer_to_uword(const void *p)
Definition: types.h:131
uword mhash_set_mem(mhash_t *h, void *key, uword *new_value, uword *old_value)
Definition: mhash.c:272
uword os_get_cpu_number(void)
Definition: unix-misc.c:206
#define hash_free(h)
Definition: hash.h:269
u32 * key_vector_free_indices
Definition: mhash.h:53
#define uword_to_pointer(u, type)
Definition: types.h:134
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:169
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
static uword mhash_key_sum_vec_string(hash_t *h, uword key)
Definition: mhash.c:141
#define clib_memcpy(a, b, c)
Definition: string.h:63
always_inline u32 load_partial_u32(void *d, uword n)
Definition: mhash.c:41
#define ARRAY_LEN(x)
Definition: clib.h:59
u32 len
Number of elements in vector (NOT its allocated length).
Definition: vec_bootstrap.h:59
always_inline uword hash_elts(void *v)
Definition: hash.h:111
#define hash_create2(_elts, _user, _value_bytes,_key_sum, _key_equal,_format_pair, _format_pair_arg)
Definition: hash.h:429
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * key_vector_or_heap
Definition: mhash.h:49
static foreach_mhash_key_size uword mhash_key_sum_c_string(hash_t *h, uword key)
Definition: mhash.c:124
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
#define hash_v3_finalize32(a, b, c)
Definition: hash.h:497
void heap_dealloc(void *v, uword handle)
Definition: heap.c:478
vector header structure
Definition: vec_bootstrap.h:55
#define heap_alloc(v, size, handle)
Definition: heap.h:309
uword * hash
Definition: mhash.h:68
u64 uword
Definition: types.h:112
static uword mhash_key_equal_c_string(hash_t *h, uword key1, uword key2)
Definition: mhash.c:132
always_inline uword key_equal(hash_t *h, uword key1, uword key2)
Definition: hash.c:301
uword( hash_key_sum_function_t)(struct hash_header *, uword key)
Definition: hash.h:49
unsigned short u16
Definition: types.h:57
u8 vector_data[0]
Vector data .
Definition: vec_bootstrap.h:61
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define MHASH_C_STRING_KEY
Definition: mhash.h:61
#define MHASH_VEC_STRING_KEY
Definition: mhash.h:60
always_inline void mhash_sanitize_hash_user(mhash_t *mh)
Definition: mhash.c:162
always_inline u32 mhash_key_sum_inline(void *data, uword n_data_bytes, u32 seed)
Definition: mhash.c:56
u8 * format_mhash_key(u8 *s, va_list *va)
Definition: mhash.c:378
uword key
Definition: hash.h:148
#define hash_unset3(h, key, old_value)
Definition: hash.h:246
static uword mhash_key_equal_vec_string(hash_t *h, uword key1, uword key2)
Definition: mhash.c:149