From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com,
stephen@networkplumber.org
Subject: [PATCH v2 1/7] net/ntnic: introduce service API for NTNIC PMD
Date: Mon, 8 Sep 2025 16:17:33 +0200 [thread overview]
Message-ID: <20250908141740.1312268-2-sil-plv@napatech.com> (raw)
In-Reply-To: <20250908141740.1312268-1-sil-plv@napatech.com>
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-plv@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
next prev parent reply other threads:[~2025-09-08 14:18 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-08 11:04 [PATCH v1 0/7] migrate threads to DPDK service framework Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 1/7] net/ntnic: introduce service API for NTNIC PMD Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 2/7] net/ntnic: migrate flm update thread to service Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 3/7] net/ntnic: migrate statistic " Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 4/7] net/ntnic: migrate port event " Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 5/7] net/ntnic: migrate adapter mon " Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 6/7] net/ntnic: add warning about service cores Serhii Iliushyk
2025-09-08 11:04 ` [PATCH v1 7/7] net/ntnic: cleanup using pthreads and rte_thread Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 0/7] migrate threads to DPDK service framework Serhii Iliushyk
2025-09-08 14:17 ` Serhii Iliushyk [this message]
2025-09-08 14:17 ` [PATCH v2 2/7] net/ntnic: migrate flm update thread to service Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 3/7] net/ntnic: migrate statistic " Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 4/7] net/ntnic: migrate port event " Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 5/7] net/ntnic: migrate adapter mon " Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 6/7] net/ntnic: add warning about service cores Serhii Iliushyk
2025-09-08 14:17 ` [PATCH v2 7/7] net/ntnic: cleanup using pthreads and rte_thread Serhii Iliushyk
2025-09-08 20:08 ` [PATCH v1 0/7] migrate threads to DPDK service framework Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250908141740.1312268-2-sil-plv@napatech.com \
--to=sil-plv@napatech.com \
--cc=ckm@napatech.com \
--cc=dev@dpdk.org \
--cc=mko-plv@napatech.com \
--cc=stephen@networkplumber.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).