#include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************* Etherfabric adapter struct ***********************************************/ /* Etherfabric adapter mode */ enum ef_adapter_mode { 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; 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 { uint32_t ip_src; struct rte_ether_addr mac_src; }; }; /* ef_peer struct */ struct ef_peer { uint32_t ef_ip_addr; rte_atomic64_t state; struct rte_ether_addr ef_mac_addr; } __rte_cache_aligned; /* ef_peer handle */ struct ef_peer_handle { uint32_t capacity; uint32_t entries; uint32_t remaining_entries; struct rte_hash * ef_peer_hash; struct ef_peer * ef_peers; }; /******************************************** Traffic Link Peer Map struct ********************************************/ struct tl_to_ef_peer_map_handle { uint16_t capacity; rte_atomic64_t * maps_table; }; /********************************************** 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 next node */ enum { EF_INGR_NEXT_CLASSIFIER = 0, EF_INGR_NEXT_PKT_DROP, EF_INGR_NEXT_MAX }; /* Etherfabric egress next node */ enum { EF_EGR_NEXT_ETH_EGRESS = 0, EF_EGR_NEXT_PKT_DROP, EF_EGR_NEXT_MAX }; /* 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 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 { 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 }; /* 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"}; /* Etherfabric config handle */ struct ef_config_handle { 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 node main struct */ struct ef_node_main { /* Number of graphs */ uint16_t nr_graphs; 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) { 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; } /** * @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) { if (handle == NULL) { MR_ERROR("The ef_adapter_handle is NULL."); return RT_ERR; } if (handle->adapters != NULL) { FREE(handle->adapters); handle->adapters = NULL; } FREE(handle); return RT_SUCCESS; } /** * @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) { assert(handle != NULL); return handle->capacity; } /** * @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; } /** * @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) { assert(handle != NULL); assert(adapter_id < handle->capacity); return &handle->adapters[adapter_id]; } /** * @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); return __ef_adapter_handle_adapter_get_by_id(handle, adapter_id); } /** * @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; } /** * @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 */ const union ef_peer_key * key = data; return key->ip_src; const uint32_t * mac_0 = (const uint32_t *)&key->mac_src.addr_bytes[0]; const uint32_t * mac_1 = (const uint32_t *)&key->mac_src.addr_bytes[4]; init_val = rte_hash_crc_4byte(key->ip_src, init_val); init_val = rte_hash_crc_4byte(*mac_0, init_val); init_val = rte_hash_crc_4byte(*mac_1, init_val); return init_val; } /** * @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 = entries, //.entries = SC_EF_PEER_ENTRIES, .key_len = sizeof(union ef_peer_key), .hash_func = ef_peer_hash_crc, .hash_func_init_val = 0, .socket_id = 0, .extra_flag = RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD | RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF, }; 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; } return RT_ERR; } /*********************************************** 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 = 0; MESA_load_profile_uint_def(sc->local_cfgfile, "ef_adapters", "sid_start", &sid_start, 100); /* Get sid range 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 */ if (sid_start > sid_end) { MR_ERROR("Etherfabric adapters config 'sid_end' less than 'sid_start' ."); return RT_ERR; } /* Parsing all config */ uint16_t nr_adapters = 0; 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; int ret = MESA_load_profile_uint_nodef(sc->local_cfgfile, str_conf_section, "mode", &mode); if (ret < 0) { continue; } 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; } /* Get etherfabric adapter id */ uint32_t ef_adapter_id = 0; ret = MESA_load_profile_uint_nodef(sc->local_cfgfile, str_conf_section, "ef_adapter_id", &ef_adapter_id); if (ret < 0) { MR_ERROR("The : %s ,No config the 'ef_adapter_id'.", str_conf_section); return RT_ERR; } 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; } /* Parsing listen device */ char str_listen_device[MR_STRING_MAX] = {}; ret = MESA_load_profile_string_nodef(sc->local_cfgfile, str_conf_section, "listen_device", str_listen_device, sizeof(str_listen_device)); if (ret < 0) { MR_ERROR("The : %s ,No config the 'listen_device'.", str_conf_section); return RT_ERR; } struct mr_dev_desc * dev_desc = mr_dev_desc_lookup(sc->devmgr_main, str_listen_device); if (dev_desc == NULL) { MR_ERROR("The : %s 'listen_device' is invalid: %s", str_conf_section, str_listen_device); return RT_ERR; } if (dev_desc->dev_mode == MR_DEV_MODE_TRUNK) { MR_ERROR("The : %s 'listen_device[%s]' is in trunk mode, which is not supported by Etherfabric.", str_conf_section, str_listen_device); return RT_ERR; } /* Port adapter mapping insert */ port_adapter_mapping_insert(dev_desc->port_id, ADAPTER_TYPE_EF); /* Save The Listen Device Port Index */ 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->listening_device = dev_desc; nr_adapters++; } /* Check nr adapter */ 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, sid_capacity); return RT_ERR; } /* 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) { 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; } } /* 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; } FREE(ef_main); return RT_SUCCESS; } /** * @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) { 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_adapter_capacity, sid_capacity, sid_start, sid_end); for (int i = 0; i < ef_adapter_capacity; i++) { char str_mode[MR_STRING_MAX] = {}; struct ef_adapter * ef_adapter = ef_adapter_handle_adapter_get_by_id(ef_main->ef_adapter_handle, i); switch (ef_adapter->mode) { case EF_MODE_VIRTUAL_WIRE: sprintf(str_mode, "virtual-wire"); break; case EF_MODE_TAP: sprintf(str_mode, "tap"); break; default: continue; } MR_INFO("Etherfabric adapter, id:%u, mode: %s, listen device: %s", ef_adapter->id, str_mode, ef_adapter->listening_device->symbol); } } /** * @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 */ 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; } /* 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; } /* 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; } 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; } /* 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; forwarder_table_insert(sid_start + ef_adapter->id, FORWARDER_TYPE_EF); } /* Dump the etherfabric adapter config */ ef_info_dump(ef_main); /* Set the global ef main */ g_ef_node_main_set(ef_main); ret = RT_SUCCESS; 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) { 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; } /*********************************************** 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) { struct ef_node_main * ef_main = __g_ef_node_main_get(); if (ef_main == NULL) { MR_ERROR("The ef node is not initialized."); return RT_ERR; } 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; } if (ef_adapter_id >= ef_adapter_capacity) { return RT_ERR; } 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_SUCCESS; } /** * @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() { struct ef_node_main * ef_main = __g_ef_node_main_get(); return ef_adapter_handle_nr_adapters_get(ef_main->ef_adapter_handle); } /** * @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); for (int i = 0; i < ef_adapters_capacity; i++) { 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) { ef_adapter_ids[adapter_count] = ef_adapter->id; adapter_count++; } if (adapter_count == nr_adapters) { return; } } } /** * @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); } /** * @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() { struct ef_node_main * ef_main = __g_ef_node_main_get(); return sid_handle_sid_start_get(ef_main->sid_handle); } /** * @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) { 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) { *out_ef_peer_index = rte_atomic64_read(&handle->maps_table[traffic_link_id]); return RT_SUCCESS; } 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 */ struct rte_ether_hdr * eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); swap_mac_addr(eth_hdr); struct rte_ipv4_hdr * ip_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr)); uint32_t _swap_ip_addr = ip_hdr->src_addr; ip_hdr->src_addr = ip_hdr->dst_addr; ip_hdr->dst_addr = _swap_ip_addr; } /** * @brief Generates a source port for VXLAN encapsulation according to RFC 7348. * * This inline function generates a source port number for VXLAN encapsulation by hashing * the packet's data (specifically the inner headers) and mapping the result to a range of * ephemeral ports (49152 to 65535). The generated source port helps to distribute the * VXLAN traffic across different paths in the network. * * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. * * @return The generated source port for VXLAN encapsulation. */ static inline uint16_t generate_vxlan_src_port(struct rte_mbuf * mbuf) { uint16_t min = 49152; uint16_t range = 65535 - 49152 + 1; return min + (uint16_t)(mbuf->hash.usr % range); } /** * @brief Constructs the VXLAN encapsulation headers for a given packet. * * This inline function constructs the VXLAN encapsulation headers, including the outer Ethernet, * IPv4, and UDP headers, as well as the VXLAN header itself. It ensures that the packet is * prepared for transmission over a VXLAN tunnel. The function returns `RT_SUCCESS` if the * headers are successfully constructed, or `RT_ERR` if any header cannot be added. * * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. * @param mrb_meta Pointer to the `mrb_metadata` structure containing metadata for the packet. * @param ef_peer Pointer to the `ef_peer` structure representing the destination peer. * @param dev_desc Pointer to the `mr_dev_desc` structure representing the device description. * * @return RT_SUCCESS if the headers are successfully constructed, RT_ERR otherwise. */ static inline int vxlan_encap_constructed_pkt(struct rte_mbuf * mbuf, struct mrb_metadata * mrb_meta, struct ef_peer * ef_peer, struct mr_dev_desc * dev_desc) { /* construct the packet by the order of inner to outer */ struct g_vxlan_hdr * p_vxlan_hdr = (struct g_vxlan_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct g_vxlan_hdr)); if (unlikely(p_vxlan_hdr == NULL)) { return RT_ERR; } /* clear the vxlan header */ memset(p_vxlan_hdr, 0, sizeof(struct g_vxlan_hdr)); p_vxlan_hdr->dir = mrb_meta->dir; p_vxlan_hdr->link_id = mrb_meta->ef_link_id; /* then, the outer udp header */ struct rte_udp_hdr * p_udp_hdr = (struct rte_udp_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_udp_hdr)); if (unlikely(p_udp_hdr == NULL)) { return RT_ERR; } /* TODO: the source port need to be fill with the hash of inner 2-tuple or 4-tuple, * ignore the udp checksum */ p_udp_hdr->src_port = htons(generate_vxlan_src_port(mbuf)); p_udp_hdr->dst_port = htons(4789); p_udp_hdr->dgram_len = htons(rte_pktmbuf_pkt_len(mbuf)); p_udp_hdr->dgram_cksum = 0; /* then, the outer ip header */ struct rte_ipv4_hdr * p_ipv4_hdr = (struct rte_ipv4_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ipv4_hdr)); if (unlikely(p_ipv4_hdr == NULL)) { return RT_ERR; } p_ipv4_hdr->version_ihl = 0x45; p_ipv4_hdr->type_of_service = 0x00; p_ipv4_hdr->packet_id = 0x0100; p_ipv4_hdr->fragment_offset = 0x0000; p_ipv4_hdr->time_to_live = 0x40; p_ipv4_hdr->next_proto_id = IPPROTO_UDP; p_ipv4_hdr->src_addr = dev_desc->in_addr.s_addr; p_ipv4_hdr->dst_addr = ef_peer->ef_ip_addr; p_ipv4_hdr->total_length = htons(rte_pktmbuf_pkt_len(mbuf)); p_ipv4_hdr->hdr_checksum = 0; p_ipv4_hdr->hdr_checksum = rte_ipv4_cksum(p_ipv4_hdr); /* outermost ether header */ struct rte_ether_hdr * eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr)); eth_hdr->ether_type = htons(RTE_ETHER_TYPE_IPV4); rte_ether_addr_copy(&ef_peer->ef_mac_addr, ð_hdr->dst_addr); rte_ether_addr_copy(&dev_desc->eth_addr, ð_hdr->src_addr); return RT_SUCCESS; } /** * @brief Generates and stores trace information for ingress packets. * * This function generates a trace record for an ingress packet as it moves through the * network. It records details such as the next node, reason for dropping the packet * (if applicable), and other metadata. The trace record is then emitted for analysis or * debugging purposes. * * @param node Pointer to the `rte_node` structure representing the current node. * @param mbuf Pointer to the `rte_mbuf` structure containing the packet. * @param next_node_index Index of the next node in the processing pipeline. * @param prepend_sid The SID to prepend in the trace. * @param drop_reason The reason for dropping the packet, if applicable. */ void gen_store_trace_info_ingress(struct rte_node * node, struct rte_mbuf * mbuf, uint16_t next_node_index, uint16_t prepend_sid, enum ef_node_ingress_metrics_key drop_reason) { /* Populate the next node infomation */ char str_record[MR_STRING_MAX]; struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_ID); 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_INGR_NEXT_PKT_DROP)) { 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 { /* Populate the ef id, traffic link id adn prepend sid */ len += snprintf(str_record + len, sizeof(str_record) - len, ", ef id:%u, trf lk id:%u, prep sid:%u", mrb_meta->adapter_id, mrb_meta->traffic_link_id, prepend_sid); /* Populate the sids information */ len += embed_sid_info(mbuf, str_record + len, sizeof(str_record) - len); } /* 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 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) { void ** batch_pkts = objs; struct rte_mbuf ** mbufs = (struct rte_mbuf **)objs; /* 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_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) { uint16_t prepend_sid = 0; struct rte_mbuf * mbuf = mbufs[0]; mbufs += 1; n_left_from -= 1; /* Prepare headers */ struct rte_ether_hdr * outer_ether_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ether_hdr *, 0); struct rte_ipv4_hdr * outer_ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr)); struct g_vxlan_hdr * outer_g_vxlan_hdr = rte_pktmbuf_mtod_offset( mbuf, struct g_vxlan_hdr *, sizeof(struct rte_udp_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_ether_hdr)); assert(outer_ipv4_hdr != NULL); assert(outer_g_vxlan_hdr != NULL); /* Etherfabric adapter lookup */ uint16_t ef_adapter_id = UINT16_MAX; 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_INGR_NEXT_PKT_DROP; drop_reason = EF_INGR_METRIC_DROP_ADP_NONEXIST; inc_values[drop_reason]++; goto node_enqueue; } /* 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)) { 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 */ uint16_t traffic_link_id; struct link_db_match_field match_field; match_field.ef_link_id = outer_g_vxlan_hdr->link_id; match_field.ef_ip_addr = outer_ipv4_hdr->src_addr; link_db_match(ef_main->link_db_ctx, &match_field, 1, &traffic_link_id); /* 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->ef_peer_index = ef_peer_index; /* Insert sid*/ prepend_sid = sid_start + ef_adapter_id; ret = sid_list_prepend(&mrb_meta->sid_list, &prepend_sid, 1); if (unlikely(ret != RT_SUCCESS)) { next_node_index = EF_INGR_NEXT_PKT_DROP; drop_reason = EF_INGR_METRIC_DROP_PRE_SID_ERR; inc_values[drop_reason]++; goto node_enqueue; } /* Swap the outer mac and ip addr */ vxlan_encap_forwarded_pkt(mbuf); complex_layer_adjust(&mrb_meta->pkt_parser_result, ef_encap_len); rte_pktmbuf_adj(mbuf, ef_encap_len); /* Send the pkt to classifier */ next_node_index = EF_INGR_NEXT_CLASSIFIER; inc_values[EF_INGR_METRIC_TO_CLASSIFIER]++; node_enqueue: #if 0 /* Check if tracing is enabled for the current Mbuf */ if (unlikely(dp_trace_record_can_emit(mbuf, DP_TRACE_MEASUREMENT_TYPE_TRACE))) { gen_store_trace_info_ingress(node, mbuf, next_node_index, prepend_sid, drop_reason); // gen_store_trace_info_sid_list(node, mbuf); // gen_store_trace_info_rte_mbuf(node, mbuf); } if (unlikely(dp_trace_record_can_emit(mbuf, DP_TRACE_MEASUREMENT_TYPE_TELEMETRY))) { gen_store_telemetry_info_adapter(mbuf); } #endif /* Judge the next index whether to change */ if (unlikely(batch_next_node_index != next_node_index)) { /* If the next index has been changed,Enqueue last pkts */ rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); batch_pkts += last_spec; last_spec = 1; batch_next_node_index = next_node_index; } else { /* If the next index not change, update the lasts */ last_spec++; } } /* Process the remaining packets */ if (likely(last_spec > 0)) rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); /* 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; } /* Etherfabric ingress node base */ static struct rte_node_register ef_ingress_node_base = { .process = ef_ingress_node_process, .name = "ef_ingress", .init = NULL, .nb_edges = EF_INGR_NEXT_MAX, .next_nodes = { [EF_INGR_NEXT_CLASSIFIER] = "classifier", [EF_INGR_NEXT_PKT_DROP] = "pkt_drop_trap", }, }; RTE_NODE_REGISTER(ef_ingress_node_base); /*********************************************** Etherfabric egress Node **********************************************/ /* Etherfabric egress node process function */ 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; /* prefetch the mbuf and it's content */ rte_prefetch0_write(mbufs[0]); rte_prefetch0_write(mrbuf_cz_data(mbufs[0], MR_NODE_CTRLZONE_ID)); uint16_t last_spec = 0; uint16_t n_left_from = cnt; 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) { struct rte_mbuf * mbuf = mbufs[0]; mbufs += 1; n_left_from -= 1; /* prefetch next mbuf */ if (n_left_from > 0) { rte_prefetch0_write(mbufs[0]); rte_prefetch0_write(mrbuf_cz_data(mbufs[0], MR_NODE_CTRLZONE_ID)); } /* Get the buffer metadata */ struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf, MR_NODE_CTRLZONE_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 EF_MODE_VIRTUAL_WIRE: { /* Get port egress */ 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 < 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_EGR_NEXT_ETH_EGRESS; inc_values[EF_EGR_METRIC_TO_ETH_EGRESS]++; } break; 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_EGR_NEXT_PKT_DROP; drop_reason = EF_EGR_METRIC_DROP_RSN_INVALID_MODE; inc_values[drop_reason]++; break; } /* Check if tracing is enabled for the current Mbuf */ if (unlikely(dp_trace_record_can_emit(mbuf, DP_TRACE_MEASUREMENT_TYPE_TRACE))) { gen_store_trace_info_egress(node, mbuf, next_node_index, drop_reason); // gen_store_trace_info_rte_mbuf(node, mbuf); } /* Determine if the next index should be changed */ if (unlikely(batch_next_node_index != next_node_index)) { /* If the next index has been changed, enqueue the last packets */ rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); batch_pkts += last_spec; last_spec = 1; batch_next_node_index = next_node_index; } else { /* If the next index does not change, update the last items */ last_spec++; } } /* Process the remaining packets */ if (likely(last_spec > 0)) rte_node_enqueue(graph, node, batch_next_node_index, batch_pkts, last_spec); /* 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; } /* Etherfabric egress node base */ static struct rte_node_register ef_egress_node_base = { .process = ef_egress_node_process, .name = "ef_egress", .init = NULL, .nb_edges = EF_EGR_NEXT_MAX, .next_nodes = { [EF_EGR_NEXT_ETH_EGRESS] = "eth_egress", [EF_EGR_NEXT_PKT_DROP] = "pkt_drop_trap", }, }; RTE_NODE_REGISTER(ef_egress_node_base);