Hybrid ICN (hICN) plugin  v21.06-rc0-4-g18fa668
hashtb.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 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 #ifndef __HICN_HASHTB_H__
17 #define __HICN_HASHTB_H__
18 
19 #include <stdint.h>
20 #include <vppinfra/bihash_8_8.h>
21 #include <vppinfra/bihash_24_8.h>
22 
23 #include "params.h"
24 #include "parser.h"
25 #include "error.h"
26 
67 /* Handy abbreviations for success status, and for boolean values */
68 #ifndef TRUE
69 #define TRUE 1
70 #endif
71 
72 #ifndef FALSE
73 #define FALSE 0
74 #endif
75 
76 #define HICN_HASH_INVALID_IDX ~0
77 /*
78  * for hicn_hashtb_next_node() iterator, this otherwise illegal context value
79  * indicates first call of iteration. Note: must not be 0, which is a legal
80  * context value.
81  */
82 #define HICN_HASH_WALK_CTX_INITIAL (~((u64) 0))
83 
84 /*
85  * Key memory allocation scheme.
86  *
87  * The key is the bytestring that a hashtable entry is storing, e.g. a fib
88  * prefix or packet name. The hash of the name is used not just to pick the
89  * bucket, but also as a surrogate for the actual key value.
90  *
91  * Client calls pass key/name as contiguous memory for lookup/add/delete but
92  * hashable stores its copy of the key/name as a list of one or more hash_key
93  * structs. - key memory is managed as a list of keys (cache line
94  * sized/aligned buffers). - If (keysize < 128) then use key struct's full
95  * 128 bytes - If not, first key struct is head of a linked list of elements
96  * where the first bytes are used for the key and the last 4 bytes are the
97  * index of the next entry (or an end marker). - key memory is generally the
98  * single largest use of memory in the hash table, especially for PIT, as
99  * names are bigger than node structs (which is also per name/entry).
100  *
101  */
102 
103 /* Compute hash node index from node pointer */
104 #define NODE_IDX_FROM_NODE(p, h) (u32) ((p) - ((h)->ht_nodes))
105 
106 #define HICN_HASH_KEY_BYTES 20
107 
108 typedef struct
109 {
110  struct
111  {
112  u8 key[HICN_HASH_KEY_BYTES];
113  } ks; /* Entire key in one block */
115 
116 /*
117  * Ratio of extra key blocks to allocate, in case the embedded ones aren't
118  * sufficient. This is the fraction of the number of entries allocated.
119  */
120 #define HICN_HASHTB_KEY_RATIO 8
121 
122 /*
123  * hash node, used to store a hash table entry; indexed by an entry in a
124  * bucket. the node contains an embedded key; long keys are stored as chains
125  * of keys.
126  *
127  * The memory block for a node includes space for storing outgoing faces for
128  * interests, additional memory located off the end of the htnode data
129  * structure.
130  *
131  */
132 
133 /* Size this so that we can offer 64B aligned on 64-bits for storing outgoing
134  * faces information
135  */
136 #define HICN_HASH_NODE_APP_DATA_SIZE 64
137 
138 /* How to align in the right way */
139 typedef struct __attribute__ ((packed)) hicn_hash_node_s
140 {
141  /* Bucket id containing the corresponding hash entry. */
142  u32 bucket_id;
143 
144  /* Hash entry index in the bucket */
145  u32 entry_idx;
146 
147  /* Total size of the key */
148  u16 hn_keysize;
149 
150  /* 1 byte of flags for application use */
151  u8 hn_flags;
152 
153  u8 _hn_reserved1; /* TBD, to align what follows back to
154  * 32 */
155 
156  hicn_hash_key_t hn_key; /* Key value embedded in the node, may chain
157  * to more key buffers if necessary */
158 
159  /* 32B + HICN_HASH_NODE_APP_DATA_SIZE */
160  /* Followed by app-specific data (fib or pit or cs entry, e.g.) */
161  u8 hn_data[HICN_HASH_NODE_APP_DATA_SIZE];
162 
163 } hicn_hash_node_t;
164 
165 #define HICN_HASH_NODE_FLAGS_DEFAULT 0x00
166 #define HICN_HASH_NODE_CS_FLAGS 0x01
167 #define HICN_HASH_NODE_OVERFLOW_BUCKET 0x02
168 
169 /*
170  * hicn_hash_entry_t Structure holding all or part of a hash value, a node
171  * index, and other key pieces of info.
172  *
173  * - 128 bytes/bucket with 19 bytes/entry gives 6 entries, or 5 entries plus
174  * next bucket ptr if overflow Changes in this structure will affect
175  * hicn_hash_bucket_t
176  */
177 typedef struct __attribute__ ((packed)) hicn_hash_entry_s
178 {
179 
180  /* MSB of the hash value */
181  u64 he_msb64;
182 
183  /* Index of node block */
184  u32 he_node;
185 
186  /*
187  * Lock to prevent hash_node deletion while there are still interest
188  * or data referring to it
189  */
190  u32 locks;
191 
192  /* Index of dpo (4B) */
193  index_t dpo_ctx_id;
194 
195  /* A few flags, including 'this points to a chain of buckets' */
196  u8 he_flags;
197 
198  /*
199  * Index of the virtual function table corresponding to the dpo_ctx
200  * strategy
201  */
202  u8 vft_id;
203 
204 } hicn_hash_entry_t; // size 22B
205 
206 STATIC_ASSERT (sizeof (index_t) <= 4, "sizeof index_t is greater than 4B");
207 
208 #define HICN_HASH_ENTRY_FLAGS_DEFAULT 0x00
209 
210 /* If entry is PIT this flag is 0 */
211 #define HICN_HASH_ENTRY_FLAG_CS_ENTRY 0x01
212 
213 /*
214  * This entry heads a chain of overflow buckets (we expect to see this only
215  * in the last entry in a bucket.) In this case, the index is to an overflow
216  * bucket rather than to a single node block.
217  */
218 #define HICN_HASH_ENTRY_FLAG_OVERFLOW 0x04
219 
220 /* This entry has been marked for deletion */
221 #define HICN_HASH_ENTRY_FLAG_DELETED 0x08
222 
223 /* Use fast he_timeout units for expiration, slow if not */
224 #define HICN_HASH_ENTRY_FLAG_FAST_TIMEOUT 0x10
225 
226 /*
227  * hash bucket: Contains an array of entries. Cache line sized/aligned, so no
228  * room for extra fields unless bucket size is increased to 2 cache lines or
229  * the entry struct shrinks.
230  */
231 
232 /*
233  * Overflow bucket ratio as a fraction of the fixed/configured count; a pool
234  * of hash buckets used if a row in the fixed table overflows.
235  */
236 #define HICN_HASHTB_BUCKET_ENTRIES 5
237 
238 typedef struct __attribute__ ((packed))
239 {
240  hicn_hash_entry_t hb_entries[HICN_HASHTB_BUCKET_ENTRIES];
241  u64 align1;
242  u64 align2;
243  u16 align3;
244 } hicn_hash_bucket_t;
245 
246 /* Overall target fill-factor for the hashtable */
247 #define HICN_HASHTB_FILL_FACTOR 4
248 
249 #define HICN_HASHTB_MIN_ENTRIES (1 << 4) // includes dummy node 0 entry
250 #define HICN_HASHTB_MAX_ENTRIES (1 << 24)
251 
252 #define HICN_HASHTB_MIN_BUCKETS (1 << 10)
253 
254 /*
255  * htab_t
256  *
257  * Hash table main structure.
258  *
259  * Contains - pointers to dynamically allocated arrays of cache-line
260  * sized/aligned structures (buckets, nodes, keys). Put frequently accessed
261  * fields in the first cache line.
262  */
263 typedef struct hicn_hashtb_s
264 {
265 
266  /* 8B - main array of hash buckets */
267  hicn_hash_bucket_t *ht_buckets;
268 
269  /* 8B - just-in-case block of overflow buckets */
270  hicn_hash_bucket_t *ht_overflow_buckets;
271 
272  /* 8B - block of nodes associated with entries in buckets */
273  hicn_hash_node_t *ht_nodes;
274 
275  /* Flags */
276  u32 ht_flags;
277 
278  /* Count of buckets allocated in the main array */
279  u32 ht_bucket_count;
280 
281  /* Count of overflow buckets allocated */
282  u32 ht_overflow_bucket_count;
283  u32 ht_overflow_buckets_used;
284 
285  /* Count of nodes allocated */
286  u32 ht_node_count;
287  u32 ht_nodes_used;
288 
289  /* Count of overflow key structs allocated */
290  u32 ht_key_count;
291  u32 ht_keys_used;
292 
294 
295 /*
296  * Offset to aligned start of additional data (PIT/CS, FIB) embedded in each
297  * node.
298  */
299 extern u32 ht_node_data_offset_aligned;
300 
301 /* Flags for hashtable */
302 
303 #define HICN_HASHTB_FLAGS_DEFAULT 0x00
304 
305 /*
306  * Don't use the last entry in each bucket - only use it for overflow. We use
307  * this for the FIB, currently, so that we can support in-place FIB changes
308  * that would be difficult if there were hash entry copies as part of
309  * overflow handling.
310  */
311 #define HICN_HASHTB_FLAG_USE_SEVEN 0x04
312 #define HICN_HASHTB_FLAG_KEY_FMT_PFX 0x08
313 #define HICN_HASHTB_FLAG_KEY_FMT_NAME 0x10
314 
315 /*
316  * Max prefix name components we'll support in our incremental hashing;
317  * currently used only for LPM in the FIB.
318  */
319 #define HICN_HASHTB_MAX_NAME_COMPS HICN_PARAM_FIB_ENTRY_PFX_COMPS_MAX
320 
321 /*
322  * APIs and inlines
323  */
324 
325 /* Compute hash node index from node pointer */
326 static inline u32
327 hicn_hashtb_node_idx_from_node (hicn_hashtb_h h, hicn_hash_node_t *p)
328 {
329  return (p - h->ht_nodes);
330 }
331 
332 /* Retrieve a hashtable node by node index */
333 static inline hicn_hash_node_t *
334 hicn_hashtb_node_from_idx (hicn_hashtb_h h, u32 idx)
335 {
336  return (pool_elt_at_index (h->ht_nodes, idx));
337 }
338 
339 /* Allocate a brand-new hashtable */
340 int hicn_hashtb_alloc (hicn_hashtb_h *ph, u32 max_elems, size_t app_data_size);
341 
342 /* Free a hashtable, including its embedded arrays */
343 int hicn_hashtb_free (hicn_hashtb_h *ph);
344 
345 /* Hash a bytestring, currently using bihash */
346 u64 hicn_hashtb_hash_bytestring (const u8 *key, u32 keylen);
347 
348 always_inline hicn_hash_entry_t *
349 hicn_hashtb_get_entry (hicn_hashtb_h h, u32 entry_idx, u32 bucket_id,
350  u8 bucket_overflow)
351 {
352  hicn_hash_bucket_t *bucket;
353  if (bucket_overflow)
354  bucket = pool_elt_at_index (h->ht_overflow_buckets, bucket_id);
355  else
356  bucket = (hicn_hash_bucket_t *) (h->ht_buckets + bucket_id);
357 
358  return &(bucket->hb_entries[entry_idx]);
359 }
360 
361 /* Hash a name, currently using bihash */
362 always_inline u64
363 hicn_hashtb_hash_name (const u8 *key, u16 keylen)
364 {
365  if (key != NULL && keylen == HICN_V4_NAME_LEN)
366  {
367  clib_bihash_kv_8_8_t kv;
368  kv.key = ((u64 *) key)[0];
369  return clib_bihash_hash_8_8 (&kv);
370  }
371  else if (key != NULL && keylen == HICN_V6_NAME_LEN)
372  {
373  clib_bihash_kv_24_8_t kv;
374  kv.key[0] = ((u64 *) key)[0];
375  kv.key[1] = ((u64 *) key)[1];
376  kv.key[2] = ((u32 *) key)[4];
377  return clib_bihash_hash_24_8 (&kv);
378  }
379  else
380  {
381  return (-1LL);
382  }
383 }
384 
385 /*
386  * Prepare a hashtable node for insertion, supplying the key and computed
387  * hash info. This sets up the node->key relationship, possibly allocating
388  * overflow key buffers.
389  */
390 void hicn_hashtb_init_node (hicn_hashtb_h h, hicn_hash_node_t *node,
391  const u8 *key, u32 keylen);
392 
393 /*
394  * Insert a node into the hashtable. We expect the caller has used the init
395  * api to set the node key and hash info, and populated the extra data area
396  * (if any) - or done the equivalent work itself.
397  */
398 int hicn_hashtb_insert (hicn_hashtb_h h, hicn_hash_node_t *node,
399  hicn_hash_entry_t **hash_entry, u64 hash, u32 *node_id,
400  index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs,
401  u8 *hash_entry_id, u32 *bucket_id,
402  u8 *bucket_is_overflow);
403 
404 /*
405  * Basic api to lookup a specific hash+key tuple. This does the entire lookup
406  * operation, retrieving node structs and comparing keys, so it's not
407  * optimized for prefetching or high performance.
408  *
409  * Returns zero and mails back a node on success, errno otherwise.
410  */
411 int hicn_hashtb_lookup_node (hicn_hashtb_h h, const u8 *key, u32 keylen,
412  u64 hashval, u8 is_data, u32 *node_id,
413  index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs,
414  u8 *hash_entry_id, u32 *bucket_id,
415  u8 *bucket_is_overflow);
416 
417 /*
418  * Extended api to lookup a specific hash+key tuple. The implementation
419  * allows the caller to locate nodes that are marked for deletion; this is
420  * part of some hashtable applications, such as the FIB.
421  *
422  * This does the entire lookup operation, retrieving node structs and comparing
423  * keys, so it's not optimized for prefetching or high performance.
424  *
425  * Returns zero and mails back a node on success, errno otherwise.
426  */
427 int hicn_hashtb_lookup_node_ex (hicn_hashtb_h h, const u8 *key, u32 keylen,
428  u64 hashval, u8 is_data, int include_deleted_p,
429  u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id,
430  u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id,
431  u8 *bucket_is_overflow);
432 
440 int hicn_node_compare (const u8 *key, u32 keylen, hicn_hash_node_t *node);
441 
442 /*
443  * Remove a node from a hashtable using the node itself. The internal data
444  * structs are cleaned up, but the node struct itself is not: the caller must
445  * free the node itself.
446  */
447 void hicn_hashtb_remove_node (hicn_hashtb_h h, hicn_hash_node_t *node,
448  u64 hashval);
449 
450 /*
451  * Delete a node from a hashtable using the node itself, and delete/free the
452  * node. Caller's pointer is cleared on success.
453  */
454 void hicn_hashtb_delete (hicn_hashtb_h h, hicn_hash_node_t **pnode,
455  u64 hashval);
456 
457 /*
458  * Utility to init a new entry in a hashtable bucket/row. We use this to add
459  * new a node+hash, and to clear out an entry during removal.
460  */
461 void hicn_hashtb_init_entry (hicn_hash_entry_t *entry, u32 nodeidx,
462  u64 hashval, u32 locks);
463 
464 /*
465  * Return data area embedded in a hash node struct. We maintain an 'offset'
466  * value in case the common node body struct doesn't leave the data area
467  * aligned properly.
468  */
469 static inline void *
470 hicn_hashtb_node_data (hicn_hash_node_t *node)
471 {
472  return ((u8 *) (node) + ht_node_data_offset_aligned);
473 }
474 
475 /*
476  * Use some bits of the low half of the hash to locate a row/bucket in the
477  * table
478  */
479 static inline u32
480 hicn_hashtb_bucket_idx (hicn_hashtb_h h, u64 hashval)
481 {
482  return ((u32) (hashval & (h->ht_bucket_count - 1)));
483 }
484 
485 /*
486  * Return a hash node struct from the free list, or NULL. Note that the
487  * returned struct is _not_ cleared/zeroed - init is up to the caller.
488  */
489 static inline hicn_hash_node_t *
490 hicn_hashtb_alloc_node (hicn_hashtb_h h)
491 {
492  hicn_hash_node_t *p = NULL;
493 
494  if (h->ht_nodes_used < h->ht_node_count)
495  {
496  pool_get_aligned (h->ht_nodes, p, 8);
497  h->ht_nodes_used++;
498  }
499  return (p);
500 }
501 
502 /*
503  * Release a hashtable node back to the free list when an entry is cleared
504  */
505 void hicn_hashtb_free_node (hicn_hashtb_h h, hicn_hash_node_t *node);
506 
507 /*
508  * Walk a hashtable, iterating through the nodes, keeping context in 'ctx'
509  * between calls.
510  *
511  * Set the context value to HICN_HASH_WALK_CTX_INITIAL to start an iteration.
512  */
513 int hicn_hashtb_next_node (hicn_hashtb_h h, hicn_hash_node_t **pnode,
514  u64 *ctx);
515 
516 int hicn_hashtb_key_to_str (hicn_hashtb_h h, const hicn_hash_node_t *node,
517  char *buf, int bufsize, int must_fit);
518 
519 /*
520  * single hash full name can pass offset for two hashes calculation in case
521  * we use CS and PIT in a two steps hashes (prefix + seqno)
522  */
523 always_inline int
524 hicn_hashtb_fullhash (const u8 *name, u16 namelen, u64 *name_hash)
525 {
526  *name_hash = hicn_hashtb_hash_name (name, namelen);
527  return (*name_hash != (-1LL) ? HICN_ERROR_NONE : HICN_ERROR_HASHTB_INVAL);
528 }
529 
530 #endif /* // __HICN_HASHTB_H__ */
531 
532 /*
533  * fd.io coding-style-patch-verification: ON
534  *
535  * Local Variables: eval: (c-set-style "gnu") End:
536  */
hicn_hashtb_s
Definition: hashtb.h:263
hicn_hash_key_t
Definition: hashtb.h:108
parser.h
error.h
hicn_node_compare
int hicn_node_compare(const u8 *key, u32 keylen, hicn_hash_node_t *node)
Compares the key in the node with the given key.
params.h