diff options
Diffstat (limited to 'hicn-plugin')
39 files changed, 2913 insertions, 3553 deletions
diff --git a/hicn-plugin/includes/vpp_plugins/hicn/error.h b/hicn-plugin/includes/vpp_plugins/hicn/error.h index af9f5da46..be4e53c27 100644 --- a/hicn-plugin/includes/vpp_plugins/hicn/error.h +++ b/hicn-plugin/includes/vpp_plugins/hicn/error.h @@ -87,7 +87,12 @@ _ (UDP_TUNNEL_SRC_DST_TYPE, -17001, \ "Src and dst addresses have different type (ipv4 and ipv6)") \ _ (MAPME_NEXT_HOP_ADDED, -18000, "Next hop added to mapme") \ - _ (MAPME_NEXT_HOP_NOT_ADDED, -18001, "Next hop added to mapme") + _ (MAPME_NEXT_HOP_NOT_ADDED, -18001, "Next hop added to mapme") \ + _ (PCS_NOT_FOUND, -19000, "Hash not found in hash table") \ + _ (PCS_HASH_INVAL, -19001, "Error while calculating the hash") \ + _ (PCS_INVAL, -19002, "Invalid argument") \ + _ (PCS_KEY_INVAL, -19003, "Invalid hashtb key") \ + _ (PCS_EXIST, -19004, "Hash already in hashtable") typedef enum { diff --git a/hicn-plugin/src/CMakeLists.txt b/hicn-plugin/src/CMakeLists.txt index e071b3b9d..d232b4ab1 100644 --- a/hicn-plugin/src/CMakeLists.txt +++ b/hicn-plugin/src/CMakeLists.txt @@ -34,7 +34,6 @@ set(HICN_PLUGIN_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/hicn.c ${CMAKE_CURRENT_SOURCE_DIR}/hicn_api.c ${CMAKE_CURRENT_SOURCE_DIR}/cli.c - ${CMAKE_CURRENT_SOURCE_DIR}/hashtb.c ${CMAKE_CURRENT_SOURCE_DIR}/infra.c ${CMAKE_CURRENT_SOURCE_DIR}/mgmt.c ${CMAKE_CURRENT_SOURCE_DIR}/pcs.c @@ -78,7 +77,6 @@ set(HICN_PLUGIN_SOURCE_FILES set(HICN_PLUGIN_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/hicn_all_api_h.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_logging.h - ${CMAKE_CURRENT_SOURCE_DIR}/hashtb.h ${CMAKE_CURRENT_SOURCE_DIR}/mgmt.h ${CMAKE_CURRENT_SOURCE_DIR}/params.h ${CMAKE_CURRENT_SOURCE_DIR}/pcs.h @@ -245,3 +243,10 @@ build_module(${HICN_API_TEST_PLUGIN} COMPILE_OPTIONS ${COMPILER_OPTIONS} INSTALL_RPATH "${VPP_INSTALL_PLUGIN}:${HICN_INSTALL_PREFIX}:${VPP_HOME}/lib" ) + +############################################################## +# Unit tests +############################################################## +if (${BUILD_TESTS}) + add_subdirectory(test) +endif()
\ No newline at end of file diff --git a/hicn-plugin/src/cache_policies/cs_lru.c b/hicn-plugin/src/cache_policies/cs_lru.c index e65f487e1..07c4916fb 100644 --- a/hicn-plugin/src/cache_policies/cs_lru.c +++ b/hicn-plugin/src/cache_policies/cs_lru.c @@ -13,7 +13,6 @@ * limitations under the License. */ -#include "../hashtb.h" #include "../strategy_dpo_manager.h" #include "../error.h" #include "cs_lru.h" @@ -32,129 +31,112 @@ hicn_cs_policy_vft_t hicn_cs_lru = { * Insert a new CS element at the head of the CS LRU */ void -hicn_cs_lru_insert (hicn_pit_cs_t *p, hicn_hash_node_t *node, - hicn_pcs_entry_t *pcs, hicn_cs_policy_t *policy_state) +hicn_cs_lru_insert (hicn_cs_policy_t *lru_policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) { - hicn_hash_node_t *lrunode; hicn_pcs_entry_t *lrupcs; u32 idx; - idx = hicn_hashtb_node_idx_from_node (p->pcs_table, node); + idx = hicn_pcs_entry_get_index (pcs, pcs_entry); - if (policy_state->head != 0) + if (lru_policy->head != HICN_CS_POLICY_END_OF_CHAIN) { - lrunode = hicn_hashtb_node_from_idx (p->pcs_table, policy_state->head); - lrupcs = hicn_pit_get_data (lrunode); + lrupcs = hicn_pcs_entry_get_entry_from_index (pcs, lru_policy->head); - ASSERT (lrupcs->u.cs.cs_lru_prev == 0); + ASSERT (lrupcs->u.cs.cs_lru_prev == HICN_CS_POLICY_END_OF_CHAIN); lrupcs->u.cs.cs_lru_prev = idx; - pcs->u.cs.cs_lru_prev = 0; - pcs->u.cs.cs_lru_next = policy_state->head; + pcs_entry->u.cs.cs_lru_prev = HICN_CS_POLICY_END_OF_CHAIN; + pcs_entry->u.cs.cs_lru_next = lru_policy->head; - policy_state->head = idx; + lru_policy->head = idx; } else { - ASSERT (policy_state->tail == 0); /* We think the list is - * empty */ + // The list should be empty + ASSERT (lru_policy->tail == HICN_CS_POLICY_END_OF_CHAIN); - policy_state->head = policy_state->tail = idx; + lru_policy->head = lru_policy->tail = idx; - pcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_prev = 0; + pcs_entry->u.cs.cs_lru_next = pcs_entry->u.cs.cs_lru_prev = + HICN_CS_POLICY_END_OF_CHAIN; } - policy_state->count++; + lru_policy->count++; } void -hicn_cs_lru_delete_get (hicn_pit_cs_t *p, hicn_cs_policy_t *policy_state, - hicn_hash_node_t **nodep, hicn_pcs_entry_t **pcs_entry, - hicn_hash_entry_t **hash_entry) +hicn_cs_lru_delete_get (hicn_cs_policy_t *lru_policy, const hicn_pit_cs_t *pcs, + hicn_pcs_entry_t **pcs_entry) { - *nodep = hicn_hashtb_node_from_idx (p->pcs_table, policy_state->tail); - *pcs_entry = hicn_pit_get_data (*nodep); - - *hash_entry = hicn_hashtb_get_entry ( - p->pcs_table, (*nodep)->entry_idx, (*nodep)->bucket_id, - (*nodep)->hn_flags & HICN_HASH_NODE_OVERFLOW_BUCKET); + *pcs_entry = hicn_pcs_entry_get_entry_from_index (pcs, lru_policy->tail); } /* * Dequeue an LRU element, for example when it has expired. */ void -hicn_cs_lru_dequeue (hicn_pit_cs_t *pit, hicn_hash_node_t *pnode, - hicn_pcs_entry_t *pcs, hicn_cs_policy_t *lru) +hicn_cs_lru_dequeue (hicn_cs_policy_t *lru_policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) { - hicn_hash_node_t *lrunode; hicn_pcs_entry_t *lrupcs; - if (pcs->u.cs.cs_lru_prev != 0) + if (pcs_entry->u.cs.cs_lru_prev != HICN_CS_POLICY_END_OF_CHAIN) { /* Not already on the head of the LRU */ - lrunode = - hicn_hashtb_node_from_idx (pit->pcs_table, pcs->u.cs.cs_lru_prev); - lrupcs = hicn_pit_get_data (lrunode); + lrupcs = + hicn_pcs_entry_get_entry_from_index (pcs, pcs_entry->u.cs.cs_lru_prev); - lrupcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_next; + lrupcs->u.cs.cs_lru_next = pcs_entry->u.cs.cs_lru_next; } else { - ASSERT (lru->head == - hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode)); - lru->head = pcs->u.cs.cs_lru_next; + ASSERT (lru_policy->head == hicn_pcs_entry_get_index (pcs, pcs_entry)); + lru_policy->head = pcs_entry->u.cs.cs_lru_next; } - if (pcs->u.cs.cs_lru_next != 0) + if (pcs_entry->u.cs.cs_lru_next != HICN_CS_POLICY_END_OF_CHAIN) { /* Not already the end of the LRU */ - lrunode = - hicn_hashtb_node_from_idx (pit->pcs_table, pcs->u.cs.cs_lru_next); - lrupcs = hicn_pit_get_data (lrunode); + lrupcs = + hicn_pcs_entry_get_entry_from_index (pcs, pcs_entry->u.cs.cs_lru_next); - lrupcs->u.cs.cs_lru_prev = pcs->u.cs.cs_lru_prev; + lrupcs->u.cs.cs_lru_prev = pcs_entry->u.cs.cs_lru_prev; } else { /* This was the last LRU element */ - ASSERT (lru->tail == - hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode)); - lru->tail = pcs->u.cs.cs_lru_prev; + ASSERT (lru_policy->tail == hicn_pcs_entry_get_index (pcs, pcs_entry)); + lru_policy->tail = pcs_entry->u.cs.cs_lru_prev; } - pcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_prev = 0; - lru->count--; + pcs_entry->u.cs.cs_lru_next = pcs_entry->u.cs.cs_lru_prev = + HICN_CS_POLICY_END_OF_CHAIN; + lru_policy->count--; } /* - * Move a CS LRU element to the head, probably after it's been used. + * Move a CS LRU element to the head. The element must be part of the LRU list. */ void -hicn_cs_lru_update_head (hicn_pit_cs_t *pit, hicn_hash_node_t *pnode, - hicn_pcs_entry_t *pcs, hicn_cs_policy_t *lru) +hicn_cs_lru_update_head (hicn_cs_policy_t *lru_policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) { - if (pcs->u.cs.cs_lru_prev != 0) + if (pcs_entry->u.cs.cs_lru_prev != HICN_CS_POLICY_END_OF_CHAIN) { /* * Not already on the head of the LRU, detach it from its * current position */ - hicn_cs_lru_dequeue (pit, pnode, pcs, lru); + hicn_cs_lru_dequeue (lru_policy, pcs, pcs_entry); /* Now detached from the list; attach at head */ - hicn_cs_lru_insert (pit, pnode, pcs, lru); + hicn_cs_lru_insert (lru_policy, pcs, pcs_entry); } else { - /* The element is already dequeue */ - if (pcs->u.cs.cs_lru_next == 0) - { - /* Now detached from the list; attach at head */ - hicn_cs_lru_insert (pit, pnode, pcs, lru); - } - ASSERT (lru->head == - hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode)); + // The element must be already at the head of the LRU + ASSERT (lru_policy->head == hicn_pcs_entry_get_index (pcs, pcs_entry)); } } @@ -164,96 +146,86 @@ hicn_cs_lru_update_head (hicn_pit_cs_t *pit, hicn_hash_node_t *pnode, * CS's limit. Return the number of removed nodes. */ int -hicn_cs_lru_trim (hicn_pit_cs_t *pit, u32 *node_list, int sz, - hicn_cs_policy_t *lru) +hicn_cs_lru_trim (hicn_cs_policy_t *lru_policy, hicn_pit_cs_t *pcs, + u32 *node_list, size_t sz) { - hicn_hash_node_t *lrunode; hicn_pcs_entry_t *lrupcs; u32 idx; int i; - idx = lru->tail; + idx = lru_policy->tail; - for (i = 0; i < sz; i++) + for (i = 0; i < sz && idx > 0; i++) { - - if (idx == 0) - { - break; - } - lrunode = hicn_hashtb_node_from_idx (pit->pcs_table, idx); - lrupcs = hicn_pit_get_data (lrunode); + lrupcs = hicn_pcs_entry_get_entry_from_index (pcs, idx); node_list[i] = idx; idx = lrupcs->u.cs.cs_lru_prev; - lrupcs->u.cs.cs_lru_prev = 0; - lrupcs->u.cs.cs_lru_next = 0; + lrupcs->u.cs.cs_lru_prev = HICN_CS_POLICY_END_OF_CHAIN; + lrupcs->u.cs.cs_lru_next = HICN_CS_POLICY_END_OF_CHAIN; } - lru->count -= i; + lru_policy->count -= i; + lru_policy->tail = idx; - lru->tail = idx; - if (idx != 0) + if (idx != HICN_CS_POLICY_END_OF_CHAIN) { - lrunode = hicn_hashtb_node_from_idx (pit->pcs_table, idx); - lrupcs = hicn_pit_get_data (lrunode); - - lrupcs->u.cs.cs_lru_next = 0; + lrupcs = hicn_pcs_entry_get_entry_from_index (pcs, idx); + lrupcs->u.cs.cs_lru_next = HICN_CS_POLICY_END_OF_CHAIN; } else { /* If the tail is empty, the whole lru is empty */ - lru->head = 0; + lru_policy->head = HICN_CS_POLICY_END_OF_CHAIN; } - return (i); + return i; } int -hicn_cs_lru_flush (vlib_main_t *vm, struct hicn_pit_cs_s *pitcs, - hicn_cs_policy_t *state) +hicn_cs_lru_flush (hicn_cs_policy_t *lru_policy, hicn_pit_cs_t *pcs) { - if (state->head == 0 && state->tail == 0) + if (lru_policy->head == HICN_CS_POLICY_END_OF_CHAIN && + lru_policy->tail == HICN_CS_POLICY_END_OF_CHAIN) return 0; - hicn_hash_node_t *lrunode; - hicn_pcs_entry_t *lrupcs; + hicn_pcs_entry_t *pcs_entry; u32 idx; int i = 0; - idx = state->tail; + idx = lru_policy->tail; - while (idx != 0) + while (idx != HICN_CS_POLICY_END_OF_CHAIN) { - lrunode = hicn_hashtb_node_from_idx (pitcs->pcs_table, idx); - lrupcs = hicn_pit_get_data (lrunode); - - u64 hashval = 0; - hicn_hashtb_fullhash ((u8 *) &(lrunode->hn_key.ks.key), - lrunode->hn_keysize, &hashval); - hicn_hash_bucket_t *bucket = NULL; - if ((hashval & (pitcs->pcs_table->ht_bucket_count - 1)) == - lrunode->bucket_id) - { - // The bucket is in the non overflown - bucket = pitcs->pcs_table->ht_buckets + lrunode->bucket_id; - } - else - { - bucket = pool_elt_at_index (pitcs->pcs_table->ht_overflow_buckets, - lrunode->bucket_id); - } - hicn_hash_entry_t *hash_entry = - &(bucket->hb_entries[lrunode->entry_idx]); - hash_entry->locks++; - hicn_pcs_cs_delete (vm, pitcs, &lrupcs, &lrunode, hash_entry, NULL, - NULL); - idx = state->tail; + // Get tail entry + pcs_entry = hicn_pcs_entry_get_entry_from_index (pcs, idx); + + // Delete entry from the PCS. This will also update the LRU. + hicn_pcs_entry_remove_lock (pcs, pcs_entry); + + // Set index to the new tail (updated in the previous call) + idx = lru_policy->tail; + + // Advance counter i++; } - return (i); + return i; +} + +hicn_cs_policy_t +hicn_cs_lru_create (u32 max_elts) +{ + hicn_cs_policy_t policy = { + .vft = hicn_cs_lru, + .head = HICN_CS_POLICY_END_OF_CHAIN, + .tail = HICN_CS_POLICY_END_OF_CHAIN, + .count = 0, + .max = max_elts, + }; + + return policy; } /* diff --git a/hicn-plugin/src/cache_policies/cs_lru.h b/hicn-plugin/src/cache_policies/cs_lru.h index 35b82ff2c..1e67cb547 100644 --- a/hicn-plugin/src/cache_policies/cs_lru.h +++ b/hicn-plugin/src/cache_policies/cs_lru.h @@ -17,7 +17,6 @@ #define __LRU_H__ #include "../pcs.h" -#include "../hashtb.h" #include "cs_policy.h" /** @@ -28,39 +27,46 @@ extern hicn_cs_policy_vft_t hicn_cs_lru; -/* - * Insert a new CS element at the head of the CS LRU +/** + * @brief Insert a new CS element at the head of the CS LRU + * + * @param policy the cs insertion/eviction policy - LRU + * @param pcs the PCS table + * @param pcs_entry the PCS entry to insert + * @return 0 on success, -1 on overflow */ -void hicn_cs_lru_insert (hicn_pit_cs_t *pcs, hicn_hash_node_t *pnode, - hicn_pcs_entry_t *entry, hicn_cs_policy_t *lru); +void hicn_cs_lru_insert (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry); /* * Dequeue an LRU element, for example when it has expired. */ -void hicn_cs_lru_dequeue (hicn_pit_cs_t *pcs, hicn_hash_node_t *pnode, - hicn_pcs_entry_t *entry, hicn_cs_policy_t *lru); +void hicn_cs_lru_dequeue (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry); /* * Move a CS LRU element to the head, probably after it's been used. */ -void hicn_cs_lru_update_head (hicn_pit_cs_t *pcs, hicn_hash_node_t *pnode, - hicn_pcs_entry_t *entry, hicn_cs_policy_t *lru); +void hicn_cs_lru_update_head (hicn_cs_policy_t *lru, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *entry); -void hicn_cs_lru_delete_get (hicn_pit_cs_t *p, hicn_cs_policy_t *policy, - hicn_hash_node_t **node, hicn_pcs_entry_t **pcs, - hicn_hash_entry_t **hash_entry); +void hicn_cs_lru_delete_get (hicn_cs_policy_t *policy, + const hicn_pit_cs_t *pcs, + hicn_pcs_entry_t **pcs_entry); /* * Remove a batch of nodes from the CS LRU, copying their node indexes into * the caller's array. We expect this is done when the LRU size exceeds the * CS's limit. Return the number of removed nodes. */ -int hicn_cs_lru_trim (hicn_pit_cs_t *pcs, u32 *node_list, int sz, - hicn_cs_policy_t *lru); +int hicn_cs_lru_trim (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + u32 *node_list, size_t sz); + +int hicn_cs_lru_flush (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs); + +hicn_cs_policy_t hicn_cs_lru_create (u32 max_elts); -int hicn_cs_lru_flush (vlib_main_t *vm, struct hicn_pit_cs_s *pitcs, - hicn_cs_policy_t *state); -#endif /* // __LRU_H__ */ +#endif /* __LRU_H__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/hicn-plugin/src/cache_policies/cs_policy.h b/hicn-plugin/src/cache_policies/cs_policy.h index 73f3de107..5280a59c2 100644 --- a/hicn-plugin/src/cache_policies/cs_policy.h +++ b/hicn-plugin/src/cache_policies/cs_policy.h @@ -16,7 +16,9 @@ #ifndef __HICN_CS_POLICY_H__ #define __HICN_CS_POLICY_H__ -#include "../hashtb.h" +#include <vppinfra/types.h> +#include <vppinfra/clib.h> +#include <stddef.h> /** * @file cs_policy.h @@ -24,25 +26,10 @@ * This file provides the needed structures to implement a CS policy */ -/* - * Structure - */ -typedef struct hicn_cs_policy_s -{ - u32 max; - u32 count; - - /* Indexes to hashtable nodes forming CS LRU */ - u32 head; - u32 tail; - -} hicn_cs_policy_t; - /* Forward declaration */ -struct hicn_pit_cs_s; -struct hicn_hash_node_s; -struct hicn_pcs_entry_s; -struct hicn_cs_policy_s; +typedef struct hicn_pit_cs_s hicn_pit_cs_t; +typedef struct hicn_pcs_entry_s hicn_pcs_entry_t; +typedef struct hicn_cs_policy_s hicn_cs_policy_t; /** * @brief Definition of the virtual functin table for a cache policy. @@ -51,40 +38,143 @@ struct hicn_cs_policy_s; * - insert: add a new element * - update: update the position of an existing element * - dequeue: remove an element from the list - * - delete_get: return the next element that should be removed trim + * - delete_get: return the next element that should be removed + * - trim: trim last sz elements from the list * - flush: clean the cs */ typedef struct hicn_cs_policy_vft_s { - void (*hicn_cs_insert) (struct hicn_pit_cs_s *p, - struct hicn_hash_node_s *node, - struct hicn_pcs_entry_s *pcs, - hicn_cs_policy_t *policy); - - void (*hicn_cs_update) (struct hicn_pit_cs_s *p, - struct hicn_hash_node_s *node, - struct hicn_pcs_entry_s *pcs, - hicn_cs_policy_t *policy); - - void (*hicn_cs_dequeue) (struct hicn_pit_cs_s *p, - struct hicn_hash_node_s *node, - struct hicn_pcs_entry_s *pcs, - hicn_cs_policy_t *policy); - - void (*hicn_cs_delete_get) (struct hicn_pit_cs_s *p, - hicn_cs_policy_t *policy, - struct hicn_hash_node_s **node, - struct hicn_pcs_entry_s **pcs, - struct hicn_hash_entry_s **hash_entry); - - int (*hicn_cs_trim) (struct hicn_pit_cs_s *p, u32 *node_list, int sz, - hicn_cs_policy_t *policy); - - int (*hicn_cs_flush) (vlib_main_t *vm, struct hicn_pit_cs_s *p, - hicn_cs_policy_t *policy_state); + void (*hicn_cs_insert) (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry); + + void (*hicn_cs_update) (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry); + + void (*hicn_cs_dequeue) (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry); + + void (*hicn_cs_delete_get) (hicn_cs_policy_t *policy, + const hicn_pit_cs_t *pcs, + hicn_pcs_entry_t **pcs_entry); + + int (*hicn_cs_trim) (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + u32 *node_list, size_t sz); + + int (*hicn_cs_flush) (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs); } hicn_cs_policy_vft_t; -#endif /* // __HICN_POLICY_H__ */ +/* + * CS policy + */ +typedef struct hicn_cs_policy_s +{ +#define HICN_CS_POLICY_END_OF_CHAIN (u32) (~0) + + /* + * VFT implementing the CS eviction/insertion policy. This must be the first + * element of the structure. + */ + hicn_cs_policy_vft_t vft; + + /* + * Max number of element in CS + */ + u32 max; + + /* + * Number of element in CS + */ + u32 count; + + /* + * Head element of the CS (i.e. the most recent element used for LRU) + */ + u32 head; + + /* + * Tail element of the LRU (i.e. the next element to evict for LRU) + */ + u32 tail; +} hicn_cs_policy_t; + +/* + * Get the max number of element in the CS + */ +always_inline u32 +hicn_cs_policy_get_max (const hicn_cs_policy_t *policy) +{ + return policy->max; +} + +/* + * Get the number of element in the CS + */ +always_inline u32 +hicn_cs_policy_get_count (const hicn_cs_policy_t *policy) +{ + return policy->count; +} + +/* + * Get the head element of the CS + */ +always_inline u32 +hicn_cs_policy_get_head (const hicn_cs_policy_t *policy) +{ + return policy->head; +} + +/* + * Get the tail element of the CS + */ +always_inline u32 +hicn_cs_policy_get_tail (const hicn_cs_policy_t *policy) +{ + return policy->tail; +} + +always_inline void +hicn_cs_policy_insert (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) +{ + return policy->vft.hicn_cs_insert (policy, pcs, pcs_entry); +} + +always_inline void +hicn_cs_policy_update (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) +{ + return policy->vft.hicn_cs_update (policy, pcs, pcs_entry); +} + +always_inline void +hicn_cs_policy_dequeue (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + hicn_pcs_entry_t *pcs_entry) +{ + return policy->vft.hicn_cs_dequeue (policy, pcs, pcs_entry); +} + +always_inline void +hicn_cs_policy_delete_get (hicn_cs_policy_t *policy, const hicn_pit_cs_t *pcs, + hicn_pcs_entry_t **pcs_entry) +{ + return policy->vft.hicn_cs_delete_get (policy, pcs, pcs_entry); +} + +always_inline int +hicn_cs_policy_trim (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs, + u32 *node_list, int sz) +{ + return policy->vft.hicn_cs_trim (policy, pcs, node_list, sz); +} + +always_inline int +hicn_cs_policy_flush (hicn_cs_policy_t *policy, hicn_pit_cs_t *pcs) +{ + return policy->vft.hicn_cs_flush (policy, pcs); +} + +#endif /* __HICN_POLICY_H__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/hicn-plugin/src/cli.c b/hicn-plugin/src/cli.c index f743f6362..70fe3307a 100644 --- a/hicn-plugin/src/cli.c +++ b/hicn-plugin/src/cli.c @@ -215,7 +215,7 @@ static clib_error_t * hicn_cli_show_command_fn (vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd) { - int face_p = 0, fib_p = 0, all_p = 0, internal_p = 0, strategies_p = 0, + int face_p = 0, fib_p = 0, all_p = 0, strategies_p = 0, ret = HICN_ERROR_NONE; /* Get a line of input. */ @@ -228,14 +228,6 @@ hicn_cli_show_command_fn (vlib_main_t *vm, unformat_input_t *main_input, { face_p = 1; } - else if (unformat (line_input, "internal")) - { - /* - * We consider 'internal' a superset, so - * include 'detail' too - */ - internal_p = 1; - } else if (unformat (line_input, "strategies")) { /* @@ -335,20 +327,6 @@ hicn_cli_show_command_fn (vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_output (vm, (char *) strbuf); } done: - if (all_p && internal_p && ret == HICN_ERROR_NONE) - { - vlib_cli_output (vm, "Plugin features: cs:%d\n", HICN_FEATURE_CS); - vlib_cli_output (vm, - "Removed CS entries (and freed vlib buffers) %d, " - "Removed PIT entries %d\n", - hicn_main.pitcs.pcs_cs_dealloc, - hicn_main.pitcs.pcs_pit_dealloc); - vlib_cli_output (vm, - "Bucke count %d, Overflow buckets count %d, used %d\n", - hicn_main.pitcs.pcs_table->ht_bucket_count, - hicn_main.pitcs.pcs_table->ht_overflow_bucket_count, - hicn_main.pitcs.pcs_table->ht_overflow_buckets_used); - } return (ret == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n", get_error_string (ret)); diff --git a/hicn-plugin/src/data_fwd.h b/hicn-plugin/src/data_fwd.h index b21fa0a2f..129ca5b73 100644 --- a/hicn-plugin/src/data_fwd.h +++ b/hicn-plugin/src/data_fwd.h @@ -62,6 +62,15 @@ typedef enum HICN_DATA_FWD_N_NEXT, } hicn_data_fwd_next_t; +/* + * Node context data; we think this is per-thread/instance + */ +typedef struct hicn_data_fwd_runtime_s +{ + int id; + hicn_pit_cs_t *pitcs; +} hicn_data_fwd_runtime_t; + /** * @brief Create a maximum of 256 clones of buffer and store them * in the supplied array. Unlike the original function in the vlib diff --git a/hicn-plugin/src/data_fwd_node.c b/hicn-plugin/src/data_fwd_node.c index a3f1a592f..f909ae536 100644 --- a/hicn-plugin/src/data_fwd_node.c +++ b/hicn-plugin/src/data_fwd_node.c @@ -32,291 +32,6 @@ static char *hicn_data_fwd_error_strings[] = { }; /* Declarations */ -always_inline void drop_packet (vlib_main_t *vm, u32 bi0, u32 *n_left_to_next, - u32 *next0, u32 **to_next, u32 *next_index, - vlib_node_runtime_t *node); - -always_inline int -hicn_satisfy_faces (vlib_main_t *vm, u32 b0, hicn_pcs_entry_t *pitp, - u32 *n_left_to_next, u32 **to_next, u32 *next_index, - vlib_node_runtime_t *node, u8 isv6, - vl_api_hicn_api_node_stats_get_reply_t *stats); - -always_inline void -clone_data_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *pitp, hicn_header_t *hicn0, f64 tnow, - hicn_hash_node_t *nodep, vlib_buffer_t *b0, - hicn_hash_entry_t *hash_entry, u64 name_hash, - hicn_buffer_t *hicnb, const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id, hicn_lifetime_t dmsg_lifetime); - -/* packet trace format function */ -always_inline u8 *hicn_data_fwd_format_trace (u8 *s, va_list *args); - -vlib_node_registration_t hicn_data_fwd_node; - -/* - * ICN forwarder node for interests: handling of Data delivered based on ACL. - * - 1 packet at a time - ipv4/tcp ipv6/tcp - */ -static uword -hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - - u32 n_left_from, *from, *to_next; - hicn_data_fwd_next_t next_index; - hicn_pit_cs_t *pitcs = &hicn_main.pitcs; - vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; - f64 tnow; - u32 data_received = 1; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - /* Capture time in vpp terms */ - tnow = vlib_time_now (vm); - - while (n_left_from > 0) - { - u32 n_left_to_next; - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - vlib_buffer_t *b0; - u8 isv6; - u8 *nameptr; - u16 namelen; - u32 bi0; - u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP; - hicn_header_t *hicn0; - hicn_buffer_t *hicnb0; - hicn_hash_node_t *node0; - const hicn_strategy_vft_t *strategy_vft0; - const hicn_dpo_vft_t *dpo_vft0; - u8 dpo_ctx_id0; - hicn_pcs_entry_t *pitp; - hicn_hash_entry_t *hash_entry0; - int ret = HICN_ERROR_NONE; - - /* Prefetch for next iteration. */ - if (n_left_from > 1) - { - vlib_buffer_t *b1; - b1 = vlib_get_buffer (vm, from[1]); - CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE); - } - /* Dequeue a packet buffer */ - /* - * Do not copy the index in the next buffer, we'll do - * it later. The packet might be cloned, so the buffer to move - * to next must be the cloned one - */ - bi0 = from[0]; - from += 1; - n_left_from -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - /* Get hicn buffer and state */ - hicnb0 = hicn_get_buffer (b0); - hicn0 = (hicn_header_t *) (vlib_buffer_get_current (b0)); - hicn_get_internal_state (hicnb0, pitcs, &node0, &strategy_vft0, - &dpo_vft0, &dpo_ctx_id0, &hash_entry0); - - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); - isv6 = hicn_buffer_is_v6 (b0); - pitp = hicn_pit_get_data (node0); - - if (PREDICT_FALSE ( - !hicn_node_compare (nameptr, namelen, node0) || - (hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY))) - { - /* - * Remove the lock acquired from - * data_pcslookup node - */ - dpo_id_t hicn_dpo_id0 = { .dpoi_type = - dpo_vft0->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_id0 }; - hicn_pcs_remove_lock (pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); - - drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next, - &next_index, node); - - goto end_processing; - } - /* - * Check if the hit is instead a collision in the - * hash table. Unlikely to happen. - */ - /* - * there is no guarantee that the type of entry has - * not changed from the lookup. - */ - - if (tnow > pitp->shared.expire_time || - (hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_DELETED)) - { - dpo_id_t hicn_dpo_id0 = { .dpoi_type = - dpo_vft0->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_id0 }; - hicn_pcs_delete (pitcs, &pitp, &node0, vm, hash_entry0, dpo_vft0, - &hicn_dpo_id0); - - drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next, - &next_index, node); - stats.pit_expired_count++; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - hicn_data_fwd_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PACKET_TYPE_DATA; - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->next_index = next0; - clib_memcpy (t->packet_data, vlib_buffer_get_current (b0), - sizeof (t->packet_data)); - } - } - else - { - ASSERT ((hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_DELETED) == - 0); - - data_received++; - /* - * We do not check if the data is coming from - * the outgoing interest face. - */ - - /* Prepare the buffer for the cloning */ - ret = - hicn_satisfy_faces (vm, bi0, pitp, &n_left_to_next, &to_next, - &next_index, node, isv6, &stats); - - dpo_id_t hicn_dpo_id0 = { .dpoi_type = - dpo_vft0->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_id0 }; - - if (PREDICT_FALSE (ret != HICN_ERROR_NONE)) - { - hicn_pcs_pit_delete (pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); - continue; - } - /* - * Call the strategy callback since the - * interest has been satisfied - */ - strategy_vft0->hicn_receive_data (dpo_ctx_id0, - pitp->u.pit.pe_txnh); - -#if HICN_FEATURE_CS - hicn_lifetime_t dmsg_lifetime; - - hicn_type_t type = hicnb0->type; - hicn_ops_vft[type.l1]->get_lifetime (type, &hicn0->protocol, - &dmsg_lifetime); - - if (dmsg_lifetime) - { - /* - * Clone data packet in the content store and - * convert the PIT entry into a CS entry - */ - clone_data_to_cs (vm, pitcs, pitp, hicn0, tnow, node0, b0, - hash_entry0, hicnb0->name_hash, hicnb0, - dpo_vft0, &hicn_dpo_id0, dmsg_lifetime); - - hicn_pcs_remove_lock (pitcs, &pitp, &node0, vm, hash_entry0, - NULL, NULL); - } - else - { - /* - * If the packet is copied and not cloned, we need to free - * the vlib_buffer - */ - if (hicnb0->flags & HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL) - { - vlib_buffer_free_one (vm, bi0); - } - else - { - /* - * Remove one reference as the buffer is no - * longer in any frame. The vlib_buffer will be freed - * when all its cloned vlib_buffer will be freed. - */ - b0->ref_count--; - } - - /* Delete the PIT entry */ - hicn_pcs_pit_delete (pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); - } -#else - ASSERT (pitp == hicn_pit_get_data (node0)); - /* - * If the packet is copied and not cloned, we need to free the - * vlib_buffer - */ - if (hicnb0->flags & HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL) - { - vlib_buffer_free_one (vm, bi0); - } - else - { - /* - * Remove one reference as the buffer is no - * longer in any frame. The vlib_buffer will be freed when - * all its cloned vlib_buffer will be freed. - */ - b0->ref_count--; - } - - /* Delete the PIT entry */ - hicn_pcs_pit_delete (pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); -#endif - } - end_processing: - - /* Incr packet counter */ - stats.pkts_processed += 1; - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - u32 pit_int_count = hicn_pit_get_int_count (pitcs); - u32 pit_cs_count = hicn_pit_get_cs_count (pitcs); - - vlib_node_increment_counter (vm, hicn_data_fwd_node.index, - HICNFWD_ERROR_DATAS, stats.pkts_data_count); - - update_node_counter (vm, hicn_data_fwd_node.index, HICNFWD_ERROR_INT_COUNT, - pit_int_count); - update_node_counter (vm, hicn_data_fwd_node.index, HICNFWD_ERROR_CS_COUNT, - pit_cs_count); - update_node_counter (vm, hicn_data_fwd_node.index, - HICNFWD_ERROR_INTEREST_AGG_ENTRY, - stats.pkts_data_count / data_received); - - return (frame->n_vectors); -} - always_inline void drop_packet (vlib_main_t *vm, u32 bi0, u32 *n_left_to_next, u32 *next0, u32 **to_next, u32 *next_index, vlib_node_runtime_t *node) @@ -339,7 +54,8 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, { int found = 0; int ret = HICN_ERROR_NONE; - u32 *clones = NULL, *header = NULL; + u32 inline_clones[HICN_FACE_DB_INLINE_FACES]; + u32 *clones = inline_clones, *header = NULL; u32 n_left_from = 0; u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP, next1 = HICN_DATA_FWD_NEXT_ERROR_DROP; @@ -354,8 +70,11 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, * need to be careful to clone it only 254 times as the buffer * already has n_add_reds=1. */ - vec_alloc (clones, pitp->u.pit.faces.n_faces); - header = clones; + if (hicn_pcs_entry_pit_get_n_faces (pitp) > HICN_FACE_DB_INLINE_FACES) + { + vec_alloc (clones, hicn_pcs_entry_pit_get_n_faces (pitp)); + header = clones; + } /* Clone bi0 */ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0); @@ -378,7 +97,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, { /* Add one reference to maintain the buffer in the CS. * b0->ref_count == 0 has two meaning: it has 1 buffer or no buffer - * chained to it. vlib_buffer_clone2 add a number of reference equalt to + * chained to it. vlib_buffer_clone2 add a number of reference equal to * pitp->u.pit.faces.n_faces - 1 as vlib_buffer_clone does. So after all * the packet are forwarded the buffer stored in the CS will have * ref_count == 0; @@ -386,17 +105,16 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, b0->ref_count++; } - found = n_left_from = vlib_buffer_clone2 ( - vm, bi0, clones, pitp->u.pit.faces.n_faces, buffer_advance); + found = n_left_from = + vlib_buffer_clone2 (vm, bi0, clones, pitp->u.pit.n_faces, buffer_advance); - ASSERT (n_left_from == pitp->u.pit.faces.n_faces); + ASSERT (n_left_from == hicn_pcs_entry_pit_get_n_faces (pitp)); /* Index to iterate over the faces */ int i = 0; while (n_left_from > 0) { - // Dual loop, X2 while (n_left_from >= 4 && *n_left_to_next >= 2) { @@ -413,8 +131,11 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, CLIB_PREFETCH (h3, 2 * CLIB_CACHE_LINE_BYTES, STORE); } - face0 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces); - face1 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces); + face0 = hicn_pcs_entry_pit_get_dpo_face (pitp, i); + face1 = hicn_pcs_entry_pit_get_dpo_face (pitp, i + 1); + + // Increment index + i += 2; h0 = vlib_get_buffer (vm, clones[0]); h1 = vlib_get_buffer (vm, clones[1]); @@ -469,7 +190,8 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, u32 hi0; hicn_face_id_t face0; - face0 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces); + face0 = hicn_pcs_entry_pit_get_dpo_face (pitp, i); + i += 1; h0 = vlib_get_buffer (vm, clones[0]); @@ -530,36 +252,28 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, } always_inline void -clone_data_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *pitp, hicn_header_t *hicn0, f64 tnow, - hicn_hash_node_t *nodep, vlib_buffer_t *b0, - hicn_hash_entry_t *hash_entry, u64 name_hash, - hicn_buffer_t *hicnb, const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id, hicn_lifetime_t dmsg_lifetime) +clone_data_to_cs (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *pcs_entry, + u32 buffer_index, hicn_header_t *hicn0, f64 tnow, + hicn_lifetime_t dmsg_lifetime) { /* * At this point we think we're safe to proceed. Store the CS buf in * the PIT/CS hashtable entry */ - /* - * Start turning the PIT into a CS. Note that we may be stepping on - * the PIT part of the union as we update the CS part, so don't - * expect the PIT part to be valid after this point. - */ - hicn_pit_to_cs (vm, pitcs, pitp, hash_entry, nodep, dpo_vft, hicn_dpo_id); - - pitp->shared.create_time = tnow; + // Start turning the PIT into a CS. Note that we may be stepping on the PIT + // part of the union as we update the CS part, so don't expect the PIT part + // to be valid after this point. + hicn_pit_to_cs (pitcs, pcs_entry, buffer_index); + hicn_pcs_entry_set_create_time (pcs_entry, tnow); if (dmsg_lifetime < HICN_PARAM_CS_LIFETIME_MIN || dmsg_lifetime > HICN_PARAM_CS_LIFETIME_MAX) { dmsg_lifetime = HICN_PARAM_CS_LIFETIME_DFLT; } - pitp->shared.expire_time = hicn_pcs_get_exp_time (tnow, dmsg_lifetime); - - /* Store the original packet buffer in the CS node */ - pitp->u.cs.cs_pkt_buf = vlib_get_buffer_index (vm, b0); + hicn_pcs_entry_set_expire_time (pcs_entry, + hicn_pcs_get_exp_time (tnow, dmsg_lifetime)); } /* packet trace format function */ @@ -579,6 +293,206 @@ hicn_data_fwd_format_trace (u8 *s, va_list *args) return (s); } +vlib_node_registration_t hicn_data_fwd_node; + +/* + * ICN forwarder node for interests: handling of Data delivered based on ACL. + * - 1 packet at a time - ipv4/tcp ipv6/tcp + */ +static uword +hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + + u32 n_left_from, *from, *to_next; + hicn_data_fwd_next_t next_index; + hicn_data_fwd_runtime_t *rt; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + f64 tnow; + u32 data_received = 1; + vlib_buffer_t *b0; + u8 isv6; + u32 bi0; + u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP; + hicn_header_t *hicn0; + hicn_buffer_t *hicnb0; + const hicn_strategy_vft_t *strategy_vft0 = NULL; + const hicn_dpo_vft_t *dpo_vft0; + u8 dpo_ctx_id0 = ~0; + u32 pcs_entry_id; + hicn_pcs_entry_t *pcs_entry = NULL; + hicn_lifetime_t dmsg_lifetime; + int ret = HICN_ERROR_NONE; + + rt = vlib_node_get_runtime_data (vm, node->node_index); + + if (PREDICT_FALSE (rt->pitcs == NULL)) + { + rt->pitcs = &hicn_main.pitcs; + } + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + /* Capture time in vpp terms */ + tnow = vlib_time_now (vm); + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + /* Prefetch for next iteration. */ + if (n_left_from > 1) + { + vlib_buffer_t *b1; + b1 = vlib_get_buffer (vm, from[1]); + CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE); + } + + // Dequeue a packet buffer. Do not copy the index in the next buffer, + // we'll do it later. The packet might be cloned, so the buffer to + // move to next must be the cloned one + bi0 = from[0]; + from += 1; + n_left_from -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + // Get hicn buffer and state + hicnb0 = hicn_get_buffer (b0); + hicn0 = (hicn_header_t *) (vlib_buffer_get_current (b0)); + + hicn_get_internal_state (hicnb0, &pcs_entry_id, &strategy_vft0, + &dpo_vft0, &dpo_ctx_id0); + + // Get PCS entry + pcs_entry = + hicn_pcs_entry_get_entry_from_index (rt->pitcs, pcs_entry_id); + + isv6 = hicn_buffer_is_v6 (b0); + + // If PCS entry is CS, drop the packet + if (PREDICT_FALSE (hicn_pcs_entry_is_cs (pcs_entry))) + { + drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next, + &next_index, node); + + goto end_processing; + } + + // We are sure the entry is a PIT entry. Check whether it is expired. + if (tnow > hicn_pcs_entry_get_expire_time (pcs_entry)) + { + // Entry expired. Release lock + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + + // Drop packet + drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next, + &next_index, node); + + // Update stats + stats.pit_expired_count++; + + // Trace + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + hicn_data_fwd_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = HICN_PACKET_TYPE_DATA; + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->next_index = next0; + clib_memcpy (t->packet_data, vlib_buffer_get_current (b0), + sizeof (t->packet_data)); + } + } + else + { + // Update stats + data_received++; + + /* + * We do not check if the data is coming from + * the outgoing interest face. + */ + + // Prepare the buffer for the cloning + ret = + hicn_satisfy_faces (vm, bi0, pcs_entry, &n_left_to_next, + &to_next, &next_index, node, isv6, &stats); + + if (PREDICT_FALSE (ret != HICN_ERROR_NONE)) + { + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + continue; + } + + // Call the strategy callback since the interest has been + // satisfied + strategy_vft0->hicn_receive_data ( + dpo_ctx_id0, vnet_buffer (b0)->ip.adj_index[VLIB_RX]); + + dmsg_lifetime = hicn_buffer_get_lifetime (b0); + + if (dmsg_lifetime) + { + // Clone data packet in the content store and convert the PIT + // entry into a CS entry + clone_data_to_cs (rt->pitcs, pcs_entry, bi0, hicn0, tnow, + dmsg_lifetime); + } + else + { + /* + * If the packet is copied and not cloned, we need to free + * the vlib_buffer + */ + if (hicnb0->flags & HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL) + { + vlib_buffer_free_one (vm, bi0); + } + else + { + /* + * Remove one reference as the buffer is no + * longer in any frame. The vlib_buffer will be freed + * when all its cloned vlib_buffer will be freed. + */ + b0->ref_count--; + } + // Delete the PIT entry + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + } + } + end_processing: + + /* Incr packet counter */ + stats.pkts_processed += 1; + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + u32 pit_int_count = hicn_pcs_get_pit_count (rt->pitcs); + u32 pit_cs_count = hicn_pcs_get_cs_count (rt->pitcs); + + vlib_node_increment_counter (vm, hicn_data_fwd_node.index, + HICNFWD_ERROR_DATAS, stats.pkts_data_count); + + update_node_counter (vm, hicn_data_fwd_node.index, HICNFWD_ERROR_INT_COUNT, + pit_int_count); + update_node_counter (vm, hicn_data_fwd_node.index, HICNFWD_ERROR_CS_COUNT, + pit_cs_count); + update_node_counter (vm, hicn_data_fwd_node.index, + HICNFWD_ERROR_INTEREST_AGG_ENTRY, + stats.pkts_data_count / data_received); + + return (frame->n_vectors); +} + /* * Node registration for the data forwarder node */ diff --git a/hicn-plugin/src/data_input_node.c b/hicn-plugin/src/data_input_node.c index 65bba7b1b..dbf49de54 100644 --- a/hicn-plugin/src/data_input_node.c +++ b/hicn-plugin/src/data_input_node.c @@ -105,6 +105,15 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u32 n_left_from, n_left_to_next, *from, *to_next; ip_lookup_next_t next; u32 thread_index = vm->thread_index; + vlib_buffer_t *p0, *p1; + u32 pi0, pi1, lbi0, lbi1, wrong_next; + ip_lookup_next_t next0, next1; + ip6_header_t *ip0, *ip1; + ip6_address_t *src_addr0, *src_addr1; + ip46_address_t dst_addr0, dst_addr1; + const dpo_id_t *dpo0, *dpo1; + const load_balance_t *lb0, *lb1; + hicn_buffer_t *hicnb0, *hicnb1; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -116,15 +125,6 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from >= 4 && n_left_to_next >= 2) { - vlib_buffer_t *p0, *p1; - u32 pi0, pi1, lbi0, lbi1, wrong_next; - ip_lookup_next_t next0, next1; - ip6_header_t *ip0, *ip1; - ip6_address_t *src_addr0, *src_addr1; - ip46_address_t dst_addr0, dst_addr1; - const dpo_id_t *dpo0, *dpo1; - const load_balance_t *lb0, *lb1; - /* Prefetch next iteration. */ { vlib_buffer_t *p2, *p3; @@ -144,6 +144,9 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, p0 = vlib_get_buffer (vm, pi0); p1 = vlib_get_buffer (vm, pi1); + hicnb0 = hicn_get_buffer (p0); + hicnb1 = hicn_get_buffer (p1); + ip0 = vlib_buffer_get_current (p0); ip1 = vlib_buffer_get_current (p1); @@ -177,6 +180,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo0)) { next0 = (ip_lookup_next_t) HICN_DATA_INPUT_IP6_NEXT_FACE; + hicnb0->dpo_ctx_id = dpo0->dpoi_index; hicn_data_input_set_adj_index ( p0, &dst_addr0, hicn_strategy_dpo_ctx_get (dpo0->dpoi_index)); } @@ -186,6 +190,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo1)) { next1 = (ip_lookup_next_t) HICN_DATA_INPUT_IP6_NEXT_FACE; + hicnb1->dpo_ctx_id = dpo1->dpoi_index; hicn_data_input_set_adj_index ( p1, &dst_addr1, hicn_strategy_dpo_ctx_get (dpo1->dpoi_index)); } @@ -267,6 +272,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u32 pi0, lbi0; ip_lookup_next_t next0; load_balance_t *lb0; + hicn_buffer_t *hicnb0; ip6_address_t *src_addr0; ip46_address_t dst_addr0; const dpo_id_t *dpo0; @@ -275,6 +281,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, to_next[0] = pi0; p0 = vlib_get_buffer (vm, pi0); + hicnb0 = hicn_get_buffer (p0); ip0 = vlib_buffer_get_current (p0); src_addr0 = &ip0->src_address; ip46_address_set_ip6 (&dst_addr0, &ip0->dst_address); @@ -294,6 +301,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, next0 = (ip_lookup_next_t) HICN_DATA_INPUT_IP6_NEXT_FACE; hicn_data_input_set_adj_index ( p0, &dst_addr0, hicn_strategy_dpo_ctx_get (dpo0->dpoi_index)); + hicnb0->dpo_ctx_id = dpo0->dpoi_index; } else next0 = (ip_lookup_next_t) HICN_DATA_INPUT_IP6_NEXT_IP6_LOCAL; @@ -365,6 +373,13 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *bufs[VLIB_FRAME_SIZE]; vlib_buffer_t **b = bufs; u16 nexts[VLIB_FRAME_SIZE], *next; + ip4_header_t *ip0, *ip1, *ip2, *ip3; + const load_balance_t *lb0, *lb1, *lb2, *lb3; + ip4_address_t *src_addr0, *src_addr1, *src_addr2, *src_addr3; + ip46_address_t dst_addr0, dst_addr1, dst_addr2, dst_addr3; + u32 lb_index0, lb_index1, lb_index2, lb_index3; + const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3; + hicn_buffer_t *hicnb0, *hicnb1, *hicnb2, *hicnb3; from = vlib_frame_vector_args (frame); n_left = frame->n_vectors; @@ -374,13 +389,6 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, #if (CLIB_N_PREFETCHES >= 8) while (n_left >= 4) { - ip4_header_t *ip0, *ip1, *ip2, *ip3; - const load_balance_t *lb0, *lb1, *lb2, *lb3; - ip4_address_t *src_addr0, *src_addr1, *src_addr2, *src_addr3; - ip46_address_t dst_addr0, dst_addr1, dst_addr2, dst_addr3; - u32 lb_index0, lb_index1, lb_index2, lb_index3; - const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3; - /* Prefetch next iteration. */ if (n_left >= 8) { @@ -400,6 +408,11 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, ip2 = vlib_buffer_get_current (b[2]); ip3 = vlib_buffer_get_current (b[3]); + hicnb0 = hicn_get_buffer (b[0]); + hicnb1 = hicn_get_buffer (b[1]); + hicnb2 = hicn_get_buffer (b[2]); + hicnb3 = hicn_get_buffer (b[3]); + src_addr0 = &ip0->src_address; src_addr1 = &ip1->src_address; src_addr2 = &ip2->src_address; @@ -444,6 +457,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo0)) { next[0] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb0->dpo_ctx_id = dpo0->dpoi_index; hicn_data_input_set_adj_index ( b[0], &dst_addr0, hicn_strategy_dpo_ctx_get (dpo0->dpoi_index)); } @@ -453,6 +467,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo1)) { next[1] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb1->dpo_ctx_id = dpo1->dpoi_index; hicn_data_input_set_adj_index ( b[1], &dst_addr1, hicn_strategy_dpo_ctx_get (dpo1->dpoi_index)); } @@ -462,6 +477,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo2)) { next[2] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb2->dpo_ctx_id = dpo2->dpoi_index; hicn_data_input_set_adj_index ( b[2], &dst_addr2, hicn_strategy_dpo_ctx_get (dpo2->dpoi_index)); } @@ -471,6 +487,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo3)) { next[3] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb3->dpo_ctx_id = dpo3->dpoi_index; hicn_data_input_set_adj_index ( b[3], &dst_addr3, hicn_strategy_dpo_ctx_get (dpo3->dpoi_index)); } @@ -533,15 +550,6 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, #elif (CLIB_N_PREFETCHES >= 4) while (n_left >= 4) { - ip4_header_t *ip0, *ip1; - const load_balance_t *lb0, *lb1; - ip4_address_t *src_addr0, *src_addr1; - ip46_address_t dst_addr0, dst_addr1; - u32 lb_index0, lb_index1; - flow_hash_config_t flow_hash_config0, flow_hash_config1; - u32 hash_c0, hash_c1; - const dpo_id_t *dpo0, *dpo1; - /* Prefetch next iteration. */ { vlib_prefetch_buffer_header (b[2], LOAD); @@ -554,6 +562,9 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, ip0 = vlib_buffer_get_current (b[0]); ip1 = vlib_buffer_get_current (b[1]); + hicnb0 = hicn_get_buffer (b[0]); + hicnb1 = hicn_get_buffer (b[1]); + src_addr0 = &ip0->src_address; src_addr1 = &ip1->src_address; @@ -582,6 +593,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo0)) { next[0] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb0->dpo_ctx_id = dpo0->dpoi_index; hicn_data_input_set_adj_index ( b[0], &dst_addr0, hicn_strategy_dpo_ctx_get (dpo0->dpoi_index)); } @@ -591,6 +603,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo1)) { next[1] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb1->dpo_ctx_id = dpo1->dpoi_index; hicn_data_input_set_adj_index ( b[1], &dst_addr1, hicn_strategy_dpo_ctx_get (dpo1->dpoi_index)); } @@ -629,23 +642,17 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, #endif while (n_left > 0) { - ip4_header_t *ip0; - const load_balance_t *lb0; - ip4_address_t *src_addr0; - ip46_address_t dst_addr0; - u32 lbi0; - const dpo_id_t *dpo0; - ip0 = vlib_buffer_get_current (b[0]); + hicnb0 = hicn_get_buffer (b[0]); src_addr0 = &ip0->src_address; ip46_address_set_ip4 (&dst_addr0, &ip0->dst_address); ip_lookup_set_buffer_fib_index (im->fib_index_by_sw_if_index, b[0]); - lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b[0])->ip.fib_index, - src_addr0); + lb_index0 = ip4_fib_forwarding_lookup (vnet_buffer (b[0])->ip.fib_index, + src_addr0); - ASSERT (lbi0); - lb0 = load_balance_get (lbi0); + ASSERT (lb_index0); + lb0 = load_balance_get (lb_index0); ASSERT (lb0->lb_n_buckets > 0); ASSERT (is_pow2 (lb0->lb_n_buckets)); @@ -655,6 +662,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, if (dpo_is_hicn (dpo0)) { next[0] = (ip_lookup_next_t) HICN_DATA_INPUT_IP4_NEXT_IP4_LOCAL; + hicnb0->dpo_ctx_id = dpo0->dpoi_index; hicn_data_input_set_adj_index ( b[0], &dst_addr0, hicn_strategy_dpo_ctx_get (dpo0->dpoi_index)); } @@ -671,7 +679,7 @@ hicn_data_input_ip4_fn (vlib_main_t *vm, vlib_node_runtime_t *node, t->isv6 = 0; } - vlib_increment_combined_counter (cm, thread_index, lbi0, 1, + vlib_increment_combined_counter (cm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, b[0])); b += 1; diff --git a/hicn-plugin/src/data_pcslookup_node.c b/hicn-plugin/src/data_pcslookup_node.c index 95db66f54..55ddda9c4 100644 --- a/hicn-plugin/src/data_pcslookup_node.c +++ b/hicn-plugin/src/data_pcslookup_node.c @@ -44,6 +44,12 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_data_pcslookup_next_t next_index; hicn_data_pcslookup_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + vlib_buffer_t *b0; + u32 bi0; + u32 next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP; + hicn_pcs_entry_t *pcs_entry = NULL; + hicn_buffer_t *hicnb0; + int ret; rt = vlib_node_get_runtime_data (vm, node->node_index); @@ -62,21 +68,7 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { - vlib_buffer_t *b0; - u8 *nameptr; - u16 namelen; - u32 bi0; - u32 next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP; - u64 name_hash = 0; - u32 node_id0 = 0; - index_t dpo_ctx_id0 = 0; - u8 vft_id0 = 0; - u8 is_cs0; - u8 hash_entry_id = 0; - u8 bucket_is_overflown = 0; - u32 bucket_id = ~0; - - /* Prefetch for next iteration. */ + // Prefetch for next iteration. if (n_left_from > 1) { vlib_buffer_t *b1; @@ -84,9 +76,9 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, // Prefetch two cache lines-- 128 byte-- so that we load the // hicn_buffer_t as well CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD); } - /* Dequeue a packet buffer */ + + // Dequeue a packet buffer bi0 = from[0]; from += 1; n_left_from -= 1; @@ -95,42 +87,34 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); + hicnb0 = hicn_get_buffer (b0); + + // By default go to drop next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP; - /* Incr packet counter */ + // Increase packet counters stats.pkts_processed += 1; + stats.pkts_data_count += 1; - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + // Lookup the name in the PIT + ret = hicn_pcs_lookup_one (rt->pitcs, hicn_buffer_get_name (b0), + &pcs_entry); - if (PREDICT_TRUE ( - hicn_hashtb_fullhash (nameptr, namelen, &name_hash) == - HICN_ERROR_NONE)) + if (ret == HICN_ERROR_NONE) { - int res = hicn_hashtb_lookup_node ( - rt->pitcs->pcs_table, nameptr, namelen, name_hash, - 1 - /*is_data. Do not take lock if hit CS */ - , - &node_id0, &dpo_ctx_id0, &vft_id0, &is_cs0, &hash_entry_id, - &bucket_id, &bucket_is_overflown); - - stats.pkts_data_count += 1; - - if (res == HICN_ERROR_NONE) - { - /* - * In case the result of the lookup - * is a CS entry, the packet is - * dropped - */ - next0 = HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD + is_cs0; - } + ret = hicn_store_internal_state ( + b0, hicn_pcs_entry_get_index (rt->pitcs, pcs_entry), + hicnb0->dpo_ctx_id); + + /* + * In case the result of the lookup + * is a CS entry, the packet is + * dropped + */ + next0 = HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD + + (hicn_pcs_entry_is_cs (pcs_entry) && !ret); } - hicn_store_internal_state (b0, name_hash, node_id0, dpo_ctx_id0, - vft_id0, hash_entry_id, bucket_id, - bucket_is_overflown); - /* * Verify speculative enqueue, maybe switch current * next frame @@ -153,11 +137,13 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, t->next_index = next0; } } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); } + /* Check the CS LRU, and trim if necessary. */ - u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs); - u32 pit_cs_count = hicn_pit_get_cs_count (rt->pitcs); + u32 pit_int_count = hicn_pcs_get_pit_count (rt->pitcs); + u32 pit_cs_count = hicn_pcs_get_cs_count (rt->pitcs); vlib_node_increment_counter (vm, hicn_data_pcslookup_node.index, HICNFWD_ERROR_PROCESSED, stats.pkts_processed); @@ -169,6 +155,7 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, HICNFWD_ERROR_INT_COUNT, pit_int_count); update_node_counter (vm, hicn_data_pcslookup_node.index, HICNFWD_ERROR_CS_COUNT, pit_cs_count); + return (frame->n_vectors); } diff --git a/hicn-plugin/src/face_db.h b/hicn-plugin/src/face_db.h deleted file mode 100644 index 37a2af9ca..000000000 --- a/hicn-plugin/src/face_db.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __HICN_FACE_DB_H__ -#define __HICN_FACE_DB_H__ - -#include <vnet/dpo/dpo.h> -#include "faces/face.h" - -/** - * @file face_db.h - * - * Define a face db that is store in every pit entry. A face db containes a - * list of incoming faces for interest packets that are used to forward data - * packets on the interests' reverse path - */ - -/* Must be power of two */ -#define HICN_FACE_DB_INLINE_FACES 8 - -#define HICN_PIT_BITMAP_SIZE_BYTE HICN_PARAM_FACES_MAX / 8 -#define HICN_PIT_N_HOP_BITMAP_SIZE HICN_PARAM_FACES_MAX - -#define HICN_PIT_N_HOP_BUCKET \ - (HICN_PARAM_PIT_ENTRY_PHOPS_MAX - HICN_FACE_DB_INLINE_FACES) - -typedef struct hicn_face_bucket_s -{ - /* Array of indexes of virtual faces */ - hicn_face_id_t faces[HICN_PIT_N_HOP_BUCKET]; - - /* Used to check if interests are retransmission */ - u8 bitmap[HICN_PIT_BITMAP_SIZE_BYTE]; - -} hicn_face_bucket_t; - -extern hicn_face_bucket_t *hicn_face_bucket_pool; - -typedef struct __attribute__ ((packed)) hicn_face_db_s -{ - /* 19B + 1B = 20B */ - /* Equal to one or zero */ - u8 is_overflow; - - /* Number of faces in the last bucket */ - /* Or next availabe entry for storing a dpo_id_t */ - /* 20B + 4B = 24B */ - u32 n_faces; - - /* 24B + 32B (8*4) = 56B */ - /* Array of indexes of virtual faces */ - hicn_face_id_t inline_faces[HICN_FACE_DB_INLINE_FACES]; - - /* 56B + 4B = 60B */ - u32 next_bucket; - - /* 60B + 4B = 64B */ - u32 align; - // align back to 64 - -} hicn_face_db_t; - -always_inline hicn_face_id_t -hicn_face_db_get_dpo_face (u32 index, hicn_face_db_t *face_db) -{ - ASSERT (index < face_db->n_faces); - - return index < HICN_FACE_DB_INLINE_FACES ? - (face_db->inline_faces[index]) : - (pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket) - ->faces[(index - HICN_FACE_DB_INLINE_FACES) & - (HICN_PIT_N_HOP_BUCKET - 1)]); -} - -always_inline void -hicn_face_db_init (int max_element) -{ - pool_init_fixed (hicn_face_bucket_pool, max_element); -} - -always_inline hicn_face_bucket_t * -hicn_face_db_get_bucket (u32 bucket_index) -{ - return pool_elt_at_index (hicn_face_bucket_pool, bucket_index); -} - -always_inline void -hicn_face_db_add_face (hicn_face_id_t face_id, hicn_face_db_t *face_db) -{ - // ASSERT (dpo->dpoi_index != ~0); - - hicn_face_bucket_t *faces_bkt = - pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket); - - hicn_face_id_t *element = - face_db->n_faces < HICN_FACE_DB_INLINE_FACES ? - &(face_db->inline_faces[face_db->n_faces]) : - &(faces_bkt->faces[(face_db->n_faces - HICN_FACE_DB_INLINE_FACES) & - (HICN_PIT_N_HOP_BUCKET - 1)]); - - *element = face_id; - - u32 bitmap_index = face_id % HICN_PIT_N_HOP_BITMAP_SIZE; - u32 position_array = bitmap_index / 8; - u8 bit_index = (u8) (bitmap_index - position_array * 8); - - faces_bkt->bitmap[position_array] |= (0x01 << bit_index); - face_db->n_faces++; -} - -always_inline u8 -hicn_face_search (hicn_face_id_t index, hicn_face_db_t *face_db) -{ - hicn_face_bucket_t *faces_bkt = - pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket); - u32 bitmap_index = index % HICN_PIT_N_HOP_BITMAP_SIZE; - - u32 position_array = bitmap_index / 8; - u8 bit_index = bitmap_index - position_array * 8; - - return (faces_bkt->bitmap[position_array] >> bit_index) & 0x01; -} - -always_inline void -hicn_faces_flush (hicn_face_db_t *face_db) -{ - hicn_face_bucket_t *faces_bkt = - pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket); - clib_memset_u8 (&(faces_bkt->bitmap), 0, HICN_PIT_BITMAP_SIZE_BYTE); - face_db->n_faces = 0; - pool_put_index (hicn_face_bucket_pool, face_db->next_bucket); -} - -#endif /* // __HICN_FACE_DB_H__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: eval: (c-set-style "gnu") End: - */ diff --git a/hicn-plugin/src/faces/app/face_app_cli.c b/hicn-plugin/src/faces/app/face_app_cli.c index b3488c462..0c00eb28d 100644 --- a/hicn-plugin/src/faces/app/face_app_cli.c +++ b/hicn-plugin/src/faces/app/face_app_cli.c @@ -18,7 +18,7 @@ #include <vlib/vlib.h> #include <vnet/ip/ip6_packet.h> -//#include "../face_dpo.h" +#include "../../params.h" #include "../face.h" #include "face_prod.h" #include "face_cons.h" diff --git a/hicn-plugin/src/faces/app/face_prod_node.c b/hicn-plugin/src/faces/app/face_prod_node.c index e3241e477..8adb7dce7 100644 --- a/hicn-plugin/src/faces/app/face_prod_node.c +++ b/hicn-plugin/src/faces/app/face_prod_node.c @@ -25,6 +25,7 @@ #include "face_prod.h" #include "../../mgmt.h" +#include "../../parser.h" static __clib_unused char *face_prod_input_error_strings[] = { #define _(sym, string) string, diff --git a/hicn-plugin/src/faces/face_node.c b/hicn-plugin/src/faces/face_node.c index 6dedbe1c4..e2fb79d17 100644 --- a/hicn-plugin/src/faces/face_node.c +++ b/hicn-plugin/src/faces/face_node.c @@ -23,6 +23,7 @@ #include "../cache_policies/cs_lru.h" #include "../infra.h" #include "../hicn.h" +#include "../parser.h" /** * @File @@ -234,7 +235,6 @@ typedef enum ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current (b1); \ \ /* Parse packet and cache useful info in opaque2 */ \ - /* Parse packet and cache useful info in opaque2 */ \ ret0 = hicn_data_parse_pkt (b0); \ ret1 = hicn_data_parse_pkt (b1); \ is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET; \ diff --git a/hicn-plugin/src/faces/iface_node.c b/hicn-plugin/src/faces/iface_node.c index 3b6634d77..2f651beb8 100644 --- a/hicn-plugin/src/faces/iface_node.c +++ b/hicn-plugin/src/faces/iface_node.c @@ -19,6 +19,7 @@ #include "../hicn.h" #include "../infra.h" #include "../cache_policies/cs_lru.h" +#include "../parser.h" /** * @File diff --git a/hicn-plugin/src/hashtb.c b/hicn-plugin/src/hashtb.c deleted file mode 100644 index eb7da81f2..000000000 --- a/hicn-plugin/src/hashtb.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include <errno.h> -#include <assert.h> -#include <inttypes.h> - -#include <vlib/vlib.h> -#include <vppinfra/pool.h> - -#include "pcs.h" -#include "hashtb.h" -#include "parser.h" -#include "error.h" - -/* return dvd/dvr, rounded up (intended for integer values) */ -#define CEIL(dvd, dvr) \ - ({ \ - __typeof__ (dvd) _dvd = (dvd); \ - __typeof__ (dvr) _dvr = (dvr); \ - (_dvd + _dvr - 1) / _dvr; \ - }) - -#ifndef ALIGN8 -#define ALIGN8(p) (((p) + 0x7) & ~(0x7)) -#endif - -#ifndef ALIGNPTR8 -#define ALIGNPTR8(p) ((void *) (((u8 *) (p) + 0x7) & ~(0x7))) -#endif - -#ifndef ALIGN64 -#define ALIGN64(p) (((p) + 0x3f) & ~(0x3f)) -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/* - * Offset to aligned start of additional data (PIT/CS, FIB) embedded in each - * node. - */ -u32 ht_node_data_offset_aligned; - -/* Some support for posix vs vpp mem management */ -#define MEM_ALLOC(x) clib_mem_alloc_aligned ((x), 8) -#define MEM_FREE(p) clib_mem_free ((p)) - -/* - * Internal utilities - */ - -/* Allocate an overflow bucket */ -static hicn_hash_bucket_t * -alloc_overflow_bucket (hicn_hashtb_h h) -{ - hicn_hash_bucket_t *newbkt = NULL; - - if (h->ht_overflow_buckets_used < h->ht_overflow_bucket_count) - { - pool_get_aligned (h->ht_overflow_buckets, newbkt, 8); - - if (newbkt) - { - h->ht_overflow_buckets_used++; - } - } - return (newbkt); -} - -/* Free an overflow bucket; clear caller's pointer */ -static void -free_overflow_bucket (hicn_hashtb_h h, hicn_hash_bucket_t **pb) -{ - hicn_hash_bucket_t *bkt = *pb; - - ASSERT (h->ht_overflow_buckets_used > 0); - - pool_put (h->ht_overflow_buckets, bkt); - h->ht_overflow_buckets_used--; - *pb = NULL; -} - -/* - * Init, allocate a new hashtable - */ -int -hicn_hashtb_alloc (hicn_hashtb_h *ph, u32 max_elems, size_t app_data_size) -{ - int ret = HICN_ERROR_NONE; - hicn_hashtb_h h = NULL; - u32 count; - u32 total_buckets; - size_t sz; - hicn_hash_node_t *nodep; - hicn_hash_bucket_t *bucket; - - if (ph == NULL) - { - ret = HICN_ERROR_HASHTB_INVAL; - goto done; - } - if (max_elems < HICN_HASHTB_MIN_ENTRIES || - max_elems > HICN_HASHTB_MAX_ENTRIES) - { - goto done; - } - /* Allocate and init main hashtable struct */ - h = MEM_ALLOC (sizeof (hicn_hashtb_t)); - if (h == NULL) - { - ret = HICN_ERROR_HASHTB_NOMEM; - goto done; - } - memset (h, 0, sizeof (hicn_hashtb_t)); - - /* Compute main table bucket (row) count and size, and allocate */ - - /* Consider the last entry as used for containing the overflow bucket */ - total_buckets = CEIL (max_elems, HICN_HASHTB_BUCKET_ENTRIES - 1); - count = ALIGN8 (CEIL (total_buckets, HICN_HASHTB_FILL_FACTOR)); - - h->ht_bucket_count = count; - - /* We _really_ expect to have buckets aligned on cache lines ... */ - sz = sizeof (hicn_hash_bucket_t); - assert (sz == ALIGN64 (sz)); - - h->ht_buckets = MEM_ALLOC (count * sz); - if (h->ht_buckets == NULL) - { - ret = HICN_ERROR_HASHTB_NOMEM; - goto done; - } - memset (h->ht_buckets, 0, count * sz); - - /* - * First time through, compute offset to aligned extra data start in - * each node struct it's crucial that both the node struct (that the - * base hashtable uses) and the extra data area (that's also probably - * a struct) are aligned. - */ - if (ht_node_data_offset_aligned == 0) - { - count = STRUCT_OFFSET_OF (hicn_hash_node_t, hn_data); - ht_node_data_offset_aligned = ALIGN8 (count); - } - // check app struct fits into space provided(HICN_HASH_NODE_APP_DATA_SIZE) - u32 ht_node_data_size; - ht_node_data_size = sizeof (hicn_hash_node_t) - ht_node_data_offset_aligned; - if (app_data_size > ht_node_data_size) - { - clib_error ( - "hicn hashtable: fatal error: requested app data size(%u) > hashtb " - "node's configured bytes available(%u), sizeof(hicn_shared_t)=%u, " - "sizeof(hicn_pit_entry_t)=%u, sizeof(hicn_cs_entry_t)=%u", - app_data_size, ht_node_data_size, sizeof (hicn_pcs_shared_t), - sizeof (hicn_pit_entry_t), sizeof (hicn_cs_entry_t)); - } - /* - * Compute entry node count and size, allocate Allocate/'Hide' the - * zero-th node so can use zero as an 'empty' value - */ - pool_alloc_aligned (h->ht_nodes, max_elems, 8); - if (h->ht_nodes == NULL) - { - ret = HICN_ERROR_HASHTB_NOMEM; - goto done; - } - pool_get_aligned (h->ht_nodes, nodep, 8); - // alloc node 0 - (void) nodep; /* Silence 'not used' warning */ - - h->ht_node_count = max_elems; - h->ht_nodes_used = 1; - - /* - * Compute overflow bucket count and size, allocate - */ - // count = ALIGN8(CEIL(max_elems, HICN_HASHTB_OVERFLOW_FRACTION)); - count = ALIGN8 (total_buckets - h->ht_bucket_count); - - pool_alloc_aligned (h->ht_overflow_buckets, count, 8); - if (h->ht_overflow_buckets == NULL) - { - ret = HICN_ERROR_HASHTB_NOMEM; - goto done; - } - /* 'Hide' the zero-th node so we can use zero as an 'empty' value */ - pool_get_aligned (h->ht_overflow_buckets, bucket, 8); - (void) bucket; /* Silence 'not used' warning */ - - h->ht_overflow_bucket_count = count; - h->ht_overflow_buckets_used = 1; - -done: - - if (h) - { - if ((ret == HICN_ERROR_NONE) && ph) - { - *ph = h; - } - else - { - hicn_hashtb_free (&h); - } - } - return (ret); -} - -/* - * Free, de-allocate a hashtable - */ -int -hicn_hashtb_free (hicn_hashtb_h *ph) -{ - int ret = 0; - - if (ph) - { - if ((*ph)->ht_nodes) - { - pool_free ((*ph)->ht_nodes); - (*ph)->ht_nodes = 0; - } - if ((*ph)->ht_overflow_buckets) - { - pool_free ((*ph)->ht_overflow_buckets); - (*ph)->ht_overflow_buckets = 0; - } - if ((*ph)->ht_buckets) - { - MEM_FREE ((*ph)->ht_buckets); - (*ph)->ht_buckets = 0; - } - MEM_FREE (*ph); - - *ph = NULL; - } - return (ret); -} - -/* - * Basic api to lookup a specific hash+key tuple. This does the entire lookup - * operation, retrieving node structs and comparing keys, so it's not - * optimized for prefetching or high performance. - * - * Returns zero and mails back a node on success, errno otherwise. - */ -int -hicn_hashtb_lookup_node (hicn_hashtb_h h, const u8 *key, u32 keylen, - u64 hashval, u8 is_data, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow) -{ - return (hicn_hashtb_lookup_node_ex ( - h, key, keylen, hashval, is_data, FALSE /* deleted nodes */, node_id, - dpo_ctx_id, vft_id, is_cs, hash_entry_id, bucket_id, bucket_is_overflow)); -} - -/* - * Extended api to lookup a specific hash+key tuple. The implementation - * allows the caller to locate nodes that are marked for deletion, which is - * part of some hashtable applications, such as the FIB. - * - * This does the entire lookup operation, retrieving node structs and comparing - * keys, so it's not optimized for prefetching or high performance. - * - * Returns zero and mails back a node on success, errno otherwise. - */ -int -hicn_hashtb_lookup_node_ex (hicn_hashtb_h h, const u8 *key, u32 keylen, - u64 hashval, u8 is_data, int include_deleted_p, - u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id, - u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow) -{ - int i, ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND; - int found_p = FALSE; - u32 bidx; - hicn_hash_bucket_t *bucket; - u32 current_bucket_id = ~0; - - /* - * Use some bits of the low half of the hash to locate a row/bucket - * in the table - */ - current_bucket_id = bidx = (hashval & (h->ht_bucket_count - 1)); - - bucket = h->ht_buckets + bidx; - - *bucket_is_overflow = 0; - /* Check the entries in the bucket for matching hash value */ - -loop_buckets: - - for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES && !found_p; i++) - { - /* - * If an entry is marked for deletion, ignore it unless the - * caller explicitly wants these nodes. - */ - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED) - { - if (!include_deleted_p) - { - continue; - } - } - if (bucket->hb_entries[i].he_msb64 == hashval) - { - /* - * Found a candidate - must retrieve the actual node - * and check the key. - */ - *node_id = bucket->hb_entries[i].he_node; - *dpo_ctx_id = bucket->hb_entries[i].dpo_ctx_id; - *vft_id = bucket->hb_entries[i].vft_id; - *is_cs = - bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY; - *hash_entry_id = i; - *bucket_id = current_bucket_id; - /* - * If we are doing lookup for a data, do not take a - * lock in case of a hit with a CS entry - */ - if (!(is_data && *is_cs)) - { - bucket->hb_entries[i].locks++; - } - found_p = TRUE; - ret = HICN_ERROR_NONE; - goto done; - } - } - - /* - * Be prepared to continue to an overflow bucket if necessary. We - * only expect the last entry in a bucket to refer to an overflow - * bucket... - */ - i = HICN_HASHTB_BUCKET_ENTRIES - 1; - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW) - { - current_bucket_id = bucket->hb_entries[i].he_node; - bucket = pool_elt_at_index (h->ht_overflow_buckets, - bucket->hb_entries[i].he_node); - *bucket_is_overflow = 1; - goto loop_buckets; - } -done: - - return (ret); -} - -/** - * This function allows to split the hash verification from the comparison of - * the entire key. Useful to exploit prefertching. - * return 1 if equals, 0 otherwise - */ -int -hicn_node_compare (const u8 *key, u32 keylen, hicn_hash_node_t *node) -{ - - int ret = 0; - - if (key && keylen == node->hn_keysize) - { - ret = (memcmp (key, node->hn_key.ks.key, keylen) == 0); - } - return ret; -} - -/* - * Utility to init a new entry in a hashtable bucket/row. We use this to add - * new a node+hash, and to clear out an entry during removal. - */ -void -hicn_hashtb_init_entry (hicn_hash_entry_t *entry, u32 nodeidx, u64 hashval, - u32 locks) -{ - entry->he_msb64 = hashval; - entry->he_node = nodeidx; - - /* Clear out some other fields in the entry */ - entry->he_flags = 0; - entry->locks = locks; - entry->vft_id = 0; - entry->dpo_ctx_id = 0; -} - -/* - * Insert a node into the hashtable. We expect the caller has a) computed the - * hash value to use, b) initialized the node with the hash and key info, and - * c) filled in its app-specific data portion of the node. - */ - -int -hicn_hashtb_insert (hicn_hashtb_h h, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hash, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, u8 *bucket_is_overflow) -{ - int i, ret = HICN_ERROR_HASHTB_INVAL; - u32 bidx; - hicn_hash_bucket_t *bucket, *newbkt; - int use_seven; - u32 current_bucket_id = ~0; - int is_overflow = 0; - - *hash_entry = NULL; - - if (h == NULL) - { - goto done; - } - /* - * Use some bits of the low half of the hash to locate a row/bucket - * in the table - */ - current_bucket_id = bidx = (hash & (h->ht_bucket_count - 1)); - - bucket = h->ht_buckets + bidx; - - use_seven = (h->ht_flags & HICN_HASHTB_FLAG_USE_SEVEN); - - /* Locate a free entry slot in the bucket */ - -loop_buckets: - - for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++) - { - - /* - * If an entry is marked for deletion, ignore it - */ - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED) - { - continue; - } - /* - * Be sure that we are not inserting the same entry twice - */ - if (bucket->hb_entries[i].he_msb64 == hash) - { - /* - * We hit an existing pit entry. increase lock. - */ - - *node_id = bucket->hb_entries[i].he_node; - *dpo_ctx_id = bucket->hb_entries[i].dpo_ctx_id; - *vft_id = bucket->hb_entries[i].vft_id; - *is_cs = - bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY; - *hash_entry_id = i; - *bucket_id = current_bucket_id; - *hash_entry = &(bucket->hb_entries[i]); - /* - * If we are doing lookup for a data, do not take a - * lock in case of a hit with a CS entry - */ - if (!(*is_cs)) - bucket->hb_entries[i].locks++; - *bucket_is_overflow = is_overflow; - ret = HICN_ERROR_HASHTB_EXIST; - goto done; - } - if ((bucket->hb_entries[i].he_msb64 == 0LL) && - (bucket->hb_entries[i].he_node == 0)) - { - /* Found a candidate -- fill it in */ - - /* - * Special case if the application asked not to use - * the last entry in each bucket. - */ - if ((i != (HICN_HASHTB_BUCKET_ENTRIES - 1)) || use_seven) - { - hicn_hashtb_init_entry (&(bucket->hb_entries[i]), - NODE_IDX_FROM_NODE (node, h), hash, 0); - - *hash_entry = &(bucket->hb_entries[i]); - - node->bucket_id = current_bucket_id; - node->entry_idx = i; - (*hash_entry)->vft_id = *vft_id; - (*hash_entry)->dpo_ctx_id = *dpo_ctx_id; - if (is_overflow) - node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET; - - ret = HICN_ERROR_NONE; - goto done; - } - } - } - /* - * Be prepared to continue to an overflow bucket if necessary, or to - * add a new overflow bucket. We only expect the last entry in a - * bucket to refer to an overflow bucket... - */ - i = HICN_HASHTB_BUCKET_ENTRIES - 1; - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW) - { - /* Existing overflow bucket - re-start the search loop */ - current_bucket_id = bucket->hb_entries[i].he_node; - bucket = pool_elt_at_index (h->ht_overflow_buckets, current_bucket_id); - is_overflow = 1; - goto loop_buckets; - } - else - { - /* - * Overflow - reached the end of a bucket without finding a - * free entry slot. Need to allocate an overflow bucket, and - * connect it to this bucket. - */ - newbkt = alloc_overflow_bucket (h); - if (newbkt == NULL) - { - ret = HICN_ERROR_HASHTB_NOMEM; - goto done; - } - /* - * We're touching some more bytes than we absolutely have to - * here, but ... that seems ok. - */ - memset (newbkt, 0, sizeof (hicn_hash_bucket_t)); - - if (use_seven) - { - /* - * Copy existing entry into new bucket - we really - * expect these to be properly aligned so they can be - * treated as int. - */ - memcpy (&(newbkt->hb_entries[0]), &(bucket->hb_entries[i]), - sizeof (hicn_hash_entry_t)); - - /* Update bucket id and entry_idx on the hash node */ - hicn_hash_node_t *node = - pool_elt_at_index (h->ht_nodes, newbkt->hb_entries[0].he_node); - node->bucket_id = (newbkt - h->ht_overflow_buckets); - node->entry_idx = 0; - node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET; - } - /* - * Connect original bucket to the index of the new overflow - * bucket - */ - bucket->hb_entries[i].he_flags |= HICN_HASH_ENTRY_FLAG_OVERFLOW; - bucket->hb_entries[i].he_node = (newbkt - h->ht_overflow_buckets); - - /* Add new entry to new overflow bucket */ - bucket = newbkt; - - /* - * Use entry [1] in the new bucket _if_ we just copied into - * entry [zero] above. - */ - if (use_seven) - { - - hicn_hashtb_init_entry (&(bucket->hb_entries[1]), - NODE_IDX_FROM_NODE (node, h), hash, 0); - *hash_entry = &(bucket->hb_entries[1]); - - node->bucket_id = (newbkt - h->ht_overflow_buckets); - node->entry_idx = 1; - node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET; - (*hash_entry)->vft_id = *vft_id; - (*hash_entry)->dpo_ctx_id = *dpo_ctx_id; - } - else - { - - hicn_hashtb_init_entry (&(bucket->hb_entries[0]), - NODE_IDX_FROM_NODE (node, h), hash, 0); - *hash_entry = &(bucket->hb_entries[0]); - node->bucket_id = (newbkt - h->ht_overflow_buckets); - node->entry_idx = 0; - node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET; - (*hash_entry)->vft_id = *vft_id; - (*hash_entry)->dpo_ctx_id = *dpo_ctx_id; - } - } - - /* And we're done with the overflow bucket */ - ret = HICN_ERROR_NONE; - -done: - - return (ret); -} - -/* - * Delete a node from a hashtable using the node itself, and delete/free the - * node. Caller's pointer is cleared on success. - */ -void -hicn_hashtb_delete (hicn_hashtb_h h, hicn_hash_node_t **pnode, u64 hashval) -{ - - hicn_hashtb_remove_node (h, *pnode, hashval); - hicn_hashtb_free_node (h, *pnode); - *pnode = NULL; -} - -/* - * Delete an entry from a hashtable using the node itself. If the node was - * stored in an overflow bucket, and the bucket is empty after freeing the - * node, the bucket is freed as well. - */ -void -hicn_hashtb_remove_node (hicn_hashtb_h h, hicn_hash_node_t *node, u64 hashval) -{ - int i, count; - u32 bidx, overflow_p; - hicn_hash_bucket_t *bucket, *parent; - - if ((h == NULL) || (node == NULL)) - { - goto done; - } - if (node->hn_flags & HICN_HASH_NODE_OVERFLOW_BUCKET) - bucket = pool_elt_at_index (h->ht_overflow_buckets, node->bucket_id); - else - { - /* - * Use some bits of the low half of the hash to locate a - * row/bucket in the table - */ - bidx = (hashval & (h->ht_bucket_count - 1)); - ASSERT (bidx == node->bucket_id); - bucket = h->ht_buckets + node->bucket_id; - } - - overflow_p = node->hn_flags & HICN_HASH_NODE_OVERFLOW_BUCKET; - - /* Clear out the entry. */ - hicn_hashtb_init_entry (&(bucket->hb_entries[node->entry_idx]), 0, 0LL, 0); - - if (!overflow_p) - { - /* - * And we're done, in the easy case where we didn't change an - * overflow bucket - */ - goto done; - } - /* - * The special case: if this is the last remaining entry in an - * overflow bucket, liberate the bucket. That in turn has a special - * case if this bucket is in the middle of a chain of overflow - * buckets. - * - * Note that we're not trying aggressively (yet) to condense buckets at - * every possible opportunity. - */ - - /* - * Reset this flag; we'll set it again if this bucket links to - * another - */ - overflow_p = FALSE; - - for (i = 0, count = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++) - { - if (bucket->hb_entries[i].he_node != 0) - { - count++; - } - if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1) && - (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW)) - { - count--; /* Doesn't count as a 'real' entry */ - overflow_p = TRUE; - } - } - - if (count > 0) - { - /* Still a (real) entry in the row */ - goto done; - } - /* - * Need to locate the predecessor of 'bucket': start at the beginning - * of the chain of buckets and move forward - */ - bidx = (hashval & (h->ht_bucket_count - 1)); - - for (parent = h->ht_buckets + bidx; parent != NULL;) - { - - if ((parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_flags & - HICN_HASH_ENTRY_FLAG_OVERFLOW) == 0) - { - parent = NULL; - break; - } - bidx = parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node; - - if (pool_elt_at_index (h->ht_overflow_buckets, bidx) == bucket) - { - /* - * Found the predecessor of 'bucket'. If 'bucket' has - * a successor, connect 'parent' to it, and take - * 'bucket out of the middle. - */ - if (overflow_p) - { - parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node = - bucket->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node; - } - else - { - /* - * Just clear the predecessor entry pointing - * at 'bucket' - */ - hicn_hashtb_init_entry ( - &parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)], 0, 0LL, - 0); - } - - break; - } - /* - * After the first iteration, 'parent' will be an overflow - * bucket too - */ - parent = pool_elt_at_index (h->ht_overflow_buckets, bidx); - } - - /* We really expect to have found the predecessor */ - ASSERT (parent != NULL); - - /* And now, finally, we can put 'bucket' back on the free list */ - free_overflow_bucket (h, &bucket); - -done: - return; -} - -/* - * Prepare a hashtable node, supplying the key, and computed hash info. - */ -void -hicn_hashtb_init_node (hicn_hashtb_h h, hicn_hash_node_t *node, const u8 *key, - u32 keylen) -{ - assert (h != NULL); - assert (node != NULL); - assert (keylen <= HICN_PARAM_HICN_NAME_LEN_MAX); - - /* Init the node struct */ - node->hn_flags = HICN_HASH_NODE_FLAGS_DEFAULT; - node->hn_keysize = 0; - node->hn_keysize = keylen; - memcpy (node->hn_key.ks.key, key, keylen); - node->bucket_id = ~0; - node->entry_idx = ~0; -} - -/* - * Release a hashtable node back to the free list when an entry is cleared - */ -void -hicn_hashtb_free_node (hicn_hashtb_h h, hicn_hash_node_t *node) -{ - ASSERT (h->ht_nodes_used > 0); - - /* Return 'node' to the free list */ - pool_put (h->ht_nodes, node); - h->ht_nodes_used--; -} - -/* - * Walk a hashtable, iterating through the nodes, keeping context in 'ctx'. - */ -int -hicn_hashtb_next_node (hicn_hashtb_h h, hicn_hash_node_t **pnode, u64 *ctx) -{ - int i, j, ret = HICN_ERROR_HASHTB_INVAL; - u32 bidx, entry; - hicn_hash_bucket_t *bucket; - - if ((h == NULL) || (pnode == NULL) || (ctx == NULL)) - { - goto done; - } - /* Special-case for new iteration */ - if (*ctx == HICN_HASH_WALK_CTX_INITIAL) - { - bidx = 0; - bucket = &h->ht_buckets[0]; - entry = 0; - j = 0; - i = 0; - goto search_table; - } - /* Convert context to bucket and entry indices */ - bidx = *ctx & 0xffffffffLL; - entry = *ctx >> 32; - - if (bidx >= h->ht_bucket_count) - { - ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND; - goto done; - } - bucket = h->ht_buckets + bidx; - - /* Init total index into entries (includes fixed bucket and overflow) */ - j = 0; - -skip_processed_bucket_chunks: - /* - * Figure out where to resume the search for the next entry in the - * table, by trying to find the last entry returned, from the cookie. - * Loop walks one (regular or overflow) bucket chunk, label is used - * for walking chain of chunks. Note that if there was a deletion or - * an addition that created an overflow, iterator can skip entries or - * return duplicate entries, for entries that are present from before - * the walk starts until after it ends. - */ - - for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++, j++) - { - if (j > entry) - { - /* - * Start search for next here, use existing 'bucket' - * and 'i' - */ - break; - } - /* - * If an entry is marked for deletion, ignore it - */ - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED) - { - continue; - } - /* - * Be prepared to continue to an overflow bucket if - * necessary. (We only expect the last entry in a bucket to - * refer to an overflow bucket...) - */ - if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1)) - { - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW) - { - bucket = pool_elt_at_index (h->ht_overflow_buckets, - bucket->hb_entries[i].he_node); - - /* Increment overall entry counter 'j' */ - j++; - - goto skip_processed_bucket_chunks; - } - /* - * end of row (end of fixed bucket plus any - * overflows) - */ - i = 0; - j = 0; - - bidx++; - - /* Special case - we're at the end */ - if (bidx >= h->ht_bucket_count) - { - ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND; - goto done; - } - bucket = h->ht_buckets + bidx; - break; - } - } - -search_table: - - /* - * Now we're searching through the table for the next entry that's - * set - */ - - for (; i < HICN_HASHTB_BUCKET_ENTRIES; i++, j++) - { - /* - * If an entry is marked for deletion, ignore it - */ - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED) - { - continue; - } - /* Is this entry set? */ - if (bucket->hb_entries[i].he_node != 0) - { - - /* Retrieve the node struct */ - *pnode = - pool_elt_at_index (h->ht_nodes, bucket->hb_entries[i].he_node); - - /* - * Set 'entry' as we exit, so we can update the - * cookie - */ - entry = j; - ret = HICN_ERROR_NONE; - break; - } - /* - * Be prepared to continue to an overflow bucket if - * necessary. (We only expect the last entry in a bucket to - * refer to an overflow bucket...) - */ - if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1)) - { - if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW) - { - bucket = pool_elt_at_index (h->ht_overflow_buckets, - bucket->hb_entries[i].he_node); - /* - * Reset per-bucket index 'i', here (not done - * in iterator) - */ - i = 0; - /* Increment overall entry counter 'j' */ - j++; - - goto search_table; - } - else - { - /* - * Move to next bucket, resetting per-bucket - * and overall entry indexes - */ - i = 0; - j = 0; - - bidx++; - - /* Special case - we're at the end */ - if (bidx >= h->ht_bucket_count) - { - ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND; - goto done; - } - bucket = h->ht_buckets + bidx; - goto search_table; - } - } - } - -done: - - if (ret == HICN_ERROR_NONE) - { - /* Update context */ - *ctx = bidx; - *ctx |= ((u64) entry << 32); - } - return (ret); -} - -int -hicn_hashtb_key_to_buf (u8 **vec_res, hicn_hashtb_h h, - const hicn_hash_node_t *node) -{ - int ret = HICN_ERROR_NONE; - u8 *vec = *vec_res; - - if (node->hn_keysize <= HICN_HASH_KEY_BYTES) - { - vec_add (vec, node->hn_key.ks.key, node->hn_keysize); - } - *vec_res = vec; - return (ret); -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: eval: (c-set-style "gnu") End: - */ diff --git a/hicn-plugin/src/hashtb.h b/hicn-plugin/src/hashtb.h deleted file mode 100644 index 4b787e2d7..000000000 --- a/hicn-plugin/src/hashtb.h +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __HICN_HASHTB_H__ -#define __HICN_HASHTB_H__ - -#include <stdint.h> -#include <vppinfra/bihash_8_8.h> -#include <vppinfra/bihash_24_8.h> - -#include "params.h" -#include "parser.h" -#include "error.h" - -/** - * @file hashtb.h - * Lookup is finding a hashtable record whose name matches the name being - * looked up. Most of the lookup work is based on the hash value of the two - * names. Note that the intel cache line size is 64 bytes, and some platforms - * load in 2 cache lines together. - * - first step is to match a record at the bucket/slot level (htab has an - * array of htbucket_t/htbc_elmt, where each bucket has 7 slots to hold - * indices for entries.) Matching at this level implies - * - the hashes of the lookup name and the record map to the same bucket - * - the high 32 bits of the hashes (slot bce_hash_msb32s) match. Read - * cost (on the hash table size, i.e. ignoring reading the name being - * looked up): - * - First step normally requires 1 cache line load to pull in the - * 64-byte htbucket_t with the 7 element slot table holding the - * hash_msb32s. - * - In the event (hopefully rare for a hash table with appropriate - * number of buckets) that more than 7 elements hash to the same bucket, - * lookup may well need to look not only at the static htbc_elmt_t but at - * the chain of dynamically allocated htbc_elmt_t's linked to the static - * htbc_elmt_t, where each of these holds slot entries for additional - * elements. - * - Before reaching that point, it is initially required to read in the - * hash table record fields (ht_bucket_buf, htnode buf, etc) holding - * pointers to the arrays, but these cache lines are common to all - * lookups so will likely already be in the cache. - * - second step is to match at the record level (htnode/htkb level) once a - * slot-level match happens. Matching at this level implies the following - * match - * - the hash values (the full 64 bits vs. bucket+32 msb, above). - * - the name which, on the hash table side, is stored as a list of htkb_t - * (key buffers). - * - * Some hashtables (for which rare false positives are tolerable) store hash - * values but no keys. (In ISM NDN forwarder, this was used for dcm_dpf: data - * cache manager's dataplane filter, where speed was critical and very rare - * false positives would be detected in the full dcm check.) - No key buffers - * are used (or even allocated at hash table creation). - */ - -/* Handy abbreviations for success status, and for boolean values */ -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#define HICN_HASH_INVALID_IDX ~0 -/* - * for hicn_hashtb_next_node() iterator, this otherwise illegal context value - * indicates first call of iteration. Note: must not be 0, which is a legal - * context value. - */ -#define HICN_HASH_WALK_CTX_INITIAL (~((u64) 0)) - -/* - * Key memory allocation scheme. - * - * The key is the bytestring that a hashtable entry is storing, e.g. a fib - * prefix or packet name. The hash of the name is used not just to pick the - * bucket, but also as a surrogate for the actual key value. - * - * Client calls pass key/name as contiguous memory for lookup/add/delete but - * hashable stores its copy of the key/name as a list of one or more hash_key - * structs. - key memory is managed as a list of keys (cache line - * sized/aligned buffers). - If (keysize < 128) then use key struct's full - * 128 bytes - If not, first key struct is head of a linked list of elements - * where the first bytes are used for the key and the last 4 bytes are the - * index of the next entry (or an end marker). - key memory is generally the - * single largest use of memory in the hash table, especially for PIT, as - * names are bigger than node structs (which is also per name/entry). - * - */ - -/* Compute hash node index from node pointer */ -#define NODE_IDX_FROM_NODE(p, h) (u32) ((p) - ((h)->ht_nodes)) - -#define HICN_HASH_KEY_BYTES 20 - -typedef struct -{ - struct - { - u8 key[HICN_HASH_KEY_BYTES]; - } ks; /* Entire key in one block */ -} hicn_hash_key_t; - -/* - * Ratio of extra key blocks to allocate, in case the embedded ones aren't - * sufficient. This is the fraction of the number of entries allocated. - */ -#define HICN_HASHTB_KEY_RATIO 8 - -/* - * hash node, used to store a hash table entry; indexed by an entry in a - * bucket. the node contains an embedded key; long keys are stored as chains - * of keys. - * - * The memory block for a node includes space for storing outgoing faces for - * interests, additional memory located off the end of the htnode data - * structure. - * - */ - -/* Size this so that we can offer 64B aligned on 64-bits for storing outgoing - * faces information - */ -#define HICN_HASH_NODE_APP_DATA_SIZE 64 - -/* How to align in the right way */ -typedef struct __attribute__ ((packed)) hicn_hash_node_s -{ - /* Bucket id containing the corresponding hash entry. */ - u32 bucket_id; - - /* Hash entry index in the bucket */ - u32 entry_idx; - - /* Total size of the key */ - u16 hn_keysize; - - /* 1 byte of flags for application use */ - u8 hn_flags; - - u8 _hn_reserved1; /* TBD, to align what follows back to - * 32 */ - - hicn_hash_key_t hn_key; /* Key value embedded in the node, may chain - * to more key buffers if necessary */ - - /* 32B + HICN_HASH_NODE_APP_DATA_SIZE */ - /* Followed by app-specific data (fib or pit or cs entry, e.g.) */ - u8 hn_data[HICN_HASH_NODE_APP_DATA_SIZE]; - -} hicn_hash_node_t; - -#define HICN_HASH_NODE_FLAGS_DEFAULT 0x00 -#define HICN_HASH_NODE_CS_FLAGS 0x01 -#define HICN_HASH_NODE_OVERFLOW_BUCKET 0x02 - -/* - * hicn_hash_entry_t Structure holding all or part of a hash value, a node - * index, and other key pieces of info. - * - * - 128 bytes/bucket with 19 bytes/entry gives 6 entries, or 5 entries plus - * next bucket ptr if overflow Changes in this structure will affect - * hicn_hash_bucket_t - */ -typedef struct __attribute__ ((packed)) hicn_hash_entry_s -{ - - /* MSB of the hash value */ - u64 he_msb64; - - /* Index of node block */ - u32 he_node; - - /* - * Lock to prevent hash_node deletion while there are still interest - * or data referring to it - */ - u32 locks; - - /* Index of dpo (4B) */ - index_t dpo_ctx_id; - - /* A few flags, including 'this points to a chain of buckets' */ - u8 he_flags; - - /* - * Index of the virtual function table corresponding to the dpo_ctx - * strategy - */ - u8 vft_id; - -} hicn_hash_entry_t; // size 22B - -STATIC_ASSERT (sizeof (index_t) <= 4, "sizeof index_t is greater than 4B"); - -#define HICN_HASH_ENTRY_FLAGS_DEFAULT 0x00 - -/* If entry is PIT this flag is 0 */ -#define HICN_HASH_ENTRY_FLAG_CS_ENTRY 0x01 - -/* - * This entry heads a chain of overflow buckets (we expect to see this only - * in the last entry in a bucket.) In this case, the index is to an overflow - * bucket rather than to a single node block. - */ -#define HICN_HASH_ENTRY_FLAG_OVERFLOW 0x04 - -/* This entry has been marked for deletion */ -#define HICN_HASH_ENTRY_FLAG_DELETED 0x08 - -/* Use fast he_timeout units for expiration, slow if not */ -#define HICN_HASH_ENTRY_FLAG_FAST_TIMEOUT 0x10 - -/* - * hash bucket: Contains an array of entries. Cache line sized/aligned, so no - * room for extra fields unless bucket size is increased to 2 cache lines or - * the entry struct shrinks. - */ - -/* - * Overflow bucket ratio as a fraction of the fixed/configured count; a pool - * of hash buckets used if a row in the fixed table overflows. - */ -#define HICN_HASHTB_BUCKET_ENTRIES 5 - -typedef struct __attribute__ ((packed)) -{ - hicn_hash_entry_t hb_entries[HICN_HASHTB_BUCKET_ENTRIES]; - u64 align1; - u64 align2; - u16 align3; -} hicn_hash_bucket_t; - -/* Overall target fill-factor for the hashtable */ -#define HICN_HASHTB_FILL_FACTOR 4 - -#define HICN_HASHTB_MIN_ENTRIES (1 << 4) // includes dummy node 0 entry -#define HICN_HASHTB_MAX_ENTRIES (1 << 24) - -#define HICN_HASHTB_MIN_BUCKETS (1 << 10) - -/* - * htab_t - * - * Hash table main structure. - * - * Contains - pointers to dynamically allocated arrays of cache-line - * sized/aligned structures (buckets, nodes, keys). Put frequently accessed - * fields in the first cache line. - */ -typedef struct hicn_hashtb_s -{ - - /* 8B - main array of hash buckets */ - hicn_hash_bucket_t *ht_buckets; - - /* 8B - just-in-case block of overflow buckets */ - hicn_hash_bucket_t *ht_overflow_buckets; - - /* 8B - block of nodes associated with entries in buckets */ - hicn_hash_node_t *ht_nodes; - - /* Flags */ - u32 ht_flags; - - /* Count of buckets allocated in the main array */ - u32 ht_bucket_count; - - /* Count of overflow buckets allocated */ - u32 ht_overflow_bucket_count; - u32 ht_overflow_buckets_used; - - /* Count of nodes allocated */ - u32 ht_node_count; - u32 ht_nodes_used; - - /* Count of overflow key structs allocated */ - u32 ht_key_count; - u32 ht_keys_used; - -} hicn_hashtb_t, *hicn_hashtb_h; - -/* - * Offset to aligned start of additional data (PIT/CS, FIB) embedded in each - * node. - */ -extern u32 ht_node_data_offset_aligned; - -/* Flags for hashtable */ - -#define HICN_HASHTB_FLAGS_DEFAULT 0x00 - -/* - * Don't use the last entry in each bucket - only use it for overflow. We use - * this for the FIB, currently, so that we can support in-place FIB changes - * that would be difficult if there were hash entry copies as part of - * overflow handling. - */ -#define HICN_HASHTB_FLAG_USE_SEVEN 0x04 -#define HICN_HASHTB_FLAG_KEY_FMT_PFX 0x08 -#define HICN_HASHTB_FLAG_KEY_FMT_NAME 0x10 - -/* - * Max prefix name components we'll support in our incremental hashing; - * currently used only for LPM in the FIB. - */ -#define HICN_HASHTB_MAX_NAME_COMPS HICN_PARAM_FIB_ENTRY_PFX_COMPS_MAX - -/* - * APIs and inlines - */ - -/* Compute hash node index from node pointer */ -static inline u32 -hicn_hashtb_node_idx_from_node (hicn_hashtb_h h, hicn_hash_node_t *p) -{ - return (p - h->ht_nodes); -} - -/* Retrieve a hashtable node by node index */ -static inline hicn_hash_node_t * -hicn_hashtb_node_from_idx (hicn_hashtb_h h, u32 idx) -{ - return (pool_elt_at_index (h->ht_nodes, idx)); -} - -/* Allocate a brand-new hashtable */ -int hicn_hashtb_alloc (hicn_hashtb_h *ph, u32 max_elems, size_t app_data_size); - -/* Free a hashtable, including its embedded arrays */ -int hicn_hashtb_free (hicn_hashtb_h *ph); - -/* Hash a bytestring, currently using bihash */ -u64 hicn_hashtb_hash_bytestring (const u8 *key, u32 keylen); - -always_inline hicn_hash_entry_t * -hicn_hashtb_get_entry (hicn_hashtb_h h, u32 entry_idx, u32 bucket_id, - u8 bucket_overflow) -{ - hicn_hash_bucket_t *bucket; - if (bucket_overflow) - bucket = pool_elt_at_index (h->ht_overflow_buckets, bucket_id); - else - bucket = (hicn_hash_bucket_t *) (h->ht_buckets + bucket_id); - - return &(bucket->hb_entries[entry_idx]); -} - -/* Hash a name, currently using bihash */ -always_inline u64 -hicn_hashtb_hash_name (const u8 *key, u16 keylen) -{ - if (key != NULL && keylen == HICN_V4_NAME_LEN) - { - clib_bihash_kv_8_8_t kv; - kv.key = ((u64 *) key)[0]; - return clib_bihash_hash_8_8 (&kv); - } - else if (key != NULL && keylen == HICN_V6_NAME_LEN) - { - clib_bihash_kv_24_8_t kv; - kv.key[0] = ((u64 *) key)[0]; - kv.key[1] = ((u64 *) key)[1]; - kv.key[2] = ((u32 *) key)[4]; - return clib_bihash_hash_24_8 (&kv); - } - else - { - return (-1LL); - } -} - -/* - * Prepare a hashtable node for insertion, supplying the key and computed - * hash info. This sets up the node->key relationship, possibly allocating - * overflow key buffers. - */ -void hicn_hashtb_init_node (hicn_hashtb_h h, hicn_hash_node_t *node, - const u8 *key, u32 keylen); - -/* - * Insert a node into the hashtable. We expect the caller has used the init - * api to set the node key and hash info, and populated the extra data area - * (if any) - or done the equivalent work itself. - */ -int hicn_hashtb_insert (hicn_hashtb_h h, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hash, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow); - -/* - * Basic api to lookup a specific hash+key tuple. This does the entire lookup - * operation, retrieving node structs and comparing keys, so it's not - * optimized for prefetching or high performance. - * - * Returns zero and mails back a node on success, errno otherwise. - */ -int hicn_hashtb_lookup_node (hicn_hashtb_h h, const u8 *key, u32 keylen, - u64 hashval, u8 is_data, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow); - -/* - * Extended api to lookup a specific hash+key tuple. The implementation - * allows the caller to locate nodes that are marked for deletion; this is - * part of some hashtable applications, such as the FIB. - * - * This does the entire lookup operation, retrieving node structs and comparing - * keys, so it's not optimized for prefetching or high performance. - * - * Returns zero and mails back a node on success, errno otherwise. - */ -int hicn_hashtb_lookup_node_ex (hicn_hashtb_h h, const u8 *key, u32 keylen, - u64 hashval, u8 is_data, int include_deleted_p, - u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id, - u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow); - -/** - * @brief Compares the key in the node with the given key - * - * This function allows to split the hash verification from the comparison of - * the entire key. Useful to exploit prefertching. - * @result 1 if equals, 0 otherwise - */ -int hicn_node_compare (const u8 *key, u32 keylen, hicn_hash_node_t *node); - -/* - * Remove a node from a hashtable using the node itself. The internal data - * structs are cleaned up, but the node struct itself is not: the caller must - * free the node itself. - */ -void hicn_hashtb_remove_node (hicn_hashtb_h h, hicn_hash_node_t *node, - u64 hashval); - -/* - * Delete a node from a hashtable using the node itself, and delete/free the - * node. Caller's pointer is cleared on success. - */ -void hicn_hashtb_delete (hicn_hashtb_h h, hicn_hash_node_t **pnode, - u64 hashval); - -/* - * Utility to init a new entry in a hashtable bucket/row. We use this to add - * new a node+hash, and to clear out an entry during removal. - */ -void hicn_hashtb_init_entry (hicn_hash_entry_t *entry, u32 nodeidx, - u64 hashval, u32 locks); - -/* - * Return data area embedded in a hash node struct. We maintain an 'offset' - * value in case the common node body struct doesn't leave the data area - * aligned properly. - */ -static inline void * -hicn_hashtb_node_data (hicn_hash_node_t *node) -{ - return ((u8 *) (node) + ht_node_data_offset_aligned); -} - -/* - * Use some bits of the low half of the hash to locate a row/bucket in the - * table - */ -static inline u32 -hicn_hashtb_bucket_idx (hicn_hashtb_h h, u64 hashval) -{ - return ((u32) (hashval & (h->ht_bucket_count - 1))); -} - -/* - * Return a hash node struct from the free list, or NULL. Note that the - * returned struct is _not_ cleared/zeroed - init is up to the caller. - */ -static inline hicn_hash_node_t * -hicn_hashtb_alloc_node (hicn_hashtb_h h) -{ - hicn_hash_node_t *p = NULL; - - if (h->ht_nodes_used < h->ht_node_count) - { - pool_get_aligned (h->ht_nodes, p, 8); - h->ht_nodes_used++; - } - return (p); -} - -/* - * Release a hashtable node back to the free list when an entry is cleared - */ -void hicn_hashtb_free_node (hicn_hashtb_h h, hicn_hash_node_t *node); - -/* - * Walk a hashtable, iterating through the nodes, keeping context in 'ctx' - * between calls. - * - * Set the context value to HICN_HASH_WALK_CTX_INITIAL to start an iteration. - */ -int hicn_hashtb_next_node (hicn_hashtb_h h, hicn_hash_node_t **pnode, - u64 *ctx); - -int hicn_hashtb_key_to_str (hicn_hashtb_h h, const hicn_hash_node_t *node, - char *buf, int bufsize, int must_fit); - -/* - * single hash full name can pass offset for two hashes calculation in case - * we use CS and PIT in a two steps hashes (prefix + seqno) - */ -always_inline int -hicn_hashtb_fullhash (const u8 *name, u16 namelen, u64 *name_hash) -{ - *name_hash = hicn_hashtb_hash_name (name, namelen); - return (*name_hash != (-1LL) ? HICN_ERROR_NONE : HICN_ERROR_HASHTB_INVAL); -} - -#endif /* // __HICN_HASHTB_H__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: eval: (c-set-style "gnu") End: - */ diff --git a/hicn-plugin/src/hicn.api b/hicn-plugin/src/hicn.api index 44382c743..8c1c78eb0 100644 --- a/hicn-plugin/src/hicn.api +++ b/hicn-plugin/src/hicn.api @@ -463,6 +463,9 @@ define hicn_api_register_prod_app /* CS memory reserved -- in number of packets */ u32 cs_reserved; + + /* Port identifying producer application */ + u16 port; }; define hicn_api_register_prod_app_reply @@ -505,6 +508,9 @@ define hicn_api_register_cons_app /* swif */ u32 swif; + + /* src port of consumer packet from this face */ + u16 port; }; define hicn_api_register_cons_app_reply diff --git a/hicn-plugin/src/hicn.c b/hicn-plugin/src/hicn.c index 1789f5407..d48ef4023 100644 --- a/hicn-plugin/src/hicn.c +++ b/hicn-plugin/src/hicn.c @@ -25,7 +25,6 @@ #include "mgmt.h" #include "error.h" #include "faces/app/address_mgr.h" -#include "face_db.h" #include "udp_tunnels/udp_tunnel.h" #include "route.h" #include "pg.h" @@ -34,14 +33,7 @@ hicn_main_t hicn_main; /* Module vars */ int hicn_infra_fwdr_initialized = 0; -/* - * Global time counters we're trying out for opportunistic hashtable - * expiration. - */ -uint16_t hicn_infra_fast_timer; /* Counts at 1 second intervals */ -uint16_t hicn_infra_slow_timer; /* Counts at 1 minute intervals */ - -hicn_face_bucket_t *hicn_face_bucket_pool; +// hicn_face_bucket_t *hicn_face_bucket_pool; /* * Init hicn forwarder with configurable PIT, CS sizes @@ -49,29 +41,27 @@ hicn_face_bucket_t *hicn_face_bucket_pool; static int hicn_infra_fwdr_init (uint32_t shard_pit_size, uint32_t shard_cs_size) { - int ret = 0; + int ret = HICN_ERROR_NONE; if (hicn_infra_fwdr_initialized) { ret = HICN_ERROR_FWD_ALREADY_ENABLED; - goto done; + goto DONE; } + /* Init per worker limits */ hicn_infra_pit_size = shard_pit_size; hicn_infra_cs_size = shard_cs_size; - /* Init the global time-compression counters */ - hicn_infra_fast_timer = 1; - hicn_infra_slow_timer = 1; + hicn_pit_create (&hicn_main.pitcs, hicn_infra_pit_size, hicn_infra_cs_size); - ret = hicn_pit_create (&hicn_main.pitcs, hicn_infra_pit_size); - hicn_pit_set_lru_max (&hicn_main.pitcs, hicn_infra_cs_size); -done: +DONE: if ((ret == HICN_ERROR_NONE) && !hicn_infra_fwdr_initialized) { hicn_infra_fwdr_initialized = 1; } - return (ret); + + return ret; } /* @@ -166,8 +156,6 @@ hicn_infra_plugin_enable_disable (int enable_disable, int pit_size_req, ret = hicn_infra_fwdr_init (pit_size, cs_size); - hicn_face_db_init (pit_size); - if (ret != HICN_ERROR_NONE) { goto done; diff --git a/hicn-plugin/src/hicn.h b/hicn-plugin/src/hicn.h index 22309e3e5..3b197d6b4 100644 --- a/hicn-plugin/src/hicn.h +++ b/hicn-plugin/src/hicn.h @@ -61,28 +61,24 @@ typedef u8 weight_t; typedef struct { /** - * Hash of the name (8) + * IDs to prefetch a PIT/CS entry (4) */ - u64 name_hash; + u32 pcs_entry_id; /** - * IDs to prefetch a PIT/CS entry (4+4+1+1) + * DPO/Stategy VFT ID. This is also the DPO type (4) */ - u32 node_id; - u32 bucket_id; - u8 hash_entry_id; - u8 hash_bucket_flags; + dpo_type_t vft_id; /** - * hICN buffer flags (1) + * DPO context ID (4) */ - u8 flags; + u32 dpo_ctx_id; /** - * used for data path (1+1) + * hICN buffer flags (1) */ - u8 dpo_ctx_id; - u8 vft_id; + u8 flags; /** * Ingress face (4) @@ -95,6 +91,7 @@ typedef struct hicn_type_t type; hicn_name_t name; u16 port; + hicn_lifetime_t lifetime; } hicn_buffer_t; STATIC_ASSERT (sizeof (hicn_buffer_t) <= @@ -113,14 +110,10 @@ hicn_is_v6 (hicn_header_t *pkt_hdr) return ((pkt_hdr->v4.ip.version_ihl >> 4) != 4); } -always_inline void -hicn_buffer_get_name_and_namelen (vlib_buffer_t *b0, u8 **nameptr, - u16 *namelen) +always_inline hicn_name_t * +hicn_buffer_get_name (vlib_buffer_t *b) { - *nameptr = (u8 *) (&hicn_get_buffer (b0)->name); - *namelen = ip_address_is_v4 (&hicn_get_buffer (b0)->name.prefix) ? - HICN_V4_NAME_LEN : - HICN_V6_NAME_LEN; + return &hicn_get_buffer (b)->name; } always_inline u8 @@ -135,6 +128,13 @@ hicn_buffer_set_flags (vlib_buffer_t *b, u8 flags) hicn_buffer_t *hb = hicn_get_buffer (b); hb->flags |= flags; } + +always_inline hicn_lifetime_t +hicn_buffer_get_lifetime (vlib_buffer_t *b) +{ + return hicn_get_buffer (b)->lifetime; +} + #endif /* __HICN_H__ */ /* diff --git a/hicn-plugin/src/infra.h b/hicn-plugin/src/infra.h index c942ad581..463617da0 100644 --- a/hicn-plugin/src/infra.h +++ b/hicn-plugin/src/infra.h @@ -46,7 +46,7 @@ typedef struct hicn_main_s * Boundaries for the interest lifetime. If greater than * pit_lifetime_max_ms, pit_lifetime_max_ms is used in the PIT */ - u64 pit_lifetime_max_ms; + u32 pit_lifetime_max_ms; vnet_link_t link; diff --git a/hicn-plugin/src/interest_hitcs_node.c b/hicn-plugin/src/interest_hitcs_node.c index 1af21191c..651b2796a 100644 --- a/hicn-plugin/src/interest_hitcs_node.c +++ b/hicn-plugin/src/interest_hitcs_node.c @@ -36,13 +36,14 @@ static char *hicn_interest_hitcs_error_strings[] = { vlib_node_registration_t hicn_interest_hitcs_node; -always_inline void drop_packet (u32 *next0); +// always_inline void drop_packet (u32 *next0); -always_inline void -clone_from_cs (vlib_main_t *vm, u32 *bi0_cs, vlib_buffer_t *dest, u8 isv6) +always_inline u32 +clone_from_cs (vlib_main_t *vm, u32 bi0_cs, vlib_buffer_t *dest, u8 isv6) { /* Retrieve the buffer to clone */ - vlib_buffer_t *cs_buf = vlib_get_buffer (vm, *bi0_cs); + u32 ret = bi0_cs; + vlib_buffer_t *cs_buf = vlib_get_buffer (vm, bi0_cs); hicn_buffer_t *hicnb = hicn_get_buffer (cs_buf); word buffer_advance = CLIB_CACHE_LINE_BYTES * 2; if (hicnb->flags & HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL) @@ -63,7 +64,7 @@ clone_from_cs (vlib_main_t *vm, u32 *bi0_cs, vlib_buffer_t *dest, u8 isv6) { vlib_buffer_t *cs_buf2 = vlib_buffer_copy (vm, cs_buf); vlib_buffer_advance (cs_buf, buffer_advance); - *bi0_cs = vlib_get_buffer_index (vm, cs_buf2); + ret = vlib_get_buffer_index (vm, cs_buf2); cs_buf->ref_count--; cs_buf = cs_buf2; } @@ -79,6 +80,8 @@ clone_from_cs (vlib_main_t *vm, u32 *bi0_cs, vlib_buffer_t *dest, u8 isv6) /* Set fag for packet coming from CS */ hicn_get_buffer (dest)->flags |= HICN_BUFFER_FLAGS_FROM_CS; + + return ret; } static uword @@ -89,6 +92,16 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_interest_hitcs_next_t next_index; hicn_interest_hitcs_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + vlib_buffer_t *b0; + u8 isv6; + u32 bi0, bi_ret; + u32 next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP; + hicn_buffer_t *hicnb0; + u32 pcs_entry_index; + hicn_pcs_entry_t *pcs_entry = NULL; + const hicn_strategy_vft_t *strategy_vft0; + const hicn_dpo_vft_t *dpo_vft0; + u8 dpo_ctx_id0; f64 tnow; rt = vlib_node_get_runtime_data (vm, hicn_interest_hitcs_node.index); @@ -109,27 +122,12 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { - vlib_buffer_t *b0; - u8 isv6; - u8 *nameptr; - u16 namelen; - u32 bi0; - u32 next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP; - hicn_buffer_t *hicnb0; - hicn_hash_node_t *node0; - hicn_pcs_entry_t *pitp; - hicn_hash_entry_t *hash_entry0; - const hicn_strategy_vft_t *strategy_vft0; - const hicn_dpo_vft_t *dpo_vft0; - u8 dpo_ctx_id0; - /* Prefetch for next iteration. */ if (n_left_from > 1) { vlib_buffer_t *b1; b1 = vlib_get_buffer (vm, from[1]); CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE); } /* Dequeue a packet buffer */ @@ -144,62 +142,43 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, /* Get hicn buffer and state */ hicnb0 = hicn_get_buffer (b0); - hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0, - &dpo_vft0, &dpo_ctx_id0, &hash_entry0); + hicn_get_internal_state (hicnb0, &pcs_entry_index, &strategy_vft0, + &dpo_vft0, &dpo_ctx_id0); + pcs_entry = + hicn_pcs_entry_get_entry_from_index (rt->pitcs, pcs_entry_index); - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); isv6 = hicn_buffer_is_v6 (b0); - pitp = hicn_pit_get_data (node0); - dpo_id_t hicn_dpo_id0 = { .dpoi_type = - dpo_vft0->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_id0 }; - - if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0))) - { - /* Remove lock from the entry */ - hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); - drop_packet (&next0); - goto end_processing; - } - if ((tnow > pitp->shared.expire_time)) + if (tnow > hicn_pcs_entry_get_expire_time (pcs_entry)) { - /* Delete and clean up expired CS entry */ - hicn_pcs_delete (rt->pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); + // Delete and clean up expired CS entry + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + + // Update stats stats.cs_expired_count++; - /* Forward interest to the strategy node */ + + // Forward interest to the strategy node next0 = HICN_INTEREST_HITCS_NEXT_STRATEGY; } else { - if (PREDICT_TRUE ( - !(hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_DELETED))) - hicn_pcs_cs_update (vm, rt->pitcs, pitp, pitp, node0); - - /* - * Retrieve the incoming iface and forward - * the data through it - */ + // Retrieve the incoming iface and forward + // the data through it next0 = isv6 ? HICN_INTEREST_HITCS_NEXT_IFACE6_OUT : HICN_INTEREST_HITCS_NEXT_IFACE4_OUT; vnet_buffer (b0)->ip.adj_index[VLIB_TX] = hicnb0->face_id; - clone_from_cs (vm, &pitp->u.cs.cs_pkt_buf, b0, isv6); + bi_ret = clone_from_cs ( + vm, hicn_pcs_entry_cs_get_buffer (pcs_entry), b0, isv6); + + hicn_pcs_entry_cs_set_buffer (pcs_entry, bi_ret); + // Update stats stats.pkts_from_cache_count++; stats.pkts_data_count++; - /* Remove lock from the entry */ - hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); } - end_processing: - - /* Maybe trace */ + // Maybe trace if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -209,20 +188,18 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } - /* Incr packet counter */ + + // Increment packet counter stats.pkts_processed += 1; - /* - * Verify speculative enqueue, maybe switch current - * next frame - */ + // Verify speculative enqueue, maybe switch current next frame vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs); + u32 pit_int_count = hicn_pcs_get_pit_count (rt->pitcs); vlib_node_increment_counter (vm, hicn_interest_hitcs_node.index, HICNFWD_ERROR_CACHED, @@ -237,11 +214,13 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, return (frame->n_vectors); } +#if 0 always_inline void drop_packet (u32 *next0) { *next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP; } +#endif /* packet trace format function */ static u8 * diff --git a/hicn-plugin/src/interest_hitpit_node.c b/hicn-plugin/src/interest_hitpit_node.c index c98baf7e9..9715fc549 100644 --- a/hicn-plugin/src/interest_hitpit_node.c +++ b/hicn-plugin/src/interest_hitpit_node.c @@ -25,7 +25,6 @@ #include "strategy_dpo_manager.h" #include "state.h" #include "error.h" -#include "face_db.h" /* packet trace format function */ static u8 *hicn_interest_hitpit_format_trace (u8 *s, va_list *args); @@ -48,11 +47,27 @@ static uword hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { + int ret; u32 n_left_from, *from, *to_next; hicn_interest_hitpit_next_t next_index; hicn_interest_hitpit_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; f64 tnow; + u32 n_left_to_next; + vlib_buffer_t *b0; + u8 isv6; + u32 bi0; + u32 next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP; + const hicn_strategy_vft_t *strategy_vft0; + const hicn_dpo_vft_t *dpo_vft0; + u8 dpo_ctx_id0; + u8 found = 0; + hicn_face_id_t outfaces[MAX_OUT_FACES]; + u32 clones[MAX_OUT_FACES]; + u16 outfaces_len; + u32 pit_entry_index; + hicn_pcs_entry_t *pcs_entry = NULL; + hicn_buffer_t *hicnb0; rt = vlib_node_get_runtime_data (vm, hicn_interest_hitpit_node.index); @@ -69,35 +84,15 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0) { - u32 n_left_to_next; vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { - vlib_buffer_t *b0; - u8 isv6; - u8 *nameptr; - u16 namelen; - u32 bi0; - u32 next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP; - hicn_hash_node_t *node0; - const hicn_strategy_vft_t *strategy_vft0; - const hicn_dpo_vft_t *dpo_vft0; - hicn_pcs_entry_t *pitp; - u8 dpo_ctx_id0; - u8 found = 0; - int nh_idx; - hicn_face_id_t outfaces[MAX_OUT_FACES]; - u32 outfaces_len; - hicn_hash_entry_t *hash_entry0; - hicn_buffer_t *hicnb0; - /* Prefetch for next iteration. */ if (n_left_from > 1) { vlib_buffer_t *b1; b1 = vlib_get_buffer (vm, from[1]); CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE); } /* Dequeue a packet buffer */ @@ -112,163 +107,142 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, /* Get hicn buffer and state */ hicnb0 = hicn_get_buffer (b0); - hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0, - &dpo_vft0, &dpo_ctx_id0, &hash_entry0); + hicn_get_internal_state (hicnb0, &pit_entry_index, &strategy_vft0, + &dpo_vft0, &dpo_ctx_id0); - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); - isv6 = hicn_buffer_is_v6 (b0); + // Retrieve PIT entry + pcs_entry = + hicn_pcs_entry_get_entry_from_index (rt->pitcs, pit_entry_index); - pitp = hicn_pit_get_data (node0); - dpo_id_t hicn_dpo_id0 = { .dpoi_type = - dpo_vft0->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_id0 }; + isv6 = hicn_buffer_is_v6 (b0); - /* - * Check if the hit is instead a collision in the - * hash table. Unlikely to happen. - */ - if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0))) - { - stats.interests_hash_collision++; - /* Remove lock from the entry */ - hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); - drop_packet (&next0); + // Increment packet counter + stats.pkts_processed += 1; - goto end_processing; - } - /* - * If the entry is expired, remove it no matter of - * the possible cases. - */ - if (tnow > pitp->shared.expire_time) + // If the entry is expired, remove it no matter of the possible + // cases. + if (tnow > hicn_pcs_entry_get_expire_time (pcs_entry)) { + // Notify strategy strategy_vft0->hicn_on_interest_timeout (dpo_ctx_id0); - hicn_pcs_delete (rt->pitcs, &pitp, &node0, vm, hash_entry0, - dpo_vft0, &hicn_dpo_id0); + + // Release lock on entry - this MUST delete the entry + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + stats.pit_expired_count++; + + // Forward to strategy node + // TODO this can be simplified by checking directly in the + // pcslookup node! next0 = HICN_INTEREST_HITPIT_NEXT_STRATEGY; } else { - if ((hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)) + // A data packet may have arrived in the time between the pcs + // lookup and now. Check again to make sure the entry is CS or + // PIT + if (hicn_pcs_entry_is_cs (pcs_entry)) { next0 = HICN_INTEREST_HITPIT_NEXT_INTEREST_HITCS; } else { - /* - * Distinguish between aggregation or - * retransmission - */ - + // Distinguish between aggregation or retransmission found = - hicn_face_search (hicnb0->face_id, &(pitp->u.pit.faces)); + hicn_pcs_entry_pit_search (pcs_entry, hicnb0->face_id); if (found) { + // Retransmission strategy_vft0->hicn_select_next_hop ( - dpo_ctx_id0, &nh_idx, outfaces, &outfaces_len); - /* Retransmission */ - /* - * Prepare the packet for the - * forwarding - */ - if (outfaces_len == 1) - { - next0 = isv6 ? - HICN_INTEREST_HITPIT_NEXT_FACE6_OUTPUT : - HICN_INTEREST_HITPIT_NEXT_FACE4_OUTPUT; - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = - outfaces[0]; + dpo_ctx_id0, outfaces, &outfaces_len); - /* - * Update the egress face in - * the PIT - */ - pitp->u.pit.pe_txnh = nh_idx; - stats.interests_retx++; + // Prepare the packet for the forwarding + next0 = isv6 ? HICN_INTEREST_HITPIT_NEXT_FACE6_OUTPUT : + HICN_INTEREST_HITPIT_NEXT_FACE4_OUTPUT; + + // Update stats + stats.interests_retx += outfaces_len; + + // Clone interest if needed + if (outfaces_len > 1) + { + ret = vlib_buffer_clone (vm, bi0, clones, + (u16) outfaces_len, + CLIB_CACHE_LINE_BYTES * 2); + ASSERT (ret == outfaces_len); } else { - // restore pointers - to_next -= 1; - n_left_to_next += 1; - u32 clones[outfaces_len]; - int ret = - vlib_buffer_clone (vm, bi0, clones, outfaces_len, - CLIB_CACHE_LINE_BYTES * 2); - ASSERT (ret == outfaces_len); - for (u32 nh = 0; nh < outfaces_len; nh++) + clones[0] = bi0; + } + + // We need to clone the packet over multiple output + // faces + + // Restore pointers + to_next -= 1; + n_left_to_next += 1; + + for (u32 nh = 0; nh < outfaces_len; nh++) + { + vlib_buffer_t *local_b0 = + vlib_get_buffer (vm, clones[nh]); + to_next[0] = clones[nh]; + to_next += 1; + n_left_to_next -= 1; + + vnet_buffer (local_b0)->ip.adj_index[VLIB_TX] = + outfaces[nh]; + + /* Maybe trace */ + if (PREDICT_FALSE ( + (node->flags & VLIB_NODE_FLAG_TRACE) && + (local_b0->flags & VLIB_BUFFER_IS_TRACED))) { - vlib_buffer_t *local_b0 = - vlib_get_buffer (vm, clones[nh]); - to_next[0] = clones[nh]; - to_next += 1; - n_left_to_next -= 1; - - next0 = - isv6 ? HICN_INTEREST_HITPIT_NEXT_FACE6_OUTPUT : - HICN_INTEREST_HITPIT_NEXT_FACE4_OUTPUT; - vnet_buffer (local_b0)->ip.adj_index[VLIB_TX] = - outfaces[nh]; - stats.interests_retx++; - - /* Maybe trace */ - if (PREDICT_FALSE ( - (node->flags & VLIB_NODE_FLAG_TRACE) && - (local_b0->flags & VLIB_BUFFER_IS_TRACED))) - { - hicn_interest_hitpit_trace_t *t = - vlib_add_trace (vm, node, local_b0, - sizeof (*t)); - t->pkt_type = HICN_PACKET_TYPE_INTEREST; - t->sw_if_index = vnet_buffer (local_b0) - ->sw_if_index[VLIB_RX]; - t->next_index = next0; - } - - /* - * Verify speculative enqueue, maybe switch - * current next frame - */ - vlib_validate_buffer_enqueue_x1 ( - vm, node, next_index, to_next, n_left_to_next, - clones[nh], next0); + hicn_interest_hitpit_trace_t *t = + vlib_add_trace (vm, node, local_b0, + sizeof (*t)); + t->pkt_type = HICN_PACKET_TYPE_INTEREST; + t->sw_if_index = + vnet_buffer (local_b0)->sw_if_index[VLIB_RX]; + t->next_index = next0; } - continue; + + /* + * Verify speculative enqueue, maybe switch + * current next frame + */ + vlib_validate_buffer_enqueue_x1 ( + vm, node, next_index, to_next, n_left_to_next, + clones[nh], next0); } + continue; } else { - hicn_face_db_add_face (hicnb0->face_id, - &pitp->u.pit.faces); + // Aggregation + hicn_pcs_entry_pit_add_face (pcs_entry, hicnb0->face_id); /* Aggregation */ drop_packet (&next0); stats.interests_aggregated++; + + /* Maybe trace */ + if (PREDICT_FALSE ( + (node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + hicn_interest_hitpit_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = HICN_PACKET_TYPE_INTEREST; + t->sw_if_index = + vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->next_index = next0; + } } - /* Remove lock from the entry */ - hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, - hash_entry0, dpo_vft0, &hicn_dpo_id0); } } - end_processing: - - /* Maybe trace */ - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - hicn_interest_hitpit_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PACKET_TYPE_INTEREST; - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->next_index = next0; - } - /* Incr packet counter */ - stats.pkts_processed += 1; /* * Verify speculative enqueue, maybe switch current @@ -279,7 +253,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs); + u32 pit_int_count = hicn_pcs_get_pit_count (rt->pitcs); vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index, HICNFWD_ERROR_PROCESSED, stats.pkts_processed); diff --git a/hicn-plugin/src/interest_pcslookup_node.c b/hicn-plugin/src/interest_pcslookup_node.c index e569573b7..a9ff9ba29 100644 --- a/hicn-plugin/src/interest_pcslookup_node.c +++ b/hicn-plugin/src/interest_pcslookup_node.c @@ -53,10 +53,15 @@ static uword hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { + int ret; u32 n_left_from, *from, *to_next; hicn_interest_pcslookup_next_t next_index; hicn_interest_pcslookup_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + vlib_buffer_t *b0; + u32 bi0; + u32 next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; + hicn_pcs_entry_t *pcs_entry = NULL; rt = vlib_node_get_runtime_data (vm, hicn_interest_pcslookup_node.index); @@ -74,29 +79,15 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { - vlib_buffer_t *b0; - u8 *nameptr; - u16 namelen; - u32 bi0; - u32 next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; - u64 name_hash = 0; - u32 node_id0 = 0; - index_t dpo_ctx_id0 = 0; - u8 vft_id0 = 0; - u8 is_cs0 = 0; - u8 hash_entry_id = 0; - u8 bucket_is_overflown = 0; - u32 bucket_id = ~0; - /* Prefetch for next iteration. */ if (n_left_from > 1) { vlib_buffer_t *b1; b1 = vlib_get_buffer (vm, from[1]); CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD); } - /* Dequeue a packet buffer */ + + // Dequeue a packet buffer bi0 = from[0]; from += 1; n_left_from -= 1; @@ -106,36 +97,34 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, b0 = vlib_get_buffer (vm, bi0); - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); - + // By default we send the interest to strategy node next0 = HICN_INTEREST_PCSLOOKUP_NEXT_STRATEGY; + + // Update stats stats.pkts_processed++; - if (PREDICT_FALSE ( - hicn_hashtb_fullhash (nameptr, namelen, &name_hash) != - HICN_ERROR_NONE)) - { - next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; - } - else + // Check if the interest is in the PCS already + ret = hicn_pcs_lookup_one (rt->pitcs, &hicn_get_buffer (b0)->name, + &pcs_entry); + + if (ret == HICN_ERROR_NONE) { - if (hicn_hashtb_lookup_node ( - rt->pitcs->pcs_table, nameptr, namelen, name_hash, - 0 /* is_data */, &node_id0, &dpo_ctx_id0, &vft_id0, - &is_cs0, &hash_entry_id, &bucket_id, - &bucket_is_overflown) == HICN_ERROR_NONE) - { - next0 = - HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITPIT + is_cs0; - } - stats.pkts_interest_count++; + // We found an entry in the PCS. Next stage for this packet is + // one of hitpit/cs nodes + next0 = HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITPIT + + hicn_pcs_entry_is_cs (pcs_entry); + + ret = hicn_store_internal_state ( + b0, hicn_pcs_entry_get_index (rt->pitcs, pcs_entry), + vnet_buffer (b0)->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (ret != HICN_ERROR_NONE)) + next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; } - hicn_store_internal_state (b0, name_hash, node_id0, dpo_ctx_id0, - vft_id0, hash_entry_id, bucket_id, - bucket_is_overflown); + stats.pkts_interest_count++; - /* Maybe trace */ + // Maybe trace if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -154,9 +143,8 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs); - u32 pit_cs_count = hicn_pit_get_cs_count (rt->pitcs); - u32 pcs_ntw_count = hicn_pcs_get_ntw_count (rt->pitcs); + u32 pit_int_count = hicn_pcs_get_pit_count (rt->pitcs); + u32 pit_cs_count = hicn_pcs_get_cs_count (rt->pitcs); vlib_node_increment_counter (vm, hicn_interest_pcslookup_node.index, HICNFWD_ERROR_PROCESSED, stats.pkts_processed); @@ -171,9 +159,6 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, update_node_counter (vm, hicn_interest_pcslookup_node.index, HICNFWD_ERROR_CS_COUNT, pit_cs_count); - update_node_counter (vm, hicn_interest_pcslookup_node.index, - HICNFWD_ERROR_CS_NTW_COUNT, pcs_ntw_count); - return (frame->n_vectors); } @@ -183,7 +168,7 @@ hicn_interest_pcslookup_format_trace (u8 *s, va_list *args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - hicn_interest_pcslookup_trace_t *t = + const hicn_interest_pcslookup_trace_t *t = va_arg (*args, hicn_interest_pcslookup_trace_t *); s = format (s, "INTEREST_PCSLOOKUP: pkt: %d, sw_if_index %d, next index %d", diff --git a/hicn-plugin/src/parser.h b/hicn-plugin/src/parser.h index 29405ebec..3c21a33f8 100644 --- a/hicn-plugin/src/parser.h +++ b/hicn-plugin/src/parser.h @@ -20,11 +20,85 @@ #include "hicn.h" #include "error.h" +#include "infra.h" /** * @file parser.h */ +#define PARSE(PACKET_TYPE) \ + do \ + { \ + if (pkt == NULL) \ + return HICN_ERROR_PARSER_PKT_INVAL; \ + \ + int ret = HICN_LIB_ERROR_NONE; \ + \ + hicn_header_t *pkt_hdr; \ + u8 *ip_pkt; \ + u8 ip_proto; \ + int isv6; \ + u8 next_proto_offset; \ + hicn_type_t type; \ + hicn_name_t *name; \ + u16 *port; \ + hicn_lifetime_t *lifetime; \ + \ + /* start parsing first fields to get the protocols */ \ + pkt_hdr = vlib_buffer_get_current (pkt); \ + isv6 = hicn_is_v6 (pkt_hdr); \ + \ + ip_pkt = vlib_buffer_get_current (pkt); \ + ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6; \ + \ + /* in the ipv6 header the next header field is at byte 6 in the ipv4*/ \ + /* header the protocol field is at byte 9*/ \ + next_proto_offset = 6 + (1 - isv6) * 3; \ + \ + /* get type info*/ \ + type.l4 = IPPROTO_NONE; \ + type.l3 = ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : \ + IPPROTO_NONE; \ + type.l2 = ip_pkt[next_proto_offset]; \ + type.l1 = ip_proto; \ + \ + /* cache hicn packet type in opaque2*/ \ + hicn_get_buffer (pkt)->type = type; \ + \ + /* get name and name length*/ \ + name = &hicn_get_buffer (pkt)->name; \ + ret = hicn_ops_vft[type.l1]->get_##PACKET_TYPE##_name ( \ + type, &pkt_hdr->protocol, name); \ + if (PREDICT_FALSE (ret)) \ + { \ + if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6) \ + { \ + return HICN_ERROR_PARSER_MAPME_PACKET; \ + } \ + return HICN_ERROR_PARSER_PKT_INVAL; \ + } \ + \ + /* get source port*/ \ + port = &hicn_get_buffer (pkt)->port; \ + hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, \ + port); \ + if (PREDICT_FALSE (ret)) \ + { \ + return HICN_ERROR_PARSER_PKT_INVAL; \ + } \ + \ + /* get lifetime*/ \ + lifetime = &hicn_get_buffer (pkt)->lifetime; \ + hicn_ops_vft[type.l1]->get_lifetime (type, &pkt_hdr->protocol, \ + lifetime); \ + \ + if (*lifetime > hicn_main.pit_lifetime_max_ms) \ + *lifetime = hicn_main.pit_lifetime_max_ms; \ + \ + return ret; \ + } \ + while (0) + /** * @brief Parse a interest packet * @@ -39,63 +113,7 @@ always_inline int hicn_interest_parse_pkt (vlib_buffer_t *pkt) { - if (pkt == NULL) - return HICN_ERROR_PARSER_PKT_INVAL; - - int ret = HICN_LIB_ERROR_NONE; - - hicn_header_t *pkt_hdr; - u8 *ip_pkt; - u8 ip_proto; - u8 next_proto_offset; - hicn_type_t type; - hicn_name_t *name; - u16 *port; - int isv6; - - // start parsing first fields to get the protocols - pkt_hdr = vlib_buffer_get_current (pkt); - isv6 = hicn_is_v6 (pkt_hdr); - - ip_pkt = vlib_buffer_get_current (pkt); - ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6; - - // in the ipv6 header the next header field is at byte 6 in the ipv4 - // header the protocol field is at byte 9 - next_proto_offset = 6 + (1 - isv6) * 3; - - // get type info - type.l4 = IPPROTO_NONE; - type.l3 = - ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE; - type.l2 = ip_pkt[next_proto_offset]; - type.l1 = ip_proto; - - // cache hicn packet type in opaque2 - hicn_get_buffer (pkt)->type = type; - - // get name and name length - name = &hicn_get_buffer (pkt)->name; - ret = - hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name); - if (PREDICT_FALSE (ret)) - { - if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6) - { - return HICN_ERROR_PARSER_MAPME_PACKET; - } - return HICN_ERROR_PARSER_PKT_INVAL; - } - - // get source port - port = &hicn_get_buffer (pkt)->port; - hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port); - if (PREDICT_FALSE (ret)) - { - return HICN_ERROR_PARSER_PKT_INVAL; - } - - return ret; + PARSE (interest); } /** @@ -112,65 +130,10 @@ hicn_interest_parse_pkt (vlib_buffer_t *pkt) always_inline int hicn_data_parse_pkt (vlib_buffer_t *pkt) { - if (pkt == NULL) - return HICN_ERROR_PARSER_PKT_INVAL; - - int ret = HICN_LIB_ERROR_NONE; - - hicn_header_t *pkt_hdr; - u8 *ip_pkt; - u8 ip_proto; - int isv6; - u8 next_proto_offset; - hicn_type_t type; - hicn_name_t *name; - u16 *port; - - // start parsing first fields to get the protocols - pkt_hdr = vlib_buffer_get_current (pkt); - isv6 = hicn_is_v6 (pkt_hdr); - - ip_pkt = vlib_buffer_get_current (pkt); - ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6; - - // in the ipv6 header the next header field is at byte 6 in the ipv4 - // header the protocol field is at byte 9 - next_proto_offset = 6 + (1 - isv6) * 3; - - // get type info - type.l4 = IPPROTO_NONE; - type.l3 = - ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE; - type.l2 = ip_pkt[next_proto_offset]; - type.l1 = ip_proto; - - // cache hicn packet type in opaque2 - hicn_get_buffer (pkt)->type = type; - - // get name and name length - name = &hicn_get_buffer (pkt)->name; - ret = hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name); - if (PREDICT_FALSE (ret)) - { - if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6) - { - return HICN_ERROR_PARSER_MAPME_PACKET; - } - return HICN_ERROR_PARSER_PKT_INVAL; - } - - // get source port - port = &hicn_get_buffer (pkt)->port; - hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port); - if (PREDICT_FALSE (ret)) - { - return HICN_ERROR_PARSER_PKT_INVAL; - } - - return ret; + PARSE (data); } -#endif /* // __HICN_PARSER_H__ */ +#endif /* __HICN_PARSER_H__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/hicn-plugin/src/pcs.c b/hicn-plugin/src/pcs.c index d6e4fd954..564a435a0 100644 --- a/hicn-plugin/src/pcs.c +++ b/hicn-plugin/src/pcs.c @@ -16,33 +16,39 @@ #include <stdlib.h> #include <vlib/vlib.h> -#include "hashtb.h" #include "pcs.h" #include "cache_policies/cs_lru.h" -int -hicn_pit_create (hicn_pit_cs_t *p, u32 num_elems) +void +hicn_pit_create (hicn_pit_cs_t *p, u32 max_pit_elt, u32 max_cs_elt) { - int ret = - hicn_hashtb_alloc (&p->pcs_table, num_elems, sizeof (hicn_pcs_entry_t)); - p->pcs_table->ht_flags |= HICN_HASHTB_FLAG_KEY_FMT_NAME; + // Allocate PCS hash table. KEY=Name, VALUE=pool_idx + clib_bihash_24_8_t *pcs_table = &p->pcs_table; + u32 n_elements = max_pit_elt / BIHASH_KVP_PER_PAGE; + clib_bihash_init_24_8 (pcs_table, "hicn_pcs_table", n_elements, 512 << 20); - p->pcs_pit_count = p->pcs_cs_count = 0; + // Allocate pool of PIT/CS entries + pool_alloc (p->pcs_entries_pool, max_pit_elt); - p->policy_state.max = - HICN_PARAM_CS_LRU_DEFAULT - - (HICN_PARAM_CS_LRU_DEFAULT * HICN_PARAM_CS_RESERVED_APP / 100); - p->policy_state.count = 0; - p->policy_state.head = p->policy_state.tail = 0; + // Init counters + p->max_pit_size = max_pit_elt; + p->pcs_pit_count = p->pcs_cs_count = 0; + p->policy_state = hicn_cs_lru_create (max_cs_elt); + p->pcs_cs_count = 0; + p->pcs_pcs_alloc = 0; + p->pcs_pcs_dealloc = 0; + p->pcs_pit_count = 0; +} - p->policy_vft.hicn_cs_insert = hicn_cs_lru.hicn_cs_insert; - p->policy_vft.hicn_cs_update = hicn_cs_lru.hicn_cs_update; - p->policy_vft.hicn_cs_dequeue = hicn_cs_lru.hicn_cs_dequeue; - p->policy_vft.hicn_cs_delete_get = hicn_cs_lru.hicn_cs_delete_get; - p->policy_vft.hicn_cs_trim = hicn_cs_lru.hicn_cs_trim; - p->policy_vft.hicn_cs_flush = hicn_cs_lru.hicn_cs_flush; +void +hicn_pit_destroy (hicn_pit_cs_t *p) +{ + // Deallocate PCS hash table. + clib_bihash_24_8_t *pcs_table = &p->pcs_table; + clib_bihash_free_24_8 (pcs_table); - return (ret); + // Deallocate pool of PIT/CS entries + pool_free (p->pcs_entries_pool); } /* diff --git a/hicn-plugin/src/pcs.h b/hicn-plugin/src/pcs.h index b98b72a53..fa5a68b27 100644 --- a/hicn-plugin/src/pcs.h +++ b/hicn-plugin/src/pcs.h @@ -16,25 +16,34 @@ #ifndef __HICN_PCS_H__ #define __HICN_PCS_H__ -#include "hashtb.h" -#include "face_db.h" #include "strategy_dpo_manager.h" #include "error.h" #include "cache_policies/cs_policy.h" #include "faces/face.h" +#include <vppinfra/bihash_24_8.h> + /** * @file pcs.h * * This file implement the PIT and CS which are collapsed in the same - * structure, thereore an entry is either a PIT entry of a CS entry. - * The implementation consist of a hash table where each entry of the - * hash table contains a PIT or CS entry, some counters to maintain the - * status of the PIT/CS and the reference to the eviction policy for - * the CS. The default eviction policy id FIFO. + * structure, therefore an entry is either a PIT entry of a CS entry. + * The implementation consists of a hash table where each entry of the + * hash table contains an index to a pool of PIT/CS entries. Each entry + * contains some counters to maintain the status of the PIT/CS and the + * reference to the eviction policy for the CS. + * The default eviction policy is LRU. */ -/* The PIT and CS are stored as a union */ +/* + * We need a definition of invalid index. ~0 is reasonable as we don't expect + * to reach that many element in the PIT. + */ +#define HICN_PCS_INVALID_INDEX ((u32) (~0)) + +/* + * The PIT and CS are stored as a union + */ #define HICN_PIT_NULL_TYPE 0 #define HICN_PIT_TYPE 1 #define HICN_CS_TYPE 2 @@ -49,740 +58,756 @@ #define HICN_INFRA_SLOW_TIMER_SECS 60 #define HICN_INFRA_SLOW_TIMER_MSECS (HICN_INFRA_SLOW_TIMER_SECS * SEC_MS) +#define HICN_CS_ENTRY_OPAQUE_SIZE 32 + +#define HICN_FACE_DB_INLINE_FACES 8 + +#define HICN_PIT_BITMAP_SIZE_U64 HICN_PARAM_FACES_MAX / 64 +#define HICN_PIT_N_HOP_BITMAP_SIZE HICN_PARAM_FACES_MAX + /* - * Note that changing this may change alignment within the PIT struct, so be - * careful. + * PCS entry. We expect this to fit in 3 cache lines, with a maximum of 8 + * output inline faces and a bitmap of 512 bits. If more faces are needed, a + * vector will be allocated, but it will endup out of the 3 cache lines. */ -typedef struct __attribute__ ((packed)) hicn_pcs_shared_s +typedef struct hicn_pcs_entry_s { + /* + * First cache line - shared data + */ + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - /* Installation/creation time (vpp float units, for now) */ + /* + * Installation/creation time (vpp float units, for now). + * 8 Bytes + */ f64 create_time; - /* Expiration time (vpp float units, for now) */ + /* + * Expiration time (vpp float units, for now) + * 8 Bytes + */ f64 expire_time; - /* Shared 'flags' octet */ - u8 entry_flags; - - /* Needed to align for the pit or cs portion */ - u8 padding; -} hicn_pcs_shared_t; - -#define HICN_PCS_ENTRY_CS_FLAG 0x01 + /* + * Name + * 24 bytes + */ + hicn_name_t name; -/* - * PIT entry, unioned with a CS entry below - */ -typedef struct __attribute__ ((packed)) hicn_pit_entry_s -{ + /* + * Cached hash of the name + * 8 bytes + */ + u64 name_hash; - /* Shared size 8 + 8 + 2 = 18B */ + /* + * Shared 'flags' octet + * 1 Byte + */ + u16 flags; /* - * Egress next hop (containes the egress face) This id refers to the - * position of the choosen face in the next_hops array of the dpo */ - /* 18B + 1B = 19B */ - u8 pe_txnh; + * Number of locks on the PCS entry + * 2 Bytes + */ + u16 locks; - /* Array of incoming ifaces */ - /* 24B + 32B (8B*4) =56B */ - hicn_face_db_t faces; + /* + * Second cache line - PIT or CS data + */ + CLIB_ALIGN_MARK (second_part, 64); -} hicn_pit_entry_t; + union + { + struct + { + /* + * Bitmap used to check if interests are retransmission + */ + u64 bitmap[HICN_PIT_BITMAP_SIZE_U64]; -#define HICN_CS_ENTRY_OPAQUE_SIZE HICN_HASH_NODE_APP_DATA_SIZE - 32 + CLIB_ALIGN_MARK (third_part, 64); -/* - * CS entry, unioned with a PIT entry below - */ -typedef struct __attribute__ ((packed)) hicn_cs_entry_s -{ - /* 18B + 2B = 20B */ - u16 align; + /* + * Total number of faces + */ + u32 n_faces; - /* Packet buffer, if held */ - /* 20B + 4B = 24B */ - u32 cs_pkt_buf; + /* + * Array of indexes of virtual faces + */ + hicn_face_id_t inline_faces[HICN_FACE_DB_INLINE_FACES]; - // /* Ingress face */ - // /* 24B + 4B = 28B */ - // hicn_face_id_t cs_rxface; + /* + * VPP vector of indexes of additional virtual faces, allocated iff + * needed + */ + hicn_face_id_t *faces; + } pit; + struct + { /* + * Packet buffer, if held + * 4 Bytes + */ + u32 cs_pkt_buf; - /* Linkage for LRU, in the form of hashtable node indexes */ - /* 24B + 8B = 32B */ - u32 cs_lru_prev; - u32 cs_lru_next; + /* + * Linkage for LRU, in the form of hashtable node indexes + * 8 Bytes + */ + u32 cs_lru_prev; + u32 cs_lru_next; + } cs; + } u; +} hicn_pcs_entry_t; - /* Reserved for implementing cache policy different than LRU */ - /* 32B + (64 - 32)B = 64B */ - u8 opaque[HICN_CS_ENTRY_OPAQUE_SIZE]; +STATIC_ASSERT (sizeof (hicn_pcs_entry_t) <= 3 * CLIB_CACHE_LINE_BYTES, + "hicn_pcs_entry_t does not fit in 3 cache lines."); + +STATIC_ASSERT (0 == offsetof (hicn_pcs_entry_t, cacheline0), + "Cacheline0 must be at the beginning of hicn_pcs_entry_t"); +STATIC_ASSERT (64 == offsetof (hicn_pcs_entry_t, second_part), + "second_part must be at byte 64 of hicn_pcs_entry_t"); +STATIC_ASSERT (64 == offsetof (hicn_pcs_entry_t, u.pit.bitmap), + "u.pit.bitmap must be at byte 64 of hicn_pcs_entry_t"); +STATIC_ASSERT (64 == offsetof (hicn_pcs_entry_t, u.pit.bitmap), + "cs_pkt_buf must be at byte 64 of hicn_pcs_entry_t"); +STATIC_ASSERT (128 == offsetof (hicn_pcs_entry_t, u.pit.third_part), + "third_part must be at byte 128 of hicn_pcs_entry_t"); +STATIC_ASSERT (128 == offsetof (hicn_pcs_entry_t, u.pit.n_faces), + "u.pit.n_faces must be at byte 128 of hicn_pcs_entry_t"); -} __attribute__ ((packed)) hicn_cs_entry_t; +#define HICN_PCS_ENTRY_CS_FLAG 0x01 /* - * Combined PIT/CS entry data structure, embedded in a hashtable entry after - * the common hashtable preamble struct. This MUST fit in the available - * (fixed) space in a hashtable node. + * Forward declarations */ -typedef struct hicn_pcs_entry_s -{ +always_inline void hicn_pcs_delete_internal (hicn_pit_cs_t *pitcs, + hicn_pcs_entry_t *pcs_entry); - hicn_pcs_shared_t shared; - - union - { - hicn_pit_entry_t pit; - hicn_cs_entry_t cs; - } u; -} hicn_pcs_entry_t; +always_inline void hicn_pcs_entry_remove_lock (hicn_pit_cs_t *pitcs, + hicn_pcs_entry_t *pcs_entry); /* - * Overall PIT/CS table, based on the common hashtable + * Overall PIT/CS table. */ typedef struct hicn_pit_cs_s { + // Hash table mapping name to hash entry index + clib_bihash_24_8_t pcs_table; + + // Total size of PCS + u32 max_pit_size; - hicn_hashtb_t *pcs_table; + // Pool of pcs entries + hicn_pcs_entry_t *pcs_entries_pool; /* Counters for PIT/CS sentries */ u32 pcs_pit_count; u32 pcs_cs_count; - u32 pcs_cs_dealloc; - u32 pcs_pit_dealloc; - - /* Total size of PCS */ - u32 pcs_size; + u32 pcs_pcs_alloc; + u32 pcs_pcs_dealloc; hicn_cs_policy_t policy_state; - hicn_cs_policy_vft_t policy_vft; - } hicn_pit_cs_t; -/* Functions declarations */ -int hicn_pit_create (hicn_pit_cs_t *p, u32 num_elems); - -always_inline void hicn_pit_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *pcs_entry, - hicn_hash_entry_t *hash_entry, - hicn_hash_node_t *node, - const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id); - -always_inline void hicn_pcs_cs_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *old_entry, - hicn_pcs_entry_t *entry, - hicn_hash_node_t *node); - -always_inline void hicn_pcs_cs_delete (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t **pcs_entry, - hicn_hash_node_t **node, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id); - -always_inline int -hicn_pcs_cs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *entry, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, u8 *bucket_is_overflow); - -always_inline int hicn_pcs_cs_insert_update ( - vlib_main_t *vm, hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, - hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry, u64 hashval, - u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, - u32 *bucket_id, u8 *bucket_is_overflow); +/************************************************************************ + **************************** Create / Destroy ************************** + ************************************************************************/ -always_inline int -hicn_pcs_pit_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, - hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry, - u64 hashval, u32 *node_id, index_t *dpo_ctx_id, - u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow); +void hicn_pit_create (hicn_pit_cs_t *p, u32 max_pit_elt, u32 max_cs_elt); +void hicn_pit_destroy (hicn_pit_cs_t *p); -always_inline void -hicn_pcs_pit_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **node, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id); - -always_inline int hicn_pcs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *entry, - hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hashval, - u32 *node_id, index_t *dpo_ctx_id, - u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, - u32 *bucket_id, u8 *bucket_is_overflow); - -always_inline void hicn_pcs_delete (hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **node, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id); +/************************************************************************ + **************************** Counters getters ************************** + ************************************************************************/ -always_inline void -hicn_pcs_remove_lock (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **node, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id); - -always_inline void hicn_cs_delete_trimmed (hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t **pcs_entryp, - hicn_hash_entry_t *hash_entry, - hicn_hash_node_t **node, - vlib_main_t *vm); - -/* Function implementation */ -/* Accessor for pit/cs data inside hash table node */ -static inline hicn_pcs_entry_t * -hicn_pit_get_data (hicn_hash_node_t *node) +always_inline u32 +hicn_pcs_get_pit_count (const hicn_pit_cs_t *pcs) { - return (hicn_pcs_entry_t *) (hicn_hashtb_node_data (node)); + return pcs->pcs_pit_count; } -/* Init pit/cs data block (usually inside hash table node) */ -static inline void -hicn_pit_init_data (hicn_pcs_entry_t *p) +always_inline u32 +hicn_pcs_get_cs_count (const hicn_pit_cs_t *pcs) { - p->shared.entry_flags = 0; - p->u.pit.faces.n_faces = 0; - p->u.pit.faces.is_overflow = 0; - hicn_face_bucket_t *face_bkt; - pool_get (hicn_face_bucket_pool, face_bkt); + return pcs->pcs_cs_count; +} - p->u.pit.faces.next_bucket = face_bkt - hicn_face_bucket_pool; +always_inline u32 +hicn_pcs_get_pcs_alloc (const hicn_pit_cs_t *pcs) +{ + return pcs->pcs_pcs_alloc; } -/* Init pit/cs data block (usually inside hash table node) */ -static inline void -hicn_cs_init_data (hicn_pcs_entry_t *p) +always_inline u32 +hicn_pcs_get_pcs_dealloc (const hicn_pit_cs_t *pcs) { - p->shared.entry_flags = 0; - p->u.pit.faces.n_faces = 0; - p->u.pit.faces.is_overflow = 0; + return pcs->pcs_pcs_dealloc; } -static inline f64 +always_inline f64 hicn_pcs_get_exp_time (f64 cur_time_sec, u64 lifetime_msec) { return (cur_time_sec + ((f64) lifetime_msec) / SEC_MS); } /* - * Configure CS LRU limit. Zero is accepted, means 'no limit', probably not a - * good choice. + * Create key from the name struct. */ -static inline void -hicn_pit_set_lru_max (hicn_pit_cs_t *p, u32 limit) +always_inline void +hicn_pcs_get_key_from_name (clib_bihash_kv_24_8_t *kv, const hicn_name_t *name) +{ + kv->key[0] = name->prefix.ip6.as_u64[0]; + kv->key[1] = name->prefix.ip6.as_u64[1]; + kv->key[2] = name->suffix; +} + +/************************************************************************ + **************************** LRU Helpers ******************************* + ************************************************************************/ + +always_inline hicn_cs_policy_t * +hicn_pcs_get_policy_state (hicn_pit_cs_t *pcs) { - p->policy_state.max = limit; + return &pcs->policy_state; } /* - * Accessor for PIT interest counter. + * Update the CS LRU, moving this item to the head */ -static inline u32 -hicn_pit_get_int_count (const hicn_pit_cs_t *pitcs) +always_inline void +hicn_pcs_cs_update_lru (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry) { - return (pitcs->pcs_pit_count); + hicn_cs_policy_t *policy_state = hicn_pcs_get_policy_state (pitcs); + hicn_cs_policy_update (policy_state, pitcs, entry); } /* - * Accessor for PIT cs entries counter. + * Update the CS LRU, inserting a new item and checking if we need to evict */ -static inline u32 -hicn_pit_get_cs_count (const hicn_pit_cs_t *pitcs) +always_inline void +hicn_pcs_cs_insert_lru (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry) { - return (pitcs->pcs_cs_count); + hicn_cs_policy_t *policy_state = hicn_pcs_get_policy_state (pitcs); + hicn_cs_policy_insert (policy_state, pitcs, entry); + pitcs->pcs_cs_count++; + + // If we reached the MAX size of the CS, let's evict one + if (policy_state->count > policy_state->max) + { + // We reached the mac number of CS entry. We need to trim one. + hicn_pcs_entry_t *pcs_entry; + hicn_cs_policy_delete_get (policy_state, pitcs, &pcs_entry); + + // Delete evicted entry from hash table + hicn_pcs_entry_remove_lock (pitcs, pcs_entry); + } } -static inline u32 -hicn_pcs_get_ntw_count (const hicn_pit_cs_t *pitcs) +/* + * Dequeue an entry from the CS LRU + */ +always_inline void +hicn_pcs_cs_dequeue_lru (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry) { - return (pitcs->policy_state.count); + // Dequeue the CS entry + hicn_cs_policy_t *policy_state = hicn_pcs_get_policy_state (pitcs); + hicn_cs_policy_dequeue (policy_state, pitcs, entry); } -static inline u32 -hicn_pit_get_htb_bucket_count (const hicn_pit_cs_t *pitcs) +/************************************************************************ + **************************** PCS Entry APIs **************************** + ************************************************************************/ + +/* + * Create new PCS entry + */ +always_inline hicn_pcs_entry_t * +_hicn_pcs_entry_get (hicn_pit_cs_t *pitcs) { - return (pitcs->pcs_table->ht_overflow_buckets_used); + hicn_pcs_entry_t *e; + pool_get (pitcs->pcs_entries_pool, e); + pitcs->pcs_pcs_alloc++; + + return e; } -static inline int -hicn_cs_enabled (hicn_pit_cs_t *pit) +/* + * Init pit/cs data block + */ +always_inline void +hicn_pcs_entry_init_data (hicn_pcs_entry_t *p, f64 tnow) { - switch (HICN_FEATURE_CS) - { - case 0: - default: - return (0); - case 1: - return (pit->policy_state.max > 0); - } + p->flags = 0; + p->u.pit.n_faces = 0; + p->locks = 1; + p->create_time = tnow; } /* - * Delete a PIT/CS entry from the hashtable, freeing the hash node struct. - * The caller's pointers are zeroed! If cs_trim is true, entry has already - * been removed from lru list The main purpose of this wrapper is helping - * maintain the per-PIT stats. + * Free PCS entry */ always_inline void -hicn_pcs_delete_internal (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_entry_t *hash_entry, - hicn_hash_node_t **node, vlib_main_t *vm, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id) +hicn_pcs_entry_put (hicn_pit_cs_t *pitcs, const hicn_pcs_entry_t *entry) { - hicn_pcs_entry_t *pcs = *pcs_entryp; - - ASSERT (pcs == hicn_hashtb_node_data (*node)); + pitcs->pcs_pcs_dealloc++; + pool_put (pitcs->pcs_entries_pool, entry); +} - if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY) - { - pitcs->pcs_cs_dealloc++; - /* Free any associated packet buffer */ - vlib_buffer_free_one (vm, pcs->u.cs.cs_pkt_buf); - pcs->u.cs.cs_pkt_buf = ~0; - ASSERT ((pcs->u.cs.cs_lru_prev == 0) && - (pcs->u.cs.cs_lru_prev == pcs->u.cs.cs_lru_next)); - } - else - { - pitcs->pcs_pit_dealloc++; +/* + * Get index from the entry. + */ +always_inline u32 +hicn_pcs_entry_get_index (const hicn_pit_cs_t *pitcs, + const hicn_pcs_entry_t *entry) +{ + ASSERT (!pool_is_free (pitcs->pcs_entries_pool, entry)); + return (u32) (entry - pitcs->pcs_entries_pool); +} - /* Flush faces */ - hicn_faces_flush (&(pcs->u.pit.faces)); - } +/* + * Get index from the entry. + */ +always_inline hicn_pcs_entry_t * +hicn_pcs_entry_get_entry_from_index (const hicn_pit_cs_t *pitcs, u32 index) +{ + ASSERT (!pool_is_free_index (pitcs->pcs_entries_pool, index)); + return pool_elt_at_index (pitcs->pcs_entries_pool, index); +} - hicn_hashtb_delete (pitcs->pcs_table, node, hash_entry->he_msb64); - *pcs_entryp = NULL; +/* + * Check if pcs entry is a content store entry + */ +always_inline int +hicn_pcs_entry_is_cs (const hicn_pcs_entry_t *entry) +{ + ASSERT (entry); + return (entry->flags & HICN_PCS_ENTRY_CS_FLAG); } /* - * Convert a PIT entry into a CS entry (assumes that the entry is already in - * the hashtable.) This is primarily here to maintain the internal counters. + * Add lock to PIT entry */ always_inline void -hicn_pit_to_cs (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *pcs_entry, hicn_hash_entry_t *hash_entry, - hicn_hash_node_t *node, const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id) +hicn_pcs_entry_add_lock (hicn_pcs_entry_t *pcs_entry) { + pcs_entry->locks++; +} - /* - * Different from the insert node. In here we don't need to add a new - * hash entry. - */ - pitcs->pcs_pit_count--; - /* Flush faces */ - hicn_faces_flush (&(pcs_entry->u.pit.faces)); +/* + * Get/Set expire time from the entry + */ +always_inline f64 +hicn_pcs_entry_get_expire_time (hicn_pcs_entry_t *pcs_entry) +{ + return pcs_entry->expire_time; +} - hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY; - node->hn_flags |= HICN_HASH_NODE_CS_FLAGS; - pcs_entry->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG; +always_inline void +hicn_pcs_entry_set_expire_time (hicn_pcs_entry_t *pcs_entry, f64 expire_time) +{ + pcs_entry->expire_time = expire_time; +} - /* Update the CS according to the policy */ - hicn_cs_policy_t *policy_state; - hicn_cs_policy_vft_t *policy_vft; +/* + * Get/Set create time from the entry + */ +always_inline f64 +hicn_pcs_entry_get_create_time (hicn_pcs_entry_t *pcs_entry) +{ + return pcs_entry->create_time; +} - policy_state = &pitcs->policy_state; - policy_vft = &pitcs->policy_vft; +always_inline void +hicn_pcs_entry_set_create_time (hicn_pcs_entry_t *pcs_entry, f64 create_time) +{ + pcs_entry->create_time = create_time; +} - policy_vft->hicn_cs_insert (pitcs, node, pcs_entry, policy_state); - pitcs->pcs_cs_count++; +/* + * Remove a lock in the entry and delete it if there are no pending lock and + * the entry is marked as to be deleted + */ +always_inline void +hicn_pcs_entry_remove_lock (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *pcs_entry) +{ + // Make sure we are removing a lock on a valid entry + ASSERT (pcs_entry->locks > 0); - if (policy_state->count > policy_state->max) + if (--pcs_entry->locks == 0) { - hicn_hash_node_t *node; - hicn_pcs_entry_t *pcs_entry; - hicn_hash_entry_t *hash_entry; - policy_vft->hicn_cs_delete_get (pitcs, policy_state, &node, &pcs_entry, - &hash_entry); - - /* - * We don't have to decrease the lock (therefore we cannot - * use hicn_pcs_cs_delete function) - */ - policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state); - - hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm); - - /* Update the global CS counter */ - pitcs->pcs_cs_count--; + hicn_pcs_delete_internal (pitcs, pcs_entry); } } -/* Functions specific for PIT or CS */ +/************************************************************************ + **************************** CS Entry APIs ***************************** + ************************************************************************/ -always_inline void -hicn_pcs_cs_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *old_entry, hicn_pcs_entry_t *entry, - hicn_hash_node_t *node) +/* + * Create new CS entry + */ +always_inline hicn_pcs_entry_t * +hicn_pcs_entry_cs_get (hicn_pit_cs_t *pitcs, f64 tnow, u32 buffer_index) { - hicn_cs_policy_t *policy_state; - hicn_cs_policy_vft_t *policy_vft; + hicn_pcs_entry_t *ret = _hicn_pcs_entry_get (pitcs); + hicn_pcs_entry_init_data (ret, tnow); + ret->flags = HICN_PCS_ENTRY_CS_FLAG; + ret->u.cs.cs_lru_next = HICN_CS_POLICY_END_OF_CHAIN; + ret->u.cs.cs_lru_prev = HICN_CS_POLICY_END_OF_CHAIN; - policy_state = &pitcs->policy_state; - policy_vft = &pitcs->policy_vft; + return ret; +} - /* Update the CS LRU, moving this item to the head */ - policy_vft->hicn_cs_update (pitcs, node, old_entry, policy_state); +always_inline u32 +hicn_pcs_entry_cs_get_buffer (hicn_pcs_entry_t *pcs_entry) +{ + return pcs_entry->u.cs.cs_pkt_buf; } always_inline void -hicn_pcs_cs_delete (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t **pcs_entryp, hicn_hash_node_t **nodep, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id) +hicn_pcs_entry_cs_set_buffer (hicn_pcs_entry_t *pcs_entry, u32 buffer_index) { - if (!(hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED)) - { - hicn_cs_policy_t *policy_state; - hicn_cs_policy_vft_t *policy_vft; + pcs_entry->u.cs.cs_pkt_buf = buffer_index; +} - policy_state = &pitcs->policy_state; - policy_vft = &pitcs->policy_vft; +always_inline u32 +hicn_pcs_entry_cs_get_next (hicn_pcs_entry_t *pcs_entry) +{ + return pcs_entry->u.cs.cs_lru_next; +} - policy_vft->hicn_cs_dequeue (pitcs, (*nodep), (*pcs_entryp), - policy_state); +always_inline void +hicn_pcs_entry_cs_set_next (hicn_pcs_entry_t *pcs_entry, u32 next) +{ + pcs_entry->u.cs.cs_lru_next = next; +} - /* Update the global CS counter */ - pitcs->pcs_cs_count--; - } +always_inline u32 +hicn_pcs_entry_cs_get_prev (hicn_pcs_entry_t *pcs_entry) +{ + return pcs_entry->u.cs.cs_lru_prev; +} - /* A data could have been inserted in the CS through a push. In this case - * locks == 0 */ - hash_entry->locks--; - if (hash_entry->locks == 0) - { - hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, nodep, vm, - dpo_vft, hicn_dpo_id); - } - else - { - hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED; - } +always_inline void +hicn_pcs_entry_cs_set_prev (hicn_pcs_entry_t *pcs_entry, u32 prev) +{ + pcs_entry->u.cs.cs_lru_prev = prev; } -always_inline int -hicn_pcs_cs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *entry, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, - u8 *hash_entry_id, u32 *bucket_id, u8 *bucket_is_overflow) +/* Init pit/cs data block (usually inside hash table node) */ +always_inline void +hicn_pcs_entry_cs_free_data (hicn_pcs_entry_t *p) { - ASSERT (entry == hicn_hashtb_node_data (node)); + CLIB_UNUSED (u32 bi) = hicn_pcs_entry_cs_get_buffer (p); - int ret = hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval, - node_id, dpo_ctx_id, vft_id, is_cs, - hash_entry_id, bucket_id, bucket_is_overflow); +#ifndef HICN_PCS_TESTING + // Release buffer + vlib_buffer_free_one (vlib_get_main (), bi); +#endif - if (PREDICT_TRUE (ret == HICN_ERROR_NONE)) - { - /* Mark the entry as a CS entry */ - node->hn_flags |= HICN_HASH_NODE_CS_FLAGS; - entry->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG; - (*hash_entry)->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY; - - hicn_cs_policy_t *policy_state; - hicn_cs_policy_vft_t *policy_vft; - - policy_state = &pitcs->policy_state; - policy_vft = &pitcs->policy_vft; - - policy_vft->hicn_cs_insert (pitcs, node, entry, policy_state); - pitcs->pcs_cs_count++; - - if (policy_state->count > policy_state->max) - { - hicn_hash_node_t *node; - hicn_pcs_entry_t *pcs_entry; - hicn_hash_entry_t *hash_entry; - policy_vft->hicn_cs_delete_get (pitcs, policy_state, &node, - &pcs_entry, &hash_entry); - - /* - * We don't have to decrease the lock (therefore we cannot - * use hicn_pcs_cs_delete function) - */ - policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state); - - hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm); - - /* Update the global CS counter */ - pitcs->pcs_cs_count--; - } - } - return ret; + // Reset the vlib_buffer index + hicn_pcs_entry_cs_set_buffer (p, ~0); } +/************************************************************************ + **************************** PIT Entry APIs **************************** + ************************************************************************/ + /* - * Insert CS entry into the hashtable The main purpose of this wrapper is - * helping maintain the per-PIT stats. + * Init pit/cs data block */ -always_inline int -hicn_pcs_cs_insert_update (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *entry, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hashval, - u32 *node_id, index_t *dpo_ctx_id, u8 *vft_id, - u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow) +always_inline hicn_pcs_entry_t * +hicn_pcs_entry_pit_get (hicn_pit_cs_t *pitcs, f64 tnow, + hicn_lifetime_t lifetime) { - int ret; - - ASSERT (entry == hicn_hashtb_node_data (node)); - - ret = hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval, - node_id, dpo_ctx_id, vft_id, is_cs, hash_entry_id, - bucket_id, bucket_is_overflow); - - /* A content already exists in CS with the same name */ - if (ret == HICN_ERROR_HASHTB_EXIST && *is_cs) - { - /* Update the entry */ - hicn_hash_node_t *existing_node = - hicn_hashtb_node_from_idx (pitcs->pcs_table, *node_id); - hicn_pcs_entry_t *pitp = hicn_pit_get_data (existing_node); - - /* Free associated packet buffer and update counter */ - pitcs->pcs_cs_dealloc++; - vlib_buffer_free_one (vm, pitp->u.cs.cs_pkt_buf); + hicn_pcs_entry_t *ret = _hicn_pcs_entry_get (pitcs); + hicn_pcs_entry_init_data (ret, tnow); + clib_memset_u64 (ret->u.pit.bitmap, 0, HICN_PIT_BITMAP_SIZE_U64); + ret->u.pit.n_faces = 0; + ret->expire_time = hicn_pcs_get_exp_time (tnow, lifetime); - pitp->shared.create_time = entry->shared.create_time; - pitp->shared.expire_time = entry->shared.expire_time; - pitp->u.cs.cs_pkt_buf = entry->u.cs.cs_pkt_buf; + return ret; +} - hicn_pcs_cs_update (vm, pitcs, pitp, entry, existing_node); - } +/* + * Free pit/cs data block + */ +always_inline void +hicn_pcs_entry_pit_free_data (hicn_pcs_entry_t *p) +{ + // Nothing to do for the moment +} - return (ret); +always_inline u32 +hicn_pcs_entry_pit_get_n_faces (hicn_pcs_entry_t *p) +{ + return p->u.pit.n_faces; } /* - * Insert PIT entry into the hashtable The main purpose of this wrapper is - * helping maintain the per-PIT stats. + * Get face id at index index */ -always_inline int -hicn_pcs_pit_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, - hicn_hash_node_t *node, hicn_hash_entry_t **hash_entry, - u64 hashval, u32 *node_id, index_t *dpo_ctx_id, - u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, u32 *bucket_id, - u8 *bucket_is_overflow) +always_inline hicn_face_id_t +hicn_pcs_entry_pit_get_dpo_face (const hicn_pcs_entry_t *pit_entry, u32 index) { - ASSERT (entry == hicn_hashtb_node_data (node)); - - int ret = hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval, - node_id, dpo_ctx_id, vft_id, is_cs, - hash_entry_id, bucket_id, bucket_is_overflow); + // Make sure the entry is PIT + ASSERT (!hicn_pcs_entry_is_cs (pit_entry)); - if (PREDICT_TRUE (ret == HICN_ERROR_NONE)) - pitcs->pcs_pit_count++; + // Make sure the index is valid + ASSERT (index < pit_entry->u.pit.n_faces); - return ret; + if (index < HICN_FACE_DB_INLINE_FACES) + return pit_entry->u.pit.inline_faces[index]; + else + return pit_entry->u.pit.faces[index - HICN_FACE_DB_INLINE_FACES]; } always_inline void -hicn_pcs_pit_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **node, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id) +hicn_pcs_entry_pit_add_face (hicn_pcs_entry_t *pit_entry, + hicn_face_id_t face_id) { - hash_entry->locks--; - if (hash_entry->locks == 0) + ASSERT (face_id < HICN_PARAM_FACES_MAX); + + if (pit_entry->u.pit.n_faces < HICN_FACE_DB_INLINE_FACES) { - pitcs->pcs_pit_count--; - hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm, - dpo_vft, hicn_dpo_id); + pit_entry->u.pit.inline_faces[pit_entry->u.pit.n_faces] = face_id; } else { - hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED; + vec_validate_aligned (pit_entry->u.pit.faces, + pit_entry->u.pit.n_faces - + HICN_FACE_DB_INLINE_FACES, + CLIB_CACHE_LINE_BYTES); + pit_entry->u.pit + .faces[pit_entry->u.pit.n_faces - HICN_FACE_DB_INLINE_FACES] = face_id; } -} -/* Generic functions for PIT/CS */ + pit_entry->u.pit.n_faces++; + + clib_bitmap_set_no_check (pit_entry->u.pit.bitmap, face_id, 1); +} /* - * Insert PIT/CS entry into the hashtable The main purpose of this wrapper is - * helping maintain the per-PIT stats. + * Search face in db + */ +always_inline u8 +hicn_pcs_entry_pit_search (const hicn_pcs_entry_t *pit_entry, + hicn_face_id_t face_id) +{ + ASSERT (face_id < HICN_PARAM_FACES_MAX); + return clib_bitmap_get_no_check ((uword *) pit_entry->u.pit.bitmap, face_id); +} + +/************************************************************************ + **************************** Lookup API ******************************** + ************************************************************************/ + +/** + * @brief Perform one lookup in the PIT/CS table using the provided name. + * + * @param pitcs the PIT/CS table + * @param name the name to lookup + * @param pcs_entry [RETURN] if the entry exists, the entry is returned + * @return HICN_ERROR_NONE if the entry is found, HICN_ERROR_PCS_NOT_FOUND + * otherwise */ always_inline int -hicn_pcs_insert (vlib_main_t *vm, hicn_pit_cs_t *pitcs, - hicn_pcs_entry_t *entry, hicn_hash_node_t *node, - hicn_hash_entry_t **hash_entry, u64 hashval, u32 *node_id, - index_t *dpo_ctx_id, u8 *vft_id, u8 *is_cs, u8 *hash_entry_id, - u32 *bucket_id, u8 *bucket_is_overflow) +hicn_pcs_lookup_one (hicn_pit_cs_t *pitcs, const hicn_name_t *name, + hicn_pcs_entry_t **pcs_entry) { int ret; - if ((*hash_entry)->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY) + // Construct the lookup key + clib_bihash_kv_24_8_t kv; + hicn_pcs_get_key_from_name (&kv, name); + + // Do a search in the has table + ret = clib_bihash_search_inline_24_8 (&pitcs->pcs_table, &kv); + + if (PREDICT_FALSE (ret != 0)) { - ret = hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval, - node_id, dpo_ctx_id, vft_id, is_cs, - hash_entry_id, bucket_id, bucket_is_overflow); + *pcs_entry = NULL; + return HICN_ERROR_PCS_NOT_FOUND; } - else + + // Retrieve entry from pool + *pcs_entry = hicn_pcs_entry_get_entry_from_index (pitcs, kv.value); + + // If entry found and it is a CS entry, let's update the LRU + if (hicn_pcs_entry_is_cs (*pcs_entry)) { - ret = hicn_pcs_pit_insert (pitcs, entry, node, hash_entry, hashval, - node_id, dpo_ctx_id, vft_id, is_cs, - hash_entry_id, bucket_id, bucket_is_overflow); + hicn_pcs_cs_update_lru (pitcs, *pcs_entry); } - return (ret); + // If the entry is found, return it + return HICN_ERROR_NONE; } +/************************************************************************ + **************************** PCS Delete API **************************** + ************************************************************************/ + /* - * Delete entry if there are no pending lock on the entry, otherwise mark it - * as to delete. + * Delete a PIT/CS entry from the hashtable. + * The caller's pointers are zeroed! If cs_trim is true, entry has already + * been removed from lru list The main purpose of this wrapper is helping + * maintain the per-PIT stats. */ always_inline void -hicn_pcs_delete (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **nodep, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, const hicn_dpo_vft_t *dpo_vft, - dpo_id_t *hicn_dpo_id) +hicn_pcs_delete_internal (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *pcs_entry) { - /* - * If the entry has already been marked as deleted, it has already - * been dequeue - */ - if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY) - { - hicn_pcs_cs_delete (vm, pitcs, pcs_entryp, nodep, hash_entry, dpo_vft, - hicn_dpo_id); - } - else + if (pcs_entry->flags & HICN_PCS_ENTRY_CS_FLAG) { - hicn_pcs_pit_delete (pitcs, pcs_entryp, nodep, vm, hash_entry, dpo_vft, - hicn_dpo_id); - } -} + // Remove entry from LRU list + hicn_pcs_cs_dequeue_lru (pitcs, pcs_entry); -/* - * Remove a lock in the entry and delete it if there are no pending lock and - * the entry is marked as to be deleted - */ -always_inline void -hicn_pcs_remove_lock (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_node_t **node, vlib_main_t *vm, - hicn_hash_entry_t *hash_entry, - const hicn_dpo_vft_t *dpo_vft, dpo_id_t *hicn_dpo_id) -{ - hash_entry->locks--; - if (hash_entry->locks == 0 && - (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED)) - { - hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm, - dpo_vft, hicn_dpo_id); - } -} + // Update counters + pitcs->pcs_cs_count--; -/* - * Delete entry which has already been bulk-removed from lru list - */ -always_inline void -hicn_cs_delete_trimmed (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t **pcs_entryp, - hicn_hash_entry_t *hash_entry, hicn_hash_node_t **node, - vlib_main_t *vm) -{ + // Free data + hicn_pcs_entry_cs_free_data (pcs_entry); - if (hash_entry->locks == 0) - { - const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (hash_entry->vft_id); - dpo_id_t hicn_dpo_id = { .dpoi_type = dpo_vft->hicn_dpo_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = hash_entry->dpo_ctx_id }; - - hicn_pcs_delete_internal (pitcs, pcs_entryp, hash_entry, node, vm, - dpo_vft, &hicn_dpo_id); + // Sanity check + ASSERT ((pcs_entry->u.cs.cs_lru_prev == HICN_CS_POLICY_END_OF_CHAIN) && + (pcs_entry->u.cs.cs_lru_prev == pcs_entry->u.cs.cs_lru_next)); } else { - hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED; + // Update counters + pitcs->pcs_pit_count--; + // Flush faces + // hicn_faces_flush (&(pcs_entry->u.pit.faces)); } -} -/* - * wrappable counter math (assumed uint16_t): return sum of addends - */ -always_inline u16 -hicn_infra_seq16_sum (u16 addend1, u16 addend2) -{ - return (addend1 + addend2); + // Delete entry from hash table + clib_bihash_kv_24_8_t kv; + hicn_pcs_get_key_from_name (&kv, &pcs_entry->name); + clib_bihash_add_del_24_8 (&pitcs->pcs_table, &kv, 0 /* is_add */); + + // Free pool entry + hicn_pcs_entry_put (pitcs, pcs_entry); } -/* - * for comparing wrapping numbers, return lt,eq,gt 0 for a lt,eq,gt b - */ +/************************************************************************ + **************************** PCS Insert API **************************** + ************************************************************************/ + always_inline int -hicn_infra_seq16_cmp (u16 a, u16 b) +hicn_pcs_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, + const hicn_name_t *name) { - return ((int16_t) (a - b)); + clib_bihash_kv_24_8_t kv; + u32 index = hicn_pcs_entry_get_index (pitcs, entry); + + // Construct KV pair and try to add it to hash table + hicn_pcs_get_key_from_name (&kv, name); + kv.value = index; + + // Get name hash + entry->name_hash = clib_bihash_hash_24_8 (&kv); + entry->name = *name; + + return clib_bihash_add_del_24_8 (&pitcs->pcs_table, &kv, + 2 /* add_but_not_replace */); } -/* - * below are wrappers for lt, le, gt, ge seq16 comparators +/** + * @brief Insert a CS entry in the PIT/CS table. This function DOES NOT check + * if the KV is already present in the table. It expects the caller to check + * this before trying to insert the new entry. + * + * @param pitcs the PIT/CS table + * @param entry the entry to insert + * @param name the name to use to compute the key + * @return always_inline */ always_inline int -hicn_infra_seq16_lt (u16 a, u16 b) +hicn_pcs_cs_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, + const hicn_name_t *name) { - return (hicn_infra_seq16_cmp (a, b) < 0); -} + // Make sure this is a CS entry + ASSERT (hicn_pcs_entry_is_cs (entry)); -always_inline int -hicn_infra_seq16_le (u16 a, u16 b) -{ - return (hicn_infra_seq16_cmp (a, b) <= 0); -} + int ret = hicn_pcs_insert (pitcs, entry, name); -always_inline int -hicn_infra_seq16_gt (u16 a, u16 b) -{ - return (hicn_infra_seq16_cmp (a, b) > 0); + // Make sure insertion happened + ASSERT (ret == 0); + + // New entry, update LRU + hicn_pcs_cs_insert_lru (pitcs, entry); + + return HICN_ERROR_NONE; } +/** + * @brief Insert a PIT entry in the PIT/CS table. This function DOES NOT check + * if the KV is already present in the table. It is expected the caller checks + * this before trying to insert the new entry. + * + * @param pitcs + * @param name + * @param pcs_entry_index + * @param dpo_ctx_id + * @param vft_id + * @param is_cs + * @return always_inline + */ always_inline int -hicn_infra_seq16_ge (u16 a, u16 b) +hicn_pcs_pit_insert (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *entry, + const hicn_name_t *name) { - return (hicn_infra_seq16_cmp (a, b) >= 0); -} + // Insert entry into hash table + int ret = hicn_pcs_insert (pitcs, entry, name); -extern u16 hicn_infra_fast_timer; /* Counts at 1 second intervals */ -extern u16 hicn_infra_slow_timer; /* Counts at 1 minute intervals */ + // Make sure insertion happened + ASSERT (ret == 0); -/* - * Utilities to convert lifetime into expiry time based on compressed clock, - * suitable for the opportunistic hashtable entry timeout processing. - */ + // Increment the number of PIT entries if insertion happened + pitcs->pcs_pit_count++; -// convert time in msec to time in clicks -always_inline u16 -hicn_infra_ms2clicks (u64 time_ms, u64 ms_per_click) -{ - f64 time_clicks = - ((f64) (time_ms + ms_per_click - 1)) / ((f64) ms_per_click); - return ((u16) time_clicks); + return HICN_ERROR_NONE; } -always_inline u16 -hicn_infra_get_fast_exp_time (u64 lifetime_ms) -{ - u16 lifetime_clicks = - hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_FAST_TIMER_MSECS); - return (hicn_infra_seq16_sum (hicn_infra_fast_timer, lifetime_clicks)); -} +/************************************************************************ + ************************** PCS Conversion API ************************** + ************************************************************************/ -always_inline u16 -hicn_infra_get_slow_exp_time (u64 lifetime_ms) +/** + * @brief Convert a PIT entry to a CS entry. + * + * @param vm + * @param pitcs + * @param pcs_entry + * @param hash_entry + * @param node + * @param dpo_vft + * @param hicn_dpo_id + * @return always_inline + */ +always_inline void +hicn_pit_to_cs (hicn_pit_cs_t *pitcs, hicn_pcs_entry_t *pit_entry, + u32 buffer_index) { - u16 lifetime_clicks = - hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_SLOW_TIMER_MSECS); - return (hicn_infra_seq16_sum (hicn_infra_slow_timer, lifetime_clicks)); + // Different from the insert node. In here we don't need to add a new + // hash entry. + pitcs->pcs_pit_count--; + + // Flush faces + // hicn_faces_flush (&(pit_entry->u.pit.faces)); + + // Set the flags + pit_entry->flags = HICN_PCS_ENTRY_CS_FLAG; + + // Set the buffer index + pit_entry->u.cs.cs_pkt_buf = buffer_index; + + hicn_pcs_cs_insert_lru (pitcs, pit_entry); } -#endif /* // __HICN_PCS_H__ */ +#endif /* __HICN_PCS_H__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/hicn-plugin/src/pg_node.c b/hicn-plugin/src/pg_node.c index 3672a6b72..1a99d3fa2 100644 --- a/hicn-plugin/src/pg_node.c +++ b/hicn-plugin/src/pg_node.c @@ -124,6 +124,12 @@ hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u16 msg_type0 = 0, msg_type1 = 0; hicnpg_main_t *hpgm = &hicnpg_main; int iface = 0; + u32 next0 = HICNPG_INTEREST_NEXT_DROP; + u32 next1 = HICNPG_INTEREST_NEXT_DROP; + u32 sw_if_index0 = ~0, sw_if_index1 = ~0; + u8 isv6_0; + u8 isv6_1; + u32 n_left_to_next; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -131,18 +137,10 @@ hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0) { - u32 n_left_to_next; - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from >= 4 && n_left_to_next >= 2) { - u32 next0 = HICNPG_INTEREST_NEXT_DROP; - u32 next1 = HICNPG_INTEREST_NEXT_DROP; - u32 sw_if_index0 = ~0, sw_if_index1 = ~0; - u8 isv6_0; - u8 isv6_1; - /* Prefetch next iteration. */ { vlib_buffer_t *p2, *p3; @@ -278,10 +276,6 @@ hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { - u32 next0 = HICNPG_INTEREST_NEXT_DROP; - u32 sw_if_index0; - u8 isv6_0; - /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; @@ -576,6 +570,9 @@ hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0, *b1; u8 pkt_type0 = 0, pkt_type1 = 0; u16 msg_type0 = 1, msg_type1 = 1; + u32 next0 = HICNPG_DATA_NEXT_DROP; + u32 next1 = HICNPG_DATA_NEXT_DROP; + u32 sw_if_index0, sw_if_index1; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -588,10 +585,6 @@ hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from >= 4 && n_left_to_next >= 2) { - u32 next0 = HICNPG_DATA_NEXT_DROP; - u32 next1 = HICNPG_DATA_NEXT_DROP; - u32 sw_if_index0, sw_if_index1; - /* Prefetch next iteration. */ { vlib_buffer_t *p2, *p3; @@ -659,9 +652,6 @@ hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { - u32 next0 = HICNPG_DATA_NEXT_DROP; - u32 sw_if_index0; - /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; @@ -815,6 +805,12 @@ hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0, *b1; u8 pkt_type0 = 0, pkt_type1 = 0; u16 msg_type0 = 0, msg_type1 = 0; + u32 next0 = HICNPG_SERVER_NEXT_DROP; + u32 next1 = HICNPG_SERVER_NEXT_DROP; + u32 sw_if_index0, sw_if_index1; + u32 hpgi0, hpgi1; + hicnpg_server_t *hpg0, *hpg1; + u32 n_left_to_next; from = vlib_frame_vector_args (frame); @@ -823,18 +819,10 @@ hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0) { - u32 n_left_to_next; - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from >= 4 && n_left_to_next >= 2) { - u32 next0 = HICNPG_SERVER_NEXT_DROP; - u32 next1 = HICNPG_SERVER_NEXT_DROP; - u32 sw_if_index0, sw_if_index1; - u32 hpgi0, hpgi1; - hicnpg_server_t *hpg0, *hpg1; - /* Prefetch next iteration. */ { vlib_buffer_t *p2, *p3; @@ -940,11 +928,6 @@ hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { - u32 next0 = HICNPG_SERVER_NEXT_DROP; - u32 sw_if_index0 = ~0; - u32 hpgi0; - hicnpg_server_t *hpg0; - /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; @@ -1126,7 +1109,3 @@ VLIB_REGISTER_NODE(hicn_pg_server4_node) = [HICNPG_SERVER_NEXT_DROP] = "error-drop", }, }; - -/* - * End of packet-generator server node - */
\ No newline at end of file diff --git a/hicn-plugin/src/state.h b/hicn-plugin/src/state.h index 39953722d..e80e81e29 100644 --- a/hicn-plugin/src/state.h +++ b/hicn-plugin/src/state.h @@ -21,7 +21,6 @@ #include "hicn.h" #include "pcs.h" -#include "hashtb.h" #include "strategy.h" #include "strategy_dpo_ctx.h" #include "strategy_dpo_manager.h" @@ -51,26 +50,14 @@ * @param hash_entry entry in the hash table referring to the buffer */ always_inline void -hicn_get_internal_state (hicn_buffer_t *hicnb, hicn_pit_cs_t *pitcs, - hicn_hash_node_t **node, +hicn_get_internal_state (hicn_buffer_t *hicnb, u32 *pit_entry_index, const hicn_strategy_vft_t **strategy_vft, - const hicn_dpo_vft_t **dpo_vft, u8 *dpo_ctx_id, - hicn_hash_entry_t **hash_entry) + const hicn_dpo_vft_t **dpo_vft, u8 *dpo_ctx_id) { - *node = pool_elt_at_index (pitcs->pcs_table->ht_nodes, hicnb->node_id); + *pit_entry_index = hicnb->pcs_entry_id; *strategy_vft = hicn_dpo_get_strategy_vft (hicnb->vft_id); *dpo_vft = hicn_dpo_get_vft (hicnb->vft_id); *dpo_ctx_id = hicnb->dpo_ctx_id; - - hicn_hash_bucket_t *bucket; - if (hicnb->hash_bucket_flags & HICN_HASH_NODE_OVERFLOW_BUCKET) - bucket = pool_elt_at_index (pitcs->pcs_table->ht_overflow_buckets, - hicnb->bucket_id); - else - bucket = - (hicn_hash_bucket_t *) (pitcs->pcs_table->ht_buckets + hicnb->bucket_id); - - *hash_entry = &(bucket->hb_entries[hicnb->hash_entry_id]); } /* @@ -83,30 +70,25 @@ hicn_get_internal_state (hicn_buffer_t *hicnb, hicn_pit_cs_t *pitcs, * @brief Store the hicn state in the hicn buffer * * @param b vlib buffer holding the hICN packet - * @param name_hash hash of the hICN name - * @param node_id id of the node in the hash table referring to the buffer - * @param dpo_ctx_id id of the dpo context id corresponding to the buffer - * @param vft_id id of the strategy vft corresponding to the buffer - * @param hash_entry_id id of the entry in the hash table referring to the - * buffer - * @param bucket_id id of the hasth table bucket that holds the hash entry - * @param bucket_is_overflow 1 if the bucket is from the ht_overflow_buckets - * pool 0 if the bucket is from the ht_buckets pool + * @param pcs_entry_index index of the PCS entry */ -always_inline void -hicn_store_internal_state (vlib_buffer_t *b, u64 name_hash, u32 node_id, - u8 dpo_ctx_id, u8 vft_id, u8 hash_entry_id, - u32 bucket_id, u8 bucket_is_overflow) +always_inline int +hicn_store_internal_state (vlib_buffer_t *b, u32 pcs_entry_index, + u32 dpo_ctx_id) { hicn_buffer_t *hicnb = hicn_get_buffer (b); - hicnb->name_hash = name_hash; - hicnb->node_id = node_id; + hicnb->dpo_ctx_id = dpo_ctx_id; - hicnb->vft_id = vft_id; - hicnb->hash_entry_id = hash_entry_id; - hicnb->bucket_id = bucket_id; - hicnb->hash_bucket_flags = - HICN_HASH_NODE_OVERFLOW_BUCKET * bucket_is_overflow; + const hicn_dpo_ctx_t *dpo_ctx = + hicn_strategy_dpo_ctx_get (hicnb->dpo_ctx_id); + + if (PREDICT_FALSE (dpo_ctx == NULL)) + return HICN_ERROR_DPO_CTX_NOT_FOUND; + + hicnb->vft_id = dpo_ctx->dpo_type; + hicnb->pcs_entry_id = pcs_entry_index; + + return HICN_ERROR_NONE; } #endif /* // __HICN_STATE__ */ diff --git a/hicn-plugin/src/strategies/strategy_mw.c b/hicn-plugin/src/strategies/strategy_mw.c index 990e64a5d..81c757f70 100644 --- a/hicn-plugin/src/strategies/strategy_mw.c +++ b/hicn-plugin/src/strategies/strategy_mw.c @@ -16,16 +16,15 @@ #include "../strategy.h" #include "../strategy_dpo_ctx.h" #include "../faces/face.h" -#include "../hashtb.h" #include "../strategy_dpo_manager.h" /* Simple strategy that chooses the next hop with the maximum weight */ /* It does not require to exend the hicn_dpo */ void hicn_receive_data_mw (index_t dpo_idx, int nh_idx); -void hicn_add_interest_mw (index_t dpo_idx, hicn_hash_entry_t *pit_entry); +void hicn_add_interest_mw (index_t dpo_idx); void hicn_on_interest_timeout_mw (index_t dpo_idx); -u32 hicn_select_next_hop_mw (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len); +u32 hicn_select_next_hop_mw (index_t dpo_idx, hicn_face_id_t *outfaces, + u16 *len); u32 get_strategy_node_index_mw (void); u8 *hicn_strategy_format_trace_mw (u8 *s, hicn_strategy_trace_t *t); u8 *hicn_strategy_format_mw (u8 *s, va_list *ap); @@ -51,8 +50,7 @@ hicn_mw_strategy_get_vft (void) /* DPO should be give in input as it containes all the information to calculate * the next hops*/ u32 -hicn_select_next_hop_mw (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len) +hicn_select_next_hop_mw (index_t dpo_idx, hicn_face_id_t *outfaces, u16 *len) { hicn_dpo_ctx_t *dpo_ctx = hicn_strategy_dpo_ctx_get (dpo_idx); @@ -82,14 +80,8 @@ hicn_select_next_hop_mw (index_t dpo_idx, int *nh_idx, } void -hicn_add_interest_mw (index_t dpo_ctx_idx, hicn_hash_entry_t *hash_entry) +hicn_add_interest_mw (index_t dpo_ctx_idx) { - hash_entry->dpo_ctx_id = dpo_ctx_idx; - dpo_id_t hicn_dpo_id = { .dpoi_type = hicn_dpo_strategy_mw_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_idx }; - hash_entry->vft_id = hicn_dpo_get_vft_id (&hicn_dpo_id); } void diff --git a/hicn-plugin/src/strategies/strategy_rp.c b/hicn-plugin/src/strategies/strategy_rp.c index 748cd69b1..eb495ff91 100644 --- a/hicn-plugin/src/strategies/strategy_rp.c +++ b/hicn-plugin/src/strategies/strategy_rp.c @@ -17,16 +17,15 @@ #include "../strategy.h" #include "../strategy_dpo_ctx.h" #include "../faces/face.h" -#include "../hashtb.h" #include "../strategy_dpo_manager.h" /* Simple strategy that forwards intertests to all next hops */ /* It does not require to exend the hicn_dpo */ void hicn_receive_data_rp (index_t dpo_idx, int nh_idx); -void hicn_add_interest_rp (index_t dpo_idx, hicn_hash_entry_t *pit_entry); +void hicn_add_interest_rp (index_t dpo_idx); void hicn_on_interest_timeout_rp (index_t dpo_idx); -u32 hicn_select_next_hop_rp (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len); +u32 hicn_select_next_hop_rp (index_t dpo_idx, hicn_face_id_t *outfaces, + u16 *len); u8 *hicn_strategy_format_trace_rp (u8 *s, hicn_strategy_trace_t *t); u8 *hicn_strategy_format_rp (u8 *s, va_list *ap); @@ -51,8 +50,7 @@ hicn_rp_strategy_get_vft (void) /* DPO should be give in input as it containes all the information to calculate * the next hops*/ u32 -hicn_select_next_hop_rp (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len) +hicn_select_next_hop_rp (index_t dpo_idx, hicn_face_id_t *outfaces, u16 *len) { hicn_dpo_ctx_t *dpo_ctx = hicn_strategy_dpo_ctx_get (dpo_idx); @@ -74,7 +72,7 @@ hicn_select_next_hop_rp (index_t dpo_idx, int *nh_idx, } void -hicn_add_interest_rp (index_t dpo_ctx_idx, hicn_hash_entry_t *hash_entry) +hicn_add_interest_rp (index_t dpo_ctx_idx) { /* Nothing to do */ } diff --git a/hicn-plugin/src/strategies/strategy_rr.c b/hicn-plugin/src/strategies/strategy_rr.c index 192cf5fc3..ef5dc3fc1 100644 --- a/hicn-plugin/src/strategies/strategy_rr.c +++ b/hicn-plugin/src/strategies/strategy_rr.c @@ -17,16 +17,15 @@ #include "../strategy.h" #include "../strategy_dpo_ctx.h" #include "../faces/face.h" -#include "../hashtb.h" #include "../strategy_dpo_manager.h" /* Simple strategy that chooses the next hop with the maximum weight */ /* It does not require to exend the hicn_dpo */ void hicn_receive_data_rr (index_t dpo_idx, int nh_idx); -void hicn_add_interest_rr (index_t dpo_idx, hicn_hash_entry_t *pit_entry); +void hicn_add_interest_rr (index_t dpo_idx); void hicn_on_interest_timeout_rr (index_t dpo_idx); -u32 hicn_select_next_hop_rr (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len); +u32 hicn_select_next_hop_rr (index_t dpo_idx, hicn_face_id_t *outfaces, + u16 *len); u8 *hicn_strategy_format_trace_rr (u8 *s, hicn_strategy_trace_t *t); u8 *hicn_strategy_format_rr (u8 *s, va_list *ap); @@ -51,8 +50,7 @@ hicn_rr_strategy_get_vft (void) /* DPO should be give in input as it containes all the information to calculate * the next hops*/ u32 -hicn_select_next_hop_rr (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len) +hicn_select_next_hop_rr (index_t dpo_idx, hicn_face_id_t *outfaces, u16 *len) { hicn_dpo_ctx_t *dpo_ctx = hicn_strategy_dpo_ctx_get (dpo_idx); @@ -75,14 +73,8 @@ hicn_select_next_hop_rr (index_t dpo_idx, int *nh_idx, } void -hicn_add_interest_rr (index_t dpo_ctx_idx, hicn_hash_entry_t *hash_entry) +hicn_add_interest_rr (index_t dpo_ctx_idx) { - hash_entry->dpo_ctx_id = dpo_ctx_idx; - dpo_id_t hicn_dpo_id = { .dpoi_type = hicn_dpo_strategy_rr_get_type (), - .dpoi_proto = 0, - .dpoi_next_node = 0, - .dpoi_index = dpo_ctx_idx }; - hash_entry->vft_id = hicn_dpo_get_vft_id (&hicn_dpo_id); } void diff --git a/hicn-plugin/src/strategy.h b/hicn-plugin/src/strategy.h index efc6e464e..85fc1e12d 100644 --- a/hicn-plugin/src/strategy.h +++ b/hicn-plugin/src/strategy.h @@ -17,7 +17,6 @@ #define __HICN_STRATEGY__ #include "hicn.h" -#include "hashtb.h" #include "mgmt.h" #include "faces/face.h" @@ -51,9 +50,9 @@ typedef struct hicn_strategy_vft_s { void (*hicn_receive_data) (index_t dpo_idx, int nh_idx); void (*hicn_on_interest_timeout) (index_t dpo_idx); - void (*hicn_add_interest) (index_t dpo_idx, hicn_hash_entry_t *pit_entry); - u32 (*hicn_select_next_hop) (index_t dpo_idx, int *nh_idx, - hicn_face_id_t *outfaces, uint32_t *len); + void (*hicn_add_interest) (index_t dpo_idx); + u32 (*hicn_select_next_hop) (index_t dpo_idx, hicn_face_id_t *outfaces, + u16 *len); u8 *(*hicn_format_strategy_trace) (u8 *, hicn_strategy_trace_t *); u8 *(*hicn_format_strategy) (u8 *s, va_list *ap); /**< Format an hICN dpo*/ diff --git a/hicn-plugin/src/strategy_node.c b/hicn-plugin/src/strategy_node.c index 3ff2d0209..565f3e496 100644 --- a/hicn-plugin/src/strategy_node.c +++ b/hicn-plugin/src/strategy_node.c @@ -20,7 +20,6 @@ #include "parser.h" #include "strategy.h" #include "strategy_dpo_ctx.h" -#include "face_db.h" #include "infra.h" #include "mgmt.h" #include "pcs.h" @@ -61,117 +60,18 @@ hicn_strategy_format_trace (u8 *s, va_list *args) return vft->hicn_format_strategy_trace (s, t); } -always_inline int -hicn_new_interest (hicn_strategy_runtime_t *rt, vlib_buffer_t *b0, u32 *next, - f64 tnow, u8 *nameptr, u16 namelen, hicn_face_id_t outface, - int nh_idx, index_t dpo_ctx_id0, - const hicn_strategy_vft_t *strategy, dpo_type_t dpo_type, - vl_api_hicn_api_node_stats_get_reply_t *stats, - u8 is_replication) +always_inline void +drop_packet (vlib_main_t *vm, u32 bi0, u32 *n_left_to_next, u32 *next0, + u32 **to_next, u32 *next_index, vlib_node_runtime_t *node) { - int ret; - hicn_hash_node_t *nodep; - hicn_pcs_entry_t *pitp; - hicn_header_t *hicn0; - hicn_main_t *sm = &hicn_main; - hicn_buffer_t *hicnb0 = hicn_get_buffer (b0); - u32 node_id0 = 0; - u8 vft_id0 = dpo_type; - u8 is_cs0 = 0; - u8 hash_entry_id = 0; - u8 bucket_is_overflow = 0; - u32 bucket_id = ~0; - u8 isv6 = hicn_buffer_is_v6 (b0); - - if (is_replication) - { - // an entry for this message alredy exists in the PIT so just send it - *next = isv6 ? HICN_STRATEGY_NEXT_INTEREST_FACE6 : - HICN_STRATEGY_NEXT_INTEREST_FACE4; - - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = outface; - stats->pkts_interest_count++; - return HICN_ERROR_NONE; - } - - /* Create PIT node and init PIT entry */ - nodep = hicn_hashtb_alloc_node (rt->pitcs->pcs_table); - if (PREDICT_FALSE (nodep == NULL)) - { - /* Nothing we can do - no mem */ - *next = HICN_STRATEGY_NEXT_ERROR_DROP; - return HICN_ERROR_HASHTB_NOMEM; - } - pitp = hicn_pit_get_data (nodep); - hicn_pit_init_data (pitp); - pitp->shared.create_time = tnow; - - hicn0 = vlib_buffer_get_current (b0); - hicn_lifetime_t imsg_lifetime; - hicn_type_t type = hicnb0->type; - hicn_ops_vft[type.l1]->get_lifetime (type, &hicn0->protocol, &imsg_lifetime); - - if (imsg_lifetime > sm->pit_lifetime_max_ms) - { - imsg_lifetime = sm->pit_lifetime_max_ms; - } - - pitp->shared.expire_time = hicn_pcs_get_exp_time (tnow, imsg_lifetime); - - /* Set up the hash node and insert it */ - hicn_hash_entry_t *hash_entry; - hicn_hashtb_init_node (rt->pitcs->pcs_table, nodep, nameptr, namelen); - - ret = hicn_pcs_pit_insert (rt->pitcs, pitp, nodep, &hash_entry, - hicnb0->name_hash, &node_id0, &dpo_ctx_id0, - &vft_id0, &is_cs0, &hash_entry_id, &bucket_id, - &bucket_is_overflow); - - if (ret == HICN_ERROR_NONE) - { - strategy->hicn_add_interest (vnet_buffer (b0)->ip.adj_index[VLIB_TX], - hash_entry); - - /* Add face */ - hicn_face_db_add_face (hicnb0->face_id, &(pitp->u.pit.faces)); + *next0 = HICN_STRATEGY_NEXT_ERROR_DROP; - *next = isv6 ? HICN_STRATEGY_NEXT_INTEREST_FACE6 : - HICN_STRATEGY_NEXT_INTEREST_FACE4; - - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = outface; - stats->pkts_interest_count++; - pitp->u.pit.pe_txnh = nh_idx; - } - else - { - /* Interest aggregate in PIT */ - if (ret == HICN_ERROR_HASHTB_EXIST) - { - hicn_store_internal_state (b0, hicnb0->name_hash, node_id0, - dpo_ctx_id0, vft_id0, hash_entry_id, - bucket_id, bucket_is_overflow); - // We need to take a lock as the lock is not taken on the hash - // entry because it is a CS entry (hash_insert function). - if (is_cs0) - { - hash_entry->locks++; - *next = HICN_STRATEGY_NEXT_INTEREST_HITCS; - } - else - { - *next = HICN_STRATEGY_NEXT_INTEREST_HITPIT; - } - } - else - { - /* Send the packet to the interest-hitpit node */ - *next = HICN_STRATEGY_NEXT_ERROR_DROP; - } - hicn_faces_flush (&(pitp->u.pit.faces)); - hicn_hashtb_free_node (rt->pitcs->pcs_table, nodep); - } + (*to_next)[0] = bi0; + *to_next += 1; + *n_left_to_next -= 1; - return (ret); + vlib_validate_buffer_enqueue_x1 (vm, node, *next_index, *to_next, + *n_left_to_next, bi0, *next0); } /* @@ -183,11 +83,22 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { + int ret; u32 n_left_from, *from, *to_next, n_left_to_next; hicn_strategy_next_t next_index; hicn_strategy_runtime_t *rt = NULL; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; f64 tnow; + vlib_buffer_t *b0; + u32 bi0; + hicn_face_id_t outfaces[MAX_OUT_FACES]; + u32 clones[MAX_OUT_FACES]; + u16 outfaces_len; + u32 next0; + const hicn_dpo_ctx_t *dpo_ctx; + const hicn_strategy_vft_t *strategy; + hicn_buffer_t *hicnb0; + hicn_pcs_entry_t *pcs_entry = NULL; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -196,6 +107,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, rt->pitcs = &hicn_main.pitcs; /* Capture time in vpp terms */ tnow = vlib_time_now (vm); + next0 = next_index; while (n_left_from > 0) { @@ -203,71 +115,87 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { - u8 *nameptr; - u16 namelen; - vlib_buffer_t *b0; - u32 bi0; - hicn_face_id_t outfaces[MAX_OUT_FACES]; - u32 outfaces_len; - int nh_idx; - u32 next0 = next_index; - - /* Prefetch for next iteration. */ + // Prefetch for next iteration if (n_left_from > 1) { vlib_buffer_t *b1; b1 = vlib_get_buffer (vm, from[1]); CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD); } - /* Dequeue a packet buffer */ + + // Dequeue a packet buffer bi0 = from[0]; from += 1; n_left_from -= 1; - b0 = vlib_get_buffer (vm, bi0); + + // Drop by default next0 = HICN_STRATEGY_NEXT_ERROR_DROP; - hicn_dpo_ctx_t *dpo_ctx = hicn_strategy_dpo_ctx_get ( + // Increment counters + stats.pkts_processed++; + + hicnb0 = hicn_get_buffer (b0); + + // Get the strategy VFT + hicnb0->dpo_ctx_id = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; + dpo_ctx = hicn_strategy_dpo_ctx_get (hicnb0->dpo_ctx_id); + hicnb0->vft_id = dpo_ctx->dpo_type; + strategy = hicn_dpo_get_strategy_vft (hicnb0->vft_id); + strategy->hicn_add_interest (hicnb0->dpo_ctx_id); + + // Check we have at least one next hop for the packet + ret = strategy->hicn_select_next_hop (hicnb0->dpo_ctx_id, outfaces, + &outfaces_len); + + if (PREDICT_FALSE (ret != HICN_ERROR_NONE || outfaces_len == 0)) + { + drop_packet (vm, bi0, &n_left_from, &next0, &to_next, + &next_index, node); + continue; + } + + // Create a new PIT entry + pcs_entry = hicn_pcs_entry_pit_get (rt->pitcs, tnow, + hicn_buffer_get_lifetime (b0)); + + // Add entry to PIT table + ret = hicn_pcs_pit_insert (rt->pitcs, pcs_entry, &hicnb0->name); + + if (PREDICT_FALSE (ret != HICN_ERROR_NONE)) + { + drop_packet (vm, bi0, &n_left_from, &next0, &to_next, + &next_index, node); + continue; + } + + // Store internal state + ret = hicn_store_internal_state ( + b0, hicn_pcs_entry_get_index (rt->pitcs, pcs_entry), vnet_buffer (b0)->ip.adj_index[VLIB_TX]); - if (PREDICT_FALSE (!dpo_ctx)) + if (PREDICT_FALSE (ret != HICN_ERROR_NONE)) { - to_next[0] = bi0; - to_next += 1; - n_left_to_next -= 1; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); + hicn_pcs_entry_remove_lock (rt->pitcs, pcs_entry); + drop_packet (vm, bi0, &n_left_from, &next0, &to_next, + &next_index, node); continue; } - const hicn_strategy_vft_t *strategy = - hicn_dpo_get_strategy_vft (dpo_ctx->dpo_type); + // Add face + hicn_pcs_entry_pit_add_face (pcs_entry, hicnb0->face_id); - hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + // Set next node + next0 = hicn_buffer_is_v6 (b0) ? HICN_STRATEGY_NEXT_INTEREST_FACE6 : + HICN_STRATEGY_NEXT_INTEREST_FACE4; - stats.pkts_processed++; - /* Select next hop */ - /* - * Double check that the interest has been through - * the interest-pcslookup node due to misconfiguration in - * the punting rules. - */ - if (PREDICT_TRUE (HICN_IS_NAMEHASH_CACHED (b0) && - strategy->hicn_select_next_hop ( - vnet_buffer (b0)->ip.adj_index[VLIB_TX], &nh_idx, - outfaces, &outfaces_len) == HICN_ERROR_NONE)) + if (PREDICT_TRUE (ret == HICN_ERROR_NONE)) { - /* - * No need to check if parsing was successful - * here. Already checked in the interest_pcslookup - * node - */ - u32 clones[outfaces_len]; + // Clone interest if needed if (outfaces_len > 1) { - int ret = vlib_buffer_clone (vm, bi0, clones, outfaces_len, - CLIB_CACHE_LINE_BYTES * 2); + ret = vlib_buffer_clone (vm, bi0, clones, (u16) outfaces_len, + CLIB_CACHE_LINE_BYTES * 2); ASSERT (ret == outfaces_len); } else @@ -275,6 +203,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, clones[0] = bi0; } + // Send interest to next hops for (u32 nh = 0; nh < outfaces_len; nh++) { vlib_buffer_t *local_b0 = vlib_get_buffer (vm, clones[nh]); @@ -283,26 +212,10 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, to_next += 1; n_left_to_next -= 1; - if (nh == 0) - { - // send first interest - hicn_new_interest ( - rt, local_b0, &next0, tnow, nameptr, namelen, - outfaces[nh], nh_idx, - vnet_buffer (local_b0)->ip.adj_index[VLIB_TX], - strategy, dpo_ctx->dpo_type, &stats, 0); - } - else - { - // send duplicated interests, avoid aggregation/drop - hicn_new_interest ( - rt, local_b0, &next0, tnow, nameptr, namelen, - outfaces[nh], nh_idx, - vnet_buffer (local_b0)->ip.adj_index[VLIB_TX], - strategy, dpo_ctx->dpo_type, &stats, 1); - } + vnet_buffer (local_b0)->ip.adj_index[VLIB_TX] = outfaces[nh]; + stats.pkts_interest_count++; - /* Maybe trace */ + // Maybe trace if (PREDICT_FALSE ( (node->flags & VLIB_NODE_FLAG_TRACE) && (local_b0->flags & VLIB_BUFFER_IS_TRACED))) @@ -313,14 +226,10 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, t->sw_if_index = vnet_buffer (local_b0)->sw_if_index[VLIB_RX]; t->next_index = next0; - t->dpo_type = dpo_ctx->dpo_type; + t->dpo_type = hicnb0->vft_id; } /* - * Verify speculative enqueue, maybe switch current - * next frame - */ - /* * Fix in case of a wrong speculation. Needed for * cloning the data in the right frame */ @@ -329,6 +238,11 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, clones[nh], next0); } } + else + { + drop_packet (vm, bi0, &n_left_from, &next0, &to_next, + &next_index, node); + } } vlib_put_next_frame (vm, node, next_index, n_left_to_next); diff --git a/hicn-plugin/src/test/CMakeLists.txt b/hicn-plugin/src/test/CMakeLists.txt new file mode 100644 index 000000000..89ad24fbb --- /dev/null +++ b/hicn-plugin/src/test/CMakeLists.txt @@ -0,0 +1,67 @@ +# Copyright (c) 2022 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################# +# Dependencies +############################################################# + +# We need a pure C test framework for the hicn-plugin. +include (UnityTestFrameworkImport) +find_package(Threads REQUIRED) + +############################################################## +# Test sources +############################################################## +list(APPEND TESTS_SRC + main.c + vpp.c + test_pcs.c +) + + +############################################################## +# Link libraries +############################################################## +set(TEST_LIBRARIES + ${VPP_LIBRARIES} + ${UNITY_LIBRARIES} + ${LIBHICN_SHARED} + ${HICNPLUGIN_SHARED} + Threads::Threads +) + +set ( + LINK_FLAGS + "-Wl,-unresolved-symbols=ignore-all" +) + + +############################################################## +# Build single unit test executable and add it to test list +############################################################## +build_executable(hicnplugin_tests + NO_INSTALL + SOURCES ${TESTS_SRC} + LINK_LIBRARIES + ${TEST_LIBRARIES} + INCLUDE_DIRS + $<TARGET_PROPERTY:${HICNPLUGIN_SHARED},INCLUDE_DIRECTORIES> + ${UNITY_INCLUDE_DIRS} + DEPENDS unity ${HICNPLUGIN_SHARED} + COMPONENT ${HICN_PLUGIN} + DEFINITIONS ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} + LINK_FLAGS ${LINK_FLAGS} +) + +unity_add_test_internal(hicnplugin_tests) diff --git a/hicn-plugin/src/test/main.c b/hicn-plugin/src/test/main.c new file mode 100644 index 000000000..82caba18a --- /dev/null +++ b/hicn-plugin/src/test/main.c @@ -0,0 +1,31 @@ + +/* + * Copyright (c) 20022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unity_fixture.h> +#include "vpp.h" + +static void +RunAllTests (void) +{ + RUN_TEST_GROUP (PCS); +} + +int +main (int argc, const char *argv[]) +{ + vpp_init (); + return UnityMain (argc, argv, RunAllTests); +}
\ No newline at end of file diff --git a/hicn-plugin/src/test/test_pcs.c b/hicn-plugin/src/test/test_pcs.c new file mode 100644 index 000000000..8e7416b8b --- /dev/null +++ b/hicn-plugin/src/test/test_pcs.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 20022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define HICN_PCS_TESTING +#include "vpp.h" +#include <pcs.h> + +#include <unity.h> +#include <unity_fixture.h> + +/* + * Global PCS instance common to each test + */ +static hicn_pit_cs_t global_pcs; + +TEST_GROUP (PCS); + +/** + * Default PIT elements + */ +#define MAX_PIT_ELEMENTS 1000000 + +/** + * Default CS elements + */ +#define MAX_CS_ELEMENTS (MAX_PIT_ELEMENTS / 10) + +TEST_SETUP (PCS) +{ + hicn_pit_cs_t *pcs = &global_pcs; + hicn_pit_create (pcs, MAX_PIT_ELEMENTS, MAX_CS_ELEMENTS); +} + +TEST_TEAR_DOWN (PCS) +{ + hicn_pit_cs_t *pcs = &global_pcs; + hicn_pit_destroy (pcs); +} + +TEST (PCS, Create) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Check counters + TEST_ASSERT_EQUAL (0, pcs->pcs_pit_count); + TEST_ASSERT_EQUAL (0, pcs->pcs_cs_count); + TEST_ASSERT_EQUAL (0, pcs->pcs_pcs_alloc); + TEST_ASSERT_EQUAL (0, pcs->pcs_pcs_dealloc); + TEST_ASSERT_EQUAL (MAX_PIT_ELEMENTS, pcs->max_pit_size); + TEST_ASSERT_EQUAL (MAX_CS_ELEMENTS, pcs->policy_state.max); + + printf ("PIT entry size: %lu", sizeof (hicn_pcs_entry_t)); +} + +TEST (PCS, Destroy) +{ + // Global PCS instance +} + +TEST (PCS, LookupEmpty) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + hicn_name_t name; + int ret = hicn_name_create ("b001::abcd", 0, &name); + TEST_ASSERT_EQUAL (0, ret); + + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + TEST_ASSERT_EQUAL (HICN_ERROR_PCS_NOT_FOUND, ret); + TEST_ASSERT_EQUAL (NULL, pcs_entry); +} + +TEST (PCS, InsertPITEntryAndLookup) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b001::1234", 0, &name); + + // Create PCS entry + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // We will not find the entry + TEST_ASSERT_EQUAL (ret, HICN_ERROR_PCS_NOT_FOUND); + TEST_ASSERT_EQUAL (NULL, pcs_entry); + + // Get a new PIT entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + pcs_entry = hicn_pcs_entry_pit_get (pcs, 0, 0); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_alloc (pcs), 1); + + // Insert PIT entry + ret = hicn_pcs_pit_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry + hicn_pcs_entry_t *pcs_entry_ret = NULL; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_NOT_NULL (pcs_entry_ret); + TEST_ASSERT_EQUAL (pcs_entry, pcs_entry_ret); + + // Release PIT entry + hicn_pcs_entry_remove_lock (pcs, pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_dealloc (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry again, we should not find it + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_PCS_NOT_FOUND, ret); + TEST_ASSERT_EQUAL (NULL, pcs_entry_ret); +} + +TEST (PCS, InsertCSEntryAndLookup) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b008::5555", 0, &name); + + // Create PCS entry + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // We will not find the entry + TEST_ASSERT_EQUAL (ret, HICN_ERROR_PCS_NOT_FOUND); + TEST_ASSERT_EQUAL (NULL, pcs_entry); + + // Get a buffer + u32 buffer_index = 198274; + + // Get a new entry from the pool + pcs_entry = hicn_pcs_entry_cs_get (pcs, 0, buffer_index); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (1, hicn_pcs_get_pcs_alloc (pcs)); + + // Insert CS entry + ret = hicn_pcs_cs_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 1); + + // Lookup CS entry + hicn_pcs_entry_t *pcs_entry_ret = NULL; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_TRUE (pcs_entry_ret->flags & HICN_PCS_ENTRY_CS_FLAG); + TEST_ASSERT_NOT_NULL (pcs_entry_ret); + TEST_ASSERT_EQUAL (pcs_entry, pcs_entry_ret); + + // Release CS entry + hicn_pcs_entry_remove_lock (pcs, pcs_entry); + TEST_ASSERT_EQUAL (1, hicn_pcs_get_pcs_dealloc (pcs)); + TEST_ASSERT_EQUAL (0, hicn_pcs_get_pit_count (pcs)); + TEST_ASSERT_EQUAL (0, hicn_pcs_get_cs_count (pcs)); + + // Lookup CS entry again, we should not find it + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_PCS_NOT_FOUND, ret); + TEST_ASSERT_EQUAL (NULL, pcs_entry_ret); +} + +TEST (PCS, PitToCS) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b001::1234", 0, &name); + + // Create PCS entry + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // We will not find the entry + TEST_ASSERT_EQUAL (ret, HICN_ERROR_PCS_NOT_FOUND); + TEST_ASSERT_EQUAL (NULL, pcs_entry); + + // Get a new entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + pcs_entry = hicn_pcs_entry_pit_get (pcs, 0, 0); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_alloc (pcs), 1); + + // Insert PIT entry + ret = hicn_pcs_pit_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry + hicn_pcs_entry_t *pcs_entry_ret = NULL; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_NOT_NULL (pcs_entry_ret); + TEST_ASSERT_EQUAL (pcs_entry, pcs_entry_ret); + + // Found the PIT entry we inserted before. + // Double check is not a CS + TEST_ASSERT_FALSE (pcs_entry_ret->flags & HICN_PCS_ENTRY_CS_FLAG); + + // Turn the PIT entry into a CS + hicn_pit_to_cs (pcs, pcs_entry, /* random buffer index */ 12345); + + // Check counters + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 1); + + // Make sure entry is now a CS + TEST_ASSERT_TRUE (pcs_entry_ret->flags & HICN_PCS_ENTRY_CS_FLAG); +} + +TEST (PCS, CheckCSLruConsistency) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b001::1234", 0, &name); + + // Create CS entry + hicn_pcs_entry_t *pcs_entry; + // Get a new entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + pcs_entry = hicn_pcs_entry_cs_get (pcs, 0, 0); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_alloc (pcs), 1); + + // Insert CS entry + ret = hicn_pcs_cs_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + + // Get pcs_entry index + uint32_t pcs_entry_index = hicn_pcs_entry_get_index (pcs, pcs_entry); + + // Check LRU + hicn_cs_policy_t *policy_state = hicn_pcs_get_policy_state (pcs); + + // Make sure MAX corresponds to what we set + TEST_ASSERT_EQUAL (MAX_CS_ELEMENTS, hicn_cs_policy_get_max (policy_state)); + + TEST_ASSERT_EQUAL (pcs_entry_index, hicn_cs_policy_get_head (policy_state)); + TEST_ASSERT_EQUAL (pcs_entry_index, hicn_cs_policy_get_tail (policy_state)); + TEST_ASSERT_EQUAL (1, hicn_cs_policy_get_count (policy_state)); + + // Check pointers of the entry + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_next (pcs_entry)); + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_prev (pcs_entry)); + + // Lookup the entry itself + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // Check again the pointers of the entry + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_next (pcs_entry)); + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_prev (pcs_entry)); + + // Remove CS entry + hicn_pcs_entry_remove_lock (pcs, pcs_entry); + TEST_ASSERT_EQUAL (1, hicn_pcs_get_pcs_dealloc (pcs)); + TEST_ASSERT_EQUAL (0, hicn_pcs_get_pit_count (pcs)); + TEST_ASSERT_EQUAL (0, hicn_pcs_get_cs_count (pcs)); + + // Check again LRU + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_cs_policy_get_head (policy_state)); + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_cs_policy_get_tail (policy_state)); + TEST_ASSERT_EQUAL (0, hicn_cs_policy_get_count (policy_state)); + + // Let's insert now 2 entries + hicn_pcs_entry_t *pcs_entry0; + hicn_pcs_entry_t *pcs_entry1; + + pcs_entry0 = hicn_pcs_entry_cs_get (pcs, 0, 0); + TEST_ASSERT_NOT_NULL (pcs_entry0); + hicn_name_t name0; + hicn_name_create ("b001::abcd", 123, &name0); + u32 index0 = hicn_pcs_entry_get_index (pcs, pcs_entry0); + + pcs_entry1 = hicn_pcs_entry_cs_get (pcs, 0, 0); + TEST_ASSERT_NOT_NULL (pcs_entry1); + hicn_name_t name1; + hicn_name_create ("b001::9999", 321, &name1); + u32 index1 = hicn_pcs_entry_get_index (pcs, pcs_entry1); + + // Insert CS entry + ret = hicn_pcs_cs_insert (pcs, pcs_entry0, &name0); + ret = hicn_pcs_cs_insert (pcs, pcs_entry1, &name1); + + // Check LRU. index1 was inserted last, so it should be at the head + TEST_ASSERT_EQUAL (index1, hicn_cs_policy_get_head (policy_state)); + // index0 was inserted first, so it should be at the tail + TEST_ASSERT_EQUAL (index0, hicn_cs_policy_get_tail (policy_state)); + // And count shoould be 2 + TEST_ASSERT_EQUAL (2, hicn_cs_policy_get_count (policy_state)); + + // Check pointers of the entries + + // pcs_entry0 should be at the tail + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_next (pcs_entry0)); + TEST_ASSERT_EQUAL (index1, hicn_pcs_entry_cs_get_prev (pcs_entry0)); + + // pcs_entry1 should be at the head + TEST_ASSERT_EQUAL (index0, hicn_pcs_entry_cs_get_next (pcs_entry1)); + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_prev (pcs_entry1)); + + // Let's lookup for entry 0 and check if the LRU is updated correctly + ret = hicn_pcs_lookup_one (pcs, &name0, &pcs_entry); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (index0, hicn_pcs_entry_get_index (pcs, pcs_entry)); + + // Check pointers of the entries + + // pcs_entry1 should be at the tail + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_next (pcs_entry1)); + TEST_ASSERT_EQUAL (index0, hicn_pcs_entry_cs_get_prev (pcs_entry1)); + + // pcs_entry0 should be at the head + TEST_ASSERT_EQUAL (index1, hicn_pcs_entry_cs_get_next (pcs_entry0)); + TEST_ASSERT_EQUAL (HICN_CS_POLICY_END_OF_CHAIN, + hicn_pcs_entry_cs_get_prev (pcs_entry0)); + + // index0 should be now the head + TEST_ASSERT_EQUAL (index0, hicn_cs_policy_get_head (policy_state)); + // index1 should be now the tail + TEST_ASSERT_EQUAL (index1, hicn_cs_policy_get_tail (policy_state)); +} + +TEST (PCS, CheckCSLruMax) +{ + hicn_pit_cs_t *pcs = &global_pcs; + int i, ret = 0; + ; + u32 pcs_entry_index = 0; + u32 pcs_entry_index0 = 0; + u32 pcs_entry_index1 = 0; + hicn_pcs_entry_t *pcs_entry = NULL; + hicn_name_t name; + + const hicn_cs_policy_t *policy_state = hicn_pcs_get_policy_state (pcs); + + for (i = 0; i < MAX_CS_ELEMENTS; i++) + { + // Allocate name + ret = hicn_name_create ("b004::aaaa", i, &name); + TEST_ASSERT_EQUAL (0, ret); + + // Create CS entry + // Get a new entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + pcs_entry = hicn_pcs_entry_cs_get (pcs, 0, i); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (i + 1, hicn_pcs_get_pcs_alloc (pcs)); + + pcs_entry_index = hicn_pcs_entry_get_index (pcs, pcs_entry); + + if (i == 0) + { + pcs_entry_index0 = pcs_entry_index; + } + + if (i == 1) + { + pcs_entry_index1 = pcs_entry_index; + } + + // Insert CS entry + ret = hicn_pcs_cs_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), i + 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + + // Check LRU + TEST_ASSERT_EQUAL (pcs_entry_index, + hicn_cs_policy_get_head (policy_state)); + TEST_ASSERT_EQUAL (pcs_entry_index0, + hicn_cs_policy_get_tail (policy_state)); + TEST_ASSERT_EQUAL (i + 1, hicn_cs_policy_get_count (policy_state)); + } + + // In this moment the CS should be full + TEST_ASSERT_EQUAL (hicn_cs_policy_get_max (policy_state), + hicn_cs_policy_get_count (policy_state)); + + // Next insertion should: + // - evict the tail + // - update the head + // - make a coffee because I am tired + ret = hicn_name_create ("b004::aaaa", i, &name); + TEST_ASSERT_EQUAL (0, ret); + + pcs_entry = hicn_pcs_entry_cs_get (pcs, 0, i); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (i + 1, hicn_pcs_get_pcs_alloc (pcs)); + + pcs_entry_index = hicn_pcs_entry_get_index (pcs, pcs_entry); + + // Insert CS entry + ret = hicn_pcs_cs_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), i); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + + // Check LRU + TEST_ASSERT_EQUAL (pcs_entry_index, hicn_cs_policy_get_head (policy_state)); + // pcs_entry_index1 should be have eveicted, and pcs_entry_index1 should be + // the tail + TEST_ASSERT_EQUAL (pcs_entry_index1, hicn_cs_policy_get_tail (policy_state)); + + // Make pcs_entry_index0 was freed. + TEST_ASSERT_TRUE ( + pool_is_free_index (pcs->pcs_entries_pool, pcs_entry_index0)); +} + +TEST (PCS, AddIngressFacesToPITEntry) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b001::9876", 0, &name); + + // Create PCS entry + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // We will not find the entry + TEST_ASSERT_EQUAL (ret, HICN_ERROR_PCS_NOT_FOUND); + TEST_ASSERT_EQUAL (NULL, pcs_entry); + + // Get a new entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + f64 tnow = 10.0; + pcs_entry = hicn_pcs_entry_pit_get (pcs, tnow, 0); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_alloc (pcs), 1); + + const u32 faceid = 20; + + // The face should not be in the PIT entry + TEST_ASSERT_EQUAL (0, hicn_pcs_entry_pit_search (pcs_entry, faceid)); + + // Add ingress face to pit entry + hicn_pcs_entry_pit_add_face (pcs_entry, faceid); + + // Insert PIT entry + ret = hicn_pcs_pit_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry + hicn_pcs_entry_t *pcs_entry_ret = NULL; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_NOT_NULL (pcs_entry_ret); + TEST_ASSERT_EQUAL (pcs_entry, pcs_entry_ret); + + // Check everything is fine + ret = hicn_pcs_entry_pit_search (pcs_entry_ret, faceid); + // Face 20 should be in the entry + TEST_ASSERT_EQUAL (ret, 1); + + // Get faces and make sure + // - there is only one face + // - the face is 20 + TEST_ASSERT_EQUAL (1, hicn_pcs_entry_pit_get_n_faces (pcs_entry_ret)); + TEST_ASSERT_EQUAL (20, hicn_pcs_entry_pit_get_dpo_face (pcs_entry_ret, 0)); + + // Release PIT entry + hicn_pcs_entry_remove_lock (pcs, pcs_entry_ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_dealloc (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry again, we should not find it + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_PCS_NOT_FOUND, ret); + TEST_ASSERT_EQUAL (NULL, pcs_entry_ret); +} + +TEST (PCS, AddIngressFacesToPitEntryCornerCases) +{ + hicn_pit_cs_t *pcs = &global_pcs; + + // Add entry to the PCS + int ret = 0; + + // Allocate name + hicn_name_t name; + hicn_name_create ("b001::9876", 0, &name); + + // Create PCS entry + hicn_pcs_entry_t *pcs_entry; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry); + + // We will not find the entry + TEST_ASSERT_EQUAL (ret, HICN_ERROR_PCS_NOT_FOUND); + TEST_ASSERT_EQUAL (NULL, pcs_entry); + + // Get a new entry from the pool + // TODO Check if the hicn_pcs_entry_pit_get is needed here + f64 tnow = 10.0; + pcs_entry = hicn_pcs_entry_pit_get (pcs, tnow, 0); + TEST_ASSERT_NOT_NULL (pcs_entry); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_alloc (pcs), 1); + + // Let's initialize HICN_FACE_DB_INLINE_FACES + 1 face IDs + u32 faceids[HICN_FACE_DB_INLINE_FACES + 1]; + for (u32 i = 0; i < HICN_FACE_DB_INLINE_FACES + 1; i++) + faceids[i] = rand () % HICN_PARAM_FACES_MAX; + + // The faces should not be in the PIT entry + for (u32 i = 0; i < HICN_FACE_DB_INLINE_FACES + 1; i++) + TEST_ASSERT_EQUAL (0, hicn_pcs_entry_pit_search (pcs_entry, faceids[i])); + + // Add ingress faces to pit entry + for (u32 i = 0; i < HICN_FACE_DB_INLINE_FACES + 1; i++) + hicn_pcs_entry_pit_add_face (pcs_entry, faceids[i]); + + // Insert PIT entry + ret = hicn_pcs_pit_insert (pcs, pcs_entry, &name); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry + hicn_pcs_entry_t *pcs_entry_ret = NULL; + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_NONE, ret); + TEST_ASSERT_NOT_NULL (pcs_entry_ret); + TEST_ASSERT_EQUAL (pcs_entry, pcs_entry_ret); + + // Check everything is fine + for (u32 i = 0; i < HICN_FACE_DB_INLINE_FACES + 1; i++) + { + ret = hicn_pcs_entry_pit_search (pcs_entry_ret, faceids[i]); + // Face 20 should be in the entry + TEST_ASSERT_EQUAL (1, ret); + } + + // Get faces and make sure + // - there are HICN_FACE_DB_INLINE_FACES + 1 faces + // - the first HICN_FACE_DB_INLINE_FACES are stored in the PIT entry + // - the face HICN_FACE_DB_INLINE_FACES + 1 is stored in the array of + // additional faces, so outside PIT entry + TEST_ASSERT_EQUAL (HICN_FACE_DB_INLINE_FACES + 1, + hicn_pcs_entry_pit_get_n_faces (pcs_entry_ret)); + for (u32 i = 0; i < HICN_FACE_DB_INLINE_FACES + 1; i++) + TEST_ASSERT_EQUAL (faceids[i], + hicn_pcs_entry_pit_get_dpo_face (pcs_entry_ret, i)); + + // Release PIT entry + hicn_pcs_entry_remove_lock (pcs, pcs_entry_ret); + TEST_ASSERT_EQUAL (hicn_pcs_get_pcs_dealloc (pcs), 1); + TEST_ASSERT_EQUAL (hicn_pcs_get_pit_count (pcs), 0); + TEST_ASSERT_EQUAL (hicn_pcs_get_cs_count (pcs), 0); + + // Lookup PIT entry again, we should not find it + ret = hicn_pcs_lookup_one (pcs, &name, &pcs_entry_ret); + TEST_ASSERT_EQUAL (HICN_ERROR_PCS_NOT_FOUND, ret); + TEST_ASSERT_EQUAL (NULL, pcs_entry_ret); +} + +TEST_GROUP_RUNNER (PCS) +{ + RUN_TEST_CASE (PCS, Create) + RUN_TEST_CASE (PCS, Destroy) + RUN_TEST_CASE (PCS, LookupEmpty) + RUN_TEST_CASE (PCS, InsertPITEntryAndLookup) + RUN_TEST_CASE (PCS, InsertCSEntryAndLookup) + RUN_TEST_CASE (PCS, PitToCS) + RUN_TEST_CASE (PCS, CheckCSLruConsistency) + RUN_TEST_CASE (PCS, CheckCSLruMax) + RUN_TEST_CASE (PCS, AddIngressFacesToPITEntry) + RUN_TEST_CASE (PCS, AddIngressFacesToPitEntryCornerCases) +} diff --git a/hicn-plugin/src/test/vpp.c b/hicn-plugin/src/test/vpp.c new file mode 100644 index 000000000..fc96e6e16 --- /dev/null +++ b/hicn-plugin/src/test/vpp.c @@ -0,0 +1,555 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <pthread.h> +#include <sched.h> + +#include <vppinfra/cpu.h> +#include <vlib/vlib.h> +#include <vlib/unix/unix.h> +#include <vlib/threads.h> +#include <vnet/plugin/plugin.h> +#include <vnet/ethernet/ethernet.h> +#include <vpp/vnet/config.h> +#include <vlibmemory/memclnt.api_enum.h> /* To get the last static message id */ +#include <limits.h> + +/* + * Load plugins from /usr/lib/vpp_plugins by default + */ +char *vlib_plugin_path = NULL; +char *vat_plugin_path = NULL; + +static void +vpp_find_plugin_path () +{ + extern char *vat_plugin_path; + char *p, path[PATH_MAX]; + int rv; + u8 *s; + + /* find executable path */ + if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1) + return; + + /* readlink doesn't provide null termination */ + path[rv] = 0; + + /* strip filename */ + if ((p = strrchr (path, '/')) == 0) + return; + *p = 0; + + /* strip bin/ */ + if ((p = strrchr (path, '/')) == 0) + return; + *p = 0; + + s = format (0, "%s/" CLIB_LIB_DIR "/vpp_plugins", path, path); + vec_add1 (s, 0); + vlib_plugin_path = (char *) s; + + s = format (0, "%s/" CLIB_LIB_DIR "/vpp_api_test_plugins", path, path); + vec_add1 (s, 0); + vat_plugin_path = (char *) s; +} + +static void +vpe_main_init (vlib_main_t *vm) +{ +#if VPP_API_TEST_BUILTIN > 0 + void vat_plugin_hash_create (void); +#endif + + if (CLIB_DEBUG > 0) + vlib_unix_cli_set_prompt ("DBGvpp# "); + else + vlib_unix_cli_set_prompt ("vpp# "); + + /* Turn off network stack components which we don't want */ + vlib_mark_init_function_complete (vm, srp_init); + + /* + * Create the binary api plugin hashes before loading plugins + */ +#if VPP_API_TEST_BUILTIN > 0 + vat_plugin_hash_create (); +#endif + + if (!vlib_plugin_path) + vpp_find_plugin_path (); +} + +/* + * Default path for runtime data + */ +char *vlib_default_runtime_dir = "vpp"; + +int +vpp_init_internal (int argc, char *argv[]) +{ + int i; + void vl_msg_api_set_first_available_msg_id (u16); + uword main_heap_size = (1ULL << 30); + u8 *sizep; + u32 size; + clib_mem_page_sz_t main_heap_log2_page_sz = CLIB_MEM_PAGE_SZ_DEFAULT; + clib_mem_page_sz_t default_log2_hugepage_sz = CLIB_MEM_PAGE_SZ_UNKNOWN; + unformat_input_t input, sub_input; + u8 *s = 0, *v = 0; + int main_core = 1; + cpu_set_t cpuset; + void *main_heap; + +#if __x86_64__ + CLIB_UNUSED (const char *msg) = + "ERROR: This binary requires CPU with %s extensions.\n"; +#define _(a, b) \ + if (!clib_cpu_supports_##a ()) \ + { \ + fprintf (stderr, msg, b); \ + exit (1); \ + } + +#if __AVX2__ + _ (avx2, "AVX2") +#endif +#if __AVX__ + _ (avx, "AVX") +#endif +#if __SSE4_2__ + _ (sse42, "SSE4.2") +#endif +#if __SSE4_1__ + _ (sse41, "SSE4.1") +#endif +#if __SSSE3__ + _ (ssse3, "SSSE3") +#endif +#if __SSE3__ + _ (sse3, "SSE3") +#endif +#undef _ +#endif + /* + * Load startup config from file. + * usage: vpp -c /etc/vpp/startup.conf + */ + if ((argc == 3) && !strncmp (argv[1], "-c", 2)) + { + FILE *fp; + char inbuf[4096]; + int argc_ = 1; + char **argv_ = NULL; + char *arg = NULL; + char *p; + + fp = fopen (argv[2], "r"); + if (fp == NULL) + { + fprintf (stderr, "open configuration file '%s' failed\n", argv[2]); + return 1; + } + argv_ = calloc (1, sizeof (char *)); + if (argv_ == NULL) + { + fclose (fp); + return 1; + } + arg = strndup (argv[0], 1024); + if (arg == NULL) + { + fclose (fp); + free (argv_); + return 1; + } + argv_[0] = arg; + + while (1) + { + if (fgets (inbuf, 4096, fp) == 0) + break; + p = strtok (inbuf, " \t\n"); + while (p != NULL) + { + if (*p == '#') + break; + argc_++; + char **tmp = realloc (argv_, argc_ * sizeof (char *)); + if (tmp == NULL) + return 1; + argv_ = tmp; + arg = strndup (p, 1024); + if (arg == NULL) + return 1; + argv_[argc_ - 1] = arg; + p = strtok (NULL, " \t\n"); + } + } + + fclose (fp); + + char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *)); + if (tmp == NULL) + return 1; + argv_ = tmp; + argv_[argc_] = NULL; + + argc = argc_; + argv = argv_; + } + + /* + * Look for and parse the "heapsize" config parameter. + * Manual since none of the clib infra has been bootstrapped yet. + * + * Format: heapsize <nn>[mM][gG] + */ + + for (i = 1; i < (argc - 1); i++) + { + if (!strncmp (argv[i], "plugin_path", 11)) + { + if (i < (argc - 1)) + vlib_plugin_path = argv[++i]; + } + if (!strncmp (argv[i], "test_plugin_path", 16)) + { + if (i < (argc - 1)) + vat_plugin_path = argv[++i]; + } + else if (!strncmp (argv[i], "heapsize", 8)) + { + sizep = (u8 *) argv[i + 1]; + size = 0; + while (*sizep >= '0' && *sizep <= '9') + { + size *= 10; + size += *sizep++ - '0'; + } + if (size == 0) + { + fprintf ( + stderr, + "warning: heapsize parse error '%s', use default %lld\n", + argv[i], (long long int) main_heap_size); + goto defaulted; + } + + main_heap_size = size; + + if (*sizep == 'g' || *sizep == 'G') + main_heap_size <<= 30; + else if (*sizep == 'm' || *sizep == 'M') + main_heap_size <<= 20; + } + else if (!strncmp (argv[i], "main-core", 9)) + { + if (i < (argc - 1)) + { + errno = 0; + unsigned long x = strtol (argv[++i], 0, 0); + if (errno == 0) + main_core = x; + } + } + } +defaulted: + + /* temporary heap */ + clib_mem_init (0, 1 << 20); + unformat_init_command_line (&input, (char **) argv); + + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&input, "memory %v", &v)) + { + unformat_init_vector (&sub_input, v); + v = 0; + while (unformat_check_input (&sub_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&sub_input, "main-heap-size %U", + unformat_memory_size, &main_heap_size)) + ; + else if (unformat (&sub_input, "main-heap-page-size %U", + unformat_log2_page_size, + &main_heap_log2_page_sz)) + ; + else if (unformat (&sub_input, "default-hugepage-size %U", + unformat_log2_page_size, + &default_log2_hugepage_sz)) + ; + else + { + fformat (stderr, "unknown 'memory' config input '%U'\n", + format_unformat_error, &sub_input); + exit (1); + } + } + unformat_free (&sub_input); + } + else if (!unformat (&input, "%s %v", &s, &v)) + break; + + vec_reset_length (s); + vec_reset_length (v); + } + vec_free (s); + vec_free (v); + + unformat_free (&input); + + /* set process affinity for main thread */ + CPU_ZERO (&cpuset); + CPU_SET (main_core, &cpuset); + pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset); + + /* Set up the plugin message ID allocator right now... */ + vl_msg_api_set_first_available_msg_id (VL_MSG_MEMCLNT_LAST + 1); + + /* destroy temporary heap and create main one */ + clib_mem_destroy (); + + if ((main_heap = clib_mem_init_with_page_size (main_heap_size, + main_heap_log2_page_sz))) + { + /* Figure out which numa runs the main thread */ + __os_numa_index = clib_get_current_numa_node (); + + if (default_log2_hugepage_sz != CLIB_MEM_PAGE_SZ_UNKNOWN) + clib_mem_set_log2_default_hugepage_size (default_log2_hugepage_sz); + + /* and use the main heap as that numa's numa heap */ + clib_mem_set_per_numa_heap (main_heap); + vlib_main_init (); + vpe_main_init (vlib_get_first_main ()); + return 0; + } + else + { + { + int rv __attribute__ ((unused)) = + write (2, "Main heap allocation failure!\r\n", 31); + } + return 1; + } +} + +static clib_error_t * +memory_config (vlib_main_t *vm, unformat_input_t *input) +{ + return 0; +} + +VLIB_CONFIG_FUNCTION (memory_config, "memory"); + +static clib_error_t * +heapsize_config (vlib_main_t *vm, unformat_input_t *input) +{ + return 0; +} + +VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize"); + +static clib_error_t * +placeholder_path_config (vlib_main_t *vm, unformat_input_t *input) +{ + u8 *junk; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%s", &junk)) + { + vec_free (junk); + return 0; + } + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + return 0; +} + +static clib_error_t * +plugin_path_config (vlib_main_t *vm, unformat_input_t *input) +{ + return placeholder_path_config (vm, input); +} + +VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path"); + +static clib_error_t * +test_plugin_path_config (vlib_main_t *vm, unformat_input_t *input) +{ + return placeholder_path_config (vm, input); +} + +VLIB_CONFIG_FUNCTION (test_plugin_path_config, "test_plugin_path"); + +void vl_msg_api_post_mortem_dump (void); +void vlib_post_mortem_dump (void); + +void +os_panic (void) +{ + vl_msg_api_post_mortem_dump (); + vlib_post_mortem_dump (); + abort (); +} + +void vhost_user_unmap_all (void) __attribute__ ((weak)); +void +vhost_user_unmap_all (void) +{ +} + +void +os_exit (int code) +{ + static int recursion_block; + + if (code) + { + if (recursion_block) + abort (); + + recursion_block = 1; + + vl_msg_api_post_mortem_dump (); + vlib_post_mortem_dump (); + vhost_user_unmap_all (); + abort (); + } + exit (code); +} + +#ifdef BARRIER_TRACING +void +vl_msg_api_barrier_trace_context (const char *context) +{ + vlib_worker_threads[0].barrier_context = context; +} +#endif + +void +vl_msg_api_barrier_sync (void) +{ + vlib_worker_thread_barrier_sync (vlib_get_main ()); +} + +void +vl_msg_api_barrier_release (void) +{ + vlib_worker_thread_barrier_release (vlib_get_main ()); +} + +/* This application needs 1 thread stack for the stats pthread */ +u32 +vlib_app_num_thread_stacks_needed (void) +{ + return 1; +} + +/* + * Depending on the configuration selected above, + * it may be necessary to generate stub graph nodes. + * It is never OK to ignore "node 'x' refers to unknown node 'y' + * messages! + */ + +#include <vppinfra/bihash_8_8.h> + +static clib_error_t * +show_bihash_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + int i; + clib_bihash_8_8_t *h; + int verbose = 0; + + if (unformat (input, "verbose")) + verbose = 1; + + for (i = 0; i < vec_len (clib_all_bihashes); i++) + { + h = (clib_bihash_8_8_t *) clib_all_bihashes[i]; + vlib_cli_output (vm, "\n%U", h->fmt_fn, h, verbose); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_bihash_command, static) = { + .path = "show bihash", + .short_help = "show bihash", + .function = show_bihash_command_fn, +}; +/* *INDENT-ON* */ + +#ifdef CLIB_SANITIZE_ADDR +/* default options for Address Sanitizer */ +const char * +__asan_default_options (void) +{ + return VPP_SANITIZE_ADDR_OPTIONS; +} +#endif /* CLIB_SANITIZE_ADDR */ + +/*********************************** + * Missing Symbol in vpp libraries + ***********************************/ + +typedef struct stat_segment_directory_entry_s stat_segment_directory_entry_t; +typedef void (*stat_segment_update_fn) (stat_segment_directory_entry_t *e, + u32 i); +clib_error_t * +stat_segment_register_gauge (u8 *name, stat_segment_update_fn update_fn, + u32 caller_index) +{ + return NULL; +} + +u8 * +format_vl_api_address_union (u8 *s, va_list *args) +{ + return NULL; +} + +int +vpp_init () +{ +#define N_ARGS 3 +#define BUFFER_LEN 1024 + // Get executable path + char buffer[BUFFER_LEN]; + int ret = readlink ("/proc/self/exe", buffer, BUFFER_LEN); + + ASSERT (ret < BUFFER_LEN); + + buffer[ret] = '\0'; + + char *argv[N_ARGS] = { buffer, "unix { nodaemon }", NULL }; + return vpp_init_internal (N_ARGS - 1, argv); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/test/vpp.h b/hicn-plugin/src/test/vpp.h new file mode 100644 index 000000000..fe680f6b6 --- /dev/null +++ b/hicn-plugin/src/test/vpp.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __VPP__ +#define __VPP__ + +int vpp_init (); + +#endif
\ No newline at end of file |