Hybrid ICN (hICN) plugin  v21.06-rc0-4-g18fa668
pcs.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2021 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_PCS_H__
17 #define __HICN_PCS_H__
18 
19 #include "hashtb.h"
20 #include "face_db.h"
21 #include "strategy_dpo_manager.h"
22 #include "error.h"
24 #include "faces/face.h"
25 
37 /* The PIT and CS are stored as a union */
38 #define HICN_PIT_NULL_TYPE 0
39 #define HICN_PIT_TYPE 1
40 #define HICN_CS_TYPE 2
41 
42 /*
43  * Definitions and Forward refs for the time counters we're trying out.
44  * Counters are maintained by the background process. TODO.
45  */
46 #define SEC_MS 1000
47 #define HICN_INFRA_FAST_TIMER_SECS 1
48 #define HICN_INFRA_FAST_TIMER_MSECS (HICN_INFRA_FAST_TIMER_SECS * SEC_MS)
49 #define HICN_INFRA_SLOW_TIMER_SECS 60
50 #define HICN_INFRA_SLOW_TIMER_MSECS (HICN_INFRA_SLOW_TIMER_SECS * SEC_MS)
51 
52 /*
53  * Note that changing this may change alignment within the PIT struct, so be
54  * careful.
55  */
56 typedef struct __attribute__ ((packed)) hicn_pcs_shared_s
57 {
58 
59  /* Installation/creation time (vpp float units, for now) */
60  f64 create_time;
61 
62  /* Expiration time (vpp float units, for now) */
63  f64 expire_time;
64 
65  /* Shared 'flags' octet */
66  u8 entry_flags;
67 
68  /* Needed to align for the pit or cs portion */
69  u8 padding;
70 } hicn_pcs_shared_t;
71 
72 #define HICN_PCS_ENTRY_CS_FLAG 0x01
73 
74 /*
75  * PIT entry, unioned with a CS entry below
76  */
77 typedef struct __attribute__ ((packed)) hicn_pit_entry_s
78 {
79 
80  /* Shared size 8 + 8 + 2 = 18B */
81 
82  /*
83  * Egress next hop (containes the egress face) This id refers to the
84  * position of the choosen face in the next_hops array of the dpo */
85  /* 18B + 1B = 19B */
86  u8 pe_txnh;
87 
88  /* Array of incoming ifaces */
89  /* 24B + 32B (8B*4) =56B */
90  hicn_face_db_t faces;
91 
92 } hicn_pit_entry_t;
93 
94 #define HICN_CS_ENTRY_OPAQUE_SIZE HICN_HASH_NODE_APP_DATA_SIZE - 36
95 
96 /*
97  * CS entry, unioned with a PIT entry below
98  */
99 typedef struct __attribute__ ((packed)) hicn_cs_entry_s
100 {
101  /* 18B + 2B = 20B */
102  u16 align;
103 
104  /* Packet buffer, if held */
105  /* 20B + 4B = 24B */
106  u32 cs_pkt_buf;
107 
108  /* Ingress face */
109  /* 24B + 4B = 28B */
110  hicn_face_id_t cs_rxface;
111 
112  /* Linkage for LRU, in the form of hashtable node indexes */
113  /* 28B + 8B = 36B */
114  u32 cs_lru_prev;
115  u32 cs_lru_next;
116 
117  /* Reserved for implementing cache policy different than LRU */
118  /* 36B + (64 - 36)B = 64B */
119  u8 opaque[HICN_CS_ENTRY_OPAQUE_SIZE];
120 
121 } __attribute__ ((packed)) hicn_cs_entry_t;
122 
123 /*
124  * Combined PIT/CS entry data structure, embedded in a hashtable entry after
125  * the common hashtable preamble struct. This MUST fit in the available
126  * (fixed) space in a hashtable node.
127  */
128 typedef struct hicn_pcs_entry_s
129 {
130 
131  hicn_pcs_shared_t shared;
132 
133  union
134  {
135  hicn_pit_entry_t pit;
136  hicn_cs_entry_t cs;
137  } u;
139 
140 /*
141  * Overall PIT/CS table, based on the common hashtable
142  */
143 typedef struct hicn_pit_cs_s
144 {
145 
146  hicn_hashtb_t *pcs_table;
147 
148  /* Counters for PIT/CS sentries */
149  u32 pcs_pit_count;
150  u32 pcs_cs_count;
151  u32 pcs_cs_dealloc;
152  u32 pcs_pit_dealloc;
153 
154  /* Total size of PCS */
155  u32 pcs_size;
156 
157  hicn_cs_policy_t policy_state;
158  hicn_cs_policy_vft_t policy_vft;
159 
160 } hicn_pit_cs_t;
161 
162 /* Functions declarations */
163 int hicn_pit_create (hicn_pit_cs_t *p, u32 num_elems);
164 
165 always_inline void hicn_pit_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
166  hicn_pcs_entry_t *pcs_entry,
167  hicn_hash_entry_t *hash_entry,
168  hicn_hash_node_t *node,
169  const hicn_dpo_vft_t *dpo_vft,
170  dpo_id_t *hicn_dpo_id,
171  hicn_face_id_t inface_id, u8 is_appface);
172 
173 always_inline void hicn_pcs_cs_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
174  hicn_pcs_entry_t *old_entry,
175  hicn_pcs_entry_t *entry,
176  hicn_hash_node_t *node);
177 
178 always_inline void hicn_pcs_cs_delete (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
179  hicn_pcs_entry_t **pcs_entry,
180  hicn_hash_node_t **node,
181  hicn_hash_entry_t *hash_entry,
182  const hicn_dpo_vft_t *dpo_vft,
183  dpo_id_t *hicn_dpo_id);
184 
185 always_inline int
186 hicn_pcs_cs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
187  hicn_pcs_entry_t *entry, hicn_hash_node_t *node,
188  hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id,
189  index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs,
190  u8 *hash_entry_id, u32 *bucket_id, u8 *bucket_is_overflow);
191 
192 always_inline int hicn_pcs_cs_insert_update (
193  vlib_main_t *vm, hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry,
194  hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry, u64 hashval,
195  u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, u8 *hash_entry_id,
196  u32 *bucket_id, u8 *bucket_is_overflow, hicn_face_id_t inface);
197 
198 always_inline int
199 hicn_pcs_pit_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry,
200  hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry,
201  u64 hashval, u32 *node_id, index_t *dpo_ctx_id,
202  u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id,
203  u8 *bucket_is_overflow);
204 
205 always_inline void
206 hicn_pcs_pit_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
207  hicn_hash_node_t **node, vlib_main_t *vm,
208  hicn_hash_entry_t *hash_entry,
209  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id);
210 
211 always_inline int hicn_pcs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
212  hicn_pcs_entry_t *entry,
213  hicn_hash_node_t *node,
214  hicn_hash_entry_t **hash_entry, u64 hashval,
215  u32 *node_id, index_t *dpo_ctx_id,
216  u8 *vft_id, u8 *is_cs, u8 *hash_entry_id,
217  u32 *bucket_id, u8 *bucket_is_overflow);
218 
219 always_inline void hicn_pcs_delete (hicn_pit_cs_t *pitcs,
220  hicn_pcs_entry_t **pcs_entryp,
221  hicn_hash_node_t **node, vlib_main_t *vm,
222  hicn_hash_entry_t *hash_entry,
223  const hicn_dpo_vft_t *dpo_vft,
224  dpo_id_t *hicn_dpo_id);
225 
226 always_inline void
227 hicn_pcs_remove_lock (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
228  hicn_hash_node_t **node, vlib_main_t *vm,
229  hicn_hash_entry_t *hash_entry,
230  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id);
231 
232 always_inline void hicn_cs_delete_trimmed (hicn_pit_cs_t *pitcs,
233  hicn_pcs_entry_t **pcs_entryp,
234  hicn_hash_entry_t *hash_entry,
235  hicn_hash_node_t **node,
236  vlib_main_t *vm);
237 
238 /* Function implementation */
239 /* Accessor for pit/cs data inside hash table node */
240 static inline hicn_pcs_entry_t *
241 hicn_pit_get_data (hicn_hash_node_t *node)
242 {
243  return (hicn_pcs_entry_t *) (hicn_hashtb_node_data (node));
244 }
245 
246 /* Init pit/cs data block (usually inside hash table node) */
247 static inline void
248 hicn_pit_init_data (hicn_pcs_entry_t *p)
249 {
250  p->shared.entry_flags = 0;
251  p->u.pit.faces.n_faces = 0;
252  p->u.pit.faces.is_overflow = 0;
253  hicn_face_bucket_t *face_bkt;
254  pool_get (hicn_face_bucket_pool, face_bkt);
255 
256  p->u.pit.faces.next_bucket = face_bkt - hicn_face_bucket_pool;
257 }
258 
259 /* Init pit/cs data block (usually inside hash table node) */
260 static inline void
261 hicn_cs_init_data (hicn_pcs_entry_t *p)
262 {
263  p->shared.entry_flags = 0;
264  p->u.pit.faces.n_faces = 0;
265  p->u.pit.faces.is_overflow = 0;
266 }
267 
268 static inline f64
269 hicn_pcs_get_exp_time (f64 cur_time_sec, u64 lifetime_msec)
270 {
271  return (cur_time_sec + ((f64) lifetime_msec) / SEC_MS);
272 }
273 
274 /*
275  * Configure CS LRU limit. Zero is accepted, means 'no limit', probably not a
276  * good choice.
277  */
278 static inline void
279 hicn_pit_set_lru_max (hicn_pit_cs_t *p, u32 limit)
280 {
281  p->policy_state.max = limit;
282 }
283 
284 /*
285  * Accessor for PIT interest counter.
286  */
287 static inline u32
288 hicn_pit_get_int_count (const hicn_pit_cs_t *pitcs)
289 {
290  return (pitcs->pcs_pit_count);
291 }
292 
293 /*
294  * Accessor for PIT cs entries counter.
295  */
296 static inline u32
297 hicn_pit_get_cs_count (const hicn_pit_cs_t *pitcs)
298 {
299  return (pitcs->pcs_cs_count);
300 }
301 
302 static inline u32
303 hicn_pcs_get_ntw_count (const hicn_pit_cs_t *pitcs)
304 {
305  return (pitcs->policy_state.count);
306 }
307 
308 static inline u32
309 hicn_pit_get_htb_bucket_count (const hicn_pit_cs_t *pitcs)
310 {
311  return (pitcs->pcs_table->ht_overflow_buckets_used);
312 }
313 
314 static inline int
315 hicn_cs_enabled (hicn_pit_cs_t *pit)
316 {
317  switch (HICN_FEATURE_CS)
318  {
319  case 0:
320  default:
321  return (0);
322  case 1:
323  return (pit->policy_state.max > 0);
324  }
325 }
326 
327 /*
328  * Delete a PIT/CS entry from the hashtable, freeing the hash node struct.
329  * The caller's pointers are zeroed! If cs_trim is true, entry has already
330  * been removed from lru list The main purpose of this wrapper is helping
331  * maintain the per-PIT stats.
332  */
333 always_inline void
334 hicn_pcs_delete_internal (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
335  hicn_hash_entry_t *hash_entry,
336  hicn_hash_node_t **node, vlib_main_t *vm,
337  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id)
338 {
339  hicn_pcs_entry_t *pcs = *pcs_entryp;
340 
341  ASSERT (pcs == hicn_hashtb_node_data (*node));
342 
343  if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
344  {
345  pitcs->pcs_cs_dealloc++;
346  /* Free any associated packet buffer */
347  vlib_buffer_free_one (vm, pcs->u.cs.cs_pkt_buf);
348  pcs->u.cs.cs_pkt_buf = ~0;
349  ASSERT ((pcs->u.cs.cs_lru_prev == 0) &&
350  (pcs->u.cs.cs_lru_prev == pcs->u.cs.cs_lru_next));
351  }
352  else
353  {
354  pitcs->pcs_pit_dealloc++;
355  hicn_strategy_dpo_ctx_unlock (hicn_dpo_id);
356 
357  /* Flush faces */
358  hicn_faces_flush (&(pcs->u.pit.faces));
359  }
360 
361  hicn_hashtb_delete (pitcs->pcs_table, node, hash_entry->he_msb64);
362  *pcs_entryp = NULL;
363 }
364 
365 /*
366  * Convert a PIT entry into a CS entry (assumes that the entry is already in
367  * the hashtable.) This is primarily here to maintain the internal counters.
368  */
369 always_inline void
370 hicn_pit_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
371  hicn_pcs_entry_t *pcs_entry, hicn_hash_entry_t *hash_entry,
372  hicn_hash_node_t *node, const hicn_dpo_vft_t *dpo_vft,
373  dpo_id_t *hicn_dpo_id, hicn_face_id_t inface_id, u8 is_appface)
374 {
375 
376  /*
377  * Different from the insert node. In here we don't need to add a new
378  * hash entry.
379  */
380  pitcs->pcs_pit_count--;
381  hicn_strategy_dpo_ctx_unlock (hicn_dpo_id);
382  /* Flush faces */
383  hicn_faces_flush (&(pcs_entry->u.pit.faces));
384 
385  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY;
386  node->hn_flags |= HICN_HASH_NODE_CS_FLAGS;
387  pcs_entry->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG;
388 
389  pcs_entry->u.cs.cs_rxface = inface_id;
390 
391  /* Update the CS according to the policy */
392  hicn_cs_policy_t *policy_state;
393  hicn_cs_policy_vft_t *policy_vft;
394 
395  policy_state = &pitcs->policy_state;
396  policy_vft = &pitcs->policy_vft;
397 
398  policy_vft->hicn_cs_insert (pitcs, node, pcs_entry, policy_state);
399  pitcs->pcs_cs_count++;
400 
401  if (policy_state->count > policy_state->max)
402  {
403  hicn_hash_node_t *node;
404  hicn_pcs_entry_t *pcs_entry;
405  hicn_hash_entry_t *hash_entry;
406  policy_vft->hicn_cs_delete_get (pitcs, policy_state, &node, &pcs_entry,
407  &hash_entry);
408 
409  /*
410  * We don't have to decrease the lock (therefore we cannot
411  * use hicn_pcs_cs_delete function)
412  */
413  policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
414 
415  hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
416 
417  /* Update the global CS counter */
418  pitcs->pcs_cs_count--;
419  }
420 }
421 
422 /* Functions specific for PIT or CS */
423 
424 always_inline void
425 hicn_pcs_cs_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
426  hicn_pcs_entry_t *old_entry, hicn_pcs_entry_t *entry,
427  hicn_hash_node_t *node)
428 {
429  hicn_cs_policy_t *policy_state;
430  hicn_cs_policy_vft_t *policy_vft;
431 
432  policy_state = &pitcs->policy_state;
433  policy_vft = &pitcs->policy_vft;
434 
435  if (entry->u.cs.cs_rxface != old_entry->u.cs.cs_rxface)
436  {
437  /* Dequeue content from the old queue */
438  policy_vft->hicn_cs_dequeue (pitcs, node, old_entry, policy_state);
439 
440  old_entry->u.cs.cs_rxface = entry->u.cs.cs_rxface;
441  policy_state = &pitcs->policy_state;
442  policy_vft = &pitcs->policy_vft;
443 
444  policy_vft->hicn_cs_insert (pitcs, node, old_entry, policy_state);
445 
446  if (policy_state->count > policy_state->max)
447  {
448  hicn_hash_node_t *node;
449  hicn_pcs_entry_t *pcs_entry;
450  hicn_hash_entry_t *hash_entry;
451  policy_vft->hicn_cs_delete_get (pitcs, policy_state, &node,
452  &pcs_entry, &hash_entry);
453 
454  /*
455  * We don't have to decrease the lock (therefore we cannot
456  * use hicn_pcs_cs_delete function)
457  */
458  policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
459 
460  hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
461 
462  /* Update the global CS counter */
463  pitcs->pcs_cs_count--;
464  }
465  }
466  else
467  /* Update the CS LRU, moving this item to the head */
468  policy_vft->hicn_cs_update (pitcs, node, old_entry, policy_state);
469 }
470 
471 always_inline void
472 hicn_pcs_cs_delete (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
473  hicn_pcs_entry_t **pcs_entryp, hicn_hash_node_t **nodep,
474  hicn_hash_entry_t *hash_entry,
475  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id)
476 {
477  if (!(hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED))
478  {
479  hicn_cs_policy_t *policy_state;
480  hicn_cs_policy_vft_t *policy_vft;
481 
482  policy_state = &pitcs->policy_state;
483  policy_vft = &pitcs->policy_vft;
484 
485  policy_vft->hicn_cs_dequeue (pitcs, (*nodep), (*pcs_entryp),
486  policy_state);
487 
488  /* Update the global CS counter */
489  pitcs->pcs_cs_count--;
490  }
491 
492  /* A data could have been inserted in the CS through a push. In this case
493  * locks == 0 */
494  hash_entry->locks--;
495  if (hash_entry->locks == 0)
496  {
497  hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, nodep, vm,
498  dpo_vft, hicn_dpo_id);
499  }
500  else
501  {
502  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
503  }
504 }
505 
506 always_inline int
507 hicn_pcs_cs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
508  hicn_pcs_entry_t *entry, hicn_hash_node_t *node,
509  hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id,
510  index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs,
511  u8 *hash_entry_id, u32 *bucket_id, u8 *bucket_is_overflow)
512 {
513  ASSERT (entry == hicn_hashtb_node_data (node));
514 
515  int ret = hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval,
516  node_id, dpo_ctx_id, vft_id, is_cs,
517  hash_entry_id, bucket_id, bucket_is_overflow);
518 
519  if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
520  {
521  /* Mark the entry as a CS entry */
522  node->hn_flags |= HICN_HASH_NODE_CS_FLAGS;
523  entry->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG;
524  (*hash_entry)->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY;
525 
526  hicn_cs_policy_t *policy_state;
527  hicn_cs_policy_vft_t *policy_vft;
528 
529  policy_state = &pitcs->policy_state;
530  policy_vft = &pitcs->policy_vft;
531 
532  policy_vft->hicn_cs_insert (pitcs, node, entry, policy_state);
533  pitcs->pcs_cs_count++;
534 
535  if (policy_state->count > policy_state->max)
536  {
537  hicn_hash_node_t *node;
538  hicn_pcs_entry_t *pcs_entry;
539  hicn_hash_entry_t *hash_entry;
540  policy_vft->hicn_cs_delete_get (pitcs, policy_state, &node,
541  &pcs_entry, &hash_entry);
542 
543  /*
544  * We don't have to decrease the lock (therefore we cannot
545  * use hicn_pcs_cs_delete function)
546  */
547  policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
548 
549  hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
550 
551  /* Update the global CS counter */
552  pitcs->pcs_cs_count--;
553  }
554  }
555  return ret;
556 }
557 
558 /*
559  * Insert CS entry into the hashtable The main purpose of this wrapper is
560  * helping maintain the per-PIT stats.
561  */
562 always_inline int
563 hicn_pcs_cs_insert_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
564  hicn_pcs_entry_t *entry, hicn_hash_node_t *node,
565  hicn_hash_entry_t **hash_entry, u64 hashval,
566  u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id,
567  u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id,
568  u8 *bucket_is_overflow, hicn_face_id_t inface)
569 {
570  int ret;
571 
572  ASSERT (entry == hicn_hashtb_node_data (node));
573 
574  entry->u.cs.cs_rxface = inface;
575  ret = hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval,
576  node_id, dpo_ctx_id, vft_id, is_cs, hash_entry_id,
577  bucket_id, bucket_is_overflow);
578 
579  /* A content already exists in CS with the same name */
580  if (ret == HICN_ERROR_HASHTB_EXIST && *is_cs)
581  {
582  /* Update the entry */
583  hicn_hash_node_t *existing_node =
584  hicn_hashtb_node_from_idx (pitcs->pcs_table, *node_id);
585  hicn_pcs_entry_t *pitp = hicn_pit_get_data (existing_node);
586 
587  /* Free associated packet buffer and update counter */
588  pitcs->pcs_cs_dealloc++;
589  vlib_buffer_free_one (vm, pitp->u.cs.cs_pkt_buf);
590 
591  pitp->shared.create_time = entry->shared.create_time;
592  pitp->shared.expire_time = entry->shared.expire_time;
593  pitp->u.cs.cs_pkt_buf = entry->u.cs.cs_pkt_buf;
594 
595  hicn_pcs_cs_update (vm, pitcs, pitp, entry, existing_node);
596  }
597 
598  return (ret);
599 }
600 
601 /*
602  * Insert PIT entry into the hashtable The main purpose of this wrapper is
603  * helping maintain the per-PIT stats.
604  */
605 always_inline int
606 hicn_pcs_pit_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry,
607  hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry,
608  u64 hashval, u32 *node_id, index_t *dpo_ctx_id,
609  u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id,
610  u8 *bucket_is_overflow)
611 {
612  ASSERT (entry == hicn_hashtb_node_data (node));
613 
614  int ret = hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval,
615  node_id, dpo_ctx_id, vft_id, is_cs,
616  hash_entry_id, bucket_id, bucket_is_overflow);
617 
618  if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
619  pitcs->pcs_pit_count++;
620 
621  return ret;
622 }
623 
624 always_inline void
625 hicn_pcs_pit_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
626  hicn_hash_node_t **node, vlib_main_t *vm,
627  hicn_hash_entry_t *hash_entry,
628  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id)
629 {
630  hash_entry->locks--;
631  if (hash_entry->locks == 0)
632  {
633  pitcs->pcs_pit_count--;
634  hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm,
635  dpo_vft, hicn_dpo_id);
636  }
637  else
638  {
639  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
640  }
641 }
642 
643 /* Generic functions for PIT/CS */
644 
645 /*
646  * Insert PIT/CS entry into the hashtable The main purpose of this wrapper is
647  * helping maintain the per-PIT stats.
648  */
649 always_inline int
650 hicn_pcs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs,
651  hicn_pcs_entry_t *entry, hicn_hash_node_t *node,
652  hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id,
653  index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, u8 *hash_entry_id,
654  u32 *bucket_id, u8 *bucket_is_overflow)
655 {
656  int ret;
657 
658  if ((*hash_entry)->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
659  {
660  ret = hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval,
661  node_id, dpo_ctx_id, vft_id, is_cs,
662  hash_entry_id, bucket_id, bucket_is_overflow);
663  }
664  else
665  {
666  ret = hicn_pcs_pit_insert (pitcs, entry, node, hash_entry, hashval,
667  node_id, dpo_ctx_id, vft_id, is_cs,
668  hash_entry_id, bucket_id, bucket_is_overflow);
669  }
670 
671  return (ret);
672 }
673 
674 /*
675  * Delete entry if there are no pending lock on the entry, otherwise mark it
676  * as to delete.
677  */
678 always_inline void
679 hicn_pcs_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
680  hicn_hash_node_t **nodep, vlib_main_t *vm,
681  hicn_hash_entry_t *hash_entry, const hicn_dpo_vft_t *dpo_vft,
682  dpo_id_t *hicn_dpo_id)
683 {
684  /*
685  * If the entry has already been marked as deleted, it has already
686  * been dequeue
687  */
688  if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
689  {
690  hicn_pcs_cs_delete (vm, pitcs, pcs_entryp, nodep, hash_entry, dpo_vft,
691  hicn_dpo_id);
692  }
693  else
694  {
695  hicn_pcs_pit_delete (pitcs, pcs_entryp, nodep, vm, hash_entry, dpo_vft,
696  hicn_dpo_id);
697  }
698 }
699 
700 /*
701  * Remove a lock in the entry and delete it if there are no pending lock and
702  * the entry is marked as to be deleted
703  */
704 always_inline void
705 hicn_pcs_remove_lock (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
706  hicn_hash_node_t **node, vlib_main_t *vm,
707  hicn_hash_entry_t *hash_entry,
708  const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id)
709 {
710  hash_entry->locks--;
711  if (hash_entry->locks == 0 &&
712  (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED))
713  {
714  hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm,
715  dpo_vft, hicn_dpo_id);
716  }
717 }
718 
719 /*
720  * Delete entry which has already been bulk-removed from lru list
721  */
722 always_inline void
723 hicn_cs_delete_trimmed (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp,
724  hicn_hash_entry_t *hash_entry, hicn_hash_node_t **node,
725  vlib_main_t *vm)
726 {
727 
728  if (hash_entry->locks == 0)
729  {
730  const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (hash_entry->vft_id);
731  dpo_id_t hicn_dpo_id = { .dpoi_type = dpo_vft->hicn_dpo_get_type (),
732  .dpoi_proto = 0,
733  .dpoi_next_node = 0,
734  .dpoi_index = hash_entry->dpo_ctx_id };
735 
736  hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm,
737  dpo_vft, &hicn_dpo_id);
738  }
739  else
740  {
741  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
742  }
743 }
744 
745 /*
746  * wrappable counter math (assumed uint16_t): return sum of addends
747  */
748 always_inline u16
749 hicn_infra_seq16_sum (u16 addend1, u16 addend2)
750 {
751  return (addend1 + addend2);
752 }
753 
754 /*
755  * for comparing wrapping numbers, return lt,eq,gt 0 for a lt,eq,gt b
756  */
757 always_inline int
758 hicn_infra_seq16_cmp (u16 a, u16 b)
759 {
760  return ((int16_t) (a - b));
761 }
762 
763 /*
764  * below are wrappers for lt, le, gt, ge seq16 comparators
765  */
766 always_inline int
767 hicn_infra_seq16_lt (u16 a, u16 b)
768 {
769  return (hicn_infra_seq16_cmp (a, b) < 0);
770 }
771 
772 always_inline int
773 hicn_infra_seq16_le (u16 a, u16 b)
774 {
775  return (hicn_infra_seq16_cmp (a, b) <= 0);
776 }
777 
778 always_inline int
779 hicn_infra_seq16_gt (u16 a, u16 b)
780 {
781  return (hicn_infra_seq16_cmp (a, b) > 0);
782 }
783 
784 always_inline int
785 hicn_infra_seq16_ge (u16 a, u16 b)
786 {
787  return (hicn_infra_seq16_cmp (a, b) >= 0);
788 }
789 
790 extern u16 hicn_infra_fast_timer; /* Counts at 1 second intervals */
791 extern u16 hicn_infra_slow_timer; /* Counts at 1 minute intervals */
792 
793 /*
794  * Utilities to convert lifetime into expiry time based on compressed clock,
795  * suitable for the opportunistic hashtable entry timeout processing.
796  */
797 
798 // convert time in msec to time in clicks
799 always_inline u16
800 hicn_infra_ms2clicks (u64 time_ms, u64 ms_per_click)
801 {
802  f64 time_clicks =
803  ((f64) (time_ms + ms_per_click - 1)) / ((f64) ms_per_click);
804  return ((u16) time_clicks);
805 }
806 
807 always_inline u16
808 hicn_infra_get_fast_exp_time (u64 lifetime_ms)
809 {
810  u16 lifetime_clicks =
811  hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_FAST_TIMER_MSECS);
812  return (hicn_infra_seq16_sum (hicn_infra_fast_timer, lifetime_clicks));
813 }
814 
815 always_inline u16
816 hicn_infra_get_slow_exp_time (u64 lifetime_ms)
817 {
818  u16 lifetime_clicks =
819  hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_SLOW_TIMER_MSECS);
820  return (hicn_infra_seq16_sum (hicn_infra_slow_timer, lifetime_clicks));
821 }
822 
823 #endif /* // __HICN_PCS_H__ */
824 
825 /*
826  * fd.io coding-style-patch-verification: ON
827  *
828  * Local Variables: eval: (c-set-style "gnu") End:
829  */
pit
Definition: pit.h:36
hicn_pcs_entry_s
Definition: pcs.h:128
hicn_strategy_dpo_ctx_unlock
void hicn_strategy_dpo_ctx_unlock(dpo_id_t *dpo)
Unlock the dpo of a strategy ctx.
strategy_dpo_manager.h
face.h
hicn_hashtb_s
Definition: hashtb.h:263
hicn_pit_cs_s
Definition: pcs.h:143
hashtb.h
face_db.h
hicn_cs_policy_s
Definition: cs_policy.h:30
error.h
cs_policy.h
hicn_dpo_get_vft
const hicn_dpo_vft_t * hicn_dpo_get_vft(dpo_type_t vfts_id)
Get the vft to manage the dpo context.
hicn_dpo_vft_s::hicn_dpo_get_type
dpo_type_t(* hicn_dpo_get_type)(void)
Definition: strategy_dpo_manager.h:50
hicn_dpo_vft_s
Definition of the virtual function table for a hICN DPO.
Definition: strategy_dpo_manager.h:45
__attribute__
struct __attribute__((packed)) hicn_pcs_shared_s
Structure representing a face. It containes the fields shared among all the types of faces as well it...
Definition: pcs.h:56
hicn_cs_policy_vft_s
Definition of the virtual functin table for a cache policy.
Definition: cs_policy.h:57
hicn_face_bucket_s
Definition: face_db.h:39