[PATCH] infra: add diagnostics (for developers)

Morten Brørup mb at smartsharesystems.com
Sun Aug 23 15:17:29 CEST 2026


Add API and CLI command to dump DPDK objects.

Intended for developers only, so the object types are not enumerated.

Signed-off-by: Morten Brørup <mb at smartsharesystems.com>
---
 api/gr_api.h                  |   6 ++
 modules/infra/api/diagnos.c   | 125 ++++++++++++++++++++++++++++++++++
 modules/infra/api/gr_infra.h  |  12 ++++
 modules/infra/api/meson.build |   1 +
 modules/infra/cli/diagnos.c   |  66 ++++++++++++++++++
 modules/infra/cli/meson.build |   1 +
 6 files changed, 211 insertions(+)
 create mode 100644 modules/infra/api/diagnos.c
 create mode 100644 modules/infra/cli/diagnos.c

diff --git a/api/gr_api.h b/api/gr_api.h
index 4ddca3f9..495f77eb 100644
--- a/api/gr_api.h
+++ b/api/gr_api.h
@@ -165,6 +165,12 @@ const char *gr_api_message_name(uint32_t type);
 
 struct gr_empty { };
 
+// Unstructured text, not zero-terminated.
+struct gr_text {
+	uint32_t len; // Limited by GR_API_MAX_MSG_LEN.
+	char text[/* len */]; // Text format.
+};
+
 #define GR_MAIN_MODULE 0xcafe
 
 enum gr_main_requests : uint32_t {
diff --git a/modules/infra/api/diagnos.c b/modules/infra/api/diagnos.c
new file mode 100644
index 00000000..16fd55ad
--- /dev/null
+++ b/modules/infra/api/diagnos.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2026 SmartShare Systems
+
+#include "module.h"
+
+#include <gr_api.h>
+#include <gr_infra.h>
+
+#include <rte_bus.h>
+#include <rte_bus_pci.h>
+#include <rte_graph.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_mbuf_dyn.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_memzone.h>
+#include <rte_ring.h>
+#include <rte_tailq.h>
+//#include <rte_timer.h>
+#include <rte_trace.h>
+
+static void
+graph_dump(FILE *f, struct rte_graph *graph)
+{
+	rte_graph_obj_dump(f, graph, true);
+}
+
+static void
+malloc_dump_stats(FILE *f)
+{
+	rte_malloc_dump_stats(f, NULL);
+}
+
+static void
+node_dump(FILE *f, uintptr_t id)
+{
+	rte_node_dump(f, (rte_node_t)id);
+}
+
+typedef void (*dump_list_fn_t)(FILE *f);
+typedef void (*dump_fn_t)(FILE *f, void *obj);
+typedef void *(*lookup_fn_t)(const char *name);
+
+struct obj_dump_helper {
+	char *type;
+	dump_list_fn_t dump_list_fn;
+	dump_fn_t dump_fn;
+	lookup_fn_t lookup_fn;
+} obj_dump_helpers[] =
+{
+	// DPDK libs first, in alphabetical order.
+	{"bus", rte_bus_dump, NULL, (lookup_fn_t)rte_bus_find_by_name},
+	{"graph", rte_graph_list_dump, (dump_fn_t)graph_dump, (lookup_fn_t)rte_graph_lookup},
+	{"lcore", rte_lcore_dump, NULL, NULL},
+	{"log", rte_log_dump, NULL, NULL},
+	{"malloc_heaps", rte_malloc_dump_heaps, NULL, NULL},
+	{"malloc_stats", malloc_dump_stats, NULL, NULL},
+	{"mbuf_dyn", rte_mbuf_dyn_dump, NULL, NULL},
+	{"mempool", rte_mempool_list_dump, (dump_fn_t)rte_mempool_dump, (lookup_fn_t)rte_mempool_lookup},
+	{"memzone", rte_memzone_dump, NULL, NULL},
+	{"node", rte_node_list_dump, (dump_fn_t)node_dump, (lookup_fn_t)rte_node_from_name},
+	{"pci", rte_pci_dump, NULL, NULL},
+	{"physmem_layout", rte_dump_physmem_layout, NULL, NULL},
+	{"ring", rte_ring_list_dump, (dump_fn_t)rte_ring_dump, (lookup_fn_t)rte_ring_lookup},
+	{"tailq", rte_dump_tailq, NULL, NULL},
+//	{"timer_stats", (dump_list_fn_t)rte_timer_dump_stats, NULL, NULL},
+	{"trace", rte_trace_dump, NULL, NULL},
+	{NULL, NULL, NULL, NULL}
+};
+
+
+static struct api_out obj_dump(const void *request, struct api_ctx *ctx) {
+	const struct gr_diagnos_obj_dump_req *req = request;
+	struct gr_text *resp;
+	struct obj_dump_helper *helper;
+	void *obj = NULL;
+	char *buf = NULL;
+	size_t len = 0, pos;
+	FILE *f;
+
+	if (strlen(req->type) == 0)
+		return api_out(EINVAL, 0, NULL);
+
+	// Lookup object type.
+	for (helper = obj_dump_helpers; helper->type != NULL; helper++)
+		if (strcmp(req->type, helper->type) == 0)
+			break;
+	if (helper->type == NULL)
+		return api_out(EINVAL, 0, NULL); // Object type not supported.
+
+	// If name provided, lookup object.
+	if (*req->name != 0) {
+		if (helper->lookup_fn == NULL || helper->dump_fn == NULL)
+			return api_out(EINVAL, 0, NULL); // Name lookup/dump not supported.
+		if ((obj = helper->lookup_fn(req->name)) == NULL)
+			return api_out(ENOENT, 0, NULL); // Not found.
+	}
+
+	if ((resp = malloc(GR_API_MAX_MSG_LEN)) == NULL)
+		return api_out(ENOMEM, 0, NULL);
+
+	f = open_memstream(&buf, &len);
+	if (obj != NULL)
+		helper->dump_fn(f, obj);
+	else
+		helper->dump_list_fn(f);
+	fclose(f);
+
+	for (pos = 0; pos < len; pos += resp->len) {
+		resp->len = RTE_MIN(GR_API_MAX_MSG_LEN - sizeof(*resp), len - pos);
+		memcpy(resp->text, buf + pos, resp->len);
+		api_send(ctx, sizeof(*resp) + resp->len, resp);
+	}
+
+	free(buf);
+	free(resp);
+
+	return api_out(0, 0, NULL);
+}
+
+RTE_INIT(diagnos_init) {
+	api_handler(GR_DIAGNOS_OBJ_DUMP, obj_dump);
+}
diff --git a/modules/infra/api/gr_infra.h b/modules/infra/api/gr_infra.h
index 72c1f79e..ef21acd4 100644
--- a/modules/infra/api/gr_infra.h
+++ b/modules/infra/api/gr_infra.h
@@ -246,6 +246,7 @@ enum gr_infra_requests : uint32_t {
 	GR_PACKET_TRACE_CLEAR,
 	GR_PACKET_TRACE_DUMP,
 	GR_PACKET_TRACE_SET,
+	GR_DIAGNOS_OBJ_DUMP,
 	GR_AFFINITY_CPU_GET,
 	GR_AFFINITY_CPU_SET,
 	GR_IFACE_MAC_ADD,
@@ -482,6 +483,17 @@ struct gr_packet_trace_set_req {
 
 GR_REQ(GR_PACKET_TRACE_SET, struct gr_packet_trace_set_req, struct gr_empty);
 
+// diagnotics (for developers) /////////////////////////////////////////////////
+
+// Dump an object.
+struct gr_diagnos_obj_dump_req {
+#define GR_DIAGNOS_OBJ_DUMP_ID_SIZE 128
+	char type[GR_DIAGNOS_OBJ_DUMP_ID_SIZE];
+	char name[GR_DIAGNOS_OBJ_DUMP_ID_SIZE]; // All if empty.
+};
+
+GR_REQ_STREAM(GR_DIAGNOS_OBJ_DUMP, struct gr_diagnos_obj_dump_req, struct gr_text);
+
 // cpu affinities //////////////////////////////////////////////////////////////
 
 // Get the current CPU affinity masks.
diff --git a/modules/infra/api/meson.build b/modules/infra/api/meson.build
index b67981a3..f12abc25 100644
--- a/modules/infra/api/meson.build
+++ b/modules/infra/api/meson.build
@@ -3,6 +3,7 @@
 
 src += files(
   'affinity.c',
+  'diagnos.c',
   'iface.c',
   'nexthop.c',
   'stats.c',
diff --git a/modules/infra/cli/diagnos.c b/modules/infra/cli/diagnos.c
new file mode 100644
index 00000000..a20e943e
--- /dev/null
+++ b/modules/infra/cli/diagnos.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2026 SmartShare Systems
+
+#include "cli.h"
+
+#include <gr_api.h>
+#include <gr_infra.h>
+
+#include <ecoli.h>
+
+#include <stdio.h>
+
+static cmd_status_t obj_dump(struct gr_api_client *c, const struct ec_pnode *p) {
+	const struct gr_text *resp = NULL;
+	struct gr_diagnos_obj_dump_req req;
+	const char *type = NULL;
+	const char *name = NULL;
+	int ret;
+
+	if ((type = arg_str(p, "TYPE")) == NULL ||
+			strlcpy(req.type, type, sizeof(req.type)) >= sizeof(req.type))
+		return CMD_ERROR;
+
+	*req.name = 0;
+	if ((name = arg_str(p, "NAME")) != NULL &&
+			strlcpy(req.name, name, sizeof(req.name)) >= sizeof(req.name))
+		return CMD_ERROR;
+
+	gr_api_client_stream_foreach(
+		resp, ret, c, GR_DIAGNOS_OBJ_DUMP, sizeof(req), &req
+	)
+		fwrite(resp->text, 1, resp->len, stdout);
+
+	if (ret < 0)
+		return CMD_ERROR;
+
+	return CMD_SUCCESS;
+}
+
+#define DIAGNOS_CTX(root) CLI_CONTEXT(root, CTX_ARG("diagnos", "Diagnostics (for developers)."))
+
+static int ctx_init(struct ec_node *root) {
+	int ret;
+
+	ret = CLI_COMMAND(
+		DIAGNOS_CTX(root),
+		"object dump TYPE [NAME]",
+		obj_dump,
+		"Dump object.",
+		with_help("Object type.", ec_node("any", "TYPE")),
+		with_help("Specific object.", ec_node("any", "NAME"))
+	);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct cli_context ctx = {
+	.name = "diagnos",
+	.init = ctx_init,
+};
+
+static void __attribute__((constructor, used)) init(void) {
+	cli_context_register(&ctx);
+}
diff --git a/modules/infra/cli/meson.build b/modules/infra/cli/meson.build
index 222f7219..9763bcb9 100644
--- a/modules/infra/cli/meson.build
+++ b/modules/infra/cli/meson.build
@@ -5,6 +5,7 @@ cli_src += files(
   'address.c',
   'affinity.c',
   'bond.c',
+  'diagnos.c',
   'events.c',
   'graph.c',
   'icmp.c',
-- 
2.43.0



More information about the grout mailing list