This commit adds a common service API for the NTNIC PMD, which includes functions for service management: add or delete a service and retrieve information about a service. The API is designed to facilitate the interaction with services within the NTNIC driver, allowing for better control and monitoring of service states.
Signed-off-by: Serhii Iliushyk <sil-...@napatech.com> --- doc/guides/nics/ntnic.rst | 112 ++++++++++++++++++++++++++ drivers/net/ntnic/meson.build | 2 + drivers/net/ntnic/ntutil/nt_service.c | 103 +++++++++++++++++++++++ drivers/net/ntnic/ntutil/nt_service.h | 62 ++++++++++++++ drivers/net/ntnic/rte_pmd_ntnic.c | 104 ++++++++++++++++++++++++ drivers/net/ntnic/rte_pmd_ntnic.h | 21 +++++ 6 files changed, 404 insertions(+) create mode 100644 drivers/net/ntnic/ntutil/nt_service.c create mode 100644 drivers/net/ntnic/ntutil/nt_service.h create mode 100644 drivers/net/ntnic/rte_pmd_ntnic.c diff --git a/doc/guides/nics/ntnic.rst b/doc/guides/nics/ntnic.rst index b3d6ad70c1..a173eaa2ac 100644 --- a/doc/guides/nics/ntnic.rst +++ b/doc/guides/nics/ntnic.rst @@ -185,3 +185,115 @@ There are list of characteristics that age timeout action has: - after flow is aged-out it's not automatically deleted; - aged-out flow can be updated with ``flow update`` command, and its aged-out status will be reverted; + +Service API +----------- + +**nthw_service_add** +**nthw_service_del** +**nthw_service_get_info** + +The NTNIC PMD provides a service API that allows applications to configure services + +The services are responsible for handling the vital functionality of the NTNIC PMD: + +- **FLM Update**: is responsible for creating and destroying flows; +- **Statistics**: is responsible for collecting statistics; +- **Port event**: is responsible for handling port events: aging, port load, and flow load; +- **Adapter monitor** is responsible for link control; + +**NOTE**: Use next EAL options to configure set service cores + * -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores; + * -S SERVICE CORELIST List of cores to run services on; + +**NOTE**: **At least 5 lcores must be reserved** for the ntnic services by EAL options. above. + +For example + +.. code-block:: console + + dpdk-testpmd -S 8,9,10,11,12 + +The PMD registers each service during initialization by function: + +.. code-block:: c + + int nthw_service_add(struct rte_service_spec *srv_spec, const enum rte_ntnic_service_tag tag) + +and unregistered by the PMD during deinitialization by the function: + +.. code-block:: c + + int nthw_service_del(const enum rte_ntnic_service_tag tag) + +The service info may be retrieved by function: + +.. code-block:: c + + struct nt_service *nthw_service_get_info(const enum rte_ntnic_service_tag tag) + +The service info includes the service ID, assigned lcore, and initialization state. + +Service API for user applications +--------------------------------- +**rte_pmd_ntnic_service_set_lcore** +**rte_pmd_ntnic_service_get_id** + +The exported service API is available for applications to configure the services. + +By API function: + +.. code-block:: c + + int rte_pmd_ntnic_service_set_lcore(enum rte_ntnic_service_tag tag, uint32_t lcore_id) + +For example to assign lcores 8,9,10,11,12 to the services, the application can use: + +.. code-block:: c + + rte_pmd_ntnic_service_set_lcore(RTE_NTNIC_SERVICE_STAT, 8); + rte_pmd_ntnic_service_set_lcore(RTE_NTNIC_SERVICE_ADAPTER_MON, 9); + rte_pmd_ntnic_service_set_lcore(RTE_NTNIC_SERVICE_PORT_0_EVENT, 10); + rte_pmd_ntnic_service_set_lcore(RTE_NTNIC_SERVICE_PORT_1_EVENT,11); + rte_pmd_ntnic_service_set_lcore(RTE_NTNIC_SERVICE_FLM_UPDATE, 12); + +The API will automatically lcore to service core list and map the service to the lcore. + +.. note:: Use `rte_service_lcore_start` to start the lcore after mapping it to the service. + +Each service has its own tag to identify it. + +.. code-block:: c + + enum rte_ntnic_service_tag { + RTE_NTNIC_SERVICE_FLM_UPDATE = 0, + RTE_NTNIC_SERVICE_STAT = 1, + RTE_NTNIC_SERVICE_PORT_0_EVENT = 2, + RTE_NTNIC_SERVICE_PORT_1_EVENT = 3, + RTE_NTNIC_SERVICE_ADAPTER_MON = 4, + RTE_NTNIC_SERVICE_MAX + }; + +The application may use next API function to retrieve the service id: + +.. code-block:: c + + int rte_pmd_ntnic_service_get_id(enum rte_ntnic_service_tag tag); + + +For example, to enable statistics for flm_update service, the application can use: + +.. code-block:: c + + int flm_update_id = rte_pmd_ntnic_service_get_id(RTE_NTNIC_SERVICE_FLM_UPDATE); + rte_service_set_stats_enable(flm_update_id, 1); + +All other manipulations with the service can be done with the service ID and rte_service* API. + +To use the service API, an application must have included the header file: + +.. code-block:: c + + #include <rte_pmd_ntnic.h> + +And linked with the library: `librte_net_ntnic.so` or `librte_net_ntnic.a` for static linking. diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build index b4c6cfe7de..785ac4836d 100644 --- a/drivers/net/ntnic/meson.build +++ b/drivers/net/ntnic/meson.build @@ -120,7 +120,9 @@ sources = files( 'ntlog/ntlog.c', 'ntnic_filter/ntnic_filter.c', 'ntutil/nt_util.c', + 'ntutil/nt_service.c', 'ntnic_mod_reg.c', 'ntnic_vfio.c', 'ntnic_ethdev.c', + 'rte_pmd_ntnic.c', ) diff --git a/drivers/net/ntnic/ntutil/nt_service.c b/drivers/net/ntnic/ntutil/nt_service.c new file mode 100644 index 0000000000..4ef1233f12 --- /dev/null +++ b/drivers/net/ntnic/ntutil/nt_service.c @@ -0,0 +1,103 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2025 Napatech A/S + */ + +#include <rte_service.h> +#include <rte_cycles.h> + +#include "nt_service.h" +#include "ntlog.h" + +#define NT_SERVICE_UNKNOWN_ID (-1) + +static struct nt_service g_nt_services[RTE_NTNIC_SERVICE_MAX] = { + [0] = { + .tag = RTE_NTNIC_SERVICE_MAX, + .id = NT_SERVICE_UNKNOWN_ID, + .lcore = RTE_MAX_LCORE, + .initialized = false, + }, +}; + +inline struct nt_service *nthw_service_get_info(const enum rte_ntnic_service_tag tag) +{ + if (tag < 0 || tag >= RTE_NTNIC_SERVICE_MAX) + return NULL; + + return &g_nt_services[tag]; +} + +int nthw_service_add(struct rte_service_spec *srv_spec, const enum rte_ntnic_service_tag tag) +{ + if (srv_spec == NULL || tag < 0 || tag >= RTE_NTNIC_SERVICE_MAX) { + NT_LOG(ERR, NTNIC, "Invalid service specification or service tag"); + return -1; + } + + int ret = rte_service_component_register(srv_spec, &g_nt_services[tag].id); + if (ret < 0) { + NT_LOG(ERR, NTNIC, "Failed to register service %s: error: %d", + srv_spec->name, ret); + return ret; + } + + const uint32_t service_id = g_nt_services[tag].id; + + NT_LOG(DBG, NTNIC, "Service %s registered with ID %u", + srv_spec->name, service_id); + + rte_service_component_runstate_set(service_id, 1); + + ret = rte_service_runstate_set(service_id, 1); + if (ret < 0) { + NT_LOG(ERR, NTNIC, "Failed to start service %s: error: %d", + srv_spec->name, ret); + rte_service_component_unregister(service_id); + return ret; + } + + return 0; +} + +int nthw_service_del(const enum rte_ntnic_service_tag tag) +{ + if (tag < 0 || tag >= RTE_NTNIC_SERVICE_MAX) { + NT_LOG(ERR, NTNIC, "Invalid service tag"); + return -1; + } + + struct nt_service *info = &g_nt_services[tag]; + + const char *service_name = rte_service_get_name(info->id); + + rte_service_component_runstate_set(info->id, 0); + + const uint32_t timeout_count = 10000; + + for (uint32_t i = 0; i < timeout_count; i++) { + if (rte_service_may_be_active(info->id) == 0) + break; + rte_delay_ms(1); + } + + int ret = rte_service_runstate_set(info->id, 0); + if (ret < 0) { + NT_LOG(ERR, NTNIC, "Failed to stop service %s: error: %d", + service_name, ret); + return ret; + } + + ret = rte_service_component_unregister(info->id); + if (ret < 0) { + NT_LOG(ERR, NTNIC, "Failed to unregister service %s: error: %d", + service_name, ret); + return ret; + } + + NT_LOG(DBG, NTNIC, "Service ID %d unregistered", info->id); + + g_nt_services[tag].id = NT_SERVICE_UNKNOWN_ID; + + return 0; +} diff --git a/drivers/net/ntnic/ntutil/nt_service.h b/drivers/net/ntnic/ntutil/nt_service.h new file mode 100644 index 0000000000..73c9076c2e --- /dev/null +++ b/drivers/net/ntnic/ntutil/nt_service.h @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2025 Napatech A/S + */ + +#ifndef __NT_SERVICE_H__ +#define __NT_SERVICE_H__ + +#include <stdint.h> +#include <rte_service_component.h> +#include <rte_stdatomic.h> +#include <rte_pmd_ntnic.h> + +#define NT_SERVICE_GET_STATE(srv) \ + rte_atomic_load_explicit(&(srv)->initialized, rte_memory_order_seq_cst) + +#define NT_SERVICE_SET_STATE(srv, state) \ + rte_atomic_store_explicit(&(srv)->initialized, state, rte_memory_order_seq_cst) + + +struct nt_service { + const enum rte_ntnic_service_tag tag; + uint32_t id; + uint32_t lcore; + RTE_ATOMIC(bool) initialized; +}; + +/** + * Get service information by tag. + * + * This function retrieves the service information based on the provided tag. + * It returns a pointer to the nt_service structure containing the service ID + * and other relevant information. + * + * @param tag The tag of the service to retrieve. + * @return Pointer to the nt_service structure or NULL if not found. + */ +struct nt_service *nthw_service_get_info(const enum rte_ntnic_service_tag tag); + +/** + * Register and start a service with the specified tag. + * + * @srv_spec: Pointer to the service specification structure. + * @tag: Tag of the service to be registered. + * + * Returns 0 on success, or a negative error code on failure. + */ +int nthw_service_add(struct rte_service_spec *srv_spec, const enum rte_ntnic_service_tag tag); + +/** + * Unregisters a service by its tag. + * + * This function stops the service, waits for it to become inactive, and then + * unregisters it from the service component. + * + * @param tag The tag of the service to be unregistered. + * @return 0 on success, negative value on failure. + */ + +int nthw_service_del(const enum rte_ntnic_service_tag tag); + +#endif /* __NT_SERVICE_H__ */ diff --git a/drivers/net/ntnic/rte_pmd_ntnic.c b/drivers/net/ntnic/rte_pmd_ntnic.c new file mode 100644 index 0000000000..fcc06a1ea0 --- /dev/null +++ b/drivers/net/ntnic/rte_pmd_ntnic.c @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2025 Napatech A/S + */ + +#include <eal_export.h> +#include <rte_service.h> +#include <rte_pmd_ntnic.h> + +#include <stdint.h> + +#include "nt_service.h" +#include "ntlog.h" + +static int nthw_service_is_mapped_to_lcore(enum rte_ntnic_service_tag tag) +{ + struct nt_service *service = nthw_service_get_info(tag); + + uint32_t cores[RTE_MAX_LCORE] = {0}; + int32_t lcore_count = rte_service_lcore_list(cores, RTE_MAX_LCORE); + + for (int32_t i = 0; i < lcore_count; i++) { + if (rte_service_map_lcore_get(service->id, cores[i])) + return cores[i]; + } + return RTE_MAX_LCORE; +} + + +RTE_EXPORT_SYMBOL(rte_pmd_ntnic_service_set_lcore) +int rte_pmd_ntnic_service_set_lcore(enum rte_ntnic_service_tag tag, uint32_t lcore_id) +{ + if (tag < 0 || tag >= RTE_NTNIC_SERVICE_MAX || lcore_id >= RTE_MAX_LCORE) { + NT_LOG(ERR, NTNIC, "Invalid service tag or lcore ID"); + return -1; + } + + struct nt_service *srv = nthw_service_get_info(tag); + const char *service_name = rte_service_get_name(srv->id); + + uint32_t service_core = nthw_service_is_mapped_to_lcore(tag); + + if (service_core != RTE_MAX_LCORE) { + NT_LOG(WRN, NTNIC, "Service %s[id=%u] is already mapped to lcore: %u", service_name, + srv->id, service_core); + /* Mapping by application has higher priority then 1:1 default mapping. + * Disable previous mapping and do remapping to new lcore. + */ + + rte_service_runstate_set(srv->id, 0); + + NT_SERVICE_SET_STATE(srv, false); + + int timeout_count = 10000; + + while (rte_service_may_be_active(srv->id) != 0) { + if (--timeout_count <= 0) { + NT_LOG(ERR, NTNIC, "Failed to stop service %s[id=%d] on lcore %u", + service_name, srv->id, service_core); + return -1; + } + rte_delay_ms(1); + } + + rte_service_map_lcore_set(srv->id, service_core, 0); + rte_service_runstate_set(srv->id, 1); + } + + int ret = rte_service_lcore_add(lcore_id); + if (ret < 0 && ret != -EALREADY) { + NT_LOG(ERR, NTNIC, "Failed to add service lcore %u for service %s: error: %d", + lcore_id, service_name, ret); + return ret; + } + + ret = rte_service_map_lcore_set(srv->id, lcore_id, 1); + if (ret < 0) { + NT_LOG(ERR, NTNIC, "Failed to map service %s to lcore %u: error: %d", + service_name, lcore_id, ret); + return ret; + } + + NT_LOG(DBG, NTNIC, "Service %s[id=%d] is mapped to lcore %u", service_name, srv->id, + lcore_id); + + return 0; +} + +RTE_EXPORT_SYMBOL(rte_pmd_ntnic_service_get_id) +int rte_pmd_ntnic_service_get_id(enum rte_ntnic_service_tag tag) +{ + if (tag < 0 || tag >= RTE_NTNIC_SERVICE_MAX) { + NT_LOG(ERR, NTNIC, "Invalid service tag"); + return -1; + } + + struct nt_service *service = nthw_service_get_info(tag); + if (service == NULL) { + NT_LOG(ERR, NTNIC, "Service with tag %d not found", tag); + return -1; + } + + return service->id; +} diff --git a/drivers/net/ntnic/rte_pmd_ntnic.h b/drivers/net/ntnic/rte_pmd_ntnic.h index 4a1ba18a5e..7a491319fa 100644 --- a/drivers/net/ntnic/rte_pmd_ntnic.h +++ b/drivers/net/ntnic/rte_pmd_ntnic.h @@ -40,4 +40,25 @@ enum rte_ntnic_event_type { RTE_NTNIC_FLM_STATS_EVENT, }; +enum rte_ntnic_service_tag { + RTE_NTNIC_SERVICE_MAX = 1 +}; + +/** + * Set the lcore for a specific service. + * + * @param tag The service tag to set the lcore for. + * @param lcore_id The lcore ID to set for the service. + * @return 0 on success, negative value on failure. + */ +int rte_pmd_ntnic_service_set_lcore(enum rte_ntnic_service_tag tag, uint32_t lcore_id); + +/** + * Get the ID of a specific service. + * + * @param tag The service tag to get the ID for. + * @return The service ID on success, negative value on failure. + */ +int rte_pmd_ntnic_service_get_id(enum rte_ntnic_service_tag tag); + #endif /* NTNIC_EVENT_H_ */ -- 2.45.0