DPDK patches and discussions
 help / color / mirror / Atom feed
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


  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).