Skip to content

Commit 40ca1d6

Browse files
committed
example/mi-conf: Add an example for MI transport configuration
With the Read MI Data Structure and MI Configuration Set functions available, we can query a device for its maximum MTU, and update the current MTU to suit. This also requires telling the local MCTP stack about the new MTU too, by sending a d-bus message to `mctpd`. This change adds a little example for this functionality, where we perform the MI query and configuration, and implements the d-bus communication for the local stack control. Signed-off-by: Jeremy Kerr <[email protected]>
1 parent 501347f commit 40ca1d6

2 files changed

Lines changed: 198 additions & 0 deletions

File tree

examples/meson.build

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,12 @@ executable(
3939
dependencies: libnvme_mi_dep,
4040
include_directories: [incdir, internal_incdir]
4141
)
42+
43+
if libsystemd_dep.found()
44+
executable(
45+
'mi-conf',
46+
['mi-conf.c'],
47+
dependencies: [libnvme_mi_dep, libsystemd_dep],
48+
include_directories: [incdir, internal_incdir]
49+
)
50+
endif

examples/mi-conf.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/**
3+
* This file is part of libnvme.
4+
* Copyright (c) 2022 Code Construct Pty Ltd.
5+
*
6+
* Authors: Jeremy Kerr <[email protected]>
7+
*/
8+
9+
/**
10+
* mi-conf: query a device for optimal MTU and set for both the local MCTP
11+
* route (through dbus to mctpd) and the device itself (through NVMe-MI
12+
* configuration commands)
13+
*/
14+
15+
#include <err.h>
16+
#include <stdbool.h>
17+
#include <stdint.h>
18+
#include <stdio.h>
19+
#include <stdlib.h>
20+
21+
#include <libnvme-mi.h>
22+
23+
#include <ccan/array_size/array_size.h>
24+
#include <ccan/endian/endian.h>
25+
26+
#include <systemd/sd-bus.h>
27+
28+
#define MCTP_DBUS_NAME "xyz.openbmc_project.MCTP"
29+
#define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp"
30+
#define MCTP_DBUS_EP_IFACE "au.com.CodeConstruct.MCTP.Endpoint"
31+
32+
static int parse_mctp(const char *devstr, unsigned int *net, uint8_t *eid)
33+
{
34+
int rc;
35+
36+
rc = sscanf(devstr, "mctp:%u,%hhu", net, eid);
37+
if (rc != 2)
38+
return -1;
39+
40+
return 0;
41+
}
42+
43+
int find_port(nvme_mi_ep_t ep, uint8_t *portp, uint16_t *mtup)
44+
{
45+
struct nvme_mi_read_nvm_ss_info ss_info;
46+
struct nvme_mi_read_port_info port_info;
47+
uint8_t port;
48+
bool found;
49+
int rc;
50+
51+
/* query number of ports */
52+
rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info);
53+
if (rc) {
54+
warn("Failed reading subsystem info");
55+
return -1;
56+
}
57+
58+
found = false;
59+
for (port = 0; port <= ss_info.nump; port++) {
60+
rc = nvme_mi_mi_read_mi_data_port(ep, port, &port_info);
61+
if (rc) {
62+
warn("Failed reading port info for port %ud", port);
63+
return -1;
64+
}
65+
66+
/* skip non-SMBus ports */
67+
if (port_info.portt != 0x2)
68+
continue;
69+
70+
if (found) {
71+
warn("Mutliple SMBus ports; skipping duplicate");
72+
} else {
73+
*portp = port;
74+
*mtup = port_info.mmctptus;
75+
found = true;
76+
}
77+
}
78+
79+
return found ? 0 : 1;
80+
}
81+
82+
int set_local_mtu(sd_bus *bus, unsigned int net, uint8_t eid, uint32_t mtu)
83+
{
84+
sd_bus_message *resp;
85+
sd_bus_error err;
86+
char *ep_path;
87+
int rc;
88+
89+
rc = asprintf(&ep_path, "%s/%u/%hhu", MCTP_DBUS_PATH, net, eid);
90+
if (rc < 0) {
91+
warn("Failed to create dbus path");
92+
return -1;
93+
}
94+
95+
rc = sd_bus_call_method(bus, MCTP_DBUS_NAME, ep_path,
96+
MCTP_DBUS_EP_IFACE, "SetMTU", &err, &resp,
97+
"u", mtu);
98+
if (rc < 0) {
99+
warnx("Failed to set local MTU: %s", strerror(-rc));
100+
return -1;
101+
}
102+
103+
return 0;
104+
}
105+
106+
int main(int argc, char **argv)
107+
{
108+
uint16_t cur_mtu, mtu;
109+
const char *devstr;
110+
uint8_t eid, port;
111+
nvme_root_t root;
112+
unsigned int net;
113+
nvme_mi_ep_t ep;
114+
sd_bus *bus;
115+
int rc;
116+
117+
if (argc != 2) {
118+
fprintf(stderr, "usage: %s mctp:<net>,<eid>\n", argv[0]);
119+
return EXIT_FAILURE;
120+
}
121+
122+
devstr = argv[1];
123+
rc = parse_mctp(devstr, &net, &eid);
124+
if (rc)
125+
errx(EXIT_FAILURE, "can't parse MI device string '%s'", devstr);
126+
127+
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
128+
if (!root)
129+
err(EXIT_FAILURE, "can't create NVMe root");
130+
131+
ep = nvme_mi_open_mctp(root, net, eid);
132+
if (!ep) {
133+
warnx("can't open MCTP endpoint %d:%d", net, eid);
134+
goto out_free_root;
135+
}
136+
137+
rc = sd_bus_default_system(&bus);
138+
if (rc < 0) {
139+
goto out_close_ep;
140+
warnx("Failed opening D-Bus: %s\n", strerror(-rc));
141+
}
142+
143+
rc = find_port(ep, &port, &mtu);
144+
if (rc) {
145+
warnx("Can't find SMBus port information");
146+
goto out_close_bus;
147+
}
148+
149+
rc = nvme_mi_mi_config_get_mctp_mtu(ep, port, &cur_mtu);
150+
if (rc) {
151+
cur_mtu = 0;
152+
warn("Can't query current MTU; no way to revert on failure");
153+
}
154+
155+
if (mtu == cur_mtu) {
156+
printf("Current MTU (%d) is already at max\n", cur_mtu);
157+
goto out_close_bus;
158+
}
159+
160+
rc = nvme_mi_mi_config_set_mctp_mtu(ep, port, mtu);
161+
if (rc) {
162+
warn("Can't set MCTP MTU");
163+
goto out_close_bus;
164+
}
165+
166+
rc = set_local_mtu(bus, net, eid, mtu);
167+
if (rc) {
168+
/* revert if we have an old setting */
169+
if (cur_mtu) {
170+
rc = nvme_mi_mi_config_set_mctp_mtu(ep, port, cur_mtu);
171+
if (rc)
172+
warn("Failed to restore previous MTU!");
173+
rc = -1;
174+
}
175+
} else {
176+
printf("MTU for port %u set to %d (was %d)\n",
177+
port, mtu, cur_mtu);
178+
}
179+
180+
out_close_bus:
181+
sd_bus_close(bus);
182+
out_close_ep:
183+
nvme_mi_close(ep);
184+
out_free_root:
185+
nvme_mi_free_root(root);
186+
187+
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
188+
}
189+

0 commit comments

Comments
 (0)