diff options
| author | songyanchao <[email protected]> | 2024-08-09 09:29:04 +0000 |
|---|---|---|
| committer | songyanchao <[email protected]> | 2024-08-09 10:23:03 +0000 |
| commit | 96e1b64b3a4b53bf4c0882dbfecddd4796e826f6 (patch) | |
| tree | e72a8b35995de537e572665a5c729fac660f14fc | |
| parent | 0975a9d01780acb8aaf89db0704c46b21d9be3c0 (diff) | |
🎈 perf(DPISDN-52): Add CMocka-based test cases for ef ingress and ef egress node.
Add CMocka-based test cases for ef ingress and ef egress node.
| -rw-r--r-- | include/internal/adapter_define.h | 2 | ||||
| -rw-r--r-- | infra/include/common.h | 2 | ||||
| -rw-r--r-- | service/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | service/include/sc_common.h | 2 | ||||
| -rw-r--r-- | service/include/sc_node_common.h | 22 | ||||
| -rw-r--r-- | service/src/node_etherfabric.c | 2669 | ||||
| -rw-r--r-- | service/src/node_link_aware_injector.c | 9 | ||||
| -rw-r--r-- | service/src/sc_metrics.c | 1 | ||||
| -rw-r--r-- | service/src/sc_node_common.c | 139 | ||||
| -rw-r--r-- | service/test/test_common.c | 160 | ||||
| -rw-r--r-- | service/test/test_node_bfd.c | 24 | ||||
| -rw-r--r-- | service/test/test_node_ef.c | 3212 |
12 files changed, 5620 insertions, 634 deletions
diff --git a/include/internal/adapter_define.h b/include/internal/adapter_define.h index 879ce52..63db8c6 100644 --- a/include/internal/adapter_define.h +++ b/include/internal/adapter_define.h @@ -14,7 +14,7 @@ enum adapter_type unsigned int nr_max_vwires_get(); uint16_t ef_nr_adapters_get(); unsigned int nr_max_ef_adapters_get(); -void ef_adapter_id_get(uint16_t * ef_adapter_ids, uint16_t nr_adapters); +void ef_adapter_ids_get(uint16_t * ef_adapter_ids, uint16_t nr_adapters); unsigned int nr_max_tera_adapters_get(); uint32_t vwire_sid_start_get(); uint32_t ef_sid_start_get(); diff --git a/infra/include/common.h b/infra/include/common.h index f3fd99d..6e97970 100644 --- a/infra/include/common.h +++ b/infra/include/common.h @@ -413,6 +413,8 @@ static inline int mr_thread_setname(pthread_t id, const char * name) return pthread_setname_np(id, name); } +/****************************************************** Sid list ******************************************************/ +/* Sid list struct */ struct sid_list { uint8_t head; diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index d33d97d..ca506a9 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories(include) set(MRZCPD_SERVICE_SOURCE_FILES src/core.c src/devmgr.c src/mrb.c src/hwinfo.c src/vdev.c - src/vdata.c src/app.c src/monit.c src/node.c src/sc_metrics.c src/node_shmdev.c + src/vdata.c src/app.c src/monit.c src/node.c src/sc_metrics.c src/sc_node_common.c src/node_shmdev.c src/node_phydev.c src/node_lb.c src/node_classifier.c src/node_etherfabric.c src/node_tera.c src/node_eth_ingress.c src/node_eth_egress.c src/node_bfd.c src/node_vwire.c src/node_health_check.c src/node_forwarder.c src/node_bridge.c src/pdump.c src/olp.c src/olp_6500.c @@ -59,3 +59,13 @@ target_link_libraries(test_sc_metrics MESA_prof_load_static ${SYSTEMD_LIBRARIES} target_link_libraries(test_sc_metrics libcmocka rt pthread dl infra z elf) target_link_options(test_sc_metrics PRIVATE --coverage -fprofile-arcs -ftest-coverage) target_include_directories(test_sc_metrics PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/") + + +add_executable(test_node_ef test/test_node_mocks.c test/test_node_ef.c test/test_common.c ${MRZCPD_SERVICE_SOURCE_FILES}) +target_compile_options(test_node_ef PRIVATE --coverage -fprofile-arcs -ftest-coverage) +target_link_libraries(test_node_ef MESA_prof_load_static ${SYSTEMD_LIBRARIES} libdpdk) +target_link_libraries(test_node_ef libcmocka rt pthread dl infra z elf) +target_link_options(test_node_ef PRIVATE --coverage -fprofile-arcs -ftest-coverage) +target_include_directories(test_node_ef PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/") +target_link_libraries(test_node_ef -Wl,--wrap=mr_dev_desc_lookup) +target_link_libraries(test_node_ef -Wl,--wrap=port_adapter_mapping_insert) diff --git a/service/include/sc_common.h b/service/include/sc_common.h index 7479121..1d99d3c 100644 --- a/service/include/sc_common.h +++ b/service/include/sc_common.h @@ -47,7 +47,7 @@ struct flow_manage_main; struct node_manager_main; struct node_classifier_main; struct node_lb_main; -struct node_ef_main; +struct ef_node_main; struct rpc_server_handler; struct node_eth_egress_main; struct node_bfd_main; diff --git a/service/include/sc_node_common.h b/service/include/sc_node_common.h index 13c234b..14b7d2e 100644 --- a/service/include/sc_node_common.h +++ b/service/include/sc_node_common.h @@ -8,6 +8,7 @@ #include <common.h> #include <ldbc.h> +#include <sc_common.h> #include <sc_devmgr.h> #define MR_NODE_CTRLZONE_ID 1 @@ -140,3 +141,24 @@ static inline cJSON * create_uint64_array(const uint64_t * value, unsigned int n return uint64_array; } + +/***************************************************** Sid handle *****************************************************/ +#define SC_SID_HANDLE_CAPACITY_MAX 256 +/* Sid handle struct */ +struct sid_handle +{ + uint16_t capacity; + uint32_t sid_start; + uint32_t sid_end; +}; + +struct sid_handle * sid_handle_create(uint32_t sid_start, uint32_t sid_end); +int sid_handle_delete(struct sid_handle * sid_handle); +uint16_t sid_handle_capacity_get(struct sid_handle * sid_handle); +uint32_t sid_handle_sid_start_get(struct sid_handle * sid_handle); +uint32_t sid_handle_sid_end_get(struct sid_handle * sid_handle); + +/******************************************** Network intersection adapter ********************************************/ +#define SC_ADAPTERS_MAX 128 + +int adapters_max_get(struct sc_main * sc, const char * key, uint32_t * adapters_max_out); diff --git a/service/src/node_etherfabric.c b/service/src/node_etherfabric.c index b959101..ca97771 100644 --- a/service/src/node_etherfabric.c +++ b/service/src/node_etherfabric.c @@ -9,46 +9,42 @@ #include <link_db.h> #include <mrb_define.h> #include <port_adapter_mapping.h> +#include <sc_metrics.h> #include <sc_node_common.h> #include <sc_trace.h> +#include <stdint.h> -/* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */ -#define LCORE_CACHE_SIZE 64 -#define NR_EF_PEER_ENTRIES 256 -#define NR_EF_PEER_MEMBER (NR_EF_PEER_ENTRIES + (RTE_MAX_LCORE - 1) * (LCORE_CACHE_SIZE - 1) + 1) - -/* Etherfabric ingress next node */ -enum -{ - EF_INGRESS_NEXT_CLASSIFIER = 0, - EF_INGRESS_NEXT_PKT_DROP, - EF_INGRESS_NEXT_MAX -}; - -/* Etherfabric egress next node */ -enum -{ - EF_EGRESS_NEXT_ETH_EGRESS = 0, - EF_EGRESS_NEXT_PKT_DROP, - EF_EGRESS_NEXT_MAX -}; - +/******************************************* Etherfabric adapter struct ***********************************************/ /* Etherfabric adapter mode */ enum ef_adapter_mode { - MODE_INVALID = 0, - MODE_VIRTUAL_WIRE, - MODE_TAP, + EF_MODE_INVALID = 0, + EF_MODE_VIRTUAL_WIRE, + EF_MODE_TAP, }; /* Etherfabric adapter struct */ struct ef_adapter { + uint16_t id; enum ef_adapter_mode mode; - uint32_t ef_adapter_id; - struct mr_dev_desc * listen_device; + struct mr_dev_desc * listening_device; +}; + +struct ef_adapter_handle +{ + uint16_t capacity; + uint16_t nr_adapters; + struct ef_adapter * adapters; }; +/********************************************** Etherfabric peer struct ***********************************************/ +/* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */ +#define LCORE_CACHE_SIZE 64 +#define SC_EF_PEER_ENTRIES 256 +// #define SC_EF_PEER_MEMBER (SC_EF_PEER_ENTRIES + (RTE_MAX_LCORE - 1) * (LCORE_CACHE_SIZE - 1) + 1) +#define SC_EF_PEER_CAPACITY_CALC(entries, cache_size) ((entries) + (RTE_MAX_LCORE - 1) * ((cache_size)-1) + 1) + /* ef_peer key */ union ef_peer_key { struct @@ -66,139 +62,336 @@ struct ef_peer struct rte_ether_addr ef_mac_addr; } __rte_cache_aligned; -/* Etherfabric main struct */ -struct node_ef_main +/* ef_peer handle */ +struct ef_peer_handle { - uint16_t nr_adapters; - uint16_t nr_global_links; - uint32_t nr_sids; - uint32_t sid_start; - uint32_t sid_end; - rte_atomic64_t tl_to_ef_peer_map[65536]; + uint32_t capacity; + uint32_t entries; + uint32_t remaining_entries; struct rte_hash * ef_peer_hash; - struct ef_adapter * ef_adapters; - struct link_db_ctx * link_db_ctx; struct ef_peer * ef_peers; }; -/* Etherfabric ingress drop reason */ -enum ef_ingress_drop_reason +/******************************************** Traffic Link Peer Map struct ********************************************/ +struct tl_to_ef_peer_map_handle { - EF_INGR_DROP_RSN_ADP_NONEXIST = 0, - EF_INGR_DROP_RSN_PRE_SID_ERR, - EF_INGR_DROP_RSN_EF_PEER_ADD_ERR, - EF_INGR_DROP_RSN_MAX + uint16_t capacity; + rte_atomic64_t * maps_table; }; -/* Etherfabric ingress drop reason string */ -char * ef_ingr_drop_rsn_str[EF_INGR_DROP_RSN_MAX] = {"drop_rsn_adapter_lookup_miss", "drop_rsn_sid_prepend_err", - "drop_rsn_ef_peer_lookup_miss"}; +/********************************************** Etherfabric main struct ***********************************************/ +/* Set the pkt offset */ +const static int ef_encap_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_udp_hdr) + sizeof(struct g_vxlan_hdr); -/* Etherfabric ingress stats struct */ -struct ef_ingress_stats +/* Etherfabric ingress next node */ +enum { - volatile uint64_t total_pkts; - volatile uint64_t pkts_per_batch; - volatile uint64_t to_classifier; - volatile uint64_t drop_reason[EF_INGR_DROP_RSN_MAX]; -} __rte_cache_aligned; + EF_INGR_NEXT_CLASSIFIER = 0, + EF_INGR_NEXT_PKT_DROP, + EF_INGR_NEXT_MAX +}; -/* Etherfabric egress drop reason */ -enum ef_egress_drop_reason +/* Etherfabric egress next node */ +enum { - EF_EGR_DROP_RSN_TAP_MODE = 0, - EF_EGR_DROP_RSN_INVALID_MODE, - EF_EGR_DROP_RSN_MAX + EF_EGR_NEXT_ETH_EGRESS = 0, + EF_EGR_NEXT_PKT_DROP, + EF_EGR_NEXT_MAX }; -/* Etherfabric egress drop reason string */ -char * ef_egr_drop_rsn_str[EF_EGR_DROP_RSN_MAX] = {"drop_rsn_tap_mode", "drop_rsn_invalid_mode"}; +/* Etherfabric ingress metrics key */ +enum ef_node_ingress_metrics_key +{ + EF_INGR_METRIC_TOT_PKTS = 0, + EF_INGR_METRIC_PKTS_PER_BATCH, + EF_INGR_METRIC_TO_CLASSIFIER, + EF_INGR_METRIC_DROP_ADP_NONEXIST, + EF_INGR_METRIC_DROP_PRE_SID_ERR, + EF_INGR_METRIC_DROP_EF_PEER_ADD_ERR, + EF_INGR_METRIC_DROP_TL_TO_EF_PEER_MAP_ERR, + EF_INGR_METRIC_MAX +}; -/* Etherfabric egress stats struct */ -struct ef_egress_stats +/* Etherfabric ingress metrics string */ +char * ef_ingr_metrics_str[EF_INGR_METRIC_MAX] = {"total_pkts", + "pkts_per_batch", + "to_classifier", + "drop_rsn_adapter_lookup_miss", + "drop_rsn_sid_prepend_err", + "drop_rsn_ef_peer_add_err", + "drop_rsn_tl_to_ef_peer_map_err"}; + +/* Etherfabric egress metrics key */ +enum ef_node_egress_metrics_key { - volatile uint64_t total_pkts; - volatile uint64_t pkts_per_batch; - volatile uint64_t vxlan_encap; - volatile uint64_t to_eth_egress; - volatile uint64_t drop_reason[EF_EGR_DROP_RSN_MAX]; -} __rte_cache_aligned; + EF_EGR_METRIC_TOT_PKTS = 0, + EF_EGR_METRIC_PKTS_PER_BATCH, + EF_EGR_METRIC_VXLAN_ENCAP, + EF_EGR_METRIC_TO_ETH_EGRESS, + EF_EGR_METRIC_DROP_RSN_TAP_MODE, + EF_EGR_METRIC_DROP_RSN_INVALID_MODE, + EF_EGR_METRIC_MAX +}; -/* Global etherfabric main and etherfabric max entry */ -static struct node_ef_main g_ef_main = {}; -static unsigned int nr_max_ef_adapters = 256; -static struct ef_ingress_stats ingress_stats_per_graph[RTE_MAX_LCORE] = {}; -static struct ef_egress_stats egress_stats_per_graph[RTE_MAX_LCORE] = {}; +/* Etherfabric egress metrics string */ +char * ef_egr_metrics_str[EF_EGR_METRIC_MAX] = {"total_pkts", "pkts_per_batch", "vxlan_encap", + "to_eth_egress", "drop_rsn_tap_mode", "drop_rsn_invalid_mode"}; -static inline struct node_ef_main * node_ef_main_get() +/* Etherfabric config handle */ +struct ef_config_handle { - return &g_ef_main; -} + uint16_t nr_adapters; + uint32_t sid_start; + uint32_t sid_end; + uint32_t ef_adapters_max; + uint32_t link_dbs_max; + struct ef_adapter * ef_adapters_data; +}; -/* Etherfabric adapters num get */ -unsigned int nr_max_ef_adapters_get() +/* Etherfabric node main struct */ +struct ef_node_main { - return nr_max_ef_adapters; -} + /* Number of graphs */ + uint16_t nr_graphs; -uint16_t ef_nr_adapters_get() + struct sid_handle * sid_handle; + struct ef_adapter_handle * ef_adapter_handle; + struct link_db_ctx * link_db_ctx; + struct ef_peer_handle * ef_peer_handle; + struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle; + + /* Etherfabric metrics handles */ + struct sc_metrics_handle ** ingress_metrics_handles; + struct sc_metrics_handle ** egress_metrics_handles; +} __rte_cache_aligned; + +/* Global variable for etherfabric management */ +static struct ef_node_main * g_ef_main = NULL; + +/******************************************** Etherfabric adapter func ************************************************/ +/** + * @brief Creates an ef_adapter_handle structure with the given capacity and adapter data. + * + * This function initializes an ef_adapter_handle structure to manage a collection of + * ef_adapter structures. It allocates memory for the handle and its adapters array based + * on the specified capacity. The function checks for invalid input conditions, such as + * zero capacity or a number of adapters that exceeds the capacity, and returns NULL + * if these conditions are met. + * + * @param adapters_data Pointer to an array of ef_adapter structures that contain the adapter data. + * @param capacity The maximum number of adapters that can be managed by the handle. + * @param nr_adapters The number of adapters provided in the adapters_data array. + * + * @return Pointer to the created ef_adapter_handle structure if successful, NULL otherwise. + */ +struct ef_adapter_handle * ef_adapter_handle_create(struct ef_adapter * adapters_data, uint16_t capacity, + uint16_t nr_adapters) { - struct node_ef_main * ef_main = node_ef_main_get(); - return ef_main->nr_adapters; + if (capacity == 0) + { + MR_ERROR("The capacity is 0."); + return NULL; + } + else if (nr_adapters > capacity) + { + MR_ERROR("The nr_adapters out of capacity."); + return NULL; + } + + assert(adapters_data != NULL); + + struct ef_adapter_handle * handle = ZMALLOC(sizeof(struct ef_adapter_handle)); + MR_VERIFY_MALLOC(handle); + + handle->capacity = capacity; + handle->nr_adapters = nr_adapters; + handle->adapters = ZMALLOC(sizeof(struct ef_adapter) * capacity); + MR_VERIFY_MALLOC(handle->adapters); + + for (int i = 0; i < capacity; i++) + { + handle->adapters[i].id = adapters_data[i].id; + handle->adapters[i].mode = adapters_data[i].mode; + handle->adapters[i].listening_device = adapters_data[i].listening_device; + } + + return handle; } -void ef_adapter_id_get(uint16_t * ef_adapter_ids, uint16_t nr_adapters) +/** + * @brief Deletes an ef_adapter_handle structure and frees its associated resources. + * + * This function releases the memory allocated for an ef_adapter_handle structure and + * its internal adapters array. It ensures that the handle and its adapters are properly + * freed, and sets the pointers to NULL to prevent dangling pointers. If the provided + * handle is NULL, an error is logged, and the function returns an error code. + * + * @param handle Pointer to the ef_adapter_handle structure to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if the handle is NULL. + */ +int ef_adapter_handle_delete(struct ef_adapter_handle * handle) { - uint16_t adapter_count = 0; - struct node_ef_main * ef_main = node_ef_main_get(); - - for (int i = 0; i < nr_max_ef_adapters; i++) + if (handle == NULL) { - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[i]; - if (ef_adapter->mode != MODE_INVALID) - { - ef_adapter_ids[adapter_count] = ef_adapter->ef_adapter_id; - adapter_count++; - } + MR_ERROR("The ef_adapter_handle is NULL."); + return RT_ERR; + } - if (adapter_count == nr_adapters) - { - return; - } + if (handle->adapters != NULL) + { + FREE(handle->adapters); + handle->adapters = NULL; } + + FREE(handle); + + return RT_SUCCESS; } -/* Etherfabric start sid get */ -uint32_t ef_sid_start_get() +/** + * @brief Retrieves the capacity of the ef_adapter_handle. + * + * This function returns the maximum number of adapters that the specified ef_adapter_handle + * can manage. The function asserts that the handle is not NULL before accessing its capacity. + * + * @param handle Pointer to the ef_adapter_handle structure. + * + * @return The capacity of the ef_adapter_handle. + */ +uint16_t ef_adapter_handle_capacity_get(struct ef_adapter_handle * handle) { - struct node_ef_main * ef_main = node_ef_main_get(); - return ef_main->sid_start; + assert(handle != NULL); + return handle->capacity; } -/* Set the pkt offset */ -const static int ef_encap_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + - sizeof(struct rte_udp_hdr) + sizeof(struct g_vxlan_hdr); +/** + * @brief Retrieves the number of adapters currently in the ef_adapter_handle. + * + * This function returns the current number of adapters stored in the specified ef_adapter_handle. + * The function asserts that the handle is not NULL before accessing its number of adapters. + * + * @param handle Pointer to the ef_adapter_handle structure. + * + * @return The number of adapters currently in the ef_adapter_handle. + */ +uint16_t ef_adapter_handle_nr_adapters_get(struct ef_adapter_handle * handle) +{ + assert(handle != NULL); + return handle->nr_adapters; +} -/* Etherfabric adapter id check */ -int ef_adapter_id_check(uint32_t ef_adapter_id) +/** + * @brief Retrieves a pointer to an ef_adapter by its ID within the ef_adapter_handle. + * + * This inline function returns a pointer to the ef_adapter structure within the ef_adapter_handle + * corresponding to the specified adapter ID. The function asserts that the handle is not NULL + * and that the adapter ID is within the valid range of the handle's capacity. + * + * @param handle Pointer to the ef_adapter_handle structure. + * @param adapter_id The ID of the adapter to retrieve. + * + * @return Pointer to the ef_adapter structure with the specified ID. + */ +static inline struct ef_adapter * __ef_adapter_handle_adapter_get_by_id(struct ef_adapter_handle * handle, + uint16_t adapter_id) { - /* Etherfabric rule id is continuous */ - if (ef_adapter_id >= nr_max_ef_adapters_get()) - return RT_ERR; + assert(handle != NULL); + assert(adapter_id < handle->capacity); - struct node_ef_main * ef_main = node_ef_main_get(); - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[ef_adapter_id]; + return &handle->adapters[adapter_id]; +} - if (ef_adapter->mode == MODE_INVALID) - return RT_ERR; +/** + * @brief Retrieves a pointer to an ef_adapter by its ID within the ef_adapter_handle. + * + * This function returns a pointer to the ef_adapter structure within the ef_adapter_handle + * corresponding to the specified adapter ID. It calls an internal function + * `__ef_adapter_handle_adapter_get_by_id` to perform the actual retrieval. The function asserts + * that the handle is not NULL and that the adapter ID is within the valid range of the handle's capacity. + * + * @param handle Pointer to the ef_adapter_handle structure. + * @param adapter_id The ID of the adapter to retrieve. + * + * @return Pointer to the ef_adapter structure with the specified ID. + */ +struct ef_adapter * ef_adapter_handle_adapter_get_by_id(struct ef_adapter_handle * handle, uint16_t adapter_id) +{ + assert(handle != NULL); + assert(adapter_id < handle->capacity); - if (ef_adapter->ef_adapter_id != ef_adapter_id) - return RT_ERR; + return __ef_adapter_handle_adapter_get_by_id(handle, adapter_id); +} - return RT_SUCCESS; +/** + * @brief Retrieves the ID of the specified ef_adapter. + * + * This function returns the ID of the given ef_adapter structure. The function asserts + * that the ef_adapter pointer is not NULL before accessing its ID. + * + * @param ef_adapter Pointer to the ef_adapter structure. + * + * @return The ID of the specified ef_adapter. + */ +uint16_t ef_adapter_id_get(struct ef_adapter * ef_adapter) +{ + assert(ef_adapter != NULL); + return ef_adapter->id; } -/* ef_peer hash crc */ +/** + * @brief Looks up an ef_adapter in the ef_adapter_handle by destination address. + * + * This function searches through the ef_adapter structures within the given ef_adapter_handle + * to find an adapter whose listening device matches the specified destination address (`dst_addr`). + * If a match is found, the ID of the matching adapter is stored in `out_ef_adapter_id`, and the + * function returns `RT_SUCCESS`. If no match is found, the function returns `RT_ERR`. The function + * asserts that the handle and the output pointer (`out_ef_adapter_id`) are not NULL. + * + * @param handle Pointer to the ef_adapter_handle structure containing the adapters. + * @param dst_addr The destination address to match against the adapters' listening devices. + * @param out_ef_adapter_id Pointer to a variable where the ID of the matching adapter will be stored. + * + * @return RT_SUCCESS if a matching adapter is found, RT_ERR otherwise. + */ +int ef_adapter_handle_adapter_lookup(struct ef_adapter_handle * handle, uint32_t dst_addr, uint16_t * out_ef_adapter_id) +{ + assert(handle != NULL); + assert(out_ef_adapter_id != NULL); + + for (uint16_t index = 0; index < handle->capacity; index++) + { + struct ef_adapter * ef_adapter = __ef_adapter_handle_adapter_get_by_id(handle, index); + + if (ef_adapter->mode == EF_MODE_INVALID) + continue; + + if (dst_addr == ef_adapter->listening_device->in_addr.s_addr) + { + *out_ef_adapter_id = ef_adapter->id; + return RT_SUCCESS; + } + } + return RT_ERR; +} + +/*********************************************** Etherfabric peer func ************************************************/ +/** + * @brief Computes a hash value for an ef_peer based on its IP address and MAC address. + * + * This inline function calculates a CRC32-based hash value for a given `ef_peer_key`, which + * consists of an IP source address and a MAC source address. The function primarily uses the + * IP address (`ip_src`) as the key for the hash. It also includes an unused section where + * the MAC address is incorporated into the hash calculation. The function returns the computed + * hash value. + * + * @param data Pointer to the `ef_peer_key` structure containing the IP and MAC addresses. + * @param data_len Unused parameter indicating the length of the data. + * @param init_val Initial value for the CRC32 hash computation. + * + * @return The computed CRC32 hash value. + */ static inline uint32_t ef_peer_hash_crc(const void * data, __rte_unused uint32_t data_len, uint32_t init_val) { /* use the etherfabric's ip addr as key */ @@ -215,12 +408,25 @@ static inline uint32_t ef_peer_hash_crc(const void * data, __rte_unused uint32_t return init_val; } -/* Initialize exact match (hash) parameters */ -int ef_peer_setup_hash(struct node_ef_main * ef_main) +/** + * @brief Creates a hash table for managing ef_peer entries. + * + * This function initializes and creates an RTE hash table specifically for storing and + * managing `ef_peer` entries. The function sets up the parameters for the hash table, + * including the number of entries, key length, hash function, and additional flags for + * memory and concurrency support. The hash function used is `ef_peer_hash_crc`. If the + * hash table cannot be created, an error is logged, and the function returns `NULL`. + * + * @param entries The maximum number of entries that the hash table can contain. + * + * @return Pointer to the created RTE hash table if successful, NULL otherwise. + */ +struct rte_hash * ef_peer_hash_create(uint32_t entries) { struct rte_hash_parameters ef_peer_hash_params = { .name = "ef_peer_hash", - .entries = NR_EF_PEER_ENTRIES, + .entries = entries, + //.entries = SC_EF_PEER_ENTRIES, .key_len = sizeof(union ef_peer_key), .hash_func = ef_peer_hash_crc, .hash_func_init_val = 0, @@ -229,25 +435,596 @@ int ef_peer_setup_hash(struct node_ef_main * ef_main) RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF, }; - ef_main->ef_peer_hash = rte_hash_create(&ef_peer_hash_params); - if (ef_main->ef_peer_hash != NULL) + struct rte_hash * ef_peer_hash = rte_hash_create(&ef_peer_hash_params); + if (ef_peer_hash == NULL) + { + MR_ERROR("Unable to create the ef_peer hash on socket 0 ."); + return NULL; + } + + return ef_peer_hash; +} + +/** + * @brief Deletes the ef_peer hash table and frees its associated resources. + * + * This function frees the memory allocated for the ef_peer hash table. It checks if the + * provided hash table pointer is NULL, logs an error if it is, and returns an error code. + * If the pointer is valid, the hash table is freed, and the function returns `RT_SUCCESS`. + * + * @param ef_peer_hash Pointer to the RTE hash table to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if the hash table is NULL. + */ +int ef_peer_hash_delete(struct rte_hash * ef_peer_hash) +{ + if (ef_peer_hash == NULL) + { + MR_ERROR("The ef_peer_hash is NULL."); + return RT_ERR; + } + + rte_hash_free(ef_peer_hash); + return RT_SUCCESS; +} + +/** + * @brief Deletes an ef_peer_handle structure and frees its associated resources. + * + * This function releases the memory allocated for an `ef_peer_handle` structure and its + * associated resources, including the `ef_peer_hash` hash table and the `ef_peers` array. + * It checks if the `ef_peer_handle` is NULL and logs an error if it is. If valid, it + * proceeds to delete the hash table and free the peers array before freeing the handle itself. + * The function returns `RT_SUCCESS` upon successful deletion, or `RT_ERR` if the handle is NULL. + * + * @param ef_peer_handle Pointer to the ef_peer_handle structure to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if the handle is NULL. + */ +int ef_peer_handle_delete(struct ef_peer_handle * ef_peer_handle) +{ + if (ef_peer_handle == NULL) + { + MR_ERROR("The ef_peer_handle is NULL."); + return RT_ERR; + } + + if (ef_peer_handle->ef_peer_hash != NULL) + { + ef_peer_hash_delete(ef_peer_handle->ef_peer_hash); + ef_peer_handle->ef_peer_hash = NULL; + } + + if (ef_peer_handle->ef_peers != NULL) + { + FREE(ef_peer_handle->ef_peers); + ef_peer_handle->ef_peers = NULL; + } + + FREE(ef_peer_handle); + + return RT_SUCCESS; +} + +/** + * @brief Creates an ef_peer_handle structure with the specified number of entries. + * + * This function initializes and creates an `ef_peer_handle` structure to manage `ef_peer` entries. + * It first calculates the capacity based on the number of entries and checks if the entries value + * is valid. The function allocates memory for the `ef_peer_handle` structure and its associated + * peers array, initializing the atomic state for each peer. It then creates the associated `ef_peer_hash` + * table. If any allocation or creation fails, appropriate error messages are logged, and the resources + * are cleaned up before returning `NULL`. + * + * @param entries The number of `ef_peer` entries to manage within the handle. + * + * @return Pointer to the created `ef_peer_handle` structure if successful, NULL otherwise. + */ +struct ef_peer_handle * ef_peer_handle_create(uint32_t entries) +{ + if (entries == 0) + { + MR_ERROR("The ef_peer entries value is 0."); + return NULL; + } + + uint32_t capacity = SC_EF_PEER_CAPACITY_CALC(entries, LCORE_CACHE_SIZE); + if (entries >= capacity) + { + MR_ERROR("The ef_peer entries value is too large."); + return NULL; + } + + struct ef_peer_handle * ef_peer_handle = ZMALLOC(sizeof(struct ef_peer_handle)); + MR_VERIFY_MALLOC(ef_peer_handle); + + struct ef_peer * ef_peers = ZMALLOC(sizeof(struct ef_peer) * capacity); + MR_VERIFY_MALLOC(ef_peers); + + ef_peer_handle->capacity = capacity; + ef_peer_handle->entries = entries; + ef_peer_handle->remaining_entries = entries; + ef_peer_handle->ef_peers = ef_peers; + + for (int i = 0; i < capacity; i++) + { + rte_atomic64_init(&ef_peers[i].state); + } + + ef_peer_handle->ef_peer_hash = ef_peer_hash_create(entries); + if (ef_peer_handle->ef_peer_hash == NULL) + { + MR_ERROR("Failed to create the ef_peer hash."); + ef_peer_handle_delete(ef_peer_handle); + return NULL; + } + + return ef_peer_handle; +} + +/** + * @brief Retrieves the capacity of the ef_peer_handle. + * + * This function returns the maximum number of `ef_peer` entries that the specified + * `ef_peer_handle` can manage. The function asserts that the handle is not NULL + * before accessing its capacity. + * + * @param handle Pointer to the `ef_peer_handle` structure. + * + * @return The capacity of the `ef_peer_handle`. + */ +uint32_t ef_peer_handle_capacity_get(struct ef_peer_handle * handle) +{ + assert(handle != NULL); + return handle->capacity; +} + +/** + * @brief Retrieves the number of entries in the ef_peer_handle. + * + * This function returns the number of `ef_peer` entries currently managed by the specified + * `ef_peer_handle`. The function asserts that the handle is not NULL before accessing its entries. + * + * @param handle Pointer to the `ef_peer_handle` structure. + * + * @return The number of entries in the `ef_peer_handle`. + */ +uint32_t ef_peer_handle_entries_get(struct ef_peer_handle * handle) +{ + assert(handle != NULL); + return handle->entries; +} + +/** + * @brief Retrieves the number of remaining entries in the ef_peer_handle. + * + * This function returns the number of remaining `ef_peer` entries that can be added to the specified + * `ef_peer_handle`. The function asserts that the handle is not NULL before accessing its remaining entries. + * + * @param handle Pointer to the `ef_peer_handle` structure. + * + * @return The number of remaining entries in the `ef_peer_handle`. + */ +uint32_t ef_peer_handle_remaining_entries_get(struct ef_peer_handle * handle) +{ + assert(handle != NULL); + return handle->remaining_entries; +} + +/** + * @brief Retrieves a pointer to an ef_peer by its index within the ef_peer_handle. + * + * This inline function returns a pointer to the `ef_peer` structure within the specified + * `ef_peer_handle` corresponding to the given `ef_peer_index`. The function asserts that + * the handle is not NULL and that the index is within the valid range of the handle's capacity. + * + * @param handle Pointer to the `ef_peer_handle` structure. + * @param ef_peer_index The index of the peer to retrieve. + * + * @return Pointer to the `ef_peer` structure at the specified index. + */ +static inline struct ef_peer * __ef_peer_handle_peer_get(struct ef_peer_handle * handle, uint16_t ef_peer_index) +{ + assert(handle != NULL); + assert(ef_peer_index < handle->capacity); + + return &handle->ef_peers[ef_peer_index]; +} + +/** + * @brief Retrieves a pointer to an ef_peer by its index within the ef_peer_handle. + * + * This function returns a pointer to the `ef_peer` structure within the specified + * `ef_peer_handle` corresponding to the given `ef_peer_index`. It simply calls the + * internal function `__ef_peer_handle_peer_get` to perform the retrieval. + * + * @param handle Pointer to the `ef_peer_handle` structure. + * @param ef_peer_index The index of the peer to retrieve. + * + * @return Pointer to the `ef_peer` structure at the specified index. + */ +struct ef_peer * ef_peer_handle_peer_get(struct ef_peer_handle * handle, uint16_t ef_peer_index) +{ + return __ef_peer_handle_peer_get(handle, ef_peer_index); +} + +/** + * @brief Looks up an ef_peer in the ef_peer_handle by its key. + * + * This inline function searches for an `ef_peer` within the specified `ef_peer_handle` using + * the given `ef_peer_key`. It utilizes the `rte_hash_lookup` function to find the index + * corresponding to the key in the hash table. The function returns the index of the found + * peer or a negative value if the key is not found. + * + * @param handle Pointer to the `ef_peer_handle` structure containing the hash table. + * @param key Pointer to the `ef_peer_key` used for lookup. + * + * @return The index of the found `ef_peer`, or a negative value if the key is not found. + */ +static inline int __ef_peer_handle_peer_lookup(struct ef_peer_handle * handle, const union ef_peer_key * key) +{ + return rte_hash_lookup(handle->ef_peer_hash, (const void *)key); +} + +/** + * @brief Looks up an ef_peer in the ef_peer_handle by its key. + * + * This function searches for an `ef_peer` within the specified `ef_peer_handle` using the + * provided `ef_peer_key`. It calls the internal function `__ef_peer_handle_peer_lookup` + * to perform the actual lookup using the hash table. The function returns the index of the + * found peer or a negative value if the key is not found. + * + * @param handle Pointer to the `ef_peer_handle` structure containing the hash table. + * @param key Pointer to the `ef_peer_key` used for lookup. + * + * @return The index of the found `ef_peer`, or a negative value if the key is not found. + */ +int ef_peer_handle_peer_lookup(struct ef_peer_handle * handle, const union ef_peer_key * key) +{ + return __ef_peer_handle_peer_lookup(handle, key); +} + +/** + * @brief Adds a new ef_peer to the ef_peer_handle using the specified key. + * + * This function attempts to add a new `ef_peer` to the `ef_peer_handle` using the provided + * `ef_peer_key`. It first adds the key to the hash table using `rte_hash_add_key`. If the + * addition is successful, the function retrieves the corresponding `ef_peer` structure and + * initializes its state and properties. The number of remaining entries in the handle is + * then decremented. If the addition is successful, information about the new `ef_peer` is + * logged, including its IP and MAC addresses. The function returns the index of the added + * peer if successful, or `RT_ERR` if the addition fails. + * + * @param handle Pointer to the `ef_peer_handle` structure where the peer will be added. + * @param key Pointer to the `ef_peer_key` structure containing the peer's IP and MAC addresses. + * + * @return The index of the added `ef_peer` if successful, or `RT_ERR` if the addition fails. + */ +int ef_peer_handle_peer_add(struct ef_peer_handle * handle, const union ef_peer_key * key) +{ + /* Add the new ef_peer */ + int ret = rte_hash_add_key(handle->ef_peer_hash, (void *)key); + + if (likely(ret >= 0)) { + /* Set the ef_peer state */ + struct ef_peer * ef_peer = __ef_peer_handle_peer_get(handle, ret); + if (rte_atomic64_test_and_set(&ef_peer->state)) + { + /* Save the ef_peer info */ + ef_peer->ef_ip_addr = key->ip_src; + rte_ether_addr_copy(&key->mac_src, &ef_peer->ef_mac_addr); + + /* Decrease the remaining entries */ + handle->remaining_entries--; + + /* Dump ef_peer for new add */ + char str_in_addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &ef_peer->ef_ip_addr, str_in_addr, sizeof(str_in_addr)); + + char str_mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; + rte_ether_format_addr(str_mac_addr, sizeof(str_mac_addr), &ef_peer->ef_mac_addr); + + MR_INFO("Ef Peer add, index %d, core %u, ip addr:%s, mac addr:%s, remaining entries:%u", ret, + rte_lcore_id(), str_in_addr, str_mac_addr, handle->remaining_entries); + } + + return ret; + } + + return RT_ERR; +} + +/** + * @brief Retrieves the IP address of the specified ef_peer. + * + * This function returns the IP address of the given `ef_peer` structure. The function asserts + * that the `ef_peer` pointer is not NULL before accessing its IP address. + * + * @param ef_peer Pointer to the `ef_peer` structure. + * + * @return The IP address of the specified `ef_peer`. + */ +uint32_t ef_peer_ip_addr_get(struct ef_peer * ef_peer) +{ + assert(ef_peer != NULL); + return ef_peer->ef_ip_addr; +} + +/** + * @brief Retrieves the MAC address of the specified ef_peer. + * + * This function returns a pointer to the MAC address of the given `ef_peer` structure. The function + * asserts that the `ef_peer` pointer is not NULL before accessing its MAC address. + * + * @param ef_peer Pointer to the `ef_peer` structure. + * + * @return Pointer to the MAC address of the specified `ef_peer`. + */ +struct rte_ether_addr * ef_peer_mac_addr_get(struct ef_peer * ef_peer) +{ + assert(ef_peer != NULL); + return &ef_peer->ef_mac_addr; +} + +/********************************************* Traffic Link Peer Map func *********************************************/ +/** + * @brief Creates a tl_to_ef_peer_map_handle structure with the specified capacity. + * + * This function initializes and allocates memory for a `tl_to_ef_peer_map_handle` structure, + * which maps TL peers to EF peers. The function ensures the provided capacity is not zero + * and allocates memory for the handle and its internal maps table. Each entry in the maps + * table is initialized with an atomic value of -1. If any allocation fails, an error is + * logged, and the function returns NULL. + * + * @param capacity The maximum number of entries in the maps table. + * + * @return Pointer to the created `tl_to_ef_peer_map_handle` structure if successful, NULL otherwise. + */ +struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle_create(uint16_t capacity) +{ + if (capacity == 0) + { + MR_ERROR("The capacity is 0."); + return NULL; + } + + struct tl_to_ef_peer_map_handle * handle = ZMALLOC(sizeof(struct tl_to_ef_peer_map_handle)); + MR_VERIFY_MALLOC(handle); + + handle->capacity = capacity; + handle->maps_table = ZMALLOC(sizeof(rte_atomic64_t) * capacity); + MR_VERIFY_MALLOC(handle->maps_table); + + for (int i = 0; i < capacity; i++) + { + rte_atomic64_init(&handle->maps_table[i]); + rte_atomic64_set(&handle->maps_table[i], -1); + } + + return handle; +} + +/** + * @brief Deletes a tl_to_ef_peer_map_handle structure and frees its associated resources. + * + * This function releases the memory allocated for a `tl_to_ef_peer_map_handle` structure + * and its internal maps table. It checks if the handle is NULL and logs an error if it is. + * If valid, it frees the maps table and the handle itself. The function returns `RT_SUCCESS` + * upon successful deletion, or `RT_ERR` if the handle is NULL. + * + * @param handle Pointer to the `tl_to_ef_peer_map_handle` structure to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if the handle is NULL. + */ +int tl_to_ef_peer_map_handle_delete(struct tl_to_ef_peer_map_handle * handle) +{ + if (handle == NULL) + { + MR_ERROR("Invalid argument: handle is NULL."); + return RT_ERR; + } + + if (handle->maps_table != NULL) + { + FREE(handle->maps_table); + handle->maps_table = NULL; + } + + FREE(handle); + + return RT_SUCCESS; +} + +/** + * @brief Associates a traffic link ID with an ef_peer index in the tl_to_ef_peer_map_handle. + * + * This inline function sets the association between a `traffic_link_id` and an `ef_peer_index` + * in the `tl_to_ef_peer_map_handle`. It checks that the `traffic_link_id` is within the valid + * range of the handle's capacity before setting the value in the maps table. The function returns + * `RT_SUCCESS` if the association is successful, or `RT_ERR` if the `traffic_link_id` is out of bounds. + * + * @param handle Pointer to the `tl_to_ef_peer_map_handle` structure. + * @param traffic_link_id The traffic link ID to associate. + * @param ef_peer_index The ef_peer index to associate with the traffic link ID. + * + * @return RT_SUCCESS on successful association, RT_ERR if the `traffic_link_id` is out of bounds. + */ +static inline int __tl_to_ef_peer_map_handle_associate(struct tl_to_ef_peer_map_handle * handle, + uint16_t traffic_link_id, int ef_peer_index) +{ + assert(handle != NULL); + + if (unlikely(traffic_link_id >= handle->capacity)) + { + return RT_ERR; + } + + rte_atomic64_set(&handle->maps_table[traffic_link_id], ef_peer_index); + + return RT_SUCCESS; +} + +/** + * @brief Associates a traffic link ID with an ef_peer index in the tl_to_ef_peer_map_handle. + * + * This function sets the association between a `traffic_link_id` and an `ef_peer_index` + * in the `tl_to_ef_peer_map_handle` by calling the internal function `__tl_to_ef_peer_map_handle_associate`. + * + * @param handle Pointer to the `tl_to_ef_peer_map_handle` structure. + * @param traffic_link_id The traffic link ID to associate. + * @param ef_peer_index The ef_peer index to associate with the traffic link ID. + * + * @return RT_SUCCESS on successful association, RT_ERR if the `traffic_link_id` is out of bounds. + */ +int tl_to_ef_peer_map_handle_associate(struct tl_to_ef_peer_map_handle * handle, uint16_t traffic_link_id, + int ef_peer_index) +{ + return __tl_to_ef_peer_map_handle_associate(handle, traffic_link_id, ef_peer_index); +} + +/** + * @brief Retrieves the capacity of the tl_to_ef_peer_map_handle. + * + * This function returns the maximum number of traffic link IDs that can be mapped within + * the specified `tl_to_ef_peer_map_handle`. The function asserts that the handle is not NULL + * before accessing its capacity. + * + * @param handle Pointer to the `tl_to_ef_peer_map_handle` structure. + * + * @return The capacity of the `tl_to_ef_peer_map_handle`. + */ +uint16_t tl_to_ef_peer_map_handle_capacity_get(struct tl_to_ef_peer_map_handle * handle) +{ + assert(handle != NULL); + return handle->capacity; +} + +/** + * @brief Retrieves the EF peer index associated with a given traffic link ID. + * + * This function searches for the EF peer index associated with the specified `traffic_link_id` + * within the `tl_to_ef_peer_map_handle`. If the handle is NULL or the `traffic_link_id` is out + * of range, the function returns `RT_ERR`. If the `traffic_link_id` is valid, the associated + * EF peer index is stored in `out_ef_peer_index`, and the function returns `RT_SUCCESS`. + * + * @param handle Pointer to the `tl_to_ef_peer_map_handle` structure. + * @param traffic_link_id The traffic link ID to look up. + * @param out_ef_peer_index Pointer to where the associated EF peer index will be stored. + * + * @return RT_SUCCESS if the EF peer index is successfully retrieved, RT_ERR otherwise. + */ +int tl_to_ef_peer_map_handle_get_ef_peer_index_by_tl_id(struct tl_to_ef_peer_map_handle * handle, + uint16_t traffic_link_id, uint16_t * out_ef_peer_index) +{ + if (handle == NULL) + { + return RT_ERR; + } + + if (unlikely(traffic_link_id < handle->capacity)) + { + *out_ef_peer_index = rte_atomic64_read(&handle->maps_table[traffic_link_id]); return RT_SUCCESS; } - MR_ERROR("Unable to create the ef_peer hash on socket 0 ."); return RT_ERR; } -/* Parsing the etherfabric adapter config */ -int parser_ef_adapter_config(struct sc_main * sc, struct node_ef_main * ef_main) +/*********************************************** Etherfabric main func ************************************************/ +/** + * @brief Creates an ef_config_handle structure with the specified maximum number of EF adapters. + * + * This function initializes and allocates memory for an `ef_config_handle` structure, which holds + * configuration data for EF adapters. It allocates memory for the handle itself and for the array + * that stores EF adapter data. The function asserts that the maximum number of adapters is greater + * than zero and verifies that the memory allocations are successful. + * + * @param ef_adapters_max The maximum number of EF adapters to be managed within the handle. + * + * @return Pointer to the created `ef_config_handle` structure if successful, NULL otherwise. + */ +struct ef_config_handle * ef_config_handle_create(uint32_t ef_adapters_max) { + assert(ef_adapters_max > 0); + + struct ef_config_handle * cfg_handle = ZMALLOC(sizeof(struct ef_config_handle)); + MR_VERIFY_MALLOC(cfg_handle); + + cfg_handle->ef_adapters_data = ZMALLOC(sizeof(struct ef_adapter) * ef_adapters_max); + MR_VERIFY_MALLOC(cfg_handle->ef_adapters_data); + + cfg_handle->ef_adapters_max = ef_adapters_max; + return cfg_handle; +} + +/** + * @brief Deletes an ef_config_handle structure and frees its associated resources. + * + * This function releases the memory allocated for an `ef_config_handle` structure and its + * associated EF adapters data. It checks if the handle or its data is NULL and logs an error + * if either is NULL. If valid, the function frees the adapters data and the handle itself. + * The function returns `RT_SUCCESS` upon successful deletion, or `RT_ERR` if the handle or + * its data is NULL. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if the handle or its data is NULL. + */ +int ef_config_handle_delete(struct ef_config_handle * cfg_handle) +{ + if (cfg_handle == NULL) + { + MR_ERROR("The ef_node_cfg is NULL."); + return RT_ERR; + } + + if (cfg_handle->ef_adapters_data == NULL) + { + MR_ERROR("The ef_node_cfg->ef_adapters_data is NULL."); + return RT_ERR; + } + + FREE(cfg_handle->ef_adapters_data); + cfg_handle->ef_adapters_data = NULL; + + FREE(cfg_handle); + + return RT_SUCCESS; +} + +/** + * @brief Parses the Etherfabric adapter configuration from the specified configuration file. + * + * This function reads and parses the configuration file to load the settings for Etherfabric + * adapters. It retrieves the maximum number of link databases, SID start and end values, + * and iterates through the configuration sections to load adapter mode, adapter ID, and + * listening device information. The function checks for valid configurations and logs errors + * if any invalid configurations are found. It also checks that the number of adapters does not + * exceed the SID capacity. The parsed data is saved into the `ef_config_handle` structure. + * + * @param sc Pointer to the `sc_main` structure containing the configuration file and device manager. + * @param cfg_handle Pointer to the `ef_config_handle` structure where the parsed data will be stored. + * + * @return RT_SUCCESS if the configuration is successfully parsed, RT_ERR otherwise. + */ +int ef_config_parse(struct sc_main * sc, struct ef_config_handle * cfg_handle) +{ + /* Get the max ef adapters */ + uint32_t link_dbs_max = 0; + MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_link_dbs", &link_dbs_max, 64); + if (link_dbs_max == 0) + { + MR_ERROR("The 'nr_max_link_dbs' is invalid."); + return RT_ERR; + } + /* Get sid range start */ - uint32_t sid_start; + uint32_t sid_start = 0; MESA_load_profile_uint_def(sc->local_cfgfile, "ef_adapters", "sid_start", &sid_start, 100); /* Get sid range end */ - uint32_t sid_end; + uint32_t sid_end = 0; MESA_load_profile_uint_def(sc->local_cfgfile, "ef_adapters", "sid_end", &sid_end, 200); /* Check the sid range */ @@ -258,20 +1035,21 @@ int parser_ef_adapter_config(struct sc_main * sc, struct node_ef_main * ef_main) } /* Parsing all config */ - int ret; uint16_t nr_adapters = 0; - for (int index = 0; index < nr_max_ef_adapters; index++) + for (int index = 0; index < cfg_handle->ef_adapters_max; index++) { char str_conf_section[MR_STRING_MAX] = {}; snprintf(str_conf_section, sizeof(str_conf_section), "ef_adapter:%d", index); /* Get etherfabric adapter mode */ uint32_t mode; - ret = MESA_load_profile_uint_nodef(sc->local_cfgfile, str_conf_section, "mode", &mode); + int ret = MESA_load_profile_uint_nodef(sc->local_cfgfile, str_conf_section, "mode", &mode); if (ret < 0) + { continue; + } - if ((mode != MODE_VIRTUAL_WIRE) && (mode != MODE_TAP)) + if ((mode != EF_MODE_VIRTUAL_WIRE) && (mode != EF_MODE_TAP)) { MR_ERROR("The : %s 'mode' is invalid: %u", str_conf_section, mode); return RT_ERR; @@ -287,7 +1065,7 @@ int parser_ef_adapter_config(struct sc_main * sc, struct node_ef_main * ef_main) return RT_ERR; } - if (ef_adapter_id >= nr_max_ef_adapters) + if (ef_adapter_id >= cfg_handle->ef_adapters_max) { MR_ERROR("The : %s 'ef_adapter_id' is invalid: %u", str_conf_section, ef_adapter_id); return RT_ERR; @@ -321,224 +1099,821 @@ int parser_ef_adapter_config(struct sc_main * sc, struct node_ef_main * ef_main) port_adapter_mapping_insert(dev_desc->port_id, ADAPTER_TYPE_EF); /* Save The Listen Device Port Index */ - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[ef_adapter_id]; + struct ef_adapter * ef_adapter = &cfg_handle->ef_adapters_data[ef_adapter_id]; + ef_adapter->id = ef_adapter_id; ef_adapter->mode = mode; - ef_adapter->ef_adapter_id = ef_adapter_id; - ef_adapter->listen_device = dev_desc; + ef_adapter->listening_device = dev_desc; nr_adapters++; } /* Check nr adapter */ - uint32_t nr_sids = sid_end - sid_start + 1; - if (nr_adapters > nr_sids) + uint32_t sid_capacity = sid_end - sid_start + 1; + if (nr_adapters > sid_capacity) { - MR_ERROR("Etherfabric adapters num:%u out of sid num: %u .", nr_adapters, nr_sids); + MR_ERROR("Etherfabric adapters num:%u out of sid num: %u .", nr_adapters, sid_capacity); return RT_ERR; } - /* Inserter sid to forwarder table */ - for (int i = 0; i < nr_max_ef_adapters; i++) + /* Save the etherfabric adapter config date */ + cfg_handle->nr_adapters = nr_adapters; + cfg_handle->sid_start = sid_start; + cfg_handle->sid_end = sid_end; + cfg_handle->link_dbs_max = link_dbs_max; + + return RT_SUCCESS; +} + +/** + * @brief Retrieves the EF adapters data array from the ef_config_handle. + * + * This function returns a pointer to the array of `ef_adapter` structures stored within the + * specified `ef_config_handle`. The function asserts that the handle is not NULL before + * accessing the data. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return Pointer to the array of `ef_adapter` structures. + */ +struct ef_adapter * ef_config_handle_adapters_data_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->ef_adapters_data; +} + +/** + * @brief Retrieves the number of adapters currently configured in the ef_config_handle. + * + * This function returns the number of EF adapters that have been successfully configured + * within the specified `ef_config_handle`. The function asserts that the handle is not NULL + * before accessing the number of adapters. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return The number of configured EF adapters. + */ +uint16_t ef_config_handle_nr_adapters_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->nr_adapters; +} + +/** + * @brief Retrieves the starting SID (Service ID) from the ef_config_handle. + * + * This function returns the starting Service ID (SID) for the EF adapters as specified in the + * configuration stored within the `ef_config_handle`. The function asserts that the handle is + * not NULL before accessing the SID start value. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return The starting SID for the EF adapters. + */ +uint32_t ef_config_handle_sid_start_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->sid_start; +} + +/** + * @brief Retrieves the ending SID (Service ID) from the ef_config_handle. + * + * This function returns the ending Service ID (SID) for the EF adapters as specified in the + * configuration stored within the `ef_config_handle`. The function asserts that the handle is + * not NULL before accessing the SID end value. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return The ending SID for the EF adapters. + */ +uint32_t ef_config_handle_sid_end_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->sid_end; +} + +/** + * @brief Retrieves the maximum number of EF adapters that can be configured in the ef_config_handle. + * + * This function returns the maximum number of EF adapters that the specified `ef_config_handle` + * can manage. The function asserts that the handle is not NULL before accessing the maximum value. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return The maximum number of EF adapters that can be configured. + */ +uint32_t ef_config_handle_ef_adapters_max_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->ef_adapters_max; +} + +/** + * @brief Retrieves the maximum number of link databases in the ef_config_handle. + * + * This function returns the maximum number of link databases that can be configured + * within the specified `ef_config_handle`. The function asserts that the handle is not NULL + * before accessing the maximum number of link databases. + * + * @param cfg_handle Pointer to the `ef_config_handle` structure. + * + * @return The maximum number of link databases. + */ +uint32_t ef_config_handle_link_dbs_max_get(struct ef_config_handle * cfg_handle) +{ + assert(cfg_handle != NULL); + return cfg_handle->link_dbs_max; +} + +/** + * @brief Retrieves a pointer to the global ef_node_main structure (internal function). + * + * This inline function returns a pointer to the global `ef_node_main` structure. It is an + * internal helper function used to access the global variable `g_ef_main`. + * + * @return Pointer to the global `ef_node_main` structure. + */ +static inline struct ef_node_main * __g_ef_node_main_get(void) +{ + return g_ef_main; +} + +/** + * @brief Retrieves a pointer to the global ef_node_main structure. + * + * This function returns a pointer to the global `ef_node_main` structure by calling the + * internal helper function `__g_ef_node_main_get`. It provides external access to the + * global variable `g_ef_main`. + * + * @return Pointer to the global `ef_node_main` structure. + */ +struct ef_node_main * g_ef_node_main_get(void) +{ + return __g_ef_node_main_get(); +} + +/** + * @brief Sets the global ef_node_main structure. + * + * This inline function assigns the provided `ef_node_main` structure to the global variable + * `g_ef_main`. It is used to update the global state with the new EF node main configuration. + * + * @param ef_main Pointer to the `ef_node_main` structure to be set as the global instance. + * + * @return RT_SUCCESS indicating the operation was successful. + */ +static inline int g_ef_node_main_set(struct ef_node_main * ef_main) +{ + g_ef_main = ef_main; + return RT_SUCCESS; +} + +/** + * @brief Deletes the ef_node_main structure and frees its associated resources. + * + * This function releases the memory and resources allocated for the `ef_node_main` structure, + * including the metrics handles, SID handle, EF adapter handle, link database context, EF peer + * handle, and traffic link to EF peer map handle. It checks for NULL pointers and logs errors + * if any are encountered. The function returns `RT_SUCCESS` upon successful deletion, or `RT_ERR` + * if any of the resources could not be freed. + * + * @param ef_main Pointer to the `ef_node_main` structure to be deleted. + * + * @return RT_SUCCESS on successful deletion, RT_ERR if any resource deletion fails. + */ +int node_ef_main_delete(struct ef_node_main * ef_main) +{ + if (ef_main == NULL) { - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[i]; - if (ef_adapter->mode == MODE_INVALID) - continue; + MR_ERROR("The ef_main is NULL."); + return RT_ERR; + } + + /* Delete the metrics handles */ + for (uint16_t i = 0; i < ef_main->nr_graphs; i++) + { + if (ef_main->ingress_metrics_handles[i] != NULL) + { + sc_metrics_handle_delete(ef_main->ingress_metrics_handles[i]); + ef_main->ingress_metrics_handles[i] = NULL; + } + + if (ef_main->egress_metrics_handles[i] != NULL) + { + sc_metrics_handle_delete(ef_main->egress_metrics_handles[i]); + ef_main->egress_metrics_handles[i] = NULL; + } + } - forwarder_table_insert(sid_start + ef_adapter->ef_adapter_id, FORWARDER_TYPE_EF); + /* Delete the sid handle */ + if (ef_main->sid_handle != NULL) + { + sid_handle_delete(ef_main->sid_handle); + ef_main->sid_handle = NULL; + } + + /* Delete the ef_adapter_handle */ + if (ef_main->ef_adapter_handle != NULL) + { + ef_adapter_handle_delete(ef_main->ef_adapter_handle); + ef_main->ef_adapter_handle = NULL; + } + + /* Delete the link db ctx */ + if (ef_main->link_db_ctx != NULL) + { + link_db_destroy(&ef_main->link_db_ctx); + ef_main->link_db_ctx = NULL; + } + + /* Delete the ef_peer_handle */ + if (ef_main->ef_peer_handle != NULL) + { + ef_peer_handle_delete(ef_main->ef_peer_handle); + ef_main->ef_peer_handle = NULL; + } + + /* Delete the tl_to_ef_peer_map_handle */ + if (ef_main->tl_to_ef_peer_map_handle != NULL) + { + tl_to_ef_peer_map_handle_delete(ef_main->tl_to_ef_peer_map_handle); + ef_main->tl_to_ef_peer_map_handle = NULL; } - /* Save the etherfabric adapter config num */ - ef_main->nr_adapters = nr_adapters; - ef_main->nr_sids = nr_sids; - ef_main->sid_start = sid_start; - ef_main->sid_end = sid_end; + FREE(ef_main); + return RT_SUCCESS; } -/* Dump etherfabric adapter config */ -void dump_ef_adapter_config(struct node_ef_main * ef_main) +/** + * @brief Creates an ef_node_main structure and initializes its components. + * + * This function initializes and allocates memory for an `ef_node_main` structure, which manages + * various resources related to Etherfabric nodes. It creates metrics handles, SID handle, EF adapter + * handle, link database context, EF peer handle, and traffic link to EF peer map handle. If any + * component creation fails, the function logs an error, cleans up resources, and returns NULL. + * + * @param sc Pointer to the `sc_main` structure containing the configuration file and other resources. + * @param ef_node_cfg Pointer to the `ef_config_handle` structure containing configuration data. + * + * @return Pointer to the created `ef_node_main` structure if successful, NULL otherwise. + */ +struct ef_node_main * node_ef_main_create(struct sc_main * sc, struct ef_config_handle * ef_node_cfg) +{ + /* Check the input */ + if (sc == NULL) + { + MR_ERROR("The sc is NULL."); + return NULL; + } + + if (ef_node_cfg == NULL) + { + MR_ERROR("The ef_node_cfg is NULL."); + return NULL; + } + + /* Create the ef main */ + struct ef_node_main * ef_main = ZMALLOC(sizeof(struct ef_node_main)); + MR_VERIFY_MALLOC(ef_main); + + /* Set the number of graphs */ + ef_main->nr_graphs = sc->nr_io_thread; + + /* Create the metrics handles */ + ef_main->ingress_metrics_handles = ZMALLOC(sizeof(struct sc_metrics_handle *) * ef_main->nr_graphs); + MR_VERIFY_MALLOC(ef_main->ingress_metrics_handles); + + ef_main->egress_metrics_handles = ZMALLOC(sizeof(struct sc_metrics_handle *) * ef_main->nr_graphs); + MR_VERIFY_MALLOC(ef_main->egress_metrics_handles); + + for (uint16_t i = 0; i < ef_main->nr_graphs; i++) + { + ef_main->ingress_metrics_handles[i] = sc_metrics_handle_create(EF_INGR_METRIC_MAX); + if (ef_main->ingress_metrics_handles[i] == NULL) + { + MR_ERROR("Failed to create the ingress metrics handle."); + goto end; + } + + ef_main->egress_metrics_handles[i] = sc_metrics_handle_create(EF_EGR_METRIC_MAX); + if (ef_main->egress_metrics_handles[i] == NULL) + { + MR_ERROR("Failed to create the egress metrics handle."); + goto end; + } + } + + /* Create sid handle */ + ef_main->sid_handle = sid_handle_create(ef_node_cfg->sid_start, ef_node_cfg->sid_end); + if (ef_main->sid_handle == NULL) + { + MR_ERROR("Failed to create the sid handle."); + goto end; + } + + /* Create ef_adapter_handle */ + ef_main->ef_adapter_handle = ef_adapter_handle_create(ef_node_cfg->ef_adapters_data, ef_node_cfg->ef_adapters_max, + ef_node_cfg->nr_adapters); + if (ef_main->ef_adapter_handle == NULL) + { + MR_ERROR("Failed to create the ef_adapter_handle."); + goto end; + } + + /* Create link db ctx */ + ef_main->link_db_ctx = link_db_create(LINK_DB_TYPE_EF, ef_node_cfg->link_dbs_max); + if (ef_main->link_db_ctx == NULL) + { + MR_ERROR("Failed to create the link db ctx."); + goto end; + } + + if (link_db_config_parse(sc->local_cfgfile, ef_main->link_db_ctx) == RT_ERR) + { + MR_ERROR("Failed to parse the link db config."); + goto end; + } + + /* Create ef peer handle */ + ef_main->ef_peer_handle = ef_peer_handle_create(SC_EF_PEER_ENTRIES); + if (ef_main->ef_peer_handle == NULL) + { + MR_ERROR("Failed to create the ef peer handle."); + goto end; + } + + /* Create tl to ef peer map handle */ + ef_main->tl_to_ef_peer_map_handle = tl_to_ef_peer_map_handle_create(UINT16_MAX); + if (ef_main->tl_to_ef_peer_map_handle == NULL) + { + MR_ERROR("Failed to create the traffic link to ef peer map handle."); + goto end; + } + + return ef_main; + +end: + node_ef_main_delete(ef_main); + return NULL; +} + +/** + * @brief Retrieves the number of graphs in the ef_node_main structure. + * + * This function returns the number of graphs (I/O threads) configured in the specified + * `ef_node_main` structure. The function asserts that the `ef_node_main` pointer is not NULL + * before accessing the number of graphs. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return The number of graphs (I/O threads) in the `ef_node_main` structure. + */ +uint16_t node_ef_main_nr_graphs_get(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + return ef_main->nr_graphs; +} + +/** + * @brief Retrieves the SID handle from the ef_node_main structure. + * + * This function returns a pointer to the SID handle (`sid_handle`) stored within the specified + * `ef_node_main` structure. The function asserts that the `ef_node_main` pointer is not NULL + * before accessing the SID handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return Pointer to the `sid_handle` structure. + */ +struct sid_handle * node_ef_main_sid_handle_get(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + return ef_main->sid_handle; +} + +/** + * @brief Retrieves the EF adapter handle from the ef_node_main structure. + * + * This function returns a pointer to the EF adapter handle (`ef_adapter_handle`) stored within + * the specified `ef_node_main` structure. The function asserts that the `ef_node_main` pointer + * is not NULL before accessing the EF adapter handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return Pointer to the `ef_adapter_handle` structure. + */ +struct ef_adapter_handle * node_ef_main_ef_adapter_handle_get(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + return ef_main->ef_adapter_handle; +} + +/** + * @brief Retrieves the link database context from the ef_node_main structure. + * + * This function returns a pointer to the link database context (`link_db_ctx`) stored within + * the specified `ef_node_main` structure. The function asserts that the `ef_node_main` pointer + * is not NULL before accessing the link database context. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return Pointer to the `link_db_ctx` structure. + */ +struct link_db_ctx * node_ef_main_link_db_ctx_get(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + return ef_main->link_db_ctx; +} + +/** + * @brief Retrieves the EF peer handle from the ef_node_main structure. + * + * This function returns a pointer to the EF peer handle (`ef_peer_handle`) stored within the + * specified `ef_node_main` structure. The function asserts that the `ef_node_main` pointer is + * not NULL before accessing the EF peer handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return Pointer to the `ef_peer_handle` structure. + */ +struct ef_peer_handle * node_ef_main_ef_peer_handle_get(struct ef_node_main * ef_main) { - if (ef_main->nr_adapters == 0) + assert(ef_main != NULL); + return ef_main->ef_peer_handle; +} + +/** + * @brief Retrieves the traffic link to EF peer map handle from the ef_node_main structure. + * + * This function returns a pointer to the traffic link to EF peer map handle (`tl_to_ef_peer_map_handle`) + * stored within the specified `ef_node_main` structure. The function asserts that the `ef_node_main` + * pointer is not NULL before accessing the map handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * + * @return Pointer to the `tl_to_ef_peer_map_handle` structure. + */ +struct tl_to_ef_peer_map_handle * node_ef_main_tl_to_ef_peer_map_handle_get(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + return ef_main->tl_to_ef_peer_map_handle; +} + +/** + * @brief Retrieves the ingress metrics handle for a specific graph from the ef_node_main structure. + * + * This function returns a pointer to the ingress metrics handle (`sc_metrics_handle`) corresponding + * to the specified `graph_id` within the `ef_node_main` structure. The function asserts that the + * `ef_node_main` pointer is not NULL and that the `graph_id` is within the valid range before + * accessing the ingress metrics handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * @param graph_id The ID of the graph (I/O thread) for which to retrieve the ingress metrics handle. + * + * @return Pointer to the ingress `sc_metrics_handle` structure for the specified graph. + */ +struct sc_metrics_handle * node_ef_main_ingress_metrics_handle_get(struct ef_node_main * ef_main, uint16_t graph_id) +{ + assert(ef_main != NULL); + assert(graph_id < ef_main->nr_graphs); + + return ef_main->ingress_metrics_handles[graph_id]; +} + +/** + * @brief Retrieves the egress metrics handle for a specific graph from the ef_node_main structure. + * + * This function returns a pointer to the egress metrics handle (`sc_metrics_handle`) corresponding + * to the specified `graph_id` within the `ef_node_main` structure. The function asserts that the + * `ef_node_main` pointer is not NULL and that the `graph_id` is within the valid range before + * accessing the egress metrics handle. + * + * @param ef_main Pointer to the `ef_node_main` structure. + * @param graph_id The ID of the graph (I/O thread) for which to retrieve the egress metrics handle. + * + * @return Pointer to the egress `sc_metrics_handle` structure for the specified graph. + */ +struct sc_metrics_handle * node_ef_main_egress_metrics_handle_get(struct ef_node_main * ef_main, uint16_t graph_id) +{ + assert(ef_main != NULL); + assert(graph_id < ef_main->nr_graphs); + + return ef_main->egress_metrics_handles[graph_id]; +} + +/** + * @brief Dumps the configuration information of Etherfabric adapters. + * + * This function logs detailed information about the Etherfabric adapters managed by the + * specified `ef_node_main` structure. It retrieves the capacity of the EF adapters and + * SID handle, and logs the total number of adapters, SID range, and the mode and listening + * device for each adapter. If no adapters are configured, the function returns without + * logging anything. + * + * @param ef_main Pointer to the `ef_node_main` structure containing the EF adapter configuration. + */ +void ef_info_dump(struct ef_node_main * ef_main) +{ + assert(ef_main != NULL); + + uint16_t ef_adapter_capacity = ef_adapter_handle_capacity_get(ef_main->ef_adapter_handle); + + if (ef_adapter_capacity == 0) + { return; + } + + uint16_t sid_capacity = sid_handle_capacity_get(ef_main->sid_handle); + uint32_t sid_start = sid_handle_sid_start_get(ef_main->sid_handle); + uint32_t sid_end = sid_handle_sid_end_get(ef_main->sid_handle); MR_INFO(" "); - MR_INFO("Etherfabric adapter, total num: %u, sid num: %u, sid start: %u, sid end:%u", ef_main->nr_adapters, - ef_main->nr_sids, ef_main->sid_start, ef_main->sid_end); + MR_INFO("Etherfabric adapter, total num: %u, sid num: %u, sid start: %u, sid end:%u", ef_adapter_capacity, + sid_capacity, sid_start, sid_end); - for (int i = 0; i < nr_max_ef_adapters; i++) + for (int i = 0; i < ef_adapter_capacity; i++) { char str_mode[MR_STRING_MAX] = {}; - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[i]; + struct ef_adapter * ef_adapter = ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, i); switch (ef_adapter->mode) { - case MODE_VIRTUAL_WIRE: + case EF_MODE_VIRTUAL_WIRE: sprintf(str_mode, "virtual-wire"); break; - case MODE_TAP: + case EF_MODE_TAP: sprintf(str_mode, "tap"); break; default: continue; } - MR_INFO("Etherfabric adapter, ef adapter id:%u, mode: %s, listen device: %s", ef_adapter->ef_adapter_id, - str_mode, ef_adapter->listen_device->symbol); + MR_INFO("Etherfabric adapter, id:%u, mode: %s, listen device: %s", ef_adapter->id, str_mode, + ef_adapter->listening_device->symbol); } } -/* Init etherfabric */ +/** + * @brief Initializes the Etherfabric node. + * + * This function initializes the Etherfabric node by retrieving the maximum number of EF adapters, + * creating the EF adapter configuration, and parsing the configuration data. It then creates the + * `ef_node_main` structure and inserts the corresponding SIDs into the forwarder table. If any step + * fails, the function logs an error, cleans up resources, and returns an error code. Upon successful + * initialization, the function dumps the Etherfabric adapter configuration and sets the global EF main. + * + * @param sc Pointer to the `sc_main` structure containing the main configuration and resources. + * + * @return RT_SUCCESS if the initialization is successful, RT_ERR otherwise. + */ int ef_init(struct sc_main * sc) { /* Get ef max entry,default is 256 */ - MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_ef_adapters", &nr_max_ef_adapters, 256); - - /* Malloc etherfabric adapter */ - struct node_ef_main * ef_main = node_ef_main_get(); - memset(ef_main, 0, sizeof(struct node_ef_main)); - ef_main->ef_adapters = ZMALLOC(sizeof(struct ef_adapter) * nr_max_ef_adapters); - MR_VERIFY_MALLOC(ef_main->ef_adapters); + uint32_t ef_adapters_max = 0; + int ret = adapters_max_get(sc, "nr_max_ef_adapters", &ef_adapters_max); + if (ret != RT_SUCCESS) + { + MR_ERROR("Failed to get the ef adapters max."); + return RT_ERR; + } - /* Parsing the etherfabric adapter config */ - if (parser_ef_adapter_config(sc, ef_main) != RT_SUCCESS) + /* Create the ef adapter config */ + struct ef_config_handle * ef_node_cfg = ef_config_handle_create(ef_adapters_max); + if (ef_node_cfg == NULL) + { + MR_ERROR("Failed to create the ef adapter cfg."); return RT_ERR; + } - /* Dump the etherfabric adapter config */ - dump_ef_adapter_config(ef_main); + /* Parse the ef adapter config */ + ret = ef_config_parse(sc, ef_node_cfg); + if (ret != RT_SUCCESS) + { + MR_ERROR("Failed to parse the ef adapter config."); + ret = RT_ERR; + goto end; + } - /* Link db ctx create */ - uint32_t max_entries; - MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_link_dbs", &max_entries, 64); - ef_main->link_db_ctx = link_db_create(LINK_DB_TYPE_EF, max_entries); - if (ef_main->link_db_ctx == NULL) - return RT_ERR; + struct ef_node_main * ef_main = node_ef_main_create(sc, ef_node_cfg); + if (ef_main == NULL) + { + MR_ERROR("Failed to create the ef main."); + ret = RT_ERR; + goto end; + } - if (link_db_config_parse(sc->local_cfgfile, ef_main->link_db_ctx) == RT_ERR) - return RT_ERR; + /* Inserter sid to forwarder table */ + uint32_t sid_start = sid_handle_sid_start_get(ef_main->sid_handle); + for (int index = 0; index < ef_adapters_max; index++) + { + struct ef_adapter * ef_adapter = ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, index); + if (ef_adapter->mode == EF_MODE_INVALID) + continue; - /* Setup ef_peer hash */ - if (ef_peer_setup_hash(ef_main) != RT_SUCCESS) - return RT_ERR; + forwarder_table_insert(sid_start + ef_adapter->id, FORWARDER_TYPE_EF); + } - /* Malloc ef_peers */ - ef_main->ef_peers = ZMALLOC(sizeof(struct ef_peer) * NR_EF_PEER_MEMBER); - MR_VERIFY_MALLOC(ef_main->ef_peers); + /* Dump the etherfabric adapter config */ + ef_info_dump(ef_main); - /* Init state */ - for (int index = 0; index < NR_EF_PEER_MEMBER; index++) - rte_atomic64_init(&ef_main->ef_peers[index].state); + /* Set the global ef main */ + g_ef_node_main_set(ef_main); + ret = RT_SUCCESS; - /* Init traffic link to ef peer map */ - for (int index = 0; index < RTE_DIM(ef_main->tl_to_ef_peer_map); index++) +end: + ef_config_handle_delete(ef_node_cfg); + return ret; +} + +/** + * @brief Deinitializes the Etherfabric node. + * + * This function deinitializes the Etherfabric node by retrieving the global `ef_node_main` structure, + * deleting it, and resetting the global EF main pointer to NULL. If the `ef_node_main` structure is + * not found, the function logs an error and returns an error code. + * + * @return RT_SUCCESS if the deinitialization is successful, RT_ERR otherwise. + */ +int ef_deinit() +{ + struct ef_node_main * ef_main = __g_ef_node_main_get(); + if (ef_main == NULL) { - rte_atomic64_init(&ef_main->tl_to_ef_peer_map[index]); - rte_atomic64_set(&ef_main->tl_to_ef_peer_map[index], -1); + MR_ERROR("The ef_main is NULL."); + return RT_ERR; } + node_ef_main_delete(ef_main); + g_ef_node_main_set(NULL); + return RT_SUCCESS; } -/************************************** Etherfabric Node **************************************/ -/* Etherfabric adapter lookup */ -int ef_adapter_lookup(struct node_ef_main * ef_main, uint32_t dst_addr, uint16_t * out_ef_adapter_id) +/*********************************************** Extern func ************************************************/ +/** + * @brief Checks if a given EF adapter ID is valid. + * + * This function checks the validity of a specified `ef_adapter_id` by ensuring that the + * Etherfabric node is initialized, the EF adapter capacity is non-zero, and the adapter ID + * is within the valid range. It also checks if the adapter's mode is not set to `EF_MODE_INVALID`. + * If any of these conditions are not met, the function returns `RT_ERR`, otherwise, it returns + * `RT_SUCCESS`. + * + * @param ef_adapter_id The ID of the EF adapter to check. + * + * @return RT_SUCCESS if the EF adapter ID is valid, RT_ERR otherwise. + */ +int ef_adapter_id_check(uint32_t ef_adapter_id) { - for (uint16_t index = 0; index < nr_max_ef_adapters; index++) + struct ef_node_main * ef_main = __g_ef_node_main_get(); + if (ef_main == NULL) { - struct ef_adapter * ef_adapter = &ef_main->ef_adapters[index]; - - if (ef_adapter->mode == MODE_INVALID) - continue; + MR_ERROR("The ef node is not initialized."); + return RT_ERR; + } - if (dst_addr == ef_adapter->listen_device->in_addr.s_addr) - { - *out_ef_adapter_id = ef_adapter->ef_adapter_id; - return RT_SUCCESS; - } + uint16_t ef_adapter_capacity = ef_adapter_handle_capacity_get(ef_main->ef_adapter_handle); + if (ef_adapter_capacity == 0) + { + MR_ERROR("The ef adapter capacity is 0."); + return RT_ERR; } - return RT_ERR; -} -#if 0 -int ef_peer_lookup(struct node_ef_main * ef_main, struct rte_ether_addr * mac_src, uint32_t ip_src) -{ - for (int i = 0; i < RTE_DIM(ef_main->ef_peers); i++) + if (ef_adapter_id >= ef_adapter_capacity) { - struct ef_peer * ef_peer_item = &ef_main->ef_peers[i]; - if (rte_atomic64_read(&ef_peer_item->state) == 0) - { - continue; - } + return RT_ERR; + } - if (ef_peer_item->ef_ip_addr == ip_src && rte_is_same_ether_addr(&ef_peer_item->ef_mac_addr, mac_src)) - { - return i; - } + struct ef_adapter * ef_adapter = ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, ef_adapter_id); + if (ef_adapter->mode == EF_MODE_INVALID) + { + return RT_ERR; } - return RT_ERR; + + return RT_SUCCESS; } -#endif -/* ef_peer lookup and add */ -int ef_peer_lookup_and_add(struct rte_hash * ef_peer_hash, struct ef_peer * ef_peers, struct rte_ether_addr * mac_src, - uint32_t ip_src) +/** + * @brief Retrieves the number of active EF adapters. + * + * This function returns the number of EF adapters currently configured and active within + * the Etherfabric node. It retrieves the `ef_node_main` structure and calls + * `ef_adapter_handle_nr_adapters_get` to get the number of adapters. + * + * @return The number of active EF adapters. + */ +uint16_t ef_nr_adapters_get() { - /* Look up the hash table */ - union ef_peer_key key = {.ip_src = ip_src}; - rte_ether_addr_copy(mac_src, &key.mac_src); - int ret = rte_hash_lookup(ef_peer_hash, (const void *)&key); - - if (likely(ret >= 0)) - { - return ret; - } + struct ef_node_main * ef_main = __g_ef_node_main_get(); + return ef_adapter_handle_nr_adapters_get(ef_main->ef_adapter_handle); +} - /* Add the new ef_peer */ - ret = rte_hash_add_key(ef_peer_hash, (void *)&key); +/** + * @brief Retrieves the IDs of all active EF adapters. + * + * This function populates an array with the IDs of all active EF adapters within the + * Etherfabric node. It iterates through the EF adapter list and copies the IDs of adapters + * that are not in the `EF_MODE_INVALID` state into the provided `ef_adapter_ids` array. The + * function stops when it has filled the array with the specified number of adapter IDs (`nr_adapters`). + * + * @param ef_adapter_ids Pointer to the array where the EF adapter IDs will be stored. + * @param nr_adapters The number of adapter IDs to retrieve. + */ +void ef_adapter_ids_get(uint16_t * ef_adapter_ids, uint16_t nr_adapters) +{ + uint16_t adapter_count = 0; + struct ef_node_main * ef_main = __g_ef_node_main_get(); + uint16_t ef_adapters_capacity = ef_adapter_handle_capacity_get(ef_main->ef_adapter_handle); - if (likely(ret >= 0)) + for (int i = 0; i < ef_adapters_capacity; i++) { - /* Set the ef_peer state */ - struct ef_peer * ef_peer_item = &ef_peers[ret]; - if (rte_atomic64_test_and_set(&ef_peer_item->state)) + struct ef_adapter * ef_adapter = ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, i); + if (ef_adapter->mode != EF_MODE_INVALID) { - /* Save the ef_peer info */ - ef_peer_item->ef_ip_addr = key.ip_src; - rte_ether_addr_copy(&key.mac_src, &ef_peer_item->ef_mac_addr); - - /* Dump ef_peer for new add */ - char str_in_addr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &ef_peer_item->ef_ip_addr, str_in_addr, sizeof(str_in_addr)); - - char str_mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; - rte_ether_format_addr(str_mac_addr, sizeof(str_mac_addr), &ef_peer_item->ef_mac_addr); - - MR_INFO("Ef Peer add, index %d, core %u, ip addr:%s, mac addr:%s", ret, rte_lcore_id(), str_in_addr, - str_mac_addr); + ef_adapter_ids[adapter_count] = ef_adapter->id; + adapter_count++; } - return ret; + if (adapter_count == nr_adapters) + { + return; + } } +} - return RT_ERR; +/** + * @brief Retrieves the maximum number of EF adapters. + * + * This function returns the maximum number of EF adapters that the Etherfabric node can manage. + * It retrieves this value from the `ef_node_main` structure by calling + * `ef_adapter_handle_capacity_get`. + * + * @return The maximum number of EF adapters. + */ +unsigned int nr_max_ef_adapters_get() +{ + struct ef_node_main * ef_main = __g_ef_node_main_get(); + return ef_adapter_handle_capacity_get(ef_main->ef_adapter_handle); } -static inline void tl_to_ef_peer_map_set(struct node_ef_main * ef_main, uint16_t traffic_link_id, int ef_peer_index) +/** + * @brief Retrieves the starting SID (Service ID) from the Etherfabric node. + * + * This function returns the starting Service ID (SID) configured within the Etherfabric node. + * It retrieves the SID start value from the `sid_handle` associated with the global + * `ef_node_main` structure. + * + * @return The starting SID for the Etherfabric node. + */ +uint32_t ef_sid_start_get() { - if (traffic_link_id != 65535) - { - rte_atomic64_set(&ef_main->tl_to_ef_peer_map[traffic_link_id], ef_peer_index); - } + struct ef_node_main * ef_main = __g_ef_node_main_get(); + return sid_handle_sid_start_get(ef_main->sid_handle); } -int tl_to_ef_peer_map_get(uint16_t traffic_link_id) +/** + * @brief Retrieves the EF peer index associated with a given traffic link ID. + * + * This function looks up the EF peer index associated with the specified `traffic_link_id` + * within the `tl_to_ef_peer_map_handle`. It first ensures that the Etherfabric node is initialized + * and that the `traffic_link_id` is within the valid range of the map's capacity. If the node is + * not initialized or the ID is out of range, the function returns `RT_ERR`. Otherwise, it retrieves + * the EF peer index from the map table and stores it in `out_ef_peer_index`, returning `RT_SUCCESS`. + * + * @param traffic_link_id The traffic link ID to look up. + * @param out_ef_peer_index Pointer to where the associated EF peer index will be stored. + * + * @return RT_SUCCESS if the EF peer index is successfully retrieved, RT_ERR otherwise. + */ +int ef_peer_index_get_by_tl_id_get(uint16_t traffic_link_id, uint16_t * out_ef_peer_index) { - if (traffic_link_id != 65535) + struct ef_node_main * ef_main = __g_ef_node_main_get(); + if (unlikely(ef_main == NULL)) + { + MR_ERROR("The ef node is not initialized."); + return RT_ERR; + } + + struct tl_to_ef_peer_map_handle * handle = ef_main->tl_to_ef_peer_map_handle; + if (traffic_link_id < handle->capacity) { - struct node_ef_main * ef_main = node_ef_main_get(); - return rte_atomic64_read(&ef_main->tl_to_ef_peer_map[traffic_link_id]); + *out_ef_peer_index = rte_atomic64_read(&handle->maps_table[traffic_link_id]); + return RT_SUCCESS; } - return -1; + return RT_ERR; } +/************************************************ Auxiliary functions *************************************************/ +/** + * @brief Swaps the Ethernet and IP source/destination addresses in a forwarded packet. + * + * This inline function modifies a packet's Ethernet and IP headers for VXLAN encapsulation. + * It swaps the source and destination MAC addresses in the Ethernet header and swaps the + * source and destination IP addresses in the IPv4 header. This is typically done before + * VXLAN encapsulation to ensure that the packet is routed correctly. + * + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + */ static inline void vxlan_encap_forwarded_pkt(struct rte_mbuf * mbuf) { /* swap eth_hdr */ @@ -551,10 +1926,116 @@ static inline void vxlan_encap_forwarded_pkt(struct rte_mbuf * mbuf) ip_hdr->dst_addr = _swap_ip_addr; } -/* Generate and store the trace information for ingress */ -static __rte_always_inline void gen_store_trace_info_ingress(struct rte_node * node, struct rte_mbuf * mbuf, - uint16_t next_node_index, uint16_t prepend_sid, - enum ef_ingress_drop_reason drop_reason) +/** + * @brief Generates a source port for VXLAN encapsulation according to RFC 7348. + * + * This inline function generates a source port number for VXLAN encapsulation by hashing + * the packet's data (specifically the inner headers) and mapping the result to a range of + * ephemeral ports (49152 to 65535). The generated source port helps to distribute the + * VXLAN traffic across different paths in the network. + * + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + * + * @return The generated source port for VXLAN encapsulation. + */ +static inline uint16_t generate_vxlan_src_port(struct rte_mbuf * mbuf) +{ + uint16_t min = 49152; + uint16_t range = 65535 - 49152 + 1; + + return min + (uint16_t)(mbuf->hash.usr % range); +} + +/** + * @brief Constructs the VXLAN encapsulation headers for a given packet. + * + * This inline function constructs the VXLAN encapsulation headers, including the outer Ethernet, + * IPv4, and UDP headers, as well as the VXLAN header itself. It ensures that the packet is + * prepared for transmission over a VXLAN tunnel. The function returns `RT_SUCCESS` if the + * headers are successfully constructed, or `RT_ERR` if any header cannot be added. + * + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + * @param mrb_meta Pointer to the `mrb_metadata` structure containing metadata for the packet. + * @param ef_peer Pointer to the `ef_peer` structure representing the destination peer. + * @param dev_desc Pointer to the `mr_dev_desc` structure representing the device description. + * + * @return RT_SUCCESS if the headers are successfully constructed, RT_ERR otherwise. + */ +static inline int vxlan_encap_constructed_pkt(struct rte_mbuf * mbuf, struct mrb_metadata * mrb_meta, + struct ef_peer * ef_peer, struct mr_dev_desc * dev_desc) +{ + /* construct the packet by the order of inner to outer */ + struct g_vxlan_hdr * p_vxlan_hdr = (struct g_vxlan_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct g_vxlan_hdr)); + if (unlikely(p_vxlan_hdr == NULL)) + { + return RT_ERR; + } + + /* clear the vxlan header */ + memset(p_vxlan_hdr, 0, sizeof(struct g_vxlan_hdr)); + p_vxlan_hdr->dir = mrb_meta->dir; + p_vxlan_hdr->link_id = mrb_meta->ef_link_id; + + /* then, the outer udp header */ + struct rte_udp_hdr * p_udp_hdr = (struct rte_udp_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_udp_hdr)); + if (unlikely(p_udp_hdr == NULL)) + { + return RT_ERR; + } + + /* TODO: the source port need to be fill with the hash of inner 2-tuple or 4-tuple, + * ignore the udp checksum */ + p_udp_hdr->src_port = htons(generate_vxlan_src_port(mbuf)); + p_udp_hdr->dst_port = htons(4789); + p_udp_hdr->dgram_len = htons(rte_pktmbuf_pkt_len(mbuf)); + p_udp_hdr->dgram_cksum = 0; + + /* then, the outer ip header */ + struct rte_ipv4_hdr * p_ipv4_hdr = (struct rte_ipv4_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ipv4_hdr)); + if (unlikely(p_ipv4_hdr == NULL)) + { + return RT_ERR; + } + + p_ipv4_hdr->version_ihl = 0x45; + p_ipv4_hdr->type_of_service = 0x00; + p_ipv4_hdr->packet_id = 0x0100; + p_ipv4_hdr->fragment_offset = 0x0000; + p_ipv4_hdr->time_to_live = 0x40; + p_ipv4_hdr->next_proto_id = IPPROTO_UDP; + p_ipv4_hdr->src_addr = dev_desc->in_addr.s_addr; + p_ipv4_hdr->dst_addr = ef_peer->ef_ip_addr; + p_ipv4_hdr->total_length = htons(rte_pktmbuf_pkt_len(mbuf)); + + p_ipv4_hdr->hdr_checksum = 0; + p_ipv4_hdr->hdr_checksum = rte_ipv4_cksum(p_ipv4_hdr); + + /* outermost ether header */ + struct rte_ether_hdr * eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr)); + + eth_hdr->ether_type = htons(RTE_ETHER_TYPE_IPV4); + rte_ether_addr_copy(&ef_peer->ef_mac_addr, ð_hdr->dst_addr); + rte_ether_addr_copy(&dev_desc->eth_addr, ð_hdr->src_addr); + + return RT_SUCCESS; +} + +/** + * @brief Generates and stores trace information for ingress packets. + * + * This function generates a trace record for an ingress packet as it moves through the + * network. It records details such as the next node, reason for dropping the packet + * (if applicable), and other metadata. The trace record is then emitted for analysis or + * debugging purposes. + * + * @param node Pointer to the `rte_node` structure representing the current node. + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + * @param next_node_index Index of the next node in the processing pipeline. + * @param prepend_sid The SID to prepend in the trace. + * @param drop_reason The reason for dropping the packet, if applicable. + */ +void gen_store_trace_info_ingress(struct rte_node * node, struct rte_mbuf * mbuf, uint16_t next_node_index, + uint16_t prepend_sid, enum ef_node_ingress_metrics_key drop_reason) { /* Populate the next node infomation */ char str_record[MR_STRING_MAX]; @@ -562,10 +2043,10 @@ static __rte_always_inline void gen_store_trace_info_ingress(struct rte_node * n int len = snprintf(str_record, sizeof(str_record), "next node:%s", node->nodes[next_node_index]->name); /* Populate the reason for next node */ - if (unlikely(next_node_index == EF_INGRESS_NEXT_PKT_DROP)) + if (unlikely(next_node_index == EF_INGR_NEXT_PKT_DROP)) { - assert(drop_reason < EF_INGR_DROP_RSN_MAX); - len += snprintf(str_record + len, sizeof(str_record) - len, ", rsn:%s", ef_ingr_drop_rsn_str[drop_reason]); + assert(drop_reason < EF_INGR_METRIC_MAX); + len += snprintf(str_record + len, sizeof(str_record) - len, ", rsn:%s", ef_ingr_metrics_str[drop_reason]); } else { @@ -583,6 +2064,213 @@ static __rte_always_inline void gen_store_trace_info_ingress(struct rte_node * n dp_trace_record_emit_str(sc_main_get()->trace, mbuf, rte_lcore_id(), &meta, str_record); } +/** + * @brief Generates and stores trace information for egress packets. + * + * This function creates a trace record for a packet as it exits the network through an egress node. + * It logs information about the next node, the reason for dropping the packet (if applicable), + * and other relevant metadata. The function checks if the packet is being dropped and, if so, + * records the specific reason. If the packet was created by a network function (NF), it also + * logs that information. Finally, the trace record is emitted for analysis or debugging. + * + * @param node Pointer to the `rte_node` structure representing the current node. + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + * @param next_node_index Index of the next node in the processing pipeline. + * @param drop_reason The reason for dropping the packet, if applicable. + */ +static void gen_store_trace_info_egress(struct rte_node * node, struct rte_mbuf * mbuf, uint16_t next_node_index, + enum ef_node_egress_metrics_key drop_reason) +{ + /* Populate the next node infomation */ + char str_record[MR_STRING_MAX]; + int len = snprintf(str_record, sizeof(str_record), "next node:%s", node->nodes[next_node_index]->name); + + /* Populate the reason for next node */ + struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_ID); + + if (unlikely(next_node_index == EF_EGR_NEXT_PKT_DROP)) + { + assert(drop_reason < EF_EGR_METRIC_MAX); + len += snprintf(str_record + len, sizeof(str_record) - len, ", rsn:%s", ef_egr_metrics_str[drop_reason]); + } + else + { + /* Populate the ef id and egress port information */ + len += snprintf(str_record + len, sizeof(str_record) - len, ", ef id:%u, tx:%u", mrb_meta->adapter_id, + mrb_meta->port_egress); + } + + /* Populate the nf create information */ + if (unlikely(mrb_meta->packet_create_from_nf)) + { + len += snprintf(str_record + len, sizeof(str_record) - len, ", nf cr:%u", mrb_meta->packet_create_from_nf); + } + + /* Emit the trace record */ + struct dp_trace_record_meta meta = { + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, .appsym = MR_TRACE_APPSYM, .module = node->name}; + dp_trace_record_emit_str(sc_main_get()->trace, mbuf, rte_lcore_id(), &meta, str_record); +} + +/** + * @brief Monitors and aggregates ingress metrics for Etherfabric nodes. + * + * This function monitors the ingress metrics for each graph (I/O thread) in the Etherfabric node + * and aggregates the data into a JSON object. It retrieves the metric values for each graph and + * stores them in an array. If the total packet count (`EF_INGR_METRIC_TOT_PKTS`) for a graph is zero, + * it skips further processing for that graph. Finally, the function creates a JSON object that + * contains the aggregated metrics data for each metric type across all graphs. + * + * @param sc Pointer to the `sc_main` structure containing the main configuration and resources. + * + * @return Pointer to the `cJSON` object containing the aggregated ingress metrics data. + */ +cJSON * ef_ingress_node_monit_loop(struct sc_main * sc) +{ + cJSON * json_root = cJSON_CreateObject(); + unsigned int nr_graphs = sc->nr_io_thread; + struct ef_node_main * ef_main = __g_ef_node_main_get(); + + assert(nr_graphs == ef_main->nr_graphs); + + uint64_t values_for_graphs[EF_INGR_METRIC_MAX][nr_graphs]; + + for (uint32_t graph_id = 0; graph_id < nr_graphs; graph_id++) + { + uint64_t values[EF_INGR_METRIC_MAX]; + sc_metrics_values_get(ef_main->ingress_metrics_handles[graph_id], values, EF_INGR_METRIC_MAX); + + if (values[EF_INGR_METRIC_TOT_PKTS] == 0) + { + for (uint32_t i = 0; i < EF_INGR_METRIC_MAX; i++) + { + values_for_graphs[i][graph_id] = 0; + } + continue; + } + + for (uint32_t i = 0; i < EF_INGR_METRIC_MAX; i++) + { + values_for_graphs[i][graph_id] = values[i]; + } + } + + for (uint32_t i = 0; i < EF_INGR_METRIC_MAX; i++) + { + char str_title[MR_STRING_MAX]; + snprintf(str_title, sizeof(str_title), "ef_ingress, %s", ef_ingr_metrics_str[i]); + + cJSON * json_counter = create_uint64_array(values_for_graphs[i], nr_graphs); + cJSON_AddItemToObject(json_root, str_title, json_counter); + } + + return json_root; +} + +/** + * @brief Monitors and aggregates egress metrics for Etherfabric nodes. + * + * This function monitors the egress metrics for each graph (I/O thread) in the Etherfabric node + * and aggregates the data into a JSON object. It retrieves the metric values for each graph and + * stores them in an array. If the total packet count (`EF_EGR_METRIC_TOT_PKTS`) for a graph is zero, + * it skips further processing for that graph. Finally, the function creates a JSON object that + * contains the aggregated metrics data for each metric type across all graphs. + * + * @param sc Pointer to the `sc_main` structure containing the main configuration and resources. + * + * @return Pointer to the `cJSON` object containing the aggregated egress metrics data. + */ +cJSON * ef_egress_node_monit_loop(struct sc_main * sc) +{ + cJSON * json_root = cJSON_CreateObject(); + unsigned int nr_graphs = sc->nr_io_thread; + struct ef_node_main * ef_main = __g_ef_node_main_get(); + + assert(nr_graphs == ef_main->nr_graphs); + + uint64_t values_for_graphs[EF_EGR_METRIC_MAX][nr_graphs]; + + for (uint32_t graph_id = 0; graph_id < nr_graphs; graph_id++) + { + uint64_t values[EF_EGR_METRIC_MAX]; + sc_metrics_values_get(ef_main->ingress_metrics_handles[graph_id], values, EF_EGR_METRIC_MAX); + + if (values[EF_INGR_METRIC_TOT_PKTS] == 0) + { + for (uint32_t i = 0; i < EF_EGR_METRIC_MAX; i++) + { + values_for_graphs[i][graph_id] = 0; + } + continue; + } + + for (uint32_t i = 0; i < EF_EGR_METRIC_MAX; i++) + { + values_for_graphs[i][graph_id] = values[i]; + } + } + + for (uint32_t i = 0; i < EF_EGR_METRIC_MAX; i++) + { + char str_title[MR_STRING_MAX]; + snprintf(str_title, sizeof(str_title), "ef_egress, %s", ef_egr_metrics_str[i]); + + cJSON * json_counter = create_uint64_array(values_for_graphs[i], nr_graphs); + cJSON_AddItemToObject(json_root, str_title, json_counter); + } + + return json_root; +} + +/** + * @brief Monitors the state and details of EF peers in the Etherfabric node. + * + * This function iterates through all EF peers in the Etherfabric node and collects information + * about active peers. For each active peer, it retrieves the IP and MAC addresses and stores + * them in a JSON object. The function then adds this information to the root JSON object. + * The total number of active peers is also recorded. The JSON object provides a snapshot of + * the current state of all EF peers in the system. + * + * @param sc Pointer to the `sc_main` structure containing the main configuration and resources. + * + * @return Pointer to the `cJSON` object containing the monitored EF peer information. + */ +cJSON * ef_peer_monit_loop(struct sc_main * sc) +{ + int nr_ef_peer = 0; + cJSON * json_root = cJSON_CreateObject(); + struct ef_node_main * ef_main = __g_ef_node_main_get(); + + uint16_t capacity = ef_peer_handle_capacity_get(ef_main->ef_peer_handle); + + for (int i = 0; i < capacity; i++) + { + struct ef_peer * ef_peer = __ef_peer_handle_peer_get(ef_main->ef_peer_handle, i); + + if (rte_atomic64_read(&ef_peer->state) == 0) + continue; + + char str_in_addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &ef_peer->ef_ip_addr, str_in_addr, sizeof(str_in_addr)); + + char str_mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; + rte_ether_format_addr(str_mac_addr, sizeof(str_mac_addr), &ef_peer->ef_mac_addr); + + cJSON * ef_peer_obj = cJSON_CreateObject(); + cJSON_AddStringToObject(ef_peer_obj, "ip addr", str_in_addr); + cJSON_AddStringToObject(ef_peer_obj, "mac addr", str_mac_addr); + + char ef_peer_index[MR_STRING_MAX]; + snprintf(ef_peer_index, sizeof(ef_peer_index), "ef_peer:%u", i); + cJSON_AddItemToObject(json_root, ef_peer_index, ef_peer_obj); + nr_ef_peer++; + } + + cJSON_AddNumberToObject(json_root, "total_num", nr_ef_peer); + return json_root; +} + +/********************************************** Etherfabric ingress Node **********************************************/ /* Etherfabric ingress node process function */ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * graph, struct rte_node * node, void ** objs, uint16_t cnt) @@ -593,10 +2281,12 @@ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * g /* Single packet processing */ uint16_t n_left_from = cnt; uint16_t last_spec = 0, next_node_index = 0; - uint16_t batch_next_node_index = EF_INGRESS_NEXT_PKT_DROP; - enum ef_ingress_drop_reason drop_reason = EF_INGR_DROP_RSN_MAX; - struct ef_ingress_stats stats = {}; - struct node_ef_main * ef_main = node_ef_main_get(); + uint16_t batch_next_node_index = EF_INGR_NEXT_PKT_DROP; + + struct ef_node_main * ef_main = __g_ef_node_main_get(); + uint32_t sid_start = sid_handle_sid_start_get(ef_main->sid_handle); + uint64_t inc_values[EF_INGR_METRIC_MAX] = {0}; + enum ef_node_ingress_metrics_key drop_reason; while (n_left_from > 0) { @@ -618,24 +2308,32 @@ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * g /* Etherfabric adapter lookup */ uint16_t ef_adapter_id = UINT16_MAX; - int ret = ef_adapter_lookup(ef_main, outer_ipv4_hdr->dst_addr, &ef_adapter_id); + int ret = ef_adapter_handle_adapter_lookup(ef_main->ef_adapter_handle, outer_ipv4_hdr->dst_addr, + &ef_adapter_id); if (unlikely(ret == RT_ERR)) { - next_node_index = EF_INGRESS_NEXT_PKT_DROP; - drop_reason = EF_INGR_DROP_RSN_ADP_NONEXIST; - stats.drop_reason[drop_reason]++; + next_node_index = EF_INGR_NEXT_PKT_DROP; + drop_reason = EF_INGR_METRIC_DROP_ADP_NONEXIST; + inc_values[drop_reason]++; goto node_enqueue; } - /* ef_peer lookup and add */ - int ef_peer_index = ef_peer_lookup_and_add(ef_main->ef_peer_hash, ef_main->ef_peers, &outer_ether_hdr->src_addr, - outer_ipv4_hdr->src_addr); - if (unlikely(ef_peer_index == RT_ERR)) + /* ef_peer lookup */ + union ef_peer_key key = {.ip_src = outer_ipv4_hdr->src_addr}; + rte_ether_addr_copy(&outer_ether_hdr->src_addr, &key.mac_src); + + int ef_peer_index = __ef_peer_handle_peer_lookup(ef_main->ef_peer_handle, &key); + + if (unlikely(ef_peer_index < 0)) { - next_node_index = EF_INGRESS_NEXT_PKT_DROP; - drop_reason = EF_INGR_DROP_RSN_EF_PEER_ADD_ERR; - stats.drop_reason[drop_reason]++; - goto node_enqueue; + ef_peer_index = ef_peer_handle_peer_add(ef_main->ef_peer_handle, &key); + if (unlikely(ef_peer_index == RT_ERR)) + { + next_node_index = EF_INGR_NEXT_PKT_DROP; + drop_reason = EF_INGR_METRIC_DROP_EF_PEER_ADD_ERR; + inc_values[drop_reason]++; + goto node_enqueue; + } } /* Traffic link id lookup */ @@ -645,26 +2343,37 @@ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * g match_field.ef_ip_addr = outer_ipv4_hdr->src_addr; link_db_match(ef_main->link_db_ctx, &match_field, 1, &traffic_link_id); - /* Set the traffic link to ef peer map */ - tl_to_ef_peer_map_set(ef_main, traffic_link_id, ef_peer_index); + /* Associate the traffic link id with ef_peer index */ + if (likely(traffic_link_id != UINT16_MAX)) + { + ret = __tl_to_ef_peer_map_handle_associate(ef_main->tl_to_ef_peer_map_handle, traffic_link_id, + ef_peer_index); + if (unlikely(ret == RT_ERR)) + { + next_node_index = EF_INGR_NEXT_PKT_DROP; + drop_reason = EF_INGR_METRIC_DROP_TL_TO_EF_PEER_MAP_ERR; + inc_values[drop_reason]++; + goto node_enqueue; + } + } /* Fill ef_peer index and dir */ struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_ID); + mrb_meta->dir = outer_g_vxlan_hdr->dir; mrb_meta->adapter_type = ADAPTER_TYPE_EF; mrb_meta->adapter_id = ef_adapter_id; mrb_meta->ef_link_id = outer_g_vxlan_hdr->link_id; mrb_meta->traffic_link_id = traffic_link_id; - mrb_meta->dir = outer_g_vxlan_hdr->dir; mrb_meta->ef_peer_index = ef_peer_index; /* Insert sid*/ - prepend_sid = ef_main->sid_start + ef_adapter_id; + prepend_sid = sid_start + ef_adapter_id; ret = sid_list_prepend(&mrb_meta->sid_list, &prepend_sid, 1); - if (unlikely(ret == RT_ERR)) + if (unlikely(ret != RT_SUCCESS)) { - next_node_index = EF_INGRESS_NEXT_PKT_DROP; - drop_reason = EF_INGR_DROP_RSN_PRE_SID_ERR; - stats.drop_reason[drop_reason]++; + next_node_index = EF_INGR_NEXT_PKT_DROP; + drop_reason = EF_INGR_METRIC_DROP_PRE_SID_ERR; + inc_values[drop_reason]++; goto node_enqueue; } @@ -675,8 +2384,8 @@ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * g rte_pktmbuf_adj(mbuf, ef_encap_len); /* Send the pkt to classifier */ - next_node_index = EF_INGRESS_NEXT_CLASSIFIER; - stats.to_classifier++; + next_node_index = EF_INGR_NEXT_CLASSIFIER; + inc_values[EF_INGR_METRIC_TO_CLASSIFIER]++; node_enqueue: #if 0 @@ -714,14 +2423,10 @@ static __rte_always_inline uint16_t ef_ingress_node_process(struct rte_graph * g if (likely(last_spec > 0)) rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); - /* Update graph stats */ - struct ef_ingress_stats * graph_stats = &ingress_stats_per_graph[graph->id]; - graph_stats->total_pkts += cnt; - graph_stats->pkts_per_batch = cnt; - graph_stats->to_classifier += stats.to_classifier; - graph_stats->drop_reason[EF_INGR_DROP_RSN_ADP_NONEXIST] += stats.drop_reason[EF_INGR_DROP_RSN_ADP_NONEXIST]; - graph_stats->drop_reason[EF_INGR_DROP_RSN_PRE_SID_ERR] += stats.drop_reason[EF_INGR_DROP_RSN_PRE_SID_ERR]; - graph_stats->drop_reason[EF_INGR_DROP_RSN_EF_PEER_ADD_ERR] += stats.drop_reason[EF_INGR_DROP_RSN_EF_PEER_ADD_ERR]; + /* Update metrics */ + inc_values[EF_INGR_METRIC_TOT_PKTS] = cnt; + sc_metrics_accumulate(ef_main->ingress_metrics_handles[graph->id], inc_values, EF_INGR_METRIC_MAX); + sc_metrics_value_set(ef_main->ingress_metrics_handles[graph->id], cnt, EF_INGR_METRIC_PKTS_PER_BATCH); return cnt; } @@ -731,127 +2436,19 @@ static struct rte_node_register ef_ingress_node_base = { .process = ef_ingress_node_process, .name = "ef_ingress", .init = NULL, - .nb_edges = EF_INGRESS_NEXT_MAX, + .nb_edges = EF_INGR_NEXT_MAX, .next_nodes = { - [EF_INGRESS_NEXT_CLASSIFIER] = "classifier", - [EF_INGRESS_NEXT_PKT_DROP] = "pkt_drop_trap", + [EF_INGR_NEXT_CLASSIFIER] = "classifier", + [EF_INGR_NEXT_PKT_DROP] = "pkt_drop_trap", }, }; RTE_NODE_REGISTER(ef_ingress_node_base); -/* Generate the source port for VXLAN encapsulation, rfc7348 */ -static inline uint16_t generate_vxlan_src_port(struct rte_mbuf * mbuf) -{ - uint16_t min = 49152; - uint16_t range = 65535 - 49152 + 1; - - return min + (uint16_t)(mbuf->hash.usr % range); -} - -/* Fill Ether IPv4 Udp Vxlan hdr for the constructed packet */ -static inline int vxlan_encap_constructed_pkt(struct rte_mbuf * mbuf, struct mrb_metadata * mrb_meta, - struct ef_peer * ef_peer_item, struct mr_dev_desc * dev_desc) -{ - /* construct the packet by the order of inner to outer */ - struct g_vxlan_hdr * p_vxlan_hdr = (struct g_vxlan_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct g_vxlan_hdr)); - if (unlikely(p_vxlan_hdr == NULL)) - { - goto errout; - } - - /* clear the vxlan header */ - memset(p_vxlan_hdr, 0, sizeof(struct g_vxlan_hdr)); - p_vxlan_hdr->dir = mrb_meta->dir; - p_vxlan_hdr->link_id = mrb_meta->ef_link_id; - - /* then, the outer udp header */ - struct rte_udp_hdr * p_udp_hdr = (struct rte_udp_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_udp_hdr)); - if (unlikely(p_udp_hdr == NULL)) - { - goto errout; - } - - /* TODO: the source port need to be fill with the hash of inner 2-tuple or 4-tuple, - * ignore the udp checksum */ - p_udp_hdr->src_port = htons(generate_vxlan_src_port(mbuf)); - p_udp_hdr->dst_port = htons(4789); - p_udp_hdr->dgram_len = htons(rte_pktmbuf_pkt_len(mbuf)); - p_udp_hdr->dgram_cksum = 0; - - /* then, the outer ip header */ - struct rte_ipv4_hdr * p_ipv4_hdr = (struct rte_ipv4_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ipv4_hdr)); - if (unlikely(p_ipv4_hdr == NULL)) - { - goto errout; - } - - p_ipv4_hdr->version_ihl = 0x45; - p_ipv4_hdr->type_of_service = 0x00; - p_ipv4_hdr->packet_id = 0x0100; - p_ipv4_hdr->fragment_offset = 0x0000; - p_ipv4_hdr->time_to_live = 0x40; - p_ipv4_hdr->next_proto_id = IPPROTO_UDP; - p_ipv4_hdr->src_addr = dev_desc->in_addr.s_addr; - p_ipv4_hdr->dst_addr = ef_peer_item->ef_ip_addr; - p_ipv4_hdr->total_length = htons(rte_pktmbuf_pkt_len(mbuf)); - - p_ipv4_hdr->hdr_checksum = 0; - p_ipv4_hdr->hdr_checksum = rte_ipv4_cksum(p_ipv4_hdr); - - /* outermost ether header */ - struct rte_ether_hdr * eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr)); - - eth_hdr->ether_type = htons(RTE_ETHER_TYPE_IPV4); - rte_ether_addr_copy(&ef_peer_item->ef_mac_addr, ð_hdr->dst_addr); - rte_ether_addr_copy(&dev_desc->eth_addr, ð_hdr->src_addr); - - return RT_SUCCESS; - -errout: - return RT_ERR; -} - -/* Generate and store the trace information for egress */ -static __rte_always_inline void gen_store_trace_info_egress(struct rte_node * node, struct rte_mbuf * mbuf, - uint16_t next_node_index, - enum ef_egress_drop_reason drop_reason) -{ - /* Populate the next node infomation */ - char str_record[MR_STRING_MAX]; - int len = snprintf(str_record, sizeof(str_record), "next node:%s", node->nodes[next_node_index]->name); - - /* Populate the reason for next node */ - struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_ID); - - if (unlikely(next_node_index == EF_EGRESS_NEXT_PKT_DROP)) - { - assert(drop_reason < EF_EGR_DROP_RSN_MAX); - len += snprintf(str_record + len, sizeof(str_record) - len, ", rsn:%s", ef_egr_drop_rsn_str[drop_reason]); - } - else - { - /* Populate the ef id and egress port information */ - len += snprintf(str_record + len, sizeof(str_record) - len, ", ef id:%u, tx:%u", mrb_meta->adapter_id, - mrb_meta->port_egress); - } - - /* Populate the nf create information */ - if (unlikely(mrb_meta->packet_create_from_nf)) - { - len += snprintf(str_record + len, sizeof(str_record) - len, ", nf cr:%u", mrb_meta->packet_create_from_nf); - } - - /* Emit the trace record */ - struct dp_trace_record_meta meta = { - .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, .appsym = MR_TRACE_APPSYM, .module = node->name}; - dp_trace_record_emit_str(sc_main_get()->trace, mbuf, rte_lcore_id(), &meta, str_record); -} - +/*********************************************** Etherfabric egress Node **********************************************/ /* Etherfabric egress node process function */ -static __rte_always_inline uint16_t ef_egress_node_process(struct rte_graph * graph, struct rte_node * node, - void ** objs, uint16_t cnt) +static uint16_t ef_egress_node_process(struct rte_graph * graph, struct rte_node * node, void ** objs, uint16_t cnt) { void ** batch_pkts = objs; struct rte_mbuf ** mbufs = (struct rte_mbuf **)objs; @@ -862,14 +2459,13 @@ static __rte_always_inline uint16_t ef_egress_node_process(struct rte_graph * gr uint16_t last_spec = 0; uint16_t n_left_from = cnt; - uint16_t next_node_index = EF_EGRESS_NEXT_ETH_EGRESS; - uint16_t batch_next_node_index = EF_EGRESS_NEXT_ETH_EGRESS; - enum ef_egress_drop_reason drop_reason = EF_EGR_DROP_RSN_MAX; - struct ef_egress_stats stats = {}; - struct node_ef_main * ef_main = node_ef_main_get(); - struct ef_peer * ef_peers = ef_main->ef_peers; - struct ef_adapter * ef_adapters = ef_main->ef_adapters; - uint32_t sid_start = ef_main->sid_start; + uint16_t next_node_index = EF_EGR_NEXT_ETH_EGRESS; + uint16_t batch_next_node_index = EF_EGR_NEXT_ETH_EGRESS; + + struct ef_node_main * ef_main = __g_ef_node_main_get(); + uint32_t sid_start = sid_handle_sid_start_get(ef_main->sid_handle); + uint64_t inc_values[EF_EGR_METRIC_MAX] = {0}; + enum ef_node_egress_metrics_key drop_reason = EF_EGR_METRIC_MAX; while (n_left_from > 0) { @@ -884,47 +2480,49 @@ static __rte_always_inline uint16_t ef_egress_node_process(struct rte_graph * gr rte_prefetch0_write(mrbuf_cz_data(mbufs[0], MR_NODE_CTRLZONE_ID)); } - /* Get etherfabric adapter item */ + /* Get the buffer metadata */ struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_ID); - uint16_t ef_adapter_id = mrb_meta->cur_sid - sid_start; - - assert(ef_adapter_id < nr_max_ef_adapters); - struct ef_adapter * ef_adapter = &ef_adapters[ef_adapter_id]; + /* Get etherfabric adapter item */ + uint16_t ef_adapter_id = mrb_meta->cur_sid - sid_start; + struct ef_adapter * ef_adapter = __ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, + ef_adapter_id); + /* According the etherfabric adapter mode to process the packet */ switch (ef_adapter->mode) { - case MODE_VIRTUAL_WIRE: { + case EF_MODE_VIRTUAL_WIRE: { /* Get port egress */ - struct mr_dev_desc * listen_device = ef_adapter->listen_device; + struct mr_dev_desc * listen_device = ef_adapter->listening_device; mrb_meta->port_egress = listen_device->port_id; /* Fill Ether IPv4 Udp Vxlan hdr for the pkt */ if (unlikely(mrb_meta->packet_create_from_nf)) { - assert(mrb_meta->ef_peer_index < NR_EF_PEER_MEMBER); - struct ef_peer * ef_peer_item = &ef_peers[mrb_meta->ef_peer_index]; - vxlan_encap_constructed_pkt(mbuf, mrb_meta, ef_peer_item, listen_device); - stats.vxlan_encap++; + assert(mrb_meta->ef_peer_index < ef_peer_handle_capacity_get(ef_main->ef_peer_handle)); + struct ef_peer * ef_peer = __ef_peer_handle_peer_get(ef_main->ef_peer_handle, mrb_meta->ef_peer_index); + vxlan_encap_constructed_pkt(mbuf, mrb_meta, ef_peer, listen_device); + inc_values[EF_EGR_METRIC_VXLAN_ENCAP]++; } else { rte_pktmbuf_prepend(mbuf, ef_encap_len); } - next_node_index = EF_EGRESS_NEXT_ETH_EGRESS; - stats.to_eth_egress++; + next_node_index = EF_EGR_NEXT_ETH_EGRESS; + inc_values[EF_EGR_METRIC_TO_ETH_EGRESS]++; } break; - case MODE_TAP: - next_node_index = EF_EGRESS_NEXT_PKT_DROP; - drop_reason = EF_EGR_DROP_RSN_TAP_MODE; - stats.drop_reason[drop_reason]++; + case EF_MODE_TAP: + next_node_index = EF_EGR_NEXT_PKT_DROP; + drop_reason = EF_EGR_METRIC_DROP_RSN_TAP_MODE; + inc_values[drop_reason]++; break; default: - next_node_index = EF_EGRESS_NEXT_PKT_DROP; - drop_reason = EF_EGR_DROP_RSN_INVALID_MODE; - stats.drop_reason[drop_reason]++; + next_node_index = EF_EGR_NEXT_PKT_DROP; + + drop_reason = EF_EGR_METRIC_DROP_RSN_INVALID_MODE; + inc_values[drop_reason]++; break; } @@ -955,15 +2553,10 @@ static __rte_always_inline uint16_t ef_egress_node_process(struct rte_graph * gr if (likely(last_spec > 0)) rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); - /* Update graph stats */ - struct ef_egress_stats * graph_stats = &egress_stats_per_graph[graph->id]; - graph_stats->total_pkts += cnt; - graph_stats->pkts_per_batch = cnt; - graph_stats->vxlan_encap += stats.vxlan_encap; - graph_stats->to_eth_egress += stats.to_eth_egress; - graph_stats->drop_reason[EF_EGR_DROP_RSN_TAP_MODE] += stats.drop_reason[EF_EGR_DROP_RSN_TAP_MODE]; - graph_stats->drop_reason[EF_EGR_DROP_RSN_INVALID_MODE] += stats.drop_reason[EF_EGR_DROP_RSN_INVALID_MODE]; - + /* Update metrics */ + inc_values[EF_EGR_METRIC_TOT_PKTS] = cnt; + sc_metrics_accumulate(ef_main->egress_metrics_handles[graph->id], inc_values, EF_EGR_METRIC_MAX); + sc_metrics_value_set(ef_main->egress_metrics_handles[graph->id], cnt, EF_EGR_METRIC_PKTS_PER_BATCH); return cnt; } @@ -972,168 +2565,12 @@ static struct rte_node_register ef_egress_node_base = { .process = ef_egress_node_process, .name = "ef_egress", .init = NULL, - .nb_edges = EF_EGRESS_NEXT_MAX, + .nb_edges = EF_EGR_NEXT_MAX, .next_nodes = { - [EF_EGRESS_NEXT_ETH_EGRESS] = "eth_egress", - [EF_EGRESS_NEXT_PKT_DROP] = "pkt_drop_trap", + [EF_EGR_NEXT_ETH_EGRESS] = "eth_egress", + [EF_EGR_NEXT_PKT_DROP] = "pkt_drop_trap", }, }; RTE_NODE_REGISTER(ef_egress_node_base); - -/************************************** Etherfabric Statistics **************************************/ -cJSON * ef_ingress_node_monit_loop(struct sc_main * sc) -{ - cJSON * json_root = cJSON_CreateObject(); - unsigned int nr_graphs = sc->nr_io_thread; - - uint64_t total_pkts[nr_graphs]; - uint64_t pkts_per_batch[nr_graphs]; - uint64_t to_classifier[nr_graphs]; - uint64_t drop_reason[EF_INGR_DROP_RSN_MAX][nr_graphs]; - - for (uint32_t graph_id = 0; graph_id < nr_graphs; graph_id++) - { - struct ef_ingress_stats * stats = &ingress_stats_per_graph[graph_id]; - if (stats->total_pkts == 0) - { - total_pkts[graph_id] = 0; - pkts_per_batch[graph_id] = 0; - to_classifier[graph_id] = 0; - - for (uint32_t i = 0; i < EF_INGR_DROP_RSN_MAX; i++) - { - drop_reason[i][graph_id] = 0; - } - - continue; - } - - total_pkts[graph_id] = stats->total_pkts; - pkts_per_batch[graph_id] = stats->pkts_per_batch; - to_classifier[graph_id] = stats->to_classifier; - - for (uint32_t i = 0; i < EF_INGR_DROP_RSN_MAX; i++) - { - drop_reason[i][graph_id] = stats->drop_reason[i]; - } - } - - cJSON * json_total_pkts = create_uint64_array(total_pkts, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_ingress, total_pkts", json_total_pkts); - - cJSON * json_pkts_per_batch = create_uint64_array(pkts_per_batch, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_ingress, pkts_per_batch", json_pkts_per_batch); - - cJSON * json_to_classifier = create_uint64_array(to_classifier, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_ingress, to_classifier", json_to_classifier); - - for (uint32_t i = 0; i < EF_INGR_DROP_RSN_MAX; i++) - { - char str_title[MR_STRING_MAX]; - snprintf(str_title, sizeof(str_title), "ef_ingress, %s", ef_ingr_drop_rsn_str[i]); - - cJSON * json_drops = create_uint64_array(drop_reason[i], nr_graphs); - cJSON_AddItemToObject(json_root, str_title, json_drops); - } - - return json_root; -} - -cJSON * ef_egress_node_monit_loop(struct sc_main * sc) -{ - cJSON * json_root = cJSON_CreateObject(); - unsigned int nr_graphs = sc->nr_io_thread; - - uint64_t total_pkts[nr_graphs]; - uint64_t pkts_per_batch[nr_graphs]; - uint64_t vxlan_encap[nr_graphs]; - uint64_t to_eth_egress[nr_graphs]; - uint64_t drop_reason[EF_EGR_DROP_RSN_MAX][nr_graphs]; - - for (uint32_t graph_id = 0; graph_id < nr_graphs; graph_id++) - { - struct ef_egress_stats * stats = &egress_stats_per_graph[graph_id]; - if (stats->total_pkts == 0) - { - total_pkts[graph_id] = 0; - pkts_per_batch[graph_id] = 0; - vxlan_encap[graph_id] = 0; - to_eth_egress[graph_id] = 0; - - for (uint32_t i = 0; i < EF_EGR_DROP_RSN_MAX; i++) - { - drop_reason[i][graph_id] = 0; - } - - continue; - } - - total_pkts[graph_id] = stats->total_pkts; - pkts_per_batch[graph_id] = stats->pkts_per_batch; - vxlan_encap[graph_id] = stats->vxlan_encap; - to_eth_egress[graph_id] = stats->to_eth_egress; - - for (uint32_t i = 0; i < EF_EGR_DROP_RSN_MAX; i++) - { - drop_reason[i][graph_id] = stats->drop_reason[i]; - } - } - - cJSON * json_total_pkts = create_uint64_array(total_pkts, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_egress, total_pkts", json_total_pkts); - - cJSON * json_pkts_per_batch = create_uint64_array(pkts_per_batch, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_egress, pkts_per_batch", json_pkts_per_batch); - - cJSON * json_vxlan_encap = create_uint64_array(vxlan_encap, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_egress, vxlan_encap", json_vxlan_encap); - - cJSON * json_to_eth_egress = create_uint64_array(to_eth_egress, nr_graphs); - cJSON_AddItemToObject(json_root, "ef_egress, to_eth_egress", json_to_eth_egress); - - for (uint32_t i = 0; i < EF_EGR_DROP_RSN_MAX; i++) - { - char str_title[MR_STRING_MAX]; - snprintf(str_title, sizeof(str_title), "ef_egress, %s", ef_egr_drop_rsn_str[i]); - - cJSON * json_drops = create_uint64_array(drop_reason[i], nr_graphs); - cJSON_AddItemToObject(json_root, str_title, json_drops); - } - - return json_root; -} - -cJSON * ef_peer_monit_loop(struct sc_main * sc) -{ - int nr_ef_peer = 0; - cJSON * json_root = cJSON_CreateObject(); - struct node_ef_main * ef_main = node_ef_main_get(); - - for (int i = 0; i < NR_EF_PEER_MEMBER; i++) - { - struct ef_peer * ef_peer_item = &ef_main->ef_peers[i]; - - if (rte_atomic64_read(&ef_peer_item->state) == 0) - continue; - - char str_in_addr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &ef_peer_item->ef_ip_addr, str_in_addr, sizeof(str_in_addr)); - - char str_mac_addr[RTE_ETHER_ADDR_FMT_SIZE]; - rte_ether_format_addr(str_mac_addr, sizeof(str_mac_addr), &ef_peer_item->ef_mac_addr); - - cJSON * ef_peer_obj = cJSON_CreateObject(); - cJSON_AddStringToObject(ef_peer_obj, "ip addr", str_in_addr); - cJSON_AddStringToObject(ef_peer_obj, "mac addr", str_mac_addr); - - char ef_peer_index[MR_STRING_MAX]; - snprintf(ef_peer_index, sizeof(ef_peer_index), "ef_peer:%u", i); - cJSON_AddItemToObject(json_root, ef_peer_index, ef_peer_obj); - nr_ef_peer++; - } - - cJSON_AddNumberToObject(json_root, "total_num", nr_ef_peer); - return json_root; -} diff --git a/service/src/node_link_aware_injector.c b/service/src/node_link_aware_injector.c index e9c5a55..372ccde 100644 --- a/service/src/node_link_aware_injector.c +++ b/service/src/node_link_aware_injector.c @@ -8,7 +8,7 @@ #include <rte_graph.h> #include <rte_graph_worker.h> -extern int tl_to_ef_peer_map_get(uint16_t traffic_link_id); +extern int ef_peer_index_get_by_tl_id_get(uint16_t traffic_link_id, uint16_t * out_ef_peer_index); /* Link aware injector next node */ enum @@ -124,7 +124,7 @@ int lai_init(struct sc_main * sc) lai_main->ef_adapter_ids = ZMALLOC(sizeof(uint16_t) * lai_main->nr_ef_adapters); MR_VERIFY_MALLOC(lai_main->ef_adapter_ids); - ef_adapter_id_get(lai_main->ef_adapter_ids, lai_main->nr_ef_adapters); + ef_adapter_ids_get(lai_main->ef_adapter_ids, lai_main->nr_ef_adapters); char str_ef_adapter_info[MR_STRING_MAX] = {0}; int len = snprintf(str_ef_adapter_info, sizeof(str_ef_adapter_info), "Link aware injector node, nr ef adapters:%u, ef adapter ids:", lai_main->nr_ef_adapters); @@ -223,8 +223,9 @@ static __rte_always_inline uint16_t lai_node_process(struct rte_graph * graph, s /* Set the next node index */ if (result.type == LINK_DB_TYPE_EF) { - int ef_peer_index = tl_to_ef_peer_map_get(mrb_meta->traffic_link_id); - if (ef_peer_index < 0) + uint16_t ef_peer_index; + int ret = ef_peer_index_get_by_tl_id_get(mrb_meta->traffic_link_id, &ef_peer_index); + if (ret == RT_ERR) { drop_reason = LAI_DROP_RSN_EF_PEER_ID_MISS; stats.drop_reason[drop_reason]++; diff --git a/service/src/sc_metrics.c b/service/src/sc_metrics.c index 72dc9ea..b07de7a 100644 --- a/service/src/sc_metrics.c +++ b/service/src/sc_metrics.c @@ -155,6 +155,7 @@ int sc_metrics_values_get(struct sc_metrics_handle * metrics_handle, uint64_t va */ int sc_metrics_value_get(struct sc_metrics_handle * metrics_handle, uint64_t * value, uint16_t key) { + assert(value != NULL); assert(metrics_handle != NULL); assert(metrics_handle->values != NULL); assert(key < metrics_handle->capacity); diff --git a/service/src/sc_node_common.c b/service/src/sc_node_common.c new file mode 100644 index 0000000..5597bd4 --- /dev/null +++ b/service/src/sc_node_common.c @@ -0,0 +1,139 @@ + +#include <MESA_prof_load.h> +#include <sc_node_common.h> + +/***************************************************** Sid handle *****************************************************/ +struct sid_handle * sid_handle_create(uint32_t sid_start, uint32_t sid_end) +{ + + if (unlikely(sid_start > sid_end)) + { + MR_ERROR("The start of the sid is larger than the end of the sid."); + return NULL; + } + + uint16_t capacity = sid_end - sid_start + 1; + if (unlikely(capacity > SC_SID_HANDLE_CAPACITY_MAX)) + { + MR_ERROR("The capacity of the sid handle is larger than the maximum value."); + return NULL; + } + + struct sid_handle * sid_handle = ZMALLOC(sizeof(struct sid_handle)); + MR_VERIFY_MALLOC(sid_handle); + + sid_handle->capacity = capacity; + sid_handle->sid_start = sid_start; + sid_handle->sid_end = sid_end; + return sid_handle; +} + +/** + * @brief Deletes a SID handle. + * + * This function frees the memory allocated for the specified SID handle. + * If the handle is NULL, the function returns immediately without performing + * any operations. Otherwise, it frees the memory and returns RT_SUCCESS. + * + * @param sid_handle A pointer to the sid_handle structure to be deleted. + * + * @return RT_SUCCESS if the handle is successfully deleted, or RT_ERR if the handle is NULL. + */ +int sid_handle_delete(struct sid_handle * sid_handle) +{ + if (sid_handle != NULL) + { + FREE(sid_handle); + return RT_SUCCESS; + } + return RT_ERR; +} + +/** + * @brief Get the capacity of the SID handle. + * + * This function returns the capacity of the specified SID handle. + * If the handle is NULL, the function returns 0. + * + * @param sid_handle A pointer to the sid_handle structure. + * + * @return The capacity of the SID handle, or 0 if the handle is NULL. + */ +inline uint16_t sid_handle_capacity_get(struct sid_handle * sid_handle) +{ + assert(sid_handle != NULL); + return sid_handle->capacity; +} + +/** + * @brief Get the starting SID of the SID handle. + * + * This function returns the starting SID of the specified SID handle. + * If the handle is NULL, the function returns 0. + * + * @param sid_handle A pointer to the sid_handle structure. + * + * @return The starting SID of the SID handle, or 0 if the handle is NULL. + */ +inline uint32_t sid_handle_sid_start_get(struct sid_handle * sid_handle) +{ + assert(sid_handle != NULL); + return sid_handle->sid_start; +} + +/** + * @brief Get the ending SID of the SID handle. + * + * This function returns the ending SID of the specified SID handle. + * If the handle is NULL, the function returns 0. + * + * @param sid_handle A pointer to the sid_handle structure. + * + * @return The ending SID of the SID handle, or 0 if the handle is NULL. + */ +inline uint32_t sid_handle_sid_end_get(struct sid_handle * sid_handle) +{ + assert(sid_handle != NULL); + return sid_handle->sid_end; +} + +/******************************************** Network intersection adapter ********************************************/ +/** + * @brief Retrieves the maximum number of adapters from the configuration. + * + * This function loads the maximum number of adapters specified in the configuration file + * using the provided key. It verifies that the loaded value is valid and does not exceed + * the predefined maximum limit (`SC_ADAPTERS_MAX`). If the value is valid, it is stored in + * the `adapters_max_out` output parameter. The function returns `RT_SUCCESS` if the value + * is successfully retrieved and valid, or `RT_ERR` if an error occurs. + * + * @param sc Pointer to the `sc_main` structure containing the configuration file and resources. + * @param key The key used to retrieve the maximum adapters value from the configuration file. + * @param adapters_max_out Pointer to where the retrieved maximum adapters value will be stored. + * + * @return RT_SUCCESS if the maximum adapters value is successfully retrieved and valid, RT_ERR otherwise. + */ +int adapters_max_get(struct sc_main * sc, const char * key, uint32_t * adapters_max_out) +{ + assert(sc != NULL); + assert(key != NULL); + assert(adapters_max_out != NULL); + + uint32_t adapters_max = 0; + MESA_load_profile_uint_def(sc->local_cfgfile, "limits", key, &adapters_max, 64); + + if (adapters_max == 0) + { + MR_ERROR("The '%s' is invalid: %u", key, adapters_max); + return RT_ERR; + } + else if (adapters_max > SC_ADAPTERS_MAX) + { + MR_ERROR("The '%s' is larger than the maximum value: %u", key, adapters_max); + return RT_ERR; + } + + *adapters_max_out = adapters_max; + + return RT_SUCCESS; +} diff --git a/service/test/test_common.c b/service/test/test_common.c index 4d9f20d..e6cffca 100644 --- a/service/test/test_common.c +++ b/service/test/test_common.c @@ -47,9 +47,11 @@ void eth_header_construct(struct rte_ether_hdr * eth_hdr, struct rte_ether_addr * @param src_ip Source IP address * @param dst_ip Destination IP address * @param proto Protocol + * @param payload_length Length of the payload (data) in bytes * @return int 0 on success, -1 on failure */ -int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, const char * dst_ip, uint8_t proto) +int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, const char * dst_ip, uint8_t proto, + uint16_t payload_length) { const char * default_src_ip = "192.168.1.1"; const char * default_dst_ip = "192.168.1.2"; @@ -68,9 +70,9 @@ int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, c ipv4_hdr->version_ihl = (4 << 4) | (sizeof(struct rte_ipv4_hdr) / 4); ipv4_hdr->type_of_service = 0; - ipv4_hdr->total_length = rte_cpu_to_be_16(sizeof(struct rte_ipv4_hdr)); + ipv4_hdr->total_length = rte_cpu_to_be_16(sizeof(struct rte_ipv4_hdr) + payload_length); ipv4_hdr->packet_id = 0; - ipv4_hdr->fragment_offset = rte_cpu_to_be_16(0x4000); // Don't fragment flag + ipv4_hdr->fragment_offset = rte_cpu_to_be_16(0x4000); ipv4_hdr->time_to_live = 64; ipv4_hdr->next_proto_id = proto; ipv4_hdr->hdr_checksum = 0; @@ -86,6 +88,53 @@ int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, c } ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr); + + return 0; +} + +/** + * @brief Construct an IPv6 header + * + * @param ipv6_hdr Pointer to the IPv6 header + * @param src_ip Source IP address + * @param dst_ip Destination IP address + * @param proto Protocol + * @param payload_length Length of the payload (data) in bytes + * @return int 0 on success, -1 on failure + */ +int ipv6_header_construct(struct rte_ipv6_hdr * ipv6_hdr, const char * src_ip, const char * dst_ip, uint8_t proto, + uint16_t payload_length) +{ + const char * default_src_ip = "2001:0db8:85a3:0000:0000:8a2e:0370:1111"; + const char * default_dst_ip = "2001:0db8:85a3:0000:0000:8a2e:0370:2222"; + + if (src_ip == NULL) + { + src_ip = default_src_ip; + } + + if (dst_ip == NULL) + { + dst_ip = default_dst_ip; + } + + memset(ipv6_hdr, 0, sizeof(struct rte_ipv6_hdr)); + + ipv6_hdr->vtc_flow = htonl((6 << 28)); + ipv6_hdr->payload_len = htons(payload_length); + ipv6_hdr->proto = proto; + ipv6_hdr->hop_limits = 64; + + if (inet_pton(AF_INET6, src_ip, &ipv6_hdr->src_addr) != 1) + { + return -1; + } + + if (inet_pton(AF_INET6, dst_ip, &ipv6_hdr->dst_addr) != 1) + { + return -1; + } + return 0; } @@ -106,6 +155,35 @@ void udp_header_construct(struct rte_udp_hdr * udp_hdr, uint16_t src_port, uint1 } /** + * @brief Construct a TCP header with default parameters + * + * This function provides default values for TCP header construction. + * + * @param tcp_hdr Pointer to the TCP header + * @param src_port Source port + * @param dst_port Destination port + * @param seq_num Sequence number, default is 0 + * @param ack_num Acknowledgment number, default is 0 + * @param data_offset Data offset, typically set to the size of the TCP header divided by 4, default is 5 (indicating 20 + * bytes) + * @param flags TCP flags (e.g., SYN, ACK, FIN), default is 0 + * @param window Window size, default is 1024 + */ +void tcp_header_construct(struct rte_tcp_hdr * tcp_hdr, uint16_t src_port, uint16_t dst_port, uint32_t seq_num, + uint32_t ack_num, uint8_t data_offset, uint8_t flags, uint16_t window) +{ + tcp_hdr->src_port = rte_cpu_to_be_16(src_port); + tcp_hdr->dst_port = rte_cpu_to_be_16(dst_port); + tcp_hdr->sent_seq = rte_cpu_to_be_32(seq_num); + tcp_hdr->recv_ack = rte_cpu_to_be_32(ack_num); + tcp_hdr->data_off = (data_offset << 4) & 0xF0; + tcp_hdr->tcp_flags = flags; + tcp_hdr->rx_win = rte_cpu_to_be_16(window); + tcp_hdr->cksum = 0; + tcp_hdr->tcp_urp = 0; +} + +/** * @brief Construct a BFD header * * @param bfd_hdr Pointer to the BFD header @@ -165,3 +243,79 @@ const char * create_config_file(const char * content) fclose(fp_cfgfile); return filename; } + +/** + * @brief Constructs a VXLAN-encapsulated packet with specified headers. + * + * This function builds a VXLAN-encapsulated packet by prepending the necessary headers + * in the correct order: VXLAN, UDP, IPv4, and Ethernet. It fills in the headers with the + * provided source and destination IP addresses, MAC addresses, and other necessary fields. + * The function returns `RT_SUCCESS` if the packet is successfully constructed, or `RT_ERR` + * if any header cannot be added. + * + * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. + * @param dir Direction flag for the VXLAN header. + * @param ef_link_id Link ID to be included in the VXLAN header. + * @param src_ip Source IP address as a string. + * @param dst_ip Destination IP address as a string. + * @param src_mac Pointer to the source MAC address. + * @param dst_mac Pointer to the destination MAC address. + * @param eth_type Ethernet type for the outermost Ethernet header. + * + * @return RT_SUCCESS if the packet is successfully constructed, RT_ERR otherwise. + */ +int vxlan_encap_constructed_pkt(struct rte_mbuf * mbuf, uint8_t dir, uint16_t ef_link_id, const char * src_ip, + const char * dst_ip, struct rte_ether_addr * src_mac, struct rte_ether_addr * dst_mac, + uint16_t eth_type) +{ + /* construct the packet by the order of inner to outer */ + struct g_vxlan_hdr * p_vxlan_hdr = (struct g_vxlan_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct g_vxlan_hdr)); + if (unlikely(p_vxlan_hdr == NULL)) + { + return RT_ERR; + } + + /* clear the vxlan header */ + memset(p_vxlan_hdr, 0, sizeof(struct g_vxlan_hdr)); + p_vxlan_hdr->dir = dir; + p_vxlan_hdr->link_id = ef_link_id; + + /* then, the outer udp header */ + struct rte_udp_hdr * p_udp_hdr = (struct rte_udp_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_udp_hdr)); + if (unlikely(p_udp_hdr == NULL)) + { + return RT_ERR; + } + + /* TODO: the source port need to be fill with the hash of inner 2-tuple or 4-tuple, + * ignore the udp checksum */ + p_udp_hdr->src_port = htons(6789); + p_udp_hdr->dst_port = htons(4789); + p_udp_hdr->dgram_len = htons(rte_pktmbuf_pkt_len(mbuf)); + p_udp_hdr->dgram_cksum = 0; + + /* then, the outer ip header */ + struct rte_ipv4_hdr * p_ipv4_hdr = (struct rte_ipv4_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ipv4_hdr)); + if (unlikely(p_ipv4_hdr == NULL)) + { + return RT_ERR; + } + + /* fill the outer ip header */ + if (ipv4_header_construct(p_ipv4_hdr, src_ip, dst_ip, IPPROTO_UDP, rte_pktmbuf_pkt_len(mbuf)) != 0) + { + return RT_ERR; + } + + /* outermost ether header */ + struct rte_ether_hdr * p_eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr)); + if (unlikely(p_eth_hdr == NULL)) + { + return RT_ERR; + } + + /* fill the outermost ether header */ + eth_header_construct(p_eth_hdr, src_mac, dst_mac, eth_type); + + return RT_SUCCESS; +} diff --git a/service/test/test_node_bfd.c b/service/test/test_node_bfd.c index d428a00..650ec70 100644 --- a/service/test/test_node_bfd.c +++ b/service/test/test_node_bfd.c @@ -46,7 +46,7 @@ extern int bfd_session_delete(struct bfd_session_handle * bfd_session_handle, ui extern void eth_header_construct(struct rte_ether_hdr * eth_hdr, struct rte_ether_addr * src_mac, struct rte_ether_addr * dst_mac, uint16_t eth_type); extern int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, const char * dst_ip, - uint8_t proto); + uint8_t proto, uint16_t payload_length); extern void udp_header_construct(struct rte_udp_hdr * udp_hdr, uint16_t src_port, uint16_t dst_port, uint16_t length); extern void bfd_header_construct(struct bfd_hdr * bfd_hdr, uint32_t * my_discriminator, uint32_t * your_discriminator, uint8_t state); @@ -160,7 +160,11 @@ static int testgroup_bfd_discriminator_method_rfc_teardown(void ** state) rte_free(bfd_test_main->mock_sc); /* destroy the graph */ - return rte_graph_destroy(bfd_test_main->graph); + rte_graph_destroy(bfd_test_main->graph); + + /* free the bfd_test_main */ + rte_free(bfd_test_main); + return 0; } static int testgroup_bfd_discriminator_method_flipping_setup(void ** state) @@ -244,7 +248,11 @@ static int testgroup_bfd_discriminator_method_flipping_teardown(void ** state) rte_free(bfd_test_main->mock_sc); /* destroy the graph */ - return rte_graph_destroy(bfd_test_main->graph); + rte_graph_destroy(bfd_test_main->graph); + + /* free the bfd_test_main */ + rte_free(bfd_test_main); + return 0; } /* --------------------------------------------------- Test case --------------------------------------------------- */ @@ -432,8 +440,7 @@ static void testcase_bfd_rfc5881(void ** state) /* alloc the mbuf as input */ struct rte_mbuf * mbuf_input[1]; mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); - - assert_non_null(mbuf_input); + assert_non_null(mbuf_input[0]); /* set the return value for the mock function */ will_return(mock_pkt_input_process, 1); @@ -466,7 +473,7 @@ static void testcase_bfd_rfc5881(void ** state) eth_header_construct(ether_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ - ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP); + ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); @@ -649,7 +656,8 @@ static void testcase_bfd_session_full(void ** state) eth_header_construct(ether_hdr, NULL, NULL, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ - ipv4_header_construct(ipv4_hdr, "172.16.1.1", NULL, IPPROTO_UDP); + ipv4_header_construct(ipv4_hdr, "172.16.1.1", NULL, IPPROTO_UDP, + sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); @@ -771,7 +779,7 @@ static void testcase_bfd_discriminator_method_flipping(void ** state) eth_header_construct(ether_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ - ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP); + ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); diff --git a/service/test/test_node_ef.c b/service/test/test_node_ef.c new file mode 100644 index 0000000..ff2cb08 --- /dev/null +++ b/service/test/test_node_ef.c @@ -0,0 +1,3212 @@ +#include <setjmp.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <cmocka.h> + +#include <rte_eal.h> +#include <rte_graph.h> +#include <rte_graph_worker.h> +#include <rte_mempool.h> + +#include <port_adapter_mapping.h> +#include <sc_node.h> +#include <sc_node_common.h> +#include <sys/types.h> + +#define MOCK_NR_DEV_MAX 512 +#define MOCK_SIZE_CFGFILE_CONTENT (128 + (MOCK_NR_DEV_MAX * 128)) + +char * mock_cfgfile_content = NULL; +char mock_devs_name[MOCK_NR_DEV_MAX][32]; +struct mr_dev_desc * mock_devs_desc[MOCK_NR_DEV_MAX]; +static struct rte_mempool * mock_pktmbuf_pool = NULL; + +extern const char * create_config_file(const char * content); + +/* + * generate the configuration string + */ +char * generate_config_string(uint32_t num_adapters, int mode, int is_random) +{ + memset(mock_cfgfile_content, 0, MOCK_SIZE_CFGFILE_CONTENT); + strcpy(mock_cfgfile_content, "[limits]\n" + "nr_max_link_dbs=64\n" + "nr_max_ef_adapters=32\n\n" + "[ef_adapters]\n" + "sid_start=100\n" + "sid_end=200\n\n"); + + /* generate the dynamic parts */ + if (is_random) + { + srand(time(NULL)); + } + + /* Allocate memory for used_ids */ + int * used_ids = (int *)calloc(num_adapters, sizeof(int)); + if (used_ids == NULL) + { + perror("Failed to allocate memory for used_ids"); + return NULL; + } + + /* generate the adapter entries */ + char adapter_entry[1024]; + for (int i = 0; i < num_adapters; i++) + { + int ef_adapter_id; + if (is_random) + { + do + { + ef_adapter_id = rand() % num_adapters; + } while (used_ids[ef_adapter_id]); + } + else + { + ef_adapter_id = i; + } + used_ids[ef_adapter_id] = 1; + + snprintf(adapter_entry, sizeof(adapter_entry), + "[ef_adapter:%d]\nef_adapter_id=%d\nmode=%d\nlisten_device=ens4f0np%d\n\n", i, ef_adapter_id, mode, i); + strcat(mock_cfgfile_content, adapter_entry); + } + + free(used_ids); + return mock_cfgfile_content; +} + +/* --------------------------------------------------- mock func --------------------------------------------------- */ +struct mr_dev_desc * __wrap_mr_dev_desc_lookup(struct devmgr_main * devmgr_main, const char * devsym) +{ + // printf("Mocking mr_dev_desc_lookup\n"); + check_expected(devsym); + return mock_type(struct mr_dev_desc *); +} + +int __wrap_port_adapter_mapping_insert(port_id_t port_id, enum adapter_type adapter_type) +{ + return RT_SUCCESS; +} + +/* ------------------------------------------- Test group setup/teardown ------------------------------------------- */ +static int testgroup_common_setup(void ** state) +{ + struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); + assert_non_null(mock_sc); + + mock_sc->nr_io_thread = 1; + *state = mock_sc; + return 0; +} + +static int testgroup_common_teardown(void ** state) +{ + struct sc_main * mock_sc = *state; + rte_free(mock_sc); + return 0; +} + +/* ------------------------------------------- Test case 'config handle' ------------------------------------------- */ +extern struct ef_config_handle * ef_config_handle_create(uint32_t ef_adapters_max); +extern int ef_config_handle_delete(struct ef_config_handle * cfg_handle); +extern int ef_config_parse(struct sc_main * sc, struct ef_config_handle * cfg_handle); +extern struct ef_adapter * ef_config_handle_adapters_data_get(struct ef_config_handle * cfg_handle); +uint16_t ef_config_handle_nr_adapters_get(struct ef_config_handle * cfg_handle); +uint32_t ef_config_handle_sid_start_get(struct ef_config_handle * cfg_handle); +uint32_t ef_config_handle_sid_end_get(struct ef_config_handle * cfg_handle); +uint32_t ef_config_handle_ef_adapters_max_get(struct ef_config_handle * cfg_handle); +uint32_t ef_config_handle_link_dbs_max_get(struct ef_config_handle * cfg_handle); + +/* + * Test Case: ef config handle success + */ +static void testcase_ef_config_handle_success(void ** state) +{ + /* + * Case 1: the etherfabric id is continuous from 100 to 200 + */ + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 200 - 100 + 1; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + uint32_t ef_adapters_max = nr_ef_adapters; + struct ef_config_handle * cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + int ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + struct ef_adapter * ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + /* check the number of ef adapters */ + assert_int_equal(ef_config_handle_nr_adapters_get(cfg_handle), nr_ef_adapters); + + /* check the sid range */ + assert_int_equal(ef_config_handle_sid_start_get(cfg_handle), 100); + assert_int_equal(ef_config_handle_sid_end_get(cfg_handle), 200); + + /* check the ef adapters max */ + assert_int_equal(ef_config_handle_ef_adapters_max_get(cfg_handle), ef_adapters_max); + + /* check the link dbs max */ + assert_int_equal(ef_config_handle_link_dbs_max_get(cfg_handle), 64); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: the etherfabric id is radom from 100 to 200 + */ + + /* generate the configuration string */ + test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 1); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + ef_adapters_max = nr_ef_adapters; + cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + /* check the number of ef adapters */ + assert_int_equal(ef_config_handle_nr_adapters_get(cfg_handle), nr_ef_adapters); + + /* check the sid range */ + assert_int_equal(ef_config_handle_sid_start_get(cfg_handle), 100); + assert_int_equal(ef_config_handle_sid_end_get(cfg_handle), 200); + + /* check the ef adapters max */ + assert_int_equal(ef_config_handle_ef_adapters_max_get(cfg_handle), ef_adapters_max); + + /* check the link dbs max */ + assert_int_equal(ef_config_handle_link_dbs_max_get(cfg_handle), 64); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 3: the nr_ef_adapters less then sid range( 100 - 200) + */ + + /* generate the configuration string */ + nr_ef_adapters = 32; + test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 1); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + ef_adapters_max = nr_ef_adapters; + cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + /* check the number of ef adapters */ + assert_int_equal(ef_config_handle_nr_adapters_get(cfg_handle), nr_ef_adapters); + + /* check the sid range */ + assert_int_equal(ef_config_handle_sid_start_get(cfg_handle), 100); + assert_int_equal(ef_config_handle_sid_end_get(cfg_handle), 200); + + /* check the ef adapters max */ + assert_int_equal(ef_config_handle_ef_adapters_max_get(cfg_handle), ef_adapters_max); + + /* check the link dbs max */ + assert_int_equal(ef_config_handle_link_dbs_max_get(cfg_handle), 64); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* + * Test Case: ef config handle failure + */ +static void testcase_ef_config_handle_failure(void ** state) +{ + /* + * Case 1: the nr etherfabric adapter is out of sid range( 100 -200) + */ + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 256; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + uint32_t ef_adapters_max = nr_ef_adapters; + struct ef_config_handle * cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + int ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_ERR); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: the nr etherfabric adapter is out of ethernet adapter capacity + */ + + /* generate the configuration string */ + nr_ef_adapters = 128; + test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + ef_adapters_max = 64; + assert(ef_adapters_max <= 512); + + for (uint32_t i = 0; i < ef_adapters_max; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + struct ef_adapter * ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + /* check the number of ef adapters */ + assert_int_equal(ef_config_handle_nr_adapters_get(cfg_handle), ef_adapters_max); + + /* check the sid range */ + assert_int_equal(ef_config_handle_sid_start_get(cfg_handle), 100); + assert_int_equal(ef_config_handle_sid_end_get(cfg_handle), 200); + + /* check the ef adapters max */ + assert_int_equal(ef_config_handle_ef_adapters_max_get(cfg_handle), ef_adapters_max); + + /* check the link dbs max */ + assert_int_equal(ef_config_handle_link_dbs_max_get(cfg_handle), 64); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* ----------------------------------------- Test case 'ef adapter handle' ----------------------------------------- */ +struct ef_adapter; +struct ef_adapter_handle; +enum ef_adapter_mode; + +extern struct ef_adapter_handle * ef_adapter_handle_create(struct ef_adapter * adapters_data, uint16_t capacity, + uint16_t nr_adapters); +extern int ef_adapter_handle_delete(struct ef_adapter_handle * handle); +extern uint16_t ef_adapter_handle_capacity_get(struct ef_adapter_handle * handle); +extern uint16_t ef_adapter_handle_nr_adapters_get(struct ef_adapter_handle * handle); +extern struct ef_adapter * ef_adapter_handle_adapter_get_by_id(struct ef_adapter_handle * handle, uint16_t adapter_id); +extern int ef_adapter_handle_adapter_lookup(struct ef_adapter_handle * handle, uint32_t dst_addr, + uint16_t * out_ef_adapter_id); +extern uint16_t ef_adapter_id_get(struct ef_adapter * ef_adapter); + +/* + * Test Case: ef adapter handle success + */ +static void testcase_ef_adapter_handle_success(void ** state) +{ + /* + * Case 1: the etherfabric id is continuous from 100 to 200 + */ + + /* generate the configuration string */ + uint16_t nr_ef_adapters = 200 - 100 + 1; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + uint32_t ef_adapters_max = nr_ef_adapters; + struct ef_config_handle * cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + int ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + struct ef_adapter * ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + uint16_t capacity = ef_config_handle_ef_adapters_max_get(cfg_handle); + assert_int_equal(capacity, ef_adapters_max); + + uint16_t nr_adapters = ef_config_handle_nr_adapters_get(cfg_handle); + assert_int_equal(nr_adapters, nr_ef_adapters); + + /* create the ef adapter handle */ + struct ef_adapter_handle * ef_adapter_handle = ef_adapter_handle_create(ef_adapters_data, capacity, nr_ef_adapters); + assert_non_null(ef_adapter_handle); + + /* check the capacity */ + assert_int_equal(ef_adapter_handle_capacity_get(ef_adapter_handle), capacity); + + /* check the number of adapters */ + assert_int_equal(ef_adapter_handle_nr_adapters_get(ef_adapter_handle), nr_adapters); + + /* check the ef adapter by id */ + for (uint16_t i = 0; i < nr_adapters; i++) + { + struct ef_adapter * adapter = ef_adapter_handle_adapter_get_by_id(ef_adapter_handle, i); + assert_non_null(adapter); + } + + /* check the ef adapter lookup */ + for (uint32_t i = 0; i < nr_adapters; i++) + { + uint16_t ef_adapter_id; + uint32_t dst_addr = htonl(0x0A0A0A0A + i); + ret = ef_adapter_handle_adapter_lookup(ef_adapter_handle, dst_addr, &ef_adapter_id); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(ef_adapter_id, i); + } + + /* delete the ef adapter handle */ + ret = ef_adapter_handle_delete(ef_adapter_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: the etherfabric id is radom from 100 to 200 + */ + + /* generate the configuration string */ + nr_ef_adapters = 200 - 100 + 1; + test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 1); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + ef_adapters_max = nr_ef_adapters; + cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + capacity = ef_config_handle_ef_adapters_max_get(cfg_handle); + assert_int_equal(capacity, ef_adapters_max); + + nr_adapters = ef_config_handle_nr_adapters_get(cfg_handle); + assert_int_equal(nr_adapters, nr_ef_adapters); + + /* create the ef adapter handle */ + ef_adapter_handle = ef_adapter_handle_create(ef_adapters_data, capacity, nr_adapters); + assert_non_null(ef_adapter_handle); + + /* check the capacity */ + assert_int_equal(ef_adapter_handle_capacity_get(ef_adapter_handle), capacity); + + /* check the number of adapters */ + assert_int_equal(ef_adapter_handle_nr_adapters_get(ef_adapter_handle), nr_adapters); + + /* check the ef adapter by id */ + for (uint16_t i = 0; i < nr_adapters; i++) + { + struct ef_adapter * adapter = ef_adapter_handle_adapter_get_by_id(ef_adapter_handle, i); + assert_non_null(adapter); + } + + /* check the ef adapter lookup */ + for (uint32_t i = 0; i < nr_adapters; i++) + { + uint16_t ef_adapter_id; + uint32_t dst_addr = htonl(0x0A0A0A0A + i); + ret = ef_adapter_handle_adapter_lookup(ef_adapter_handle, dst_addr, &ef_adapter_id); + assert_int_equal(ret, RT_SUCCESS); + + struct ef_adapter * adapter = ef_adapter_handle_adapter_get_by_id(ef_adapter_handle, ef_adapter_id); + assert_non_null(adapter); + + assert_int_equal(ef_adapter_id, ef_adapter_id_get(adapter)); + } + + /* delete the ef adapter handle */ + ret = ef_adapter_handle_delete(ef_adapter_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* + * Test Case: ef adapter handle failure + */ +static void testcase_ef_adapter_handle_failure(void ** state) +{ + /* + * Case 1: adapter lookup failure + */ + + /* generate the configuration string */ + uint16_t nr_ef_adapters = 200 - 100 + 1; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + uint32_t ef_adapters_max = nr_ef_adapters; + struct ef_config_handle * cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + int ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + struct ef_adapter * ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + uint16_t capacity = ef_config_handle_ef_adapters_max_get(cfg_handle); + assert_int_equal(capacity, ef_adapters_max); + + uint16_t nr_adapters = ef_config_handle_nr_adapters_get(cfg_handle); + assert_int_equal(nr_adapters, nr_ef_adapters); + + /* create the ef adapter handle */ + struct ef_adapter_handle * ef_adapter_handle = ef_adapter_handle_create(ef_adapters_data, capacity, nr_adapters); + assert_non_null(ef_adapter_handle); + + /* check the capacity */ + assert_int_equal(ef_adapter_handle_capacity_get(ef_adapter_handle), capacity); + + /* check the number of adapters */ + assert_int_equal(ef_adapter_handle_nr_adapters_get(ef_adapter_handle), nr_adapters); + + /* check the ef adapter lookup */ + uint16_t ef_adapter_id; + uint32_t dst_addr = 0x0A0A0A0A + 256; + ret = ef_adapter_handle_adapter_lookup(ef_adapter_handle, dst_addr, &ef_adapter_id); + assert_int_equal(ret, RT_ERR); + + /* delete the ef adapter handle */ + ret = ef_adapter_handle_delete(ef_adapter_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: the number of adapter is out of capacity + */ + + /* generate the configuration string */ + nr_ef_adapters = 200 - 100 + 1; + test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + assert_non_null(test_cfgfile_content); + + /* create the configuration file */ + filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + ef_adapters_max = nr_ef_adapters; + cfg_handle = ef_config_handle_create(ef_adapters_max); + + /* parse the configuration */ + ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + capacity = ef_config_handle_ef_adapters_max_get(cfg_handle); + assert_int_equal(capacity, ef_adapters_max); + + nr_adapters = ef_config_handle_nr_adapters_get(cfg_handle); + assert_int_equal(nr_adapters, nr_ef_adapters); + + /* create the ef adapter handle */ + capacity = 64; + ef_adapter_handle = ef_adapter_handle_create(ef_adapters_data, capacity, nr_adapters); + assert_null(ef_adapter_handle); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 3: delete the ef adapter handle + */ + ret = ef_adapter_handle_delete(NULL); + assert_int_equal(ret, RT_ERR); +} + +/* ------------------------------------------- Test case 'ef peer handle' ------------------------------------------ */ +/* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */ +#define LCORE_CACHE_SIZE 64 +#define SC_EF_PEER_ENTRIES 256 +// #define SC_EF_PEER_MEMBER (SC_EF_PEER_ENTRIES + (RTE_MAX_LCORE - 1) * (LCORE_CACHE_SIZE - 1) + 1) +#define SC_EF_PEER_CAPACITY_CALC(entries, cache_size) ((entries) + (RTE_MAX_LCORE - 1) * ((cache_size)-1) + 1) + +struct ef_peer_handle; +union ef_peer_key { + struct + { + uint32_t ip_src; + struct rte_ether_addr mac_src; + }; + xmm_t xmm; +}; + +extern int ef_peer_handle_delete(struct ef_peer_handle * ef_peer_handle); +extern struct ef_peer_handle * ef_peer_handle_create(uint32_t entries); +extern uint16_t ef_peer_handle_capacity_get(struct ef_peer_handle * handle); +extern uint32_t ef_peer_handle_entries_get(struct ef_peer_handle * handle); +extern uint32_t ef_peer_handle_remaining_entries_get(struct ef_peer_handle * handle); +extern struct ef_peer * ef_peer_handle_peer_get(struct ef_peer_handle * handle, uint16_t ef_peer_index); +extern int ef_peer_handle_peer_lookup(struct ef_peer_handle * handle, const union ef_peer_key * key); +extern int ef_peer_handle_peer_add(struct ef_peer_handle * handle, const union ef_peer_key * key); +extern uint32_t ef_peer_ip_addr_get(struct ef_peer * ef_peer); +extern struct rte_ether_addr * ef_peer_mac_addr_get(struct ef_peer * ef_peer); + +/* + * Test Case: ef peer handle success + */ +static void testcase_ef_peer_handle_success(void ** state) +{ + /* + * Case 1: basic test for ef peer handle + */ + + /* create the ef peer handle */ + struct ef_peer_handle * ef_peer_handle = ef_peer_handle_create(SC_EF_PEER_ENTRIES); + assert_non_null(ef_peer_handle); + + /* check the ef peer handle */ + assert_int_equal(ef_peer_handle_capacity_get(ef_peer_handle), + SC_EF_PEER_CAPACITY_CALC(SC_EF_PEER_ENTRIES, LCORE_CACHE_SIZE)); + + /* check the ef peer handle entries */ + assert_int_equal(ef_peer_handle_entries_get(ef_peer_handle), SC_EF_PEER_ENTRIES); + + /* check the ef peer handle peer get */ + for (uint16_t i = 0; i < SC_EF_PEER_ENTRIES; i++) + { + struct ef_peer * peer = ef_peer_handle_peer_get(ef_peer_handle, i); + assert_non_null(peer); + } + + /* check the ef peer handle peer lookup */ + union ef_peer_key key; + key.ip_src = 0x0A0A0A0A; + struct rte_ether_addr mac_src = {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; + key.mac_src = mac_src; + + int ret = ef_peer_handle_peer_lookup(ef_peer_handle, &key); + assert_int_equal(ret < 0, 1); + + /* check the ef peer handle peer add */ + int out_add_peer_id = ef_peer_handle_peer_add(ef_peer_handle, &key); + assert_int_not_equal(out_add_peer_id, RT_ERR); + + /* check the ef peer handle peer lookup */ + int peer_id = ef_peer_handle_peer_lookup(ef_peer_handle, &key); + assert_int_not_equal(peer_id, RT_ERR); + assert_int_equal(out_add_peer_id, peer_id); + + /* check the ef peer handle peer get */ + struct ef_peer * ef_peer = ef_peer_handle_peer_get(ef_peer_handle, peer_id); + assert_non_null(ef_peer); + + /* check the ef peer ip addr */ + assert_int_equal(ef_peer_ip_addr_get(ef_peer), key.ip_src); + + /* check the ef peer mac addr */ + assert_memory_equal(ef_peer_mac_addr_get(ef_peer), &key.mac_src, sizeof(struct rte_ether_addr)); + + /* delete the ef peer handle */ + ret = ef_peer_handle_delete(ef_peer_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: add peer to full ef peer handle + */ + + /* create the ef peer handle */ + ef_peer_handle = ef_peer_handle_create(SC_EF_PEER_ENTRIES); + assert_non_null(ef_peer_handle); + + /* check the ef peer handle */ + assert_int_equal(ef_peer_handle_capacity_get(ef_peer_handle), + SC_EF_PEER_CAPACITY_CALC(SC_EF_PEER_ENTRIES, LCORE_CACHE_SIZE)); + + /* check the ef peer handle entries */ + uint32_t nr_entries = ef_peer_handle_entries_get(ef_peer_handle); + assert_int_equal(nr_entries, SC_EF_PEER_ENTRIES); + + /* Add peer to full ef peer handle */ + int out_add_peer_ids[nr_entries]; + for (uint16_t i = 0; i < nr_entries; i++) + { + key.ip_src = 0x0A0A0A0A + i; + key.mac_src.addr_bytes[5] = i; + out_add_peer_ids[i] = ef_peer_handle_peer_add(ef_peer_handle, &key); + assert_int_not_equal(out_add_peer_ids[i], RT_ERR); + } + + /* lookup peer from full ef peer handle */ + int out_peer_ids[nr_entries]; + for (uint16_t i = 0; i < nr_entries; i++) + { + key.ip_src = 0x0A0A0A0A + i; + key.mac_src.addr_bytes[5] = i; + out_peer_ids[i] = ef_peer_handle_peer_lookup(ef_peer_handle, &key); + assert_int_not_equal(out_peer_ids[i], RT_ERR); + } + + /* check the ef peer handle peer get */ + for (uint16_t i = 0; i < nr_entries; i++) + { + struct ef_peer * ef_peer = ef_peer_handle_peer_get(ef_peer_handle, out_peer_ids[i]); + assert_non_null(ef_peer); + + key.ip_src = 0x0A0A0A0A + i; + key.mac_src.addr_bytes[5] = i; + + assert_int_equal(out_add_peer_ids[i], out_peer_ids[i]); + assert_int_equal(ef_peer_ip_addr_get(ef_peer), key.ip_src); + assert_memory_equal(ef_peer_mac_addr_get(ef_peer), &key.mac_src, sizeof(struct rte_ether_addr)); + } + + /* delete the ef peer handle */ + ret = ef_peer_handle_delete(ef_peer_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* + * Test Case: ef peer handle failure + */ +static void testcase_ef_peer_handle_failure(void ** state) +{ + /* + * Case 1: delete the ef peer handle (NULL) + */ + int ret = ef_peer_handle_delete(NULL); + assert_int_equal(ret, RT_ERR); + + /* + * Case 2: create the ef peer handle with invalid entries + */ + struct ef_peer_handle * ef_peer_handle = ef_peer_handle_create(0); + assert_null(ef_peer_handle); + + /* + * Case 3:create the ef peer handle with entries too large + */ + ef_peer_handle = ef_peer_handle_create(UINT32_MAX); + assert_null(ef_peer_handle); + + /* + * Case 4: lookup the ef peer with invalid key + */ + ef_peer_handle = ef_peer_handle_create(SC_EF_PEER_ENTRIES); + assert_non_null(ef_peer_handle); + + union ef_peer_key key; + key.ip_src = 0x0A0A0A0A; + struct rte_ether_addr mac_src = {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; + key.mac_src = mac_src; + + int peer_id = ef_peer_handle_peer_lookup(ef_peer_handle, &key); + assert_int_equal(peer_id < 0, 1); + + /* delete the ef peer handle */ + ret = ef_peer_handle_delete(ef_peer_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 5: Adding ef peers exceeds the maximum number of entries + */ + /* create the ef peer handle */ + ef_peer_handle = ef_peer_handle_create(SC_EF_PEER_ENTRIES); + assert_non_null(ef_peer_handle); + + /* check the ef peer handle */ + assert_int_equal(ef_peer_handle_capacity_get(ef_peer_handle), + SC_EF_PEER_CAPACITY_CALC(SC_EF_PEER_ENTRIES, LCORE_CACHE_SIZE)); + + /* check the ef peer handle entries */ + uint32_t nr_entries = ef_peer_handle_entries_get(ef_peer_handle); + assert_int_equal(nr_entries, SC_EF_PEER_ENTRIES); + + /* Add peer to full ef peer handle */ + for (uint32_t i = 0; i < nr_entries; i++) + { + key.ip_src = 0x0A0A0A0A + i; + key.mac_src.addr_bytes[5] = i; + ef_peer_handle_peer_add(ef_peer_handle, &key); + + if (ef_peer_handle_remaining_entries_get(ef_peer_handle) == 0) + { + break; + } + } + + /* Add peer to full ef peer handle */ + uint32_t nr_remaining_entries = ef_peer_handle_remaining_entries_get(ef_peer_handle); + assert_int_equal(nr_remaining_entries, 0); + + /* delete the ef peer handle */ + ret = ef_peer_handle_delete(ef_peer_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* ---------------------------- Test case 'traffic link to etherfabric peer map handle' ---------------------------- */ +struct tl_to_ef_peer_map_handle; + +extern struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle_create(uint16_t capacity); +extern int tl_to_ef_peer_map_handle_delete(struct tl_to_ef_peer_map_handle * handle); +extern uint16_t tl_to_ef_peer_map_handle_capacity_get(struct tl_to_ef_peer_map_handle * handle); +extern int tl_to_ef_peer_map_handle_associate(struct tl_to_ef_peer_map_handle * handle, uint16_t traffic_link_id, + int ef_peer_index); +extern int tl_to_ef_peer_map_handle_get_ef_peer_index_by_tl_id(struct tl_to_ef_peer_map_handle * handle, + uint16_t traffic_link_id, uint16_t * out_ef_peer_index); +/* + * Test Case: tl to ef peer map handle success + */ +static void testcase_tl_to_ef_peer_map_handle_success(void ** state) +{ + /* + * Case 1: basic test for tl to ef peer map handle + */ + + /* create the tl to ef peer map handle */ + uint16_t capacity = 1; + struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle = tl_to_ef_peer_map_handle_create(capacity); + assert_non_null(tl_to_ef_peer_map_handle); + + /* check the tl to ef peer map handle */ + assert_int_equal(tl_to_ef_peer_map_handle_capacity_get(tl_to_ef_peer_map_handle), capacity); + + /* associate the tl to ef peer map handle */ + int ret = tl_to_ef_peer_map_handle_associate(tl_to_ef_peer_map_handle, 0, 0); + assert_int_equal(ret, RT_SUCCESS); + + /* check the tl to ef peer map handle get ef peer index by tl id */ + uint16_t ef_peer_index; + ret = tl_to_ef_peer_map_handle_get_ef_peer_index_by_tl_id(tl_to_ef_peer_map_handle, 0, &ef_peer_index); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(ef_peer_index, 0); + + /* delete the tl to ef peer map handle */ + ret = tl_to_ef_peer_map_handle_delete(tl_to_ef_peer_map_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* + * Case 2: associate the traffic link ID with the EtherFabric peer map at full capacity + */ + + /* create the tl to ef peer map handle */ + capacity = UINT16_MAX; + tl_to_ef_peer_map_handle = tl_to_ef_peer_map_handle_create(capacity); + assert_non_null(tl_to_ef_peer_map_handle); + + /* check the tl to ef peer map handle */ + assert_int_equal(tl_to_ef_peer_map_handle_capacity_get(tl_to_ef_peer_map_handle), capacity); + + /* associate the tl to ef peer map handle */ + for (uint16_t i = 0; i < capacity; i++) + { + int ret = tl_to_ef_peer_map_handle_associate(tl_to_ef_peer_map_handle, i, i); + assert_int_equal(ret, RT_SUCCESS); + } + + /* check the tl to ef peer map handle get ef peer index by tl id */ + for (uint16_t i = 0; i < capacity; i++) + { + uint16_t ef_peer_index; + int ret = tl_to_ef_peer_map_handle_get_ef_peer_index_by_tl_id(tl_to_ef_peer_map_handle, i, &ef_peer_index); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(ef_peer_index, i); + } + + /* delete the tl to ef peer map handle */ + ret = tl_to_ef_peer_map_handle_delete(tl_to_ef_peer_map_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* + * Test Case: tl to ef peer map handle failure + */ +static void testcase_tl_to_ef_peer_map_handle_failure(void ** state) +{ + /* + * Case 1: delete the tl to ef peer map handle (NULL) + */ + int ret = tl_to_ef_peer_map_handle_delete(NULL); + assert_int_equal(ret, RT_ERR); + + /* + * Case 2: create the tl to ef peer map handle with invalid capacity + */ + struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle = tl_to_ef_peer_map_handle_create(0); + assert_null(tl_to_ef_peer_map_handle); + + /* + * Case 3: associate the traffic link ID with the EtherFabric peer map out of capacity + */ + /* create the tl to ef peer map handle */ + uint32_t capacity = UINT16_MAX; + tl_to_ef_peer_map_handle = tl_to_ef_peer_map_handle_create(capacity); + assert_non_null(tl_to_ef_peer_map_handle); + + /* check the tl to ef peer map handle */ + assert_int_equal(tl_to_ef_peer_map_handle_capacity_get(tl_to_ef_peer_map_handle), capacity); + + /* associate the tl to ef peer map handle */ + for (uint32_t i = 0; i < capacity; i++) + { + int ret = tl_to_ef_peer_map_handle_associate(tl_to_ef_peer_map_handle, i, i); + assert_int_equal(ret, RT_SUCCESS); + } + + /* associate the tl to ef peer map handle at full capacity */ + ret = tl_to_ef_peer_map_handle_associate(tl_to_ef_peer_map_handle, capacity, capacity); + assert_int_equal(ret, RT_ERR); + + /* delete the tl to ef peer map handle */ + ret = tl_to_ef_peer_map_handle_delete(tl_to_ef_peer_map_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* ------------------------------------------- Test case 'ef node main' -------------------------------------------- */ +struct ef_node_main; +extern int node_ef_main_delete(struct ef_node_main * ef_main); +extern struct ef_node_main * node_ef_main_create(struct sc_main * sc, struct ef_config_handle * ef_node_cfg); +extern void ef_info_dump(struct ef_node_main * ef_main); +extern uint16_t node_ef_main_nr_graphs_get(struct ef_node_main * ef_main); +extern struct sid_handle * node_ef_main_sid_handle_get(struct ef_node_main * ef_main); +extern struct ef_adapter_handle * node_ef_main_ef_adapter_handle_get(struct ef_node_main * ef_main); +extern struct link_db_ctx * node_ef_main_link_db_ctx_get(struct ef_node_main * ef_main); +extern struct ef_peer_handle * node_ef_main_ef_peer_handle_get(struct ef_node_main * ef_main); +extern struct tl_to_ef_peer_map_handle * node_ef_main_tl_to_ef_peer_map_handle_get(struct ef_node_main * ef_main); +extern struct sc_metrics_handle * node_ef_main_ingress_metrics_handle_get(struct ef_node_main * ef_main, + uint16_t graph_id); +extern struct sc_metrics_handle * node_ef_main_egress_metrics_handle_get(struct ef_node_main * ef_main, + uint16_t graph_id); + +/* + * Test Case: ef node main success + */ +static void testcase_ef_node_main_success(void ** state) +{ + /* + * Case 1: basic test for ef node main + */ + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 200 - 100 + 1; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* create the ef config handle */ + uint32_t ef_adapters_max = nr_ef_adapters; + struct ef_config_handle * cfg_handle = ef_config_handle_create(ef_adapters_max); + assert_non_null(cfg_handle); + + /* parse the configuration */ + int ret = ef_config_parse(mock_sc, cfg_handle); + assert_int_equal(ret, RT_SUCCESS); + + /* check the ef adapters data */ + struct ef_adapter * ef_adapters_data = ef_config_handle_adapters_data_get(cfg_handle); + assert_non_null(ef_adapters_data); + + /* check the number of ef adapters */ + assert_int_equal(ef_config_handle_nr_adapters_get(cfg_handle), nr_ef_adapters); + + /* check the sid range */ + assert_int_equal(ef_config_handle_sid_start_get(cfg_handle), 100); + assert_int_equal(ef_config_handle_sid_end_get(cfg_handle), 200); + + /* check the ef adapters max */ + assert_int_equal(ef_config_handle_ef_adapters_max_get(cfg_handle), ef_adapters_max); + + /* check the link dbs max */ + assert_int_equal(ef_config_handle_link_dbs_max_get(cfg_handle), 64); + + /* create the ef node main */ + struct ef_node_main * ef_main = node_ef_main_create(mock_sc, cfg_handle); + assert_non_null(ef_main); + + /* check the ef node main */ + ef_info_dump(ef_main); + + /* check the number of graphs */ + assert_int_equal(node_ef_main_nr_graphs_get(ef_main), 1); + + /* check the sid handle */ + struct sid_handle * sid_handle = node_ef_main_sid_handle_get(ef_main); + assert_non_null(sid_handle); + + /* check the ef adapter handle */ + struct ef_adapter_handle * ef_adapter_handle = node_ef_main_ef_adapter_handle_get(ef_main); + assert_non_null(ef_adapter_handle); + + /* check the link db ctx */ + struct link_db_ctx * link_db_ctx = node_ef_main_link_db_ctx_get(ef_main); + assert_non_null(link_db_ctx); + + /* check the ef peer handle */ + struct ef_peer_handle * ef_peer_handle = node_ef_main_ef_peer_handle_get(ef_main); + assert_non_null(ef_peer_handle); + + /* check the tl to ef peer map handle */ + struct tl_to_ef_peer_map_handle * tl_to_ef_peer_map_handle = node_ef_main_tl_to_ef_peer_map_handle_get(ef_main); + assert_non_null(tl_to_ef_peer_map_handle); + + /* check the ingress metrics handle */ + struct sc_metrics_handle * ingress_metrics_handle = node_ef_main_ingress_metrics_handle_get(ef_main, 0); + assert_non_null(ingress_metrics_handle); + + /* check the egress metrics handle */ + struct sc_metrics_handle * egress_metrics_handle = node_ef_main_egress_metrics_handle_get(ef_main, 0); + assert_non_null(egress_metrics_handle); + + /* delete the ef node main */ + ret = node_ef_main_delete(ef_main); + assert_int_equal(ret, RT_SUCCESS); + + /* delete the ef config handle */ + ret = ef_config_handle_delete(cfg_handle); + assert_int_equal(ret, RT_SUCCESS); +} + +/* + * Test Case: ef node main failure + */ +static void testcase_ef_node_main_failure(void ** state) +{ + /* + * Case 1: delete the ef node main (NULL) + */ + int ret = node_ef_main_delete(NULL); + assert_int_equal(ret, RT_ERR); + + /* + * Case 2: create the ef node main with a NULL argument + */ + struct ef_node_main * ef_main = node_ef_main_create(NULL, NULL); + assert_null(ef_main); +} + +/* ---------------------------------------------- Test case 'ef init' ---------------------------------------------- */ +extern int ef_init(struct sc_main * sc); +extern int ef_deinit(); + +/* + * Test Case: ef init success + */ +static void testcase_ef_init_success(void ** state) +{ + /* + * Case 1: basic test for ef init + */ + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 32; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + struct sc_main * mock_sc = *state; + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* Initialize the ef */ + int ret = ef_init(mock_sc); + assert_int_equal(ret, RT_SUCCESS); + + /* Deinitialize the ef */ + ret = ef_deinit(); + assert_int_equal(ret, RT_SUCCESS); +} + +/* ---------------------------------------------- Test case 'ef node' ---------------------------------------------- */ +struct ef_test_main +{ + struct sc_main * mock_sc; + rte_graph_t graph; +}; + +/* Set the pkt offset */ +const static int ef_encap_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_udp_hdr) + sizeof(struct g_vxlan_hdr); +extern struct ef_node_main * g_ef_node_main_get(void); +extern void eth_header_construct(struct rte_ether_hdr * eth_hdr, struct rte_ether_addr * src_mac, + struct rte_ether_addr * dst_mac, uint16_t eth_type); +extern int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, const char * dst_ip, + uint8_t proto, uint16_t payload_length); +extern int ipv6_header_construct(struct rte_ipv6_hdr * ipv6_hdr, const char * src_ip, const char * dst_ip, + uint8_t proto, uint16_t payload_length); +extern void udp_header_construct(struct rte_udp_hdr * udp_hdr, uint16_t src_port, uint16_t dst_port, uint16_t length); +extern void tcp_header_construct(struct rte_tcp_hdr * tcp_hdr, uint16_t src_port, uint16_t dst_port, uint32_t seq_num, + uint32_t ack_num, uint8_t data_offset, uint8_t flags, uint16_t window); +extern int vxlan_encap_constructed_pkt(struct rte_mbuf * mbuf, uint8_t dir, uint16_t ef_link_id, const char * src_ip, + const char * dst_ip, struct rte_ether_addr * src_mac, + struct rte_ether_addr * dst_mac, uint16_t eth_type); +extern int sc_metrics_value_get(struct sc_metrics_handle * metrics_handle, uint64_t * value, uint16_t key); + +/* + * Etherfabric ingress setup + */ +static int testgroup_ef_ingress_setup(void ** state) +{ + /* mock pkt source to generate mock packets */ + const char * node_patterns[] = { + "mock_pkt_input", + "mock_pkt_output", + "ef_ingress", + }; + + /* create a fake graph */ + struct rte_graph_param graph_param = { + .node_patterns = node_patterns, + .nb_node_patterns = RTE_DIM(node_patterns), + .socket_id = 0, + }; + + /* Update the pkt input's next id */ + rte_node_t node_id_pkt_input = rte_node_from_name("mock_pkt_input"); + assert_int_not_equal(node_id_pkt_input, RTE_NODE_ID_INVALID); + + const char * updated_next_node[] = {"ef_ingress"}; + int rc = rte_node_edge_update(node_id_pkt_input, 0, updated_next_node, RTE_DIM(updated_next_node)); + assert_int_equal(rc, 1); + + /* Update the node edge */ + rte_node_t node_id_ef_ingress = rte_node_from_name("ef_ingress"); + assert_int_not_equal(node_id_ef_ingress, RTE_NODE_ID_INVALID); + + const char * ef_ingress_updated_next_node[] = { + "mock_pkt_output", + "mock_pkt_drop", + }; + + rc = rte_node_edge_update(node_id_ef_ingress, 0, ef_ingress_updated_next_node, + RTE_DIM(ef_ingress_updated_next_node)); + assert_int_equal(rc, 2); + + rte_graph_t graph = rte_graph_create("test_ef_ingress", &graph_param); + assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); + + /* create a graph worker */ + struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); + assert_non_null(mock_sc); + + mock_sc->nr_io_thread = 1; + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 32; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* ef init */ + int ret = ef_init(mock_sc); + assert_int_equal(ret, RT_SUCCESS); + + /* create the ef test main */ + struct ef_test_main * ef_test_main = rte_zmalloc(NULL, sizeof(struct ef_test_main), 0); + assert_non_null(ef_test_main); + + ef_test_main->mock_sc = mock_sc; + ef_test_main->graph = graph; + + *state = ef_test_main; + return 0; +} + +/* + * Etherfabric ingress teardown + */ +static int testgroup_ef_ingress_teardown(void ** state) +{ + struct ef_test_main * ef_test_main = *state; + + /* ef deinit */ + int ret = ef_deinit(); + assert_int_equal(ret, RT_SUCCESS); + + /* free the mock_sc */ + rte_free(ef_test_main->mock_sc); + + /* destroy the graph */ + rte_graph_destroy(ef_test_main->graph); + + /* free the ef test main */ + rte_free(ef_test_main); + return 0; +} + +/* + * Etherfabric egress vwire mode setup + */ +static int testgroup_ef_egress_vwire_mode_setup(void ** state) +{ + /* mock pkt source to generate mock packets */ + const char * node_patterns[] = { + "mock_pkt_input", + "mock_pkt_output", + "ef_egress", + }; + + /* create a fake graph */ + struct rte_graph_param graph_param = { + .node_patterns = node_patterns, + .nb_node_patterns = RTE_DIM(node_patterns), + .socket_id = 0, + }; + + /* Update the pkt input's next id */ + rte_node_t node_id_pkt_input = rte_node_from_name("mock_pkt_input"); + assert_int_not_equal(node_id_pkt_input, RTE_NODE_ID_INVALID); + + const char * updated_next_node[] = {"ef_egress"}; + int rc = rte_node_edge_update(node_id_pkt_input, 0, updated_next_node, RTE_DIM(updated_next_node)); + assert_int_equal(rc, 1); + + /* Update the node edge */ + rte_node_t node_id_ef_ingress = rte_node_from_name("ef_egress"); + assert_int_not_equal(node_id_ef_ingress, RTE_NODE_ID_INVALID); + + const char * ef_ingress_updated_next_node[] = { + "mock_pkt_output", + "mock_pkt_drop", + }; + + rc = rte_node_edge_update(node_id_ef_ingress, 0, ef_ingress_updated_next_node, + RTE_DIM(ef_ingress_updated_next_node)); + assert_int_equal(rc, 2); + + rte_graph_t graph = rte_graph_create("test_ef_egress", &graph_param); + assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); + + /* create a graph worker */ + struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); + assert_non_null(mock_sc); + + mock_sc->nr_io_thread = 1; + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 32; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 1, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* ef init */ + int ret = ef_init(mock_sc); + assert_int_equal(ret, RT_SUCCESS); + + /* create the ef test main */ + struct ef_test_main * ef_test_main = rte_zmalloc(NULL, sizeof(struct ef_test_main), 0); + assert_non_null(ef_test_main); + + ef_test_main->mock_sc = mock_sc; + ef_test_main->graph = graph; + + *state = ef_test_main; + return 0; +} + +/* + * Etherfabric egress tap mode setup + */ +static int testgroup_ef_egress_tap_mode_setup(void ** state) +{ + /* mock pkt source to generate mock packets */ + const char * node_patterns[] = { + "mock_pkt_input", + "mock_pkt_output", + "ef_egress", + }; + + /* create a fake graph */ + struct rte_graph_param graph_param = { + .node_patterns = node_patterns, + .nb_node_patterns = RTE_DIM(node_patterns), + .socket_id = 0, + }; + + /* Update the pkt input's next id */ + rte_node_t node_id_pkt_input = rte_node_from_name("mock_pkt_input"); + assert_int_not_equal(node_id_pkt_input, RTE_NODE_ID_INVALID); + + const char * updated_next_node[] = {"ef_egress"}; + int rc = rte_node_edge_update(node_id_pkt_input, 0, updated_next_node, RTE_DIM(updated_next_node)); + assert_int_equal(rc, 1); + + /* Update the node edge */ + rte_node_t node_id_ef_ingress = rte_node_from_name("ef_egress"); + assert_int_not_equal(node_id_ef_ingress, RTE_NODE_ID_INVALID); + + const char * ef_ingress_updated_next_node[] = { + "mock_pkt_output", + "mock_pkt_drop", + }; + + rc = rte_node_edge_update(node_id_ef_ingress, 0, ef_ingress_updated_next_node, + RTE_DIM(ef_ingress_updated_next_node)); + assert_int_equal(rc, 2); + + rte_graph_t graph = rte_graph_create("test_ef_egress", &graph_param); + assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); + + /* create a graph worker */ + struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); + assert_non_null(mock_sc); + + mock_sc->nr_io_thread = 1; + + /* generate the configuration string */ + uint32_t nr_ef_adapters = 32; + char * test_cfgfile_content = generate_config_string(nr_ef_adapters, 2, 0); + + /* create the configuration file */ + const char * filename = create_config_file(test_cfgfile_content); + assert_non_null(filename); + + strcpy(mock_sc->local_cfgfile, filename); + + /* mock the mr_dev_desc_lookup function */ + assert(nr_ef_adapters <= MOCK_NR_DEV_MAX); + for (uint32_t i = 0; i < nr_ef_adapters; i++) + { + expect_string(__wrap_mr_dev_desc_lookup, devsym, mock_devs_name[i]); + will_return(__wrap_mr_dev_desc_lookup, mock_devs_desc[i]); + } + + /* ef init */ + int ret = ef_init(mock_sc); + assert_int_equal(ret, RT_SUCCESS); + + /* create the ef test main */ + struct ef_test_main * ef_test_main = rte_zmalloc(NULL, sizeof(struct ef_test_main), 0); + assert_non_null(ef_test_main); + + ef_test_main->mock_sc = mock_sc; + ef_test_main->graph = graph; + + *state = ef_test_main; + return 0; +} + +/* + * Etherfabric egress common teardown + */ +static int testgroup_ef_egress_common_teardown(void ** state) +{ + struct ef_test_main * ef_test_main = *state; + + /* ef deinit */ + int ret = ef_deinit(); + assert_int_equal(ret, RT_SUCCESS); + + /* free the mock_sc */ + rte_free(ef_test_main->mock_sc); + + /* destroy the graph */ + rte_graph_destroy(ef_test_main->graph); + + /* free the ef test main */ + rte_free(ef_test_main); + return 0; +} + +/* + * Test Case: ef ingress forward pkts + */ +static void testcase_ef_ingress_forward_pkts(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_ingress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[2]; + for (uint8_t i = 0; i < 2; i++) + { + mbuf_input[i] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[i]); + } + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 2); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + struct rte_mbuf * mbuf_drop[2] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* + * construct the test packet for IPv4 + */ + + /* set mbuf pkt_len for IPv4 */ + uint32_t input_internal_pkt_len_0 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_internal_pkt_len_0; + mbuf_input[0]->pkt_len = input_internal_pkt_len_0; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(input_internal_eth_hdr_0 + 1); + struct rte_tcp_hdr * input_internal_tcp_hdr = (struct rte_tcp_hdr *)(input_internal_ipv4_hdr + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_internal_eth_hdr_0, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_internal_ipv4_hdr, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_internal_tcp_hdr, 80, 80, 0, 0, 5, 0, 1000); + + /* encap vxlan */ + uint8_t input_dir_0 = 0; + uint16_t input_ef_link_id_0 = 31; + const char * input_src_ip_0 = "10.11.11.11"; + const char * input_dst_ip_0 = "10.10.10.10"; + struct rte_ether_addr src_mac_0 = {.addr_bytes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}; + struct rte_ether_addr dst_mac_0 = {.addr_bytes = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}; + + int ret = vxlan_encap_constructed_pkt(mbuf_input[0], input_dir_0, input_ef_link_id_0, input_src_ip_0, + input_dst_ip_0, &src_mac_0, &dst_mac_0, RTE_ETHER_TYPE_IPV4); + assert_int_equal(ret, RT_SUCCESS); + + /* get external ether header */ + struct rte_ether_hdr * external_ether_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + assert_non_null(external_ether_hdr_0); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_0); + sid_list_init(&input_mrb_meta_0->sid_list); + + /* prepare to parse the ingress pkt */ + struct pkt_parser input_pkt_parser_0; + pkt_parser_init(&input_pkt_parser_0, &input_mrb_meta_0->pkt_parser_result, LAYER_TYPE_ALL, + MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&input_pkt_parser_0, mbuf_input[0]); + + /* save the pkt parser result */ + struct pkt_parser_result input_pkt_parser_result_0; + rte_memcpy(&input_pkt_parser_result_0, &input_mrb_meta_0->pkt_parser_result, sizeof(struct pkt_parser_result)); + + /* + * construct the test packet for ipv6 + */ + /* set mbuf pkt_len for ipv6 */ + uint32_t input_internal_pkt_len_1 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr) + + sizeof(struct rte_udp_hdr); + mbuf_input[1]->data_len = input_internal_pkt_len_1; + mbuf_input[1]->pkt_len = input_internal_pkt_len_1; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + struct rte_ipv6_hdr * ipv6_hdr = (struct rte_ipv6_hdr *)(input_internal_eth_hdr_1 + 1); + struct rte_udp_hdr * udp_hdr = (struct rte_udp_hdr *)(ipv6_hdr + 1); + + /* set the ether header */ + eth_header_construct(input_internal_eth_hdr_1, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV6); + + /* set the ipv6 header */ + ipv6_header_construct(ipv6_hdr, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr)); + + /* set the udp header */ + udp_header_construct(udp_hdr, 80, 80, sizeof(struct rte_udp_hdr)); + + /* encap vxlan */ + uint8_t input_dir_1 = 1; + uint16_t input_ef_link_id_1 = 30; + const char * input_src_ip_1 = "10.11.11.12"; + const char * input_dst_ip_1 = "10.10.10.11"; + struct rte_ether_addr src_mac_1 = {.addr_bytes = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01}}; + struct rte_ether_addr dst_mac_1 = {.addr_bytes = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}; + + ret = vxlan_encap_constructed_pkt(mbuf_input[1], input_dir_1, input_ef_link_id_1, input_src_ip_1, input_dst_ip_1, + &src_mac_1, &dst_mac_1, RTE_ETHER_TYPE_IPV6); + assert_int_equal(ret, RT_SUCCESS); + + /* get external ether header */ + struct rte_ether_hdr * external_ether_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + assert_non_null(external_ether_hdr_1); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_1); + sid_list_init(&input_mrb_meta_1->sid_list); + + /* prepare to parse the ingress pkt */ + struct pkt_parser input_pkt_parser_1; + pkt_parser_init(&input_pkt_parser_1, &input_mrb_meta_1->pkt_parser_result, LAYER_TYPE_ALL, + MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&input_pkt_parser_1, mbuf_input[0]); + + /* save the pkt parser result */ + struct pkt_parser_result input_pkt_parser_result_1; + rte_memcpy(&input_pkt_parser_result_1, &input_mrb_meta_1->pkt_parser_result, sizeof(struct pkt_parser_result)); + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_output, 2); + + /* check the output mbuf */ + for (uint8_t i = 0; i < nr_mbuf_output; i++) + { + assert_non_null(mbuf_output[i]); + assert_ptr_equal(mbuf_output[i], mbuf_input[i]); + } + + /* + * check the output mbuf 0 (IPv4) + */ + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_0 = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); + assert_int_equal(output_mrb_meta_0->adapter_type, ADAPTER_TYPE_EF); + assert_int_equal(output_mrb_meta_0->adapter_id, 0); + assert_int_equal(output_mrb_meta_0->ef_link_id, input_ef_link_id_0); + assert_int_equal(output_mrb_meta_0->traffic_link_id, UINT16_MAX); + assert_int_equal(output_mrb_meta_0->dir, input_dir_0); + + /* check the peer index */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + assert_non_null(ef_main); + + struct ef_peer_handle * ef_peer_handle = node_ef_main_ef_peer_handle_get(ef_main); + assert_non_null(ef_peer_handle); + + struct ef_peer * ef_peer = ef_peer_handle_peer_get(ef_peer_handle, output_mrb_meta_0->ef_peer_index); + assert_non_null(ef_peer); + + assert_memory_equal(ef_peer_mac_addr_get(ef_peer), &src_mac_0, sizeof(struct rte_ether_addr)); + assert_int_equal(ef_peer_ip_addr_get(ef_peer), inet_addr(input_src_ip_0)); + + /* check the sid */ + unsigned int nr_mbuf_0_sids = 0; + uint16_t mbuf_0_sids[MR_NODE_COMMON_MAX_SID_NUM] = {}; + nr_mbuf_0_sids = sid_list_get(&output_mrb_meta_0->sid_list, mbuf_0_sids, RTE_DIM(mbuf_0_sids)); + assert_int_equal(nr_mbuf_0_sids, 1); + assert_int_equal(mbuf_0_sids[0], 100); + + /* check the pkt parser result */ + assert_int_equal(output_mrb_meta_0->pkt_parser_result.start_layers, input_pkt_parser_result_0.start_layers + 4); + + /* check the pkt */ + uint32_t output_pkt_len_0 = rte_pktmbuf_pkt_len(mbuf_output[0]); + assert_int_equal(output_pkt_len_0, input_internal_pkt_len_0); + + /* check the outer ether header */ + assert_memory_equal(external_ether_hdr_0->src_addr.addr_bytes, dst_mac_0.addr_bytes, RTE_ETHER_ADDR_LEN); + assert_memory_equal(external_ether_hdr_0->dst_addr.addr_bytes, src_mac_0.addr_bytes, RTE_ETHER_ADDR_LEN); + + /* check the interne pkt */ + struct rte_ether_hdr * out_ether_hdr_0 = rte_pktmbuf_mtod(mbuf_output[0], struct rte_ether_hdr *); + assert_non_null(out_ether_hdr_0); + + struct rte_ipv4_hdr * out_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(out_ether_hdr_0 + 1); + assert_non_null(out_ipv4_hdr_0); + + struct rte_tcp_hdr * out_tcp_hdr_0 = (struct rte_tcp_hdr *)(out_ipv4_hdr_0 + 1); + assert_non_null(out_tcp_hdr_0); + + assert_memory_equal(out_ether_hdr_0, input_internal_eth_hdr_0, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_ipv4_hdr_0, input_internal_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(out_tcp_hdr_0, input_internal_tcp_hdr, sizeof(struct rte_tcp_hdr)); + + /* + * check the output mbuf 1 (IPv6) + */ + + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_1 = mrbuf_cz_data(mbuf_output[1], MR_NODE_CTRLZONE_ID); + assert_int_equal(output_mrb_meta_1->adapter_type, ADAPTER_TYPE_EF); + assert_int_equal(output_mrb_meta_1->adapter_id, 1); + assert_int_equal(output_mrb_meta_1->ef_link_id, input_ef_link_id_1); + assert_int_equal(output_mrb_meta_1->traffic_link_id, UINT16_MAX); + assert_int_equal(output_mrb_meta_1->dir, input_dir_1); + + /* check the peer index */ + struct ef_peer * ef_peer_1 = ef_peer_handle_peer_get(ef_peer_handle, output_mrb_meta_1->ef_peer_index); + assert_non_null(ef_peer_1); + + assert_memory_equal(ef_peer_mac_addr_get(ef_peer_1), &src_mac_1, sizeof(struct rte_ether_addr)); + assert_int_equal(ef_peer_ip_addr_get(ef_peer_1), inet_addr(input_src_ip_1)); + + /* check the sid */ + unsigned int nr_mbuf_1_sids = 0; + uint16_t mbuf_1_sids[MR_NODE_COMMON_MAX_SID_NUM] = {}; + nr_mbuf_1_sids = sid_list_get(&output_mrb_meta_1->sid_list, mbuf_1_sids, RTE_DIM(mbuf_1_sids)); + assert_int_equal(nr_mbuf_1_sids, 1); + assert_int_equal(mbuf_1_sids[0], 101); + + /* check the pkt parser result */ + assert_int_equal(output_mrb_meta_1->pkt_parser_result.start_layers, input_pkt_parser_result_1.start_layers + 4); + + /* check the pkt */ + uint32_t output_pkt_len_1 = rte_pktmbuf_pkt_len(mbuf_output[1]); + assert_int_equal(output_pkt_len_1, input_internal_pkt_len_1); + + /* check the outer ether header */ + assert_memory_equal(external_ether_hdr_1->src_addr.addr_bytes, dst_mac_1.addr_bytes, RTE_ETHER_ADDR_LEN); + assert_memory_equal(external_ether_hdr_1->dst_addr.addr_bytes, src_mac_1.addr_bytes, RTE_ETHER_ADDR_LEN); + + /* check the interne pkt */ + struct rte_ether_hdr * out_ether_hdr_1 = rte_pktmbuf_mtod(mbuf_output[1], struct rte_ether_hdr *); + assert_non_null(out_ether_hdr_1); + + struct rte_ipv6_hdr * out_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(out_ether_hdr_1 + 1); + assert_non_null(out_ipv6_hdr_1); + + struct rte_udp_hdr * out_udp_hdr_1 = (struct rte_udp_hdr *)(out_ipv6_hdr_1 + 1); + assert_non_null(out_udp_hdr_1); + + assert_memory_equal(out_ether_hdr_1, input_internal_eth_hdr_1, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_ipv6_hdr_1, ipv6_hdr, sizeof(struct rte_ipv6_hdr)); + assert_memory_equal(out_udp_hdr_1, udp_hdr, sizeof(struct rte_udp_hdr)); + + /* check metrics */ + struct sc_metrics_handle * ingress_metrics_handle = node_ef_main_ingress_metrics_handle_get(ef_main, 0); + assert_non_null(ingress_metrics_handle); + + uint64_t total_pkts; + ret = sc_metrics_value_get(ingress_metrics_handle, &total_pkts, 0); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(total_pkts, 2); + + uint64_t to_classifier_pkts; + ret = sc_metrics_value_get(ingress_metrics_handle, &to_classifier_pkts, 2); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(to_classifier_pkts, 2); + + /* release the mbufs */ + for (uint8_t i = 0; i < 2; i++) + { + rte_pktmbuf_free(mbuf_input[i]); + } + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Case: ef ingress drop for adapter no exist + */ +static void testcase_ef_ingress_drop_adapter_no_exist(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_ingress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[1]; + mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[0]); + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 1); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_drop[1] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* + * construct the test packet + */ + + /* set mbuf pkt_len */ + uint32_t input_internal_pkt_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_internal_pkt_len; + mbuf_input[0]->pkt_len = input_internal_pkt_len; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(input_internal_eth_hdr + 1); + struct rte_tcp_hdr * input_internal_tcp_hdr = (struct rte_tcp_hdr *)(input_internal_ipv4_hdr + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_internal_eth_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_internal_ipv4_hdr, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_internal_tcp_hdr, 80, 80, 0, 0, 5, 0, 1000); + + /* encap vxlan */ + uint8_t input_dir_0 = 0; + uint16_t input_ef_link_id_0 = 31; + const char * input_src_ip_0 = "10.11.11.11"; + const char * input_dst_ip_0 = "192.168.1.1"; + struct rte_ether_addr src_mac_0 = {.addr_bytes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}; + struct rte_ether_addr dst_mac_0 = {.addr_bytes = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}; + + int ret = vxlan_encap_constructed_pkt(mbuf_input[0], input_dir_0, input_ef_link_id_0, input_src_ip_0, + input_dst_ip_0, &src_mac_0, &dst_mac_0, RTE_ETHER_TYPE_IPV4); + assert_int_equal(ret, RT_SUCCESS); + + /* get external header */ + struct rte_ether_hdr * input_external_ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + assert_non_null(input_external_ether_hdr); + + struct rte_ipv4_hdr * input_external_ipv4_hdr = (struct rte_ipv4_hdr *)(input_external_ether_hdr + 1); + assert_non_null(input_external_ipv4_hdr); + + struct rte_udp_hdr * input_external_udp_hdr = (struct rte_udp_hdr *)(input_external_ipv4_hdr + 1); + assert_non_null(input_external_udp_hdr); + + struct g_vxlan_hdr * input_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(input_external_udp_hdr + 1); + assert_non_null(input_external_p_vxlan_hdr); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta); + sid_list_init(&input_mrb_meta->sid_list); + + /* prepare to parse the ingress pkt */ + struct pkt_parser input_pkt_parser; + pkt_parser_init(&input_pkt_parser, &input_mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&input_pkt_parser, mbuf_input[0]); + + /* save the pkt parser result */ + struct pkt_parser_result input_pkt_parser_result; + rte_memcpy(&input_pkt_parser_result, &input_mrb_meta->pkt_parser_result, sizeof(struct pkt_parser_result)); + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_drop, 1); + + /* check the drop mbuf */ + assert_non_null(mbuf_drop[0]); + assert_ptr_equal(mbuf_drop[0], mbuf_input[0]); + + /* check the metadata */ + struct mrb_metadata * drop_mrb_meta = mrbuf_cz_data(mbuf_drop[0], MR_NODE_CTRLZONE_ID); + assert_memory_equal(drop_mrb_meta, input_mrb_meta, sizeof(struct mrb_metadata)); + + /* check the pkt */ + uint32_t drop_pkt_len = rte_pktmbuf_pkt_len(mbuf_drop[0]); + assert_int_equal(drop_pkt_len, input_internal_pkt_len + ef_encap_len); + + /* check the drop external ether header */ + struct rte_ether_hdr * drop_external_ether_hdr = rte_pktmbuf_mtod(mbuf_drop[0], struct rte_ether_hdr *); + assert_non_null(drop_external_ether_hdr); + assert_memory_equal(drop_external_ether_hdr, input_external_ether_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop external ipv4 header */ + struct rte_ipv4_hdr * drop_external_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_external_ether_hdr + 1); + assert_non_null(drop_external_ipv4_hdr); + assert_memory_equal(drop_external_ipv4_hdr, input_external_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop external udp header */ + struct rte_udp_hdr * drop_external_udp_hdr = (struct rte_udp_hdr *)(drop_external_ipv4_hdr + 1); + assert_non_null(drop_external_udp_hdr); + assert_memory_equal(drop_external_udp_hdr, input_external_udp_hdr, sizeof(struct rte_udp_hdr)); + + /* check the drop external vxlan header */ + struct g_vxlan_hdr * drop_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(drop_external_udp_hdr + 1); + assert_non_null(drop_external_p_vxlan_hdr); + assert_memory_equal(drop_external_p_vxlan_hdr, input_external_p_vxlan_hdr, sizeof(struct g_vxlan_hdr)); + + /* check the drop internal ether header */ + struct rte_ether_hdr * drop_internal_eth_hdr = (struct rte_ether_hdr *)(drop_external_p_vxlan_hdr + 1); + assert_non_null(drop_internal_eth_hdr); + assert_memory_equal(drop_internal_eth_hdr, input_internal_eth_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop internal ipv4 header */ + struct rte_ipv4_hdr * drop_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_internal_eth_hdr + 1); + assert_non_null(drop_internal_ipv4_hdr); + assert_memory_equal(drop_internal_ipv4_hdr, input_internal_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop internal tcp header */ + struct rte_tcp_hdr * drop_internal_tcp_hdr = (struct rte_tcp_hdr *)(drop_internal_ipv4_hdr + 1); + assert_non_null(drop_internal_tcp_hdr); + assert_memory_equal(drop_internal_tcp_hdr, input_internal_tcp_hdr, sizeof(struct rte_tcp_hdr)); + + /* check metrics */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + assert_non_null(ef_main); + + struct sc_metrics_handle * ingress_metrics_handle = node_ef_main_ingress_metrics_handle_get(ef_main, 0); + assert_non_null(ingress_metrics_handle); + + uint64_t dorp_adapter_no_exist_pkts; + ret = sc_metrics_value_get(ingress_metrics_handle, &dorp_adapter_no_exist_pkts, 3); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(dorp_adapter_no_exist_pkts, 1); + + /* release the mbufs */ + rte_pktmbuf_free(mbuf_input[0]); + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Case: ef ingress drop for prepend sid error + */ +static void testcase_ef_ingress_drop_prepend_sid_error(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_ingress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[1]; + mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[0]); + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 1); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_drop[1] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* + * construct the test packet + */ + + /* set mbuf pkt_len */ + uint32_t input_internal_pkt_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_internal_pkt_len; + mbuf_input[0]->pkt_len = input_internal_pkt_len; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(input_internal_eth_hdr + 1); + struct rte_tcp_hdr * input_internal_tcp_hdr = (struct rte_tcp_hdr *)(input_internal_ipv4_hdr + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_internal_eth_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_internal_ipv4_hdr, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_internal_tcp_hdr, 80, 80, 0, 0, 5, 0, 1000); + + /* encap vxlan */ + uint8_t input_dir_0 = 0; + uint16_t input_ef_link_id_0 = 31; + const char * input_src_ip_0 = "10.11.11.13"; + const char * input_dst_ip_0 = "10.10.10.10"; + struct rte_ether_addr src_mac_0 = {.addr_bytes = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}}; + struct rte_ether_addr dst_mac_0 = {.addr_bytes = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}; + + int ret = vxlan_encap_constructed_pkt(mbuf_input[0], input_dir_0, input_ef_link_id_0, input_src_ip_0, + input_dst_ip_0, &src_mac_0, &dst_mac_0, RTE_ETHER_TYPE_IPV4); + assert_int_equal(ret, RT_SUCCESS); + + /* get external header */ + struct rte_ether_hdr * input_external_ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + assert_non_null(input_external_ether_hdr); + + struct rte_ipv4_hdr * input_external_ipv4_hdr = (struct rte_ipv4_hdr *)(input_external_ether_hdr + 1); + assert_non_null(input_external_ipv4_hdr); + + struct rte_udp_hdr * input_external_udp_hdr = (struct rte_udp_hdr *)(input_external_ipv4_hdr + 1); + assert_non_null(input_external_udp_hdr); + + struct g_vxlan_hdr * input_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(input_external_udp_hdr + 1); + assert_non_null(input_external_p_vxlan_hdr); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta); + sid_list_init(&input_mrb_meta->sid_list); + + ret = RT_SUCCESS; + do + { + /* set the sid */ + uint16_t sid = 111; + ret = sid_list_prepend(&input_mrb_meta->sid_list, &sid, 1); + } while (ret == RT_SUCCESS); + + /* prepare to parse the ingress pkt */ + struct pkt_parser input_pkt_parser; + pkt_parser_init(&input_pkt_parser, &input_mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&input_pkt_parser, mbuf_input[0]); + + /* save the pkt parser result */ + struct pkt_parser_result input_pkt_parser_result; + rte_memcpy(&input_pkt_parser_result, &input_mrb_meta->pkt_parser_result, sizeof(struct pkt_parser_result)); + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_drop, 1); + + /* check the drop mbuf */ + assert_non_null(mbuf_drop[0]); + assert_ptr_equal(mbuf_drop[0], mbuf_input[0]); + + /* check the metadata */ + struct mrb_metadata * drop_mrb_meta = mrbuf_cz_data(mbuf_drop[0], MR_NODE_CTRLZONE_ID); + drop_mrb_meta->dir = input_dir_0; + drop_mrb_meta->adapter_type = ADAPTER_TYPE_EF; + drop_mrb_meta->adapter_id = 0; + drop_mrb_meta->ef_link_id = input_ef_link_id_0; + drop_mrb_meta->traffic_link_id = UINT16_MAX; + + /* check the peer index */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + assert_non_null(ef_main); + + struct ef_peer_handle * ef_peer_handle = node_ef_main_ef_peer_handle_get(ef_main); + assert_non_null(ef_peer_handle); + + struct ef_peer * ef_peer_1 = ef_peer_handle_peer_get(ef_peer_handle, drop_mrb_meta->ef_peer_index); + assert_non_null(ef_peer_1); + + assert_memory_equal(ef_peer_mac_addr_get(ef_peer_1), &src_mac_0, sizeof(struct rte_ether_addr)); + assert_int_equal(ef_peer_ip_addr_get(ef_peer_1), inet_addr(input_src_ip_0)); + + /* check the pkt */ + uint32_t drop_pkt_len = rte_pktmbuf_pkt_len(mbuf_drop[0]); + assert_int_equal(drop_pkt_len, input_internal_pkt_len + ef_encap_len); + + /* check the drop external ether header */ + struct rte_ether_hdr * drop_external_ether_hdr = rte_pktmbuf_mtod(mbuf_drop[0], struct rte_ether_hdr *); + assert_non_null(drop_external_ether_hdr); + assert_memory_equal(drop_external_ether_hdr, input_external_ether_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop external ipv4 header */ + struct rte_ipv4_hdr * drop_external_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_external_ether_hdr + 1); + assert_non_null(drop_external_ipv4_hdr); + assert_memory_equal(drop_external_ipv4_hdr, input_external_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop external udp header */ + struct rte_udp_hdr * drop_external_udp_hdr = (struct rte_udp_hdr *)(drop_external_ipv4_hdr + 1); + assert_non_null(drop_external_udp_hdr); + assert_memory_equal(drop_external_udp_hdr, input_external_udp_hdr, sizeof(struct rte_udp_hdr)); + + /* check the drop external vxlan header */ + struct g_vxlan_hdr * drop_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(drop_external_udp_hdr + 1); + assert_non_null(drop_external_p_vxlan_hdr); + assert_memory_equal(drop_external_p_vxlan_hdr, input_external_p_vxlan_hdr, sizeof(struct g_vxlan_hdr)); + + /* check the drop internal ether header */ + struct rte_ether_hdr * drop_internal_eth_hdr = (struct rte_ether_hdr *)(drop_external_p_vxlan_hdr + 1); + assert_non_null(drop_internal_eth_hdr); + assert_memory_equal(drop_internal_eth_hdr, input_internal_eth_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop internal ipv4 header */ + struct rte_ipv4_hdr * drop_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_internal_eth_hdr + 1); + assert_non_null(drop_internal_ipv4_hdr); + assert_memory_equal(drop_internal_ipv4_hdr, input_internal_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop internal tcp header */ + struct rte_tcp_hdr * drop_internal_tcp_hdr = (struct rte_tcp_hdr *)(drop_internal_ipv4_hdr + 1); + assert_non_null(drop_internal_tcp_hdr); + assert_memory_equal(drop_internal_tcp_hdr, input_internal_tcp_hdr, sizeof(struct rte_tcp_hdr)); + + /* check metrics */ + + struct sc_metrics_handle * ingress_metrics_handle = node_ef_main_ingress_metrics_handle_get(ef_main, 0); + assert_non_null(ingress_metrics_handle); + + uint64_t dorp_sid_prepend_err_pkts; + ret = sc_metrics_value_get(ingress_metrics_handle, &dorp_sid_prepend_err_pkts, 4); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(dorp_sid_prepend_err_pkts, 1); + + /* release the mbufs */ + rte_pktmbuf_free(mbuf_input[0]); + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Case: ef ingress drop for peer add error + */ +static void testcase_ef_ingress_drop_peer_add_error(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_ingress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[1]; + mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[0]); + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 1); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_drop[1] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* + * construct the test packet + */ + + /* set mbuf pkt_len */ + uint32_t input_internal_pkt_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_internal_pkt_len; + mbuf_input[0]->pkt_len = input_internal_pkt_len; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(input_internal_eth_hdr + 1); + struct rte_tcp_hdr * input_internal_tcp_hdr = (struct rte_tcp_hdr *)(input_internal_ipv4_hdr + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_internal_eth_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_internal_ipv4_hdr, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_internal_tcp_hdr, 80, 80, 0, 0, 5, 0, 1000); + + /* encap vxlan */ + uint8_t input_dir_0 = 0; + uint16_t input_ef_link_id_0 = 31; + const char * input_src_ip_0 = "192.168.1.1"; + const char * input_dst_ip_0 = "10.10.10.10"; + struct rte_ether_addr src_mac_0 = {.addr_bytes = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}}; + struct rte_ether_addr dst_mac_0 = {.addr_bytes = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}; + + int ret = vxlan_encap_constructed_pkt(mbuf_input[0], input_dir_0, input_ef_link_id_0, input_src_ip_0, + input_dst_ip_0, &src_mac_0, &dst_mac_0, RTE_ETHER_TYPE_IPV4); + assert_int_equal(ret, RT_SUCCESS); + + /* get external header */ + struct rte_ether_hdr * input_external_ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + assert_non_null(input_external_ether_hdr); + + struct rte_ipv4_hdr * input_external_ipv4_hdr = (struct rte_ipv4_hdr *)(input_external_ether_hdr + 1); + assert_non_null(input_external_ipv4_hdr); + + struct rte_udp_hdr * input_external_udp_hdr = (struct rte_udp_hdr *)(input_external_ipv4_hdr + 1); + assert_non_null(input_external_udp_hdr); + + struct g_vxlan_hdr * input_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(input_external_udp_hdr + 1); + assert_non_null(input_external_p_vxlan_hdr); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta); + sid_list_init(&input_mrb_meta->sid_list); + + /* prepare to parse the ingress pkt */ + struct pkt_parser input_pkt_parser; + pkt_parser_init(&input_pkt_parser, &input_mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&input_pkt_parser, mbuf_input[0]); + + /* save the pkt parser result */ + struct pkt_parser_result input_pkt_parser_result; + rte_memcpy(&input_pkt_parser_result, &input_mrb_meta->pkt_parser_result, sizeof(struct pkt_parser_result)); + + struct ef_node_main * ef_main = g_ef_node_main_get(); + assert_non_null(ef_main); + + struct ef_peer_handle * ef_peer_handle = node_ef_main_ef_peer_handle_get(ef_main); + assert_non_null(ef_peer_handle); + + ret = RT_SUCCESS; + uint32_t nr_add_ef_adapters = 0; + do + { + union ef_peer_key key = {}; + key.ip_src = nr_add_ef_adapters; + key.mac_src.addr_bytes[5] = nr_add_ef_adapters; + ret = ef_peer_handle_peer_add(ef_peer_handle, &key); + nr_add_ef_adapters++; + + } while (ef_peer_handle_remaining_entries_get(ef_peer_handle) > 0); + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_drop, 1); + + /* check the drop mbuf */ + assert_non_null(mbuf_drop[0]); + assert_ptr_equal(mbuf_drop[0], mbuf_input[0]); + + /* check the metadata */ + struct mrb_metadata * drop_mrb_meta = mrbuf_cz_data(mbuf_drop[0], MR_NODE_CTRLZONE_ID); + assert_memory_equal(drop_mrb_meta, input_mrb_meta, sizeof(struct mrb_metadata)); + + /* check the pkt */ + uint32_t drop_pkt_len = rte_pktmbuf_pkt_len(mbuf_drop[0]); + assert_int_equal(drop_pkt_len, input_internal_pkt_len + ef_encap_len); + + /* check the drop external ether header */ + struct rte_ether_hdr * drop_external_ether_hdr = rte_pktmbuf_mtod(mbuf_drop[0], struct rte_ether_hdr *); + assert_non_null(drop_external_ether_hdr); + assert_memory_equal(drop_external_ether_hdr, input_external_ether_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop external ipv4 header */ + struct rte_ipv4_hdr * drop_external_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_external_ether_hdr + 1); + assert_non_null(drop_external_ipv4_hdr); + assert_memory_equal(drop_external_ipv4_hdr, input_external_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop external udp header */ + struct rte_udp_hdr * drop_external_udp_hdr = (struct rte_udp_hdr *)(drop_external_ipv4_hdr + 1); + assert_non_null(drop_external_udp_hdr); + assert_memory_equal(drop_external_udp_hdr, input_external_udp_hdr, sizeof(struct rte_udp_hdr)); + + /* check the drop external vxlan header */ + struct g_vxlan_hdr * drop_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(drop_external_udp_hdr + 1); + assert_non_null(drop_external_p_vxlan_hdr); + assert_memory_equal(drop_external_p_vxlan_hdr, input_external_p_vxlan_hdr, sizeof(struct g_vxlan_hdr)); + + /* check the drop internal ether header */ + struct rte_ether_hdr * drop_internal_eth_hdr = (struct rte_ether_hdr *)(drop_external_p_vxlan_hdr + 1); + assert_non_null(drop_internal_eth_hdr); + assert_memory_equal(drop_internal_eth_hdr, input_internal_eth_hdr, sizeof(struct rte_ether_hdr)); + + /* check the drop internal ipv4 header */ + struct rte_ipv4_hdr * drop_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(drop_internal_eth_hdr + 1); + assert_non_null(drop_internal_ipv4_hdr); + assert_memory_equal(drop_internal_ipv4_hdr, input_internal_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + + /* check the drop internal tcp header */ + struct rte_tcp_hdr * drop_internal_tcp_hdr = (struct rte_tcp_hdr *)(drop_internal_ipv4_hdr + 1); + assert_non_null(drop_internal_tcp_hdr); + assert_memory_equal(drop_internal_tcp_hdr, input_internal_tcp_hdr, sizeof(struct rte_tcp_hdr)); + + /* check metrics */ + + struct sc_metrics_handle * ingress_metrics_handle = node_ef_main_ingress_metrics_handle_get(ef_main, 0); + assert_non_null(ingress_metrics_handle); + + uint64_t dorp_peer_add_err_pkts; + ret = sc_metrics_value_get(ingress_metrics_handle, &dorp_peer_add_err_pkts, 5); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(dorp_peer_add_err_pkts, 1); + + /* release the mbufs */ + rte_pktmbuf_free(mbuf_input[0]); + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Case: ef egress forward pkts + */ +static void testcase_ef_egress_forward_pkts(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_egress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[2]; + for (uint8_t i = 0; i < 2; i++) + { + mbuf_input[i] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[i]); + } + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 2); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + /* + * construct the test packet for IPv4 + */ + + /* set mbuf pkt_len for IPv4 */ + uint32_t input_internal_pkt_len_0 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_internal_pkt_len_0; + mbuf_input[0]->pkt_len = input_internal_pkt_len_0; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(input_internal_eth_hdr_0 + 1); + struct rte_tcp_hdr * input_internal_tcp_hdr = (struct rte_tcp_hdr *)(input_internal_ipv4_hdr + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_internal_eth_hdr_0, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_internal_ipv4_hdr, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_internal_tcp_hdr, 80, 80, 0, 0, 5, 0, 1000); + + /* encap vxlan */ + uint8_t input_dir_0 = 0; + uint16_t input_ef_link_id_0 = 31; + const char * input_src_ip_0 = "10.11.11.11"; + const char * input_dst_ip_0 = "10.10.10.10"; + struct rte_ether_addr src_mac_0 = {.addr_bytes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}; + struct rte_ether_addr dst_mac_0 = {.addr_bytes = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}; + + int ret = vxlan_encap_constructed_pkt(mbuf_input[0], input_dir_0, input_ef_link_id_0, input_src_ip_0, + input_dst_ip_0, &src_mac_0, &dst_mac_0, RTE_ETHER_TYPE_IPV4); + assert_int_equal(ret, RT_SUCCESS); + + /* get external ether header */ + struct rte_ether_hdr * input_external_ether_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + assert_non_null(input_external_ether_hdr_0); + + struct rte_ipv4_hdr * input_external_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(input_external_ether_hdr_0 + 1); + assert_non_null(input_external_ipv4_hdr_0); + + struct rte_udp_hdr * input_external_udp_hdr_0 = (struct rte_udp_hdr *)(input_external_ipv4_hdr_0 + 1); + assert_non_null(input_external_udp_hdr_0); + + struct g_vxlan_hdr * input_external_p_vxlan_hdr_0 = (struct g_vxlan_hdr *)(input_external_udp_hdr_0 + 1); + assert_non_null(input_external_p_vxlan_hdr_0); + + /* offset to the internal packet within the buffer */ + rte_pktmbuf_adj(mbuf_input[0], ef_encap_len); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_0); + sid_list_init(&input_mrb_meta_0->sid_list); + input_mrb_meta_0->packet_create_from_nf = 0; + input_mrb_meta_0->cur_sid = 100; + + /* + * construct the test packet for ipv6 + */ + /* set mbuf pkt_len for ipv6 */ + uint32_t input_internal_pkt_len_1 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr) + + sizeof(struct rte_udp_hdr); + mbuf_input[1]->data_len = input_internal_pkt_len_1; + mbuf_input[1]->pkt_len = input_internal_pkt_len_1; + + /* prepare the test packet */ + struct rte_ether_hdr * input_internal_eth_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + struct rte_ipv6_hdr * input_internal_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(input_internal_eth_hdr_1 + 1); + struct rte_udp_hdr * input_internal_udp_hdr_1 = (struct rte_udp_hdr *)(input_internal_ipv6_hdr_1 + 1); + + /* set the ether header */ + eth_header_construct(input_internal_eth_hdr_1, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV6); + + /* set the ipv6 header */ + ipv6_header_construct(input_internal_ipv6_hdr_1, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr)); + + /* set the udp header */ + udp_header_construct(input_internal_udp_hdr_1, 80, 80, sizeof(struct rte_udp_hdr)); + + /* encap vxlan */ + uint8_t input_dir_1 = 1; + uint16_t input_ef_link_id_1 = 30; + const char * input_src_ip_1 = "10.11.11.12"; + const char * input_dst_ip_1 = "10.10.10.11"; + struct rte_ether_addr src_mac_1 = {.addr_bytes = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01}}; + struct rte_ether_addr dst_mac_1 = {.addr_bytes = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA}}; + + ret = vxlan_encap_constructed_pkt(mbuf_input[1], input_dir_1, input_ef_link_id_1, input_src_ip_1, input_dst_ip_1, + &src_mac_1, &dst_mac_1, RTE_ETHER_TYPE_IPV6); + assert_int_equal(ret, RT_SUCCESS); + + /* get external ether header */ + struct rte_ether_hdr * input_external_ether_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + assert_non_null(input_external_ether_hdr_1); + + struct rte_ipv4_hdr * input_external_ipv4_hdr_1 = (struct rte_ipv4_hdr *)(input_external_ether_hdr_1 + 1); + assert_non_null(input_external_ipv4_hdr_1); + + struct rte_udp_hdr * input_external_udp_hdr_1 = (struct rte_udp_hdr *)(input_external_ipv4_hdr_1 + 1); + assert_non_null(input_external_udp_hdr_1); + + struct g_vxlan_hdr * input_external_p_vxlan_hdr_1 = (struct g_vxlan_hdr *)(input_external_udp_hdr_1 + 1); + assert_non_null(input_external_p_vxlan_hdr_1); + + /* offset to the internal packet within the buffer */ + rte_pktmbuf_adj(mbuf_input[1], ef_encap_len); + + /* set metadata */ + struct mrb_metadata * input_mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_1); + sid_list_init(&input_mrb_meta_1->sid_list); + input_mrb_meta_1->packet_create_from_nf = 0; + input_mrb_meta_1->cur_sid = 101; + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_output, 2); + + /* check the output mbuf */ + for (uint8_t i = 0; i < nr_mbuf_output; i++) + { + assert_non_null(mbuf_output[i]); + assert_ptr_equal(mbuf_output[i], mbuf_input[i]); + } + + /* + * check the output mbuf 0 (IPv4) + */ + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_0 = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); + assert_int_equal(output_mrb_meta_0->port_egress, 0); + + /* check the pkt len */ + uint32_t output_pkt_len_0 = rte_pktmbuf_pkt_len(mbuf_output[0]); + assert_int_equal(output_pkt_len_0, input_internal_pkt_len_0 + ef_encap_len); + + /* check the outer external pkt */ + struct rte_ether_hdr * out_external_ether_hdr_0 = rte_pktmbuf_mtod(mbuf_output[0], struct rte_ether_hdr *); + assert_non_null(out_external_ether_hdr_0); + + struct rte_ipv4_hdr * out_external_ipv4_hdr = (struct rte_ipv4_hdr *)(out_external_ether_hdr_0 + 1); + assert_non_null(out_external_ipv4_hdr); + + struct rte_udp_hdr * out_external_udp_hdr = (struct rte_udp_hdr *)(out_external_ipv4_hdr + 1); + assert_non_null(out_external_udp_hdr); + + struct g_vxlan_hdr * out_external_p_vxlan_hdr = (struct g_vxlan_hdr *)(out_external_udp_hdr + 1); + assert_non_null(out_external_p_vxlan_hdr); + + assert_memory_equal(out_external_ether_hdr_0, input_external_ether_hdr_0, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_external_ipv4_hdr, input_external_ipv4_hdr_0, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(out_external_udp_hdr, input_external_udp_hdr_0, sizeof(struct rte_udp_hdr)); + assert_memory_equal(out_external_p_vxlan_hdr, input_external_p_vxlan_hdr_0, sizeof(struct g_vxlan_hdr)); + + /* check the outer internal pkt */ + struct rte_ether_hdr * out_internal_eth_hdr_0 = (struct rte_ether_hdr *)(out_external_p_vxlan_hdr + 1); + assert_non_null(out_internal_eth_hdr_0); + + struct rte_ipv4_hdr * out_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(out_internal_eth_hdr_0 + 1); + assert_non_null(out_internal_ipv4_hdr); + + struct rte_tcp_hdr * out_internal_tcp_hdr = (struct rte_tcp_hdr *)(out_internal_ipv4_hdr + 1); + assert_non_null(out_internal_tcp_hdr); + + assert_memory_equal(out_internal_eth_hdr_0, input_internal_eth_hdr_0, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_internal_ipv4_hdr, input_internal_ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(out_internal_tcp_hdr, input_internal_tcp_hdr, sizeof(struct rte_tcp_hdr)); + + /* + * check the output mbuf 1 (IPv6) + */ + + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_1 = mrbuf_cz_data(mbuf_output[1], MR_NODE_CTRLZONE_ID); + assert_int_equal(output_mrb_meta_1->port_egress, 1); + + /* check the pkt len */ + uint32_t output_pkt_len_1 = rte_pktmbuf_pkt_len(mbuf_output[1]); + assert_int_equal(output_pkt_len_1, input_internal_pkt_len_1 + ef_encap_len); + + /* check the outer external pkt */ + struct rte_ether_hdr * out_external_ether_hdr_1 = rte_pktmbuf_mtod(mbuf_output[1], struct rte_ether_hdr *); + assert_non_null(out_external_ether_hdr_1); + + struct rte_ipv4_hdr * out_external_ipv4_hdr_1 = (struct rte_ipv4_hdr *)(out_external_ether_hdr_1 + 1); + assert_non_null(out_external_ipv4_hdr_1); + + struct rte_udp_hdr * out_external_udp_hdr_1 = (struct rte_udp_hdr *)(out_external_ipv4_hdr_1 + 1); + assert_non_null(out_external_udp_hdr_1); + + struct g_vxlan_hdr * out_external_p_vxlan_hdr_1 = (struct g_vxlan_hdr *)(out_external_udp_hdr_1 + 1); + assert_non_null(out_external_p_vxlan_hdr_1); + + assert_memory_equal(out_external_ether_hdr_1, input_external_ether_hdr_1, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_external_ipv4_hdr_1, input_external_ipv4_hdr_1, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(out_external_udp_hdr_1, input_external_udp_hdr_1, sizeof(struct rte_udp_hdr)); + assert_memory_equal(out_external_p_vxlan_hdr_1, input_external_p_vxlan_hdr_1, sizeof(struct g_vxlan_hdr)); + + /* check the outer internal pkt */ + struct rte_ether_hdr * out_internal_eth_hdr_1 = (struct rte_ether_hdr *)(out_external_p_vxlan_hdr_1 + 1); + assert_non_null(out_internal_eth_hdr_1); + + struct rte_ipv6_hdr * out_internal_ipv6_hdr = (struct rte_ipv6_hdr *)(out_internal_eth_hdr_1 + 1); + assert_non_null(out_internal_ipv6_hdr); + + struct rte_udp_hdr * out_internal_udp_hdr = (struct rte_udp_hdr *)(out_internal_ipv6_hdr + 1); + assert_non_null(out_internal_udp_hdr); + + assert_memory_equal(out_internal_eth_hdr_1, input_internal_eth_hdr_1, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_internal_ipv6_hdr, input_internal_ipv6_hdr_1, sizeof(struct rte_ipv6_hdr)); + assert_memory_equal(out_internal_udp_hdr, input_internal_udp_hdr_1, sizeof(struct rte_udp_hdr)); + + /* check metrics */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + struct sc_metrics_handle * egress_metrics_handle = node_ef_main_egress_metrics_handle_get(ef_main, 0); + assert_non_null(egress_metrics_handle); + + uint64_t total_pkts; + ret = sc_metrics_value_get(egress_metrics_handle, &total_pkts, 0); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(total_pkts, 2); + + uint64_t to_eth_egress_pkts; + ret = sc_metrics_value_get(egress_metrics_handle, &to_eth_egress_pkts, 3); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(to_eth_egress_pkts, 2); + + /* release the mbufs */ + for (uint8_t i = 0; i < 2; i++) + { + rte_pktmbuf_free(mbuf_input[i]); + } + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Group: ef egress nf create pkts + */ +static void testgroup_ef_egress_nf_create_pkts(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_egress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[2]; + for (uint8_t i = 0; i < 2; i++) + { + mbuf_input[i] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[i]); + } + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 2); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + /* + * construct the test packet for IPv4 + */ + /* set mbuf pkt_len for IPv4 */ + uint32_t input_pkt_len_0 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_pkt_len_0; + mbuf_input[0]->pkt_len = input_pkt_len_0; + + /* set the hash for mbuf */ + mbuf_input[0]->hash.usr = 16384; + + /* prepare the test packet */ + struct rte_ether_hdr * input_eth_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(input_eth_hdr_0 + 1); + struct rte_tcp_hdr * input_tcp_hdr_0 = (struct rte_tcp_hdr *)(input_ipv4_hdr_0 + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_eth_hdr_0, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_ipv4_hdr_0, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_tcp_hdr_0, 80, 80, 0, 0, 5, 0, 1000); + + /* add the peer */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + assert_non_null(ef_main); + + struct ef_peer_handle * ef_peer_handle = node_ef_main_ef_peer_handle_get(ef_main); + assert_non_null(ef_peer_handle); + + union ef_peer_key key; + uint32_t peer_add_ip_0; + inet_pton(AF_INET, "192.168.2.1", &peer_add_ip_0); + struct rte_ether_addr peer_ether_addr_0 = {.addr_bytes = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x01}}; + + key.ip_src = peer_add_ip_0; + rte_memcpy(&key.mac_src, &peer_ether_addr_0, sizeof(struct rte_ether_addr)); + + int peer_index_0 = ef_peer_handle_peer_add(ef_peer_handle, &key); + assert_int_not_equal(peer_index_0, RT_ERR); + + /* set metadata */ + uint8_t input_dir_0 = 0; + uint16_t ef_link_id_0 = 30; + struct mrb_metadata * input_mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_0); + sid_list_init(&input_mrb_meta_0->sid_list); + input_mrb_meta_0->packet_create_from_nf = 1; + input_mrb_meta_0->cur_sid = 100; + input_mrb_meta_0->ef_peer_index = peer_index_0; + input_mrb_meta_0->dir = input_dir_0; + input_mrb_meta_0->ef_link_id = ef_link_id_0; + + /* + * construct the test packet for ipv6 + */ + /* set mbuf pkt_len for ipv6 */ + uint32_t input_pkt_len_1 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr) + sizeof(struct rte_udp_hdr); + mbuf_input[1]->data_len = input_pkt_len_1; + mbuf_input[1]->pkt_len = input_pkt_len_1; + + /* set the hash for mbuf */ + mbuf_input[1]->hash.usr = 16385; + + /* prepare the test packet */ + struct rte_ether_hdr * input_eth_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + struct rte_ipv6_hdr * input_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(input_eth_hdr_1 + 1); + struct rte_udp_hdr * input_udp_hdr_1 = (struct rte_udp_hdr *)(input_ipv6_hdr_1 + 1); + + /* set the ether header */ + eth_header_construct(input_eth_hdr_1, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV6); + + /* set the ipv6 header */ + ipv6_header_construct(input_ipv6_hdr_1, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr)); + + /* set the udp header */ + udp_header_construct(input_udp_hdr_1, 80, 80, sizeof(struct rte_udp_hdr)); + + /* add the peer */ + uint32_t peer_add_ip_1; + inet_pton(AF_INET, "192.168.2.2", &peer_add_ip_1); + struct rte_ether_addr peer_ether_addr_1 = {.addr_bytes = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x02}}; + + key.ip_src = peer_add_ip_1; + rte_memcpy(&key.mac_src, &peer_ether_addr_1, sizeof(struct rte_ether_addr)); + + int peer_index_1 = ef_peer_handle_peer_add(ef_peer_handle, &key); + assert_int_not_equal(peer_index_1, RT_ERR); + + /* set metadata */ + uint8_t input_dir_1 = 1; + uint16_t ef_link_id_1 = 31; + struct mrb_metadata * input_mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_1); + sid_list_init(&input_mrb_meta_1->sid_list); + input_mrb_meta_1->packet_create_from_nf = 1; + input_mrb_meta_1->cur_sid = 101; + input_mrb_meta_1->ef_peer_index = peer_index_1; + input_mrb_meta_1->dir = input_dir_1; + input_mrb_meta_1->ef_link_id = ef_link_id_1; + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_output, 2); + + /* check the output mbuf */ + for (uint8_t i = 0; i < nr_mbuf_output; i++) + { + assert_non_null(mbuf_output[i]); + assert_ptr_equal(mbuf_output[i], mbuf_input[i]); + } + + /* + * check the output mbuf 0 (IPv4) + */ + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_0 = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); + assert_non_null(output_mrb_meta_0); + assert_int_equal(output_mrb_meta_0->port_egress, 0); + + /* check the pkt len */ + uint32_t output_pkt_len_0 = rte_pktmbuf_pkt_len(mbuf_output[0]); + assert_int_equal(output_pkt_len_0, input_pkt_len_0 + ef_encap_len); + + /* check the outer external pkt */ + struct rte_ether_hdr * out_external_ether_hdr_0 = rte_pktmbuf_mtod(mbuf_output[0], struct rte_ether_hdr *); + assert_non_null(out_external_ether_hdr_0); + + struct rte_ipv4_hdr * out_external_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(out_external_ether_hdr_0 + 1); + assert_non_null(out_external_ipv4_hdr_0); + + struct rte_udp_hdr * out_external_udp_hdr_0 = (struct rte_udp_hdr *)(out_external_ipv4_hdr_0 + 1); + assert_non_null(out_external_udp_hdr_0); + + struct g_vxlan_hdr * out_external_p_vxlan_hdr_0 = (struct g_vxlan_hdr *)(out_external_udp_hdr_0 + 1); + assert_non_null(out_external_p_vxlan_hdr_0); + + /* check the outer eth header */ + assert_memory_equal(&out_external_ether_hdr_0->dst_addr, &peer_ether_addr_0, sizeof(struct rte_ether_addr)); + assert_memory_equal(&out_external_ether_hdr_0->src_addr, &mock_devs_desc[output_mrb_meta_0->port_egress]->eth_addr, + sizeof(struct rte_ether_addr)); + assert_int_equal(out_external_ether_hdr_0->ether_type, rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)); + + /* check the outer ipv4 header */ + assert_int_equal(out_external_ipv4_hdr_0->version_ihl, 0x45); + assert_int_equal(out_external_ipv4_hdr_0->type_of_service, 0); + assert_int_equal(out_external_ipv4_hdr_0->packet_id, 0x0100); + assert_int_equal(out_external_ipv4_hdr_0->fragment_offset, 0); + assert_int_equal(out_external_ipv4_hdr_0->time_to_live, 0x40); + assert_int_equal(out_external_ipv4_hdr_0->next_proto_id, IPPROTO_UDP); + assert_int_equal(out_external_ipv4_hdr_0->src_addr, mock_devs_desc[output_mrb_meta_0->port_egress]->in_addr.s_addr); + assert_int_equal(out_external_ipv4_hdr_0->dst_addr, peer_add_ip_0); + assert_int_equal(out_external_ipv4_hdr_0->total_length, + rte_cpu_to_be_16(input_pkt_len_0 + ef_encap_len - sizeof(struct rte_ether_hdr))); + uint16_t out_external_ipv4_checksum_0 = out_external_ipv4_hdr_0->hdr_checksum; + out_external_ipv4_hdr_0->hdr_checksum = 0; + assert_int_equal(rte_ipv4_cksum(out_external_ipv4_hdr_0), out_external_ipv4_checksum_0); + + /* check the outer udp header */ + assert_int_equal(out_external_udp_hdr_0->src_port, rte_cpu_to_be_16(49152)); + assert_int_equal(out_external_udp_hdr_0->dst_port, rte_cpu_to_be_16(4789)); + assert_int_equal( + out_external_udp_hdr_0->dgram_len, + rte_cpu_to_be_16(input_pkt_len_0 + ef_encap_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr))); + assert_int_equal(out_external_udp_hdr_0->dgram_cksum, 0); + + /* check the outer vxlan header */ + assert_int_equal(out_external_p_vxlan_hdr_0->flags, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->reserved[0], 0); + assert_int_equal(out_external_p_vxlan_hdr_0->reserved[1], 0); + assert_int_equal(out_external_p_vxlan_hdr_0->reserved[2], 0); + assert_int_equal(out_external_p_vxlan_hdr_0->vlan_id_half_high, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->link_layer_type, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->vlan_id_half_low, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->dir, input_dir_0); + assert_int_equal(out_external_p_vxlan_hdr_0->link_id, ef_link_id_0); + assert_int_equal(out_external_p_vxlan_hdr_0->online_test, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r7, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r6, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r5, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r4, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->vni_flag, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r2, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r1, 0); + assert_int_equal(out_external_p_vxlan_hdr_0->r0, 0); + + /* check the outer internal pkt */ + struct rte_ether_hdr * out_internal_eth_hdr_0 = (struct rte_ether_hdr *)(out_external_p_vxlan_hdr_0 + 1); + assert_non_null(out_internal_eth_hdr_0); + + struct rte_ipv4_hdr * out_internal_ipv4_hdr = (struct rte_ipv4_hdr *)(out_internal_eth_hdr_0 + 1); + assert_non_null(out_internal_ipv4_hdr); + + struct rte_tcp_hdr * out_internal_tcp_hdr = (struct rte_tcp_hdr *)(out_internal_ipv4_hdr + 1); + assert_non_null(out_internal_tcp_hdr); + + assert_memory_equal(out_internal_eth_hdr_0, input_eth_hdr_0, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_internal_ipv4_hdr, input_ipv4_hdr_0, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(out_internal_tcp_hdr, input_tcp_hdr_0, sizeof(struct rte_tcp_hdr)); + + /* + * check the output mbuf 1 (IPv6) + */ + + /* check the metadata */ + struct mrb_metadata * output_mrb_meta_1 = mrbuf_cz_data(mbuf_output[1], MR_NODE_CTRLZONE_ID); + assert_non_null(output_mrb_meta_1); + assert_int_equal(output_mrb_meta_1->port_egress, 1); + + /* check the pkt len */ + uint32_t output_pkt_len_1 = rte_pktmbuf_pkt_len(mbuf_output[1]); + assert_int_equal(output_pkt_len_1, input_pkt_len_1 + ef_encap_len); + + /* check the outer external pkt */ + struct rte_ether_hdr * out_external_ether_hdr_1 = rte_pktmbuf_mtod(mbuf_output[1], struct rte_ether_hdr *); + assert_non_null(out_external_ether_hdr_1); + + struct rte_ipv4_hdr * out_external_ipv4_hdr_1 = (struct rte_ipv4_hdr *)(out_external_ether_hdr_1 + 1); + assert_non_null(out_external_ipv4_hdr_1); + + struct rte_udp_hdr * out_external_udp_hdr_1 = (struct rte_udp_hdr *)(out_external_ipv4_hdr_1 + 1); + assert_non_null(out_external_udp_hdr_1); + + struct g_vxlan_hdr * out_external_p_vxlan_hdr_1 = (struct g_vxlan_hdr *)(out_external_udp_hdr_1 + 1); + assert_non_null(out_external_p_vxlan_hdr_1); + + /* check the outer eth header */ + assert_memory_equal(&out_external_ether_hdr_1->dst_addr, &peer_ether_addr_1, sizeof(struct rte_ether_addr)); + assert_memory_equal(&out_external_ether_hdr_1->src_addr, &mock_devs_desc[output_mrb_meta_1->port_egress]->eth_addr, + sizeof(struct rte_ether_addr)); + assert_int_equal(out_external_ether_hdr_1->ether_type, rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)); + + /* check the outer ipv4 header */ + assert_int_equal(out_external_ipv4_hdr_1->version_ihl, 0x45); + assert_int_equal(out_external_ipv4_hdr_1->type_of_service, 0); + assert_int_equal(out_external_ipv4_hdr_1->packet_id, 0x0100); + assert_int_equal(out_external_ipv4_hdr_1->fragment_offset, 0); + assert_int_equal(out_external_ipv4_hdr_1->time_to_live, 0x40); + assert_int_equal(out_external_ipv4_hdr_1->next_proto_id, IPPROTO_UDP); + assert_int_equal(out_external_ipv4_hdr_1->src_addr, mock_devs_desc[output_mrb_meta_1->port_egress]->in_addr.s_addr); + assert_int_equal(out_external_ipv4_hdr_1->dst_addr, peer_add_ip_1); + assert_int_equal(out_external_ipv4_hdr_1->total_length, + rte_cpu_to_be_16(input_pkt_len_1 + ef_encap_len - sizeof(struct rte_ether_hdr))); + uint16_t out_external_ipv4_checksum_1 = out_external_ipv4_hdr_1->hdr_checksum; + out_external_ipv4_hdr_1->hdr_checksum = 0; + assert_int_equal(rte_ipv4_cksum(out_external_ipv4_hdr_1), out_external_ipv4_checksum_1); + + /* check the outer udp header */ + assert_int_equal(out_external_udp_hdr_1->src_port, rte_cpu_to_be_16(49153)); + assert_int_equal(out_external_udp_hdr_1->dst_port, rte_cpu_to_be_16(4789)); + assert_int_equal( + out_external_udp_hdr_1->dgram_len, + rte_cpu_to_be_16(input_pkt_len_1 + ef_encap_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr))); + assert_int_equal(out_external_udp_hdr_1->dgram_cksum, 0); + + /* check the outer vxlan header */ + assert_int_equal(out_external_p_vxlan_hdr_1->flags, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->reserved[0], 0); + assert_int_equal(out_external_p_vxlan_hdr_1->reserved[1], 0); + assert_int_equal(out_external_p_vxlan_hdr_1->reserved[2], 0); + assert_int_equal(out_external_p_vxlan_hdr_1->vlan_id_half_high, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->link_layer_type, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->vlan_id_half_low, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->dir, input_dir_1); + assert_int_equal(out_external_p_vxlan_hdr_1->link_id, ef_link_id_1); + assert_int_equal(out_external_p_vxlan_hdr_1->online_test, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r7, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r6, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r5, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r4, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->vni_flag, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r2, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r1, 0); + assert_int_equal(out_external_p_vxlan_hdr_1->r0, 0); + + /* check the outer internal pkt */ + struct rte_ether_hdr * out_internal_eth_hdr_1 = (struct rte_ether_hdr *)(out_external_p_vxlan_hdr_1 + 1); + assert_non_null(out_internal_eth_hdr_1); + + struct rte_ipv6_hdr * out_internal_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(out_internal_eth_hdr_1 + 1); + assert_non_null(out_internal_ipv6_hdr_1); + + struct rte_udp_hdr * out_internal_udp_hdr_1 = (struct rte_udp_hdr *)(out_internal_ipv6_hdr_1 + 1); + assert_non_null(out_internal_udp_hdr_1); + + assert_memory_equal(out_internal_eth_hdr_1, input_eth_hdr_1, sizeof(struct rte_ether_hdr)); + assert_memory_equal(out_internal_ipv6_hdr_1, input_ipv6_hdr_1, sizeof(struct rte_ipv6_hdr)); + assert_memory_equal(out_internal_udp_hdr_1, input_udp_hdr_1, sizeof(struct rte_udp_hdr)); + + /* check metrics */ + struct sc_metrics_handle * egress_metrics_handle = node_ef_main_egress_metrics_handle_get(ef_main, 0); + assert_non_null(egress_metrics_handle); + + uint64_t nr_vxlan_encap_pkts; + int ret = sc_metrics_value_get(egress_metrics_handle, &nr_vxlan_encap_pkts, 2); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(nr_vxlan_encap_pkts, 2); + + /* release the mbufs */ + for (uint8_t i = 0; i < 2; i++) + { + rte_pktmbuf_free(mbuf_input[i]); + } + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* + * Test Group: ef egress tap mode + */ +static void testgroup_ef_egress_tap_mode(void ** state) +{ + /* get the graph pointer */ + struct rte_graph * graph_ptr = rte_graph_lookup("test_ef_egress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[2]; + for (uint8_t i = 0; i < 2; i++) + { + mbuf_input[i] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + assert_non_null(mbuf_input[i]); + } + + /* set the return value for the mock function */ + will_return(mock_pkt_input_process, 2); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + struct rte_mbuf * mbuf_drop[2] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* + * construct the test packet for IPv4 + */ + /* set mbuf pkt_len for IPv4 */ + uint32_t input_pkt_len_0 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_tcp_hdr); + mbuf_input[0]->data_len = input_pkt_len_0; + mbuf_input[0]->pkt_len = input_pkt_len_0; + + /* prepare the test packet */ + struct rte_ether_hdr * input_eth_hdr_0 = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); + struct rte_ipv4_hdr * input_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(input_eth_hdr_0 + 1); + struct rte_tcp_hdr * input_tcp_hdr_0 = (struct rte_tcp_hdr *)(input_ipv4_hdr_0 + 1); + + /* set the ether header */ + struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; + struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + eth_header_construct(input_eth_hdr_0, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); + + /* set the IPv4 header */ + ipv4_header_construct(input_ipv4_hdr_0, NULL, NULL, IPPROTO_TCP, sizeof(struct rte_tcp_hdr)); + + /* set the tcp header */ + tcp_header_construct(input_tcp_hdr_0, 80, 80, 0, 0, 5, 0, 1000); + + /* set metadata */ + uint8_t input_dir_0 = 0; + uint16_t ef_link_id_0 = 30; + struct mrb_metadata * input_mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_0); + sid_list_init(&input_mrb_meta_0->sid_list); + input_mrb_meta_0->cur_sid = 100; + input_mrb_meta_0->dir = input_dir_0; + input_mrb_meta_0->ef_link_id = ef_link_id_0; + + /* + * construct the test packet for ipv6 + */ + /* set mbuf pkt_len for ipv6 */ + uint32_t input_pkt_len_1 = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr) + sizeof(struct rte_udp_hdr); + mbuf_input[1]->data_len = input_pkt_len_1; + mbuf_input[1]->pkt_len = input_pkt_len_1; + + /* prepare the test packet */ + struct rte_ether_hdr * input_eth_hdr_1 = rte_pktmbuf_mtod(mbuf_input[1], struct rte_ether_hdr *); + struct rte_ipv6_hdr * input_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(input_eth_hdr_1 + 1); + struct rte_udp_hdr * input_udp_hdr_1 = (struct rte_udp_hdr *)(input_ipv6_hdr_1 + 1); + + /* set the ether header */ + eth_header_construct(input_eth_hdr_1, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV6); + + /* set the ipv6 header */ + ipv6_header_construct(input_ipv6_hdr_1, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr)); + + /* set the udp header */ + udp_header_construct(input_udp_hdr_1, 80, 80, sizeof(struct rte_udp_hdr)); + + /* set metadata */ + uint8_t input_dir_1 = 1; + uint16_t ef_link_id_1 = 31; + struct mrb_metadata * input_mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(input_mrb_meta_1); + sid_list_init(&input_mrb_meta_1->sid_list); + input_mrb_meta_1->cur_sid = 101; + input_mrb_meta_1->dir = input_dir_1; + input_mrb_meta_1->ef_link_id = ef_link_id_1; + + /* walk the graph */ + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_drop, 2); + + /* check the drop mbuf */ + for (uint8_t i = 0; i < nr_mbuf_drop; i++) + { + assert_non_null(mbuf_drop[i]); + assert_ptr_equal(mbuf_drop[i], mbuf_input[i]); + } + + /* + * check the output mbuf 0 (IPv4) + */ + /* check the drop pkt */ + struct rte_ether_hdr * drop_eth_hdr_0 = rte_pktmbuf_mtod(mbuf_drop[0], struct rte_ether_hdr *); + assert_non_null(drop_eth_hdr_0); + + struct rte_ipv4_hdr * drop_ipv4_hdr_0 = (struct rte_ipv4_hdr *)(drop_eth_hdr_0 + 1); + assert_non_null(drop_ipv4_hdr_0); + + struct rte_tcp_hdr * drop_tcp_hdr_0 = (struct rte_tcp_hdr *)(drop_ipv4_hdr_0 + 1); + assert_non_null(drop_tcp_hdr_0); + + assert_memory_equal(drop_eth_hdr_0, input_eth_hdr_0, sizeof(struct rte_ether_hdr)); + assert_memory_equal(drop_ipv4_hdr_0, input_ipv4_hdr_0, sizeof(struct rte_ipv4_hdr)); + assert_memory_equal(drop_tcp_hdr_0, input_tcp_hdr_0, sizeof(struct rte_tcp_hdr)); + + /* + * check the output mbuf 1 (IPv6) + */ + /* check the drop pkt */ + struct rte_ether_hdr * drop_eth_hdr_1 = rte_pktmbuf_mtod(mbuf_drop[1], struct rte_ether_hdr *); + assert_non_null(drop_eth_hdr_1); + + struct rte_ipv6_hdr * drop_ipv6_hdr_1 = (struct rte_ipv6_hdr *)(drop_eth_hdr_1 + 1); + assert_non_null(drop_ipv6_hdr_1); + + struct rte_udp_hdr * drop_udp_hdr_1 = (struct rte_udp_hdr *)(drop_ipv6_hdr_1 + 1); + assert_non_null(drop_udp_hdr_1); + + assert_memory_equal(drop_eth_hdr_1, input_eth_hdr_1, sizeof(struct rte_ether_hdr)); + assert_memory_equal(drop_ipv6_hdr_1, input_ipv6_hdr_1, sizeof(struct rte_ipv6_hdr)); + assert_memory_equal(drop_udp_hdr_1, input_udp_hdr_1, sizeof(struct rte_udp_hdr)); + + /* check metrics */ + struct ef_node_main * ef_main = g_ef_node_main_get(); + struct sc_metrics_handle * egress_metrics_handle = node_ef_main_egress_metrics_handle_get(ef_main, 0); + assert_non_null(egress_metrics_handle); + + uint64_t nr_drop_rsn_tap_mode; + int ret = sc_metrics_value_get(egress_metrics_handle, &nr_drop_rsn_tap_mode, 4); + assert_int_equal(ret, RT_SUCCESS); + assert_int_equal(nr_drop_rsn_tap_mode, 2); + + /* release the mbufs */ + for (uint8_t i = 0; i < 2; i++) + { + rte_pktmbuf_free(mbuf_input[i]); + } + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +/* ------------------------------------------------------ Main ----------------------------------------------------- + */ +int main(int argc, char * argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "test_node_ef", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + mock_pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", 1024, 32, 128, RTE_MBUF_DEFAULT_BUF_SIZE, + SOCKET_ID_ANY); + assert_non_null(mock_pktmbuf_pool); + + mock_cfgfile_content = rte_zmalloc(NULL, MOCK_SIZE_CFGFILE_CONTENT, 0); + + uint32_t in_addr = 0x0A0A0A0A; + for (int i = 0; i < MOCK_NR_DEV_MAX; i++) + { + + mock_devs_desc[i] = (struct mr_dev_desc *)rte_zmalloc(NULL, sizeof(struct mr_dev_desc), 0); + assert_non_null(mock_devs_desc[i]); + + mock_devs_desc[i]->port_id = i; + mock_devs_desc[i]->in_addr.s_addr = htonl(in_addr + i); + + struct rte_ether_addr eth_addr = {.addr_bytes = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, i}}; + rte_memcpy(&mock_devs_desc[i]->eth_addr, ð_addr, RTE_ETHER_ADDR_LEN); + + snprintf(mock_devs_name[i], 32, "ens4f0np%d", i); + rte_memcpy(mock_devs_desc[i]->symbol, mock_devs_name[i], strlen(mock_devs_name[i])); + } + + const struct CMUnitTest group_ef_config_handle[] = { + cmocka_unit_test(testcase_ef_config_handle_success), + cmocka_unit_test(testcase_ef_config_handle_failure), + }; + + const struct CMUnitTest group_ef_adapter_handle[] = { + cmocka_unit_test(testcase_ef_adapter_handle_success), + cmocka_unit_test(testcase_ef_adapter_handle_failure), + }; + + const struct CMUnitTest group_ef_peer_handle[] = { + cmocka_unit_test(testcase_ef_peer_handle_success), + cmocka_unit_test(testcase_ef_peer_handle_failure), + }; + + const struct CMUnitTest group_tl_to_ef_peer_map_handle[] = { + cmocka_unit_test(testcase_tl_to_ef_peer_map_handle_success), + cmocka_unit_test(testcase_tl_to_ef_peer_map_handle_failure), + }; + + const struct CMUnitTest group_ef_node_main[] = { + cmocka_unit_test(testcase_ef_node_main_success), + cmocka_unit_test(testcase_ef_node_main_failure), + }; + + const struct CMUnitTest group_ef_init[] = { + cmocka_unit_test(testcase_ef_init_success), + }; + + const struct CMUnitTest group_ef_ingress[] = { + cmocka_unit_test(testcase_ef_ingress_forward_pkts), + cmocka_unit_test(testcase_ef_ingress_drop_adapter_no_exist), + cmocka_unit_test(testcase_ef_ingress_drop_prepend_sid_error), + cmocka_unit_test(testcase_ef_ingress_drop_peer_add_error), + }; + + const struct CMUnitTest group_ef_egress_vwire_mode[] = { + cmocka_unit_test(testcase_ef_egress_forward_pkts), + cmocka_unit_test(testgroup_ef_egress_nf_create_pkts), + }; + + const struct CMUnitTest group_ef_egress_tap_mode[] = { + cmocka_unit_test(testgroup_ef_egress_tap_mode), + }; + + cmocka_run_group_tests(group_ef_config_handle, testgroup_common_setup, testgroup_common_teardown); + cmocka_run_group_tests(group_ef_adapter_handle, testgroup_common_setup, testgroup_common_teardown); + cmocka_run_group_tests(group_ef_peer_handle, NULL, NULL); + cmocka_run_group_tests(group_tl_to_ef_peer_map_handle, NULL, NULL); + cmocka_run_group_tests(group_ef_node_main, testgroup_common_setup, testgroup_common_teardown); + cmocka_run_group_tests(group_ef_init, testgroup_common_setup, testgroup_common_teardown); + cmocka_run_group_tests(group_ef_ingress, testgroup_ef_ingress_setup, testgroup_ef_ingress_teardown); + cmocka_run_group_tests(group_ef_egress_vwire_mode, testgroup_ef_egress_vwire_mode_setup, + testgroup_ef_egress_common_teardown); + cmocka_run_group_tests(group_ef_egress_tap_mode, testgroup_ef_egress_tap_mode_setup, + testgroup_ef_egress_common_teardown); + + /* free the memory */ + rte_free(mock_cfgfile_content); + + for (int i = 0; i < MOCK_NR_DEV_MAX; i++) + { + rte_free(mock_devs_desc[i]); + } + + rte_mempool_free(mock_pktmbuf_pool); + + rte_eal_cleanup(); + return 0; +} |
