Sharing a list of names across API and CLI
Morten Brørup
mb at smartsharesystems.com
Sat Aug 22 12:01:49 CEST 2026
> From: Robin Jarry [mailto:rjarry at redhat.com]
> Sent: Saturday, 22 August 2026 11.41
>
> Hi Morten,
>
> Morten Brørup, Aug 21, 2026 at 19:22:
> > Seeking guidance...
> >
> > I'm working on a Grout "dump" API+CLI to call the various _dump()
> functions in DPDK.
> >
> > My modules/infra/api/dump.c has the table below.
> >
> > I want the type names in the table to be shared with
> modules/infra/cli/dump.c, so I can avoid copy-paste, and only have one
> place to add new entries.
> >
> > I suppose this can be done using a macro with two variants; one
> variant for use in the cli file, and another variant for use in the api
> file.
> >
> > E.g.
> > #if API
> > #define GR_DUMP_MACRO(name, description, dump_list_fn, dump_fn,
> lookup_fn) \
> > {name, dump_list_fn, dump_fn, lookup_fn}
> > #elif CLI
> > #define
> GR_DUMP_MACRO(name,description,dump_list_fn,dump_fn,lookup_fn) \
> > with_help(description, ec_node_str(EC_NO_ID, name))
> > #endif
>
> What would the API messages look like?
// Dump an object.
struct gr_dump_obj_req {
#define GR_DUMP_OBJ_ID_SIZE 128
char type[GR_DUMP_OBJ_ID_SIZE];
char name[GR_DUMP_OBJ_ID_SIZE]; // All if empty.
};
struct gr_dump_obj_resp {
uint32_t len; // Limited by GR_API_MAX_MSG_LEN.
char text[/* len */]; // Text format.
};
GR_REQ(GR_DUMP_OBJ, struct gr_dump_obj_req, struct gr_dump_obj_resp);
>
> > And then the shared table using these macros:
> > [...]
> > GR_DUMP_MACRO("graph", "DPDK graph.", rte_graph_list_dump,
> (dump_fn_t)graph_dump, (lookup_fn_t)rte_graph_lookup),
> > GR_DUMP_MACRO("memzone", "DPDK memzone.", rte_memzone_dump, NULL,
> NULL),
> > [...]
> >
> > Now, my question is:
> > In which directory should I put the file with the shared table?
>
> The issue is that grcli concerns have nothing to do with the API socket
> itself. It may not be possible to avoid duplication.
The cli command is something like:
Dump object TYPE all|(name NAME)
Maybe I should just leave TYPE to be "any string" instead of an enum of specific strings.
>
> > Or should I use a completely different design pattern?
>
> I must ask: is this intended for debugging/development or do you expect
> to use this in production? What do you want to do with these dumps?
It's for development (debugging and performance analysis); but it might be enabled in some production environments.
>
> Does this need to go through the API socket and grcli? I am wondering
> if
> such dumps would fit better in the openmetrics endpoints. E.g.:
>
> https://github.com/DPDK/grout/blob/v0.17.1/modules/infra/api/iface.c#L2
> 18-L239
> https://github.com/DPDK/grout/blob/v0.17.1/modules/infra/api/stats.c#L2
> 63-L306
>
> These endpoints are self describing, no need to duplicate anything and
> eventually, this data could be scraped by prometheus and stored in
> a time series db for later analysis.
>
> However, that means you need to expose "structured" information (i.e.
> key=value pairs) which may not fit with the "dump" functions from DPDK
> that seem to only expose text blobs.
They only expose text blobs, not structured information.
So openmetrics is not an option for these.
>
> If you are concerned with exposing too much information, they could be
> hidden by default and only exposed when a certain variable is set (e.g.
> GROUT_METRICS_DEBUG=1)
Good point.
>
> What do you think?
Since it's for development purposes only, I will compromise on user friendliness, and simply use "any string", so I don't need to synchronize the list of TYPE strings to the CLI.
Thank you for bringing a broader perspective, Robin.
It's valuable for learning about Grout foundation and design patterns.
>
>
> > modules/infra/api/dump.c:
> >
> > 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 dump_obj_helper {
> > char *type;
> > dump_list_fn_t dump_list_fn;
> > dump_fn_t dump_fn;
> > lookup_fn_t lookup_fn;
> > } dump_obj_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},
> > {"trace", rte_trace_dump, NULL, NULL},
> > {NULL, NULL, NULL, NULL}
> > };
>
>
> --
> Robin
>
> # Disposable, use only once.
More information about the grout
mailing list