Skip to content

Commit e11d94e

Browse files
mkjjk-ozlabs
authored andcommitted
mi: Add facility to scan MI endpoints from MCTP daemon
This change adds support for querying a local MCTP daemon ("mctpd") instance over its D-Bus interface, to populate the list of available enpoints in root->endpoints. This requires libsystemd for sdbus, if not available the nvme_mi_scan_mctp() will always return failure at runtime. Update for v1.x root API by Jeremy Kerr <[email protected]>. Signed-off-by: Matt Johnston <[email protected]> Signed-off-by: Jeremy Kerr <[email protected]>
1 parent 97a16dc commit e11d94e

5 files changed

Lines changed: 321 additions & 0 deletions

File tree

meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ if openssl_dep.found()
7878
description: 'OpenSSL version 3.x')
7979
endif
8080

81+
# Check for libsystemd availability. Optional, only required for MCTP dbus scan
82+
libsystemd_dep = dependency('libsystemd', required: false)
83+
conf.set('CONFIG_LIBSYSTEMD', libsystemd_dep.found(), description: 'Is libsystemd available?')
84+
8185
# local (cross-compilable) implementations of ccan configure steps
8286
conf.set10(
8387
'HAVE_BUILTIN_TYPES_COMPATIBLE_P',

src/libnvme-mi.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ LIBNVME_MI_1_1 {
2020
nvme_mi_first_endpoint;
2121
nvme_mi_next_endpoint;
2222
nvme_mi_open_mctp;
23+
nvme_mi_scan_mctp;
2324
local:
2425
*;
2526
};

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ deps = [
3535

3636
mi_deps = [
3737
libuuid_dep,
38+
libsystemd_dep,
3839
]
3940

4041
source_dir = meson.current_source_dir()

src/nvme/mi-mctp.c

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
#include <ccan/endian/endian.h>
2323

24+
#ifdef CONFIG_LIBSYSTEMD
25+
#include <systemd/sd-event.h>
26+
#include <systemd/sd-bus.h>
27+
#include <systemd/sd-id128.h>
28+
#endif
29+
2430
#include "private.h"
2531
#include "log.h"
2632
#include "mi.h"
@@ -74,6 +80,10 @@ struct nvme_mi_transport_mctp {
7480
int sd;
7581
};
7682

83+
#define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp"
84+
#define MCTP_DBUS_IFACE "xyz.openbmc_project.MCTP"
85+
#define MCTP_DBUS_IFACE_ENDPOINT "xyz.openbmc_project.MCTP.Endpoint"
86+
7787
static const struct nvme_mi_transport nvme_mi_transport_mctp;
7888

7989
static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
@@ -245,3 +255,294 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid)
245255
free(ep);
246256
return NULL;
247257
}
258+
259+
#ifdef CONFIG_LIBSYSTEMD
260+
261+
static void _dbus_err(nvme_root_t root, int rc, int line) {
262+
nvme_msg(root, LOG_ERR, "MCTP D-Bus failed line %d: %s %d\n",
263+
line, strerror(-rc), rc);
264+
}
265+
266+
#define dbus_err(r, rc) _dbus_err(r, rc, __LINE__)
267+
268+
/* Returns -EEXISTS on duplicate */
269+
static int nvme_mi_mctp_add(nvme_root_t root, unsigned int netid, __u8 eid)
270+
{
271+
nvme_mi_ep_t ep = NULL;
272+
273+
/* ensure we don't already have an endpoint with the same net/eid */
274+
list_for_each(&root->endpoints, ep, root_entry) {
275+
if (ep->transport != &nvme_mi_transport_mctp) {
276+
continue;
277+
}
278+
const struct nvme_mi_transport_mctp *t = ep->transport_data;
279+
if (t->eid == eid && t->net == netid) {
280+
return -EEXIST;
281+
}
282+
}
283+
284+
ep = nvme_mi_open_mctp(root, netid, eid);
285+
if (!ep) {
286+
return -ENOMEM;
287+
}
288+
289+
return 0;
290+
}
291+
292+
/* We can't rely on sd_bus_message_enter_container() == 0 at the end of
293+
a dictionary (it returns -ENXIO) so we test separately */
294+
static bool container_end(sd_bus_message *m)
295+
{
296+
return sd_bus_message_peek_type(m, NULL, NULL) == 0;
297+
}
298+
299+
static int handle_mctp_endpoint(nvme_root_t root, const char* objpath,
300+
sd_bus_message *m)
301+
{
302+
bool have_eid = false, have_net = false, have_nvmemi = false;
303+
mctp_eid_t eid;
304+
int net;
305+
int rc;
306+
307+
/* Iterate properties on this interface */
308+
while (!container_end(m)) {
309+
/* Enter property dict */
310+
rc = sd_bus_message_enter_container(m, 'a', "{sv}");
311+
if (rc < 0) {
312+
dbus_err(root, rc);
313+
return rc;
314+
}
315+
316+
while (!container_end(m)) {
317+
char *propname = NULL;
318+
size_t sz;
319+
const uint8_t *types = NULL;
320+
/* Enter property item */
321+
rc = sd_bus_message_enter_container(m, 'e', "sv");
322+
if (rc < 0) {
323+
dbus_err(root, rc);
324+
return rc;
325+
}
326+
327+
rc = sd_bus_message_read(m, "s", &propname);
328+
if (rc < 0) {
329+
dbus_err(root, rc);
330+
return rc;
331+
}
332+
333+
if (strcmp(propname, "EID") == 0) {
334+
rc = sd_bus_message_read(m, "v", "y", &eid);
335+
have_eid = true;
336+
} else if (strcmp(propname, "NetworkId") == 0) {
337+
rc = sd_bus_message_read(m, "v", "i", &net);
338+
have_net = true;
339+
} else if (strcmp(propname, "SupportedMessageTypes") == 0) {
340+
sd_bus_message_enter_container(m, 'v', "ay");
341+
rc = sd_bus_message_read_array(m, 'y', (const void**)&types, &sz);
342+
if (rc >= 0)
343+
for (size_t s = 0; s < sz; s++)
344+
if (types[s] == MCTP_TYPE_NVME)
345+
have_nvmemi = true;
346+
sd_bus_message_exit_container(m);
347+
} else {
348+
rc = sd_bus_message_skip(m, "v");
349+
}
350+
351+
if (rc < 0) {
352+
dbus_err(root, rc);
353+
return rc;
354+
}
355+
356+
/* Exit prop item */
357+
rc = sd_bus_message_exit_container(m);
358+
if (rc < 0) {
359+
dbus_err(root, rc);
360+
return rc;
361+
}
362+
}
363+
364+
/* Exit property dict */
365+
rc = sd_bus_message_exit_container(m);
366+
if (rc < 0) {
367+
dbus_err(root, rc);
368+
return rc;
369+
}
370+
}
371+
372+
if (have_nvmemi) {
373+
if (!(have_eid && have_net)) {
374+
nvme_msg(root, LOG_ERR,
375+
"Missing property for %s\n", objpath);
376+
return -ENOENT;
377+
}
378+
rc = nvme_mi_mctp_add(root, net, eid);
379+
if (rc < 0) {
380+
nvme_msg(root, LOG_ERR,
381+
"Error adding net %d eid %d: %s\n",
382+
net, eid, strerror(-rc));
383+
}
384+
} else {
385+
/* Ignore other endpoints */
386+
rc = 0;
387+
}
388+
return rc;
389+
}
390+
391+
static int handle_mctp_obj(nvme_root_t root, sd_bus_message *m)
392+
{
393+
char *objpath = NULL;
394+
char *ifname = NULL;
395+
int rc;
396+
397+
rc = sd_bus_message_read(m, "o", &objpath);
398+
if (rc < 0) {
399+
dbus_err(root, rc);
400+
return rc;
401+
}
402+
403+
/* Enter response object: our array of (string, property dict)
404+
* values */
405+
rc = sd_bus_message_enter_container(m, 'a', "{sa{sv}}");
406+
if (rc < 0) {
407+
dbus_err(root, rc);
408+
return rc;
409+
}
410+
411+
412+
/* for each interface */
413+
while (!container_end(m)) {
414+
/* Enter interface item */
415+
rc = sd_bus_message_enter_container(m, 'e', "sa{sv}");
416+
if (rc < 0) {
417+
dbus_err(root, rc);
418+
return rc;
419+
}
420+
421+
rc = sd_bus_message_read(m, "s", &ifname);
422+
if (rc < 0) {
423+
dbus_err(root, rc);
424+
return rc;
425+
}
426+
427+
if (!strcmp(ifname, MCTP_DBUS_IFACE_ENDPOINT)) {
428+
429+
rc = handle_mctp_endpoint(root, objpath, m);
430+
if (rc < 0) {
431+
/* continue to next object */
432+
}
433+
} else {
434+
/* skip the interfaces we don't care about */
435+
rc = sd_bus_message_skip(m, "a{sv}");
436+
if (rc < 0) {
437+
dbus_err(root, rc);
438+
return rc;
439+
}
440+
}
441+
442+
/* Exit interface item */
443+
rc = sd_bus_message_exit_container(m);
444+
if (rc < 0) {
445+
dbus_err(root, rc);
446+
return rc;
447+
}
448+
}
449+
450+
/* Exit response object */
451+
rc = sd_bus_message_exit_container(m);
452+
if (rc < 0) {
453+
dbus_err(root, rc);
454+
return rc;
455+
}
456+
457+
return 0;
458+
}
459+
460+
nvme_root_t nvme_mi_scan_mctp(void)
461+
{
462+
sd_bus *bus = NULL;
463+
sd_bus_message *resp = NULL;
464+
sd_bus_error berr = SD_BUS_ERROR_NULL;
465+
nvme_root_t root;
466+
int rc;
467+
468+
root = nvme_mi_create_root(NULL, DEFAULT_LOGLEVEL);
469+
if (!root) {
470+
rc = -ENOMEM;
471+
goto out;
472+
}
473+
474+
rc = sd_bus_default_system(&bus);
475+
if (rc < 0) {
476+
nvme_msg(root, LOG_ERR, "Failed opening D-Bus: %s\n",
477+
strerror(-rc));
478+
goto out;
479+
}
480+
481+
rc = sd_bus_call_method(bus,
482+
MCTP_DBUS_IFACE,
483+
MCTP_DBUS_PATH,
484+
"org.freedesktop.DBus.ObjectManager",
485+
"GetManagedObjects",
486+
&berr,
487+
&resp,
488+
"");
489+
if (rc < 0) {
490+
nvme_msg(root, LOG_ERR, "Failed querying MCTP D-Bus: %s (%s)\n",
491+
berr.message, berr.name);
492+
goto out;
493+
}
494+
495+
rc = sd_bus_message_enter_container(resp, 'a', "{oa{sa{sv}}}");
496+
if (rc != 1) {
497+
dbus_err(root, rc);
498+
if (rc == 0)
499+
rc = -EPROTO;
500+
goto out;
501+
}
502+
503+
/* Iterate over all managed objects */
504+
while (!container_end(resp)) {
505+
rc = sd_bus_message_enter_container(resp, 'e', "oa{sa{sv}}");
506+
if (rc < 0) {
507+
dbus_err(root, rc);
508+
goto out;
509+
}
510+
511+
handle_mctp_obj(root, resp);
512+
513+
rc = sd_bus_message_exit_container(resp);
514+
if (rc < 0) {
515+
dbus_err(root, rc);
516+
goto out;
517+
}
518+
}
519+
520+
rc = sd_bus_message_exit_container(resp);
521+
if (rc < 0) {
522+
dbus_err(root, rc);
523+
goto out;
524+
}
525+
rc = 0;
526+
527+
out:
528+
sd_bus_error_free(&berr);
529+
sd_bus_message_unref(resp);
530+
sd_bus_unref(bus);
531+
532+
if (rc < 0) {
533+
if (root) {
534+
nvme_mi_free_root(root);
535+
}
536+
root = NULL;
537+
}
538+
return root;
539+
}
540+
541+
#else /* CONFIG_LIBSYSTEMD */
542+
543+
nvme_root_t nvme_mi_scan_mctp(void)
544+
{
545+
return NULL;
546+
}
547+
548+
#endif /* CONFIG_LIBSYSTEMD */

src/nvme/mi.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,20 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, uint8_t eid
360360
*/
361361
void nvme_mi_close(nvme_mi_ep_t ep);
362362

363+
/**
364+
* nvme_mi_scan_mctp - look for MCTP-connected NVMe-MI endpoints.
365+
*
366+
* This function queries the system mctp daemon ("mctpd") over dbus, to find
367+
* MCTP endpoints that report support for NVMe-MI over MCTP.
368+
*
369+
* This requires libvnme-mi to be compiled with D-Bus support; if not, this
370+
* will return NULL.
371+
*
372+
* Return: A @nvme_root_t populated with a set of MCTP-connected endpoints,
373+
* or NULL on failure
374+
*/
375+
nvme_root_t nvme_mi_scan_mctp(void);
376+
363377
/**
364378
* nvme_mi_init_ctrl() - initialise a NVMe controller.
365379
* @ep: Endpoint to create under

0 commit comments

Comments
 (0)