summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsongyanchao <[email protected]>2024-08-09 09:29:04 +0000
committersongyanchao <[email protected]>2024-08-09 10:23:03 +0000
commit96e1b64b3a4b53bf4c0882dbfecddd4796e826f6 (patch)
treee72a8b35995de537e572665a5c729fac660f14fc
parent0975a9d01780acb8aaf89db0704c46b21d9be3c0 (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.h2
-rw-r--r--infra/include/common.h2
-rw-r--r--service/CMakeLists.txt12
-rw-r--r--service/include/sc_common.h2
-rw-r--r--service/include/sc_node_common.h22
-rw-r--r--service/src/node_etherfabric.c2669
-rw-r--r--service/src/node_link_aware_injector.c9
-rw-r--r--service/src/sc_metrics.c1
-rw-r--r--service/src/sc_node_common.c139
-rw-r--r--service/test/test_common.c160
-rw-r--r--service/test/test_node_bfd.c24
-rw-r--r--service/test/test_node_ef.c3212
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, &eth_hdr->dst_addr);
+ rte_ether_addr_copy(&dev_desc->eth_addr, &eth_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, &eth_hdr->dst_addr);
- rte_ether_addr_copy(&dev_desc->eth_addr, &eth_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, &eth_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;
+}