Skip to content

Commit f807b33

Browse files
mctpd: Send Discovery Notify on Endpoint role set
This commit adds support for Discovery Notify messages, specified in DSP0236 section 12.14. In our implementation, a Discovery Notify message is sent when mctpd sets an interface role from Unknown to Endpoint. To avoid notify discovery messages getting lost, retry the messages for a few time with delays. Signed-off-by: Khang D Nguyen <[email protected]>
1 parent 5211a29 commit f807b33

File tree

2 files changed

+148
-14
lines changed

2 files changed

+148
-14
lines changed

src/mctpd.c

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ enum discovery_state {
126126
};
127127

128128
struct link {
129-
enum discovery_state discovered;
130129
bool published;
131130
int ifindex;
132131
enum endpoint_role role;
@@ -135,6 +134,14 @@ struct link {
135134
sd_bus_slot *slot_iface;
136135
sd_bus_slot *slot_busowner;
137136

137+
struct {
138+
enum discovery_state flag;
139+
sd_event_source *notify_source;
140+
dest_phys notify_dest;
141+
uint64_t notify_retry_delay;
142+
uint8_t notify_retries_left;
143+
} discovery;
144+
138145
struct ctx *ctx;
139146
};
140147

@@ -793,8 +800,8 @@ static int handle_control_set_endpoint_id(struct ctx *ctx, int sd,
793800
warnx("ERR: cannot add bus owner to object lists");
794801
}
795802

796-
if (link_data->discovered != DISCOVERY_UNSUPPORTED) {
797-
link_data->discovered = DISCOVERY_DISCOVERED;
803+
if (link_data->discovery.flag != DISCOVERY_UNSUPPORTED) {
804+
link_data->discovery.flag = DISCOVERY_DISCOVERED;
798805
}
799806
resp->status =
800807
SET_MCTP_EID_ASSIGNMENT_STATUS(MCTP_SET_EID_ACCEPTED) |
@@ -805,13 +812,13 @@ static int handle_control_set_endpoint_id(struct ctx *ctx, int sd,
805812
return reply_message(ctx, sd, resp, resp_len, addr);
806813

807814
case MCTP_SET_EID_DISCOVERED:
808-
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
815+
if (link_data->discovery.flag == DISCOVERY_UNSUPPORTED) {
809816
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
810817
resp_len = sizeof(struct mctp_ctrl_resp);
811818
return reply_message(ctx, sd, resp, resp_len, addr);
812819
}
813820

814-
link_data->discovered = DISCOVERY_DISCOVERED;
821+
link_data->discovery.flag = DISCOVERY_DISCOVERED;
815822
resp->status =
816823
SET_MCTP_EID_ASSIGNMENT_STATUS(MCTP_SET_EID_REJECTED) |
817824
SET_MCTP_EID_ALLOCATION_STATUS(MCTP_SET_EID_POOL_NONE);
@@ -1009,16 +1016,16 @@ static int handle_control_prepare_endpoint_discovery(
10091016
resp = (void *)resp;
10101017
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, *req);
10111018

1012-
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
1019+
if (link_data->discovery.flag == DISCOVERY_UNSUPPORTED) {
10131020
warnx("received prepare for discovery request to unsupported interface %d",
10141021
addr->smctp_ifindex);
10151022
resp->completion_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
10161023
return reply_message_phys(ctx, sd, resp,
10171024
sizeof(struct mctp_ctrl_resp), addr);
10181025
}
10191026

1020-
if (link_data->discovered == DISCOVERY_DISCOVERED) {
1021-
link_data->discovered = DISCOVERY_UNDISCOVERED;
1027+
if (link_data->discovery.flag == DISCOVERY_DISCOVERED) {
1028+
link_data->discovery.flag = DISCOVERY_UNDISCOVERED;
10221029
warnx("clear discovered flag of interface %d",
10231030
addr->smctp_ifindex);
10241031
}
@@ -1053,13 +1060,13 @@ handle_control_endpoint_discovery(struct ctx *ctx, int sd,
10531060
return 0;
10541061
}
10551062

1056-
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
1063+
if (link_data->discovery.flag == DISCOVERY_UNSUPPORTED) {
10571064
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
10581065
return reply_message(ctx, sd, resp,
10591066
sizeof(struct mctp_ctrl_resp), addr);
10601067
}
10611068

1062-
if (link_data->discovered == DISCOVERY_DISCOVERED) {
1069+
if (link_data->discovery.flag == DISCOVERY_DISCOVERED) {
10631070
// if we are already discovered (i.e, assigned an EID), then no reply
10641071
return 0;
10651072
}
@@ -3460,6 +3467,81 @@ static int bus_link_get_prop(sd_bus *bus, const char *path,
34603467
return rc;
34613468
}
34623469

3470+
static int query_discovery_notify(struct link *link)
3471+
{
3472+
struct mctp_ctrl_cmd_discovery_notify req = { 0 };
3473+
struct mctp_ctrl_resp_discovery_notify *resp;
3474+
struct sockaddr_mctp_ext resp_addr;
3475+
size_t buf_size;
3476+
uint8_t *buf;
3477+
int rc;
3478+
3479+
mctp_ctrl_msg_hdr_init_req(&req.ctrl_hdr, mctp_next_iid(link->ctx),
3480+
MCTP_CTRL_CMD_DISCOVERY_NOTIFY);
3481+
3482+
rc = endpoint_query_phys(link->ctx, &link->discovery.notify_dest,
3483+
MCTP_CTRL_HDR_MSG_TYPE, &req, sizeof(req),
3484+
&buf, &buf_size, &resp_addr);
3485+
if (rc < 0)
3486+
goto free_buf;
3487+
3488+
if (buf_size != sizeof(*resp)) {
3489+
warnx("%s: wrong reply length %zu bytes. dest %s", __func__,
3490+
buf_size, dest_phys_tostr(&link->discovery.notify_dest));
3491+
rc = -ENOMSG;
3492+
goto free_buf;
3493+
}
3494+
3495+
resp = (void *)buf;
3496+
if (resp->completion_code != 0) {
3497+
warnx("Failure completion code 0x%02x from %s",
3498+
resp->completion_code,
3499+
dest_phys_tostr(&link->discovery.notify_dest));
3500+
rc = -ECONNREFUSED;
3501+
goto free_buf;
3502+
}
3503+
3504+
free_buf:
3505+
free(buf);
3506+
return rc;
3507+
}
3508+
3509+
static int link_discovery_notify_callback(sd_event_source *source,
3510+
uint64_t time, void *userdata)
3511+
{
3512+
struct link *link = userdata;
3513+
struct ctx *ctx = link->ctx;
3514+
int rc;
3515+
3516+
// sanity check
3517+
assert(link->discovery.notify_source == source);
3518+
3519+
// Discovery notify succeeded
3520+
if (link->discovery.flag == DISCOVERY_DISCOVERED) {
3521+
sd_event_source_disable_unref(source);
3522+
link->discovery.notify_source = NULL;
3523+
return 0;
3524+
}
3525+
3526+
rc = query_discovery_notify(link);
3527+
if (rc < 0) {
3528+
if (ctx->verbose) {
3529+
warnx("failed to send discovery notify at retry %d: %s",
3530+
link->discovery.notify_retries_left,
3531+
strerror(-rc));
3532+
}
3533+
}
3534+
link->discovery.notify_retries_left -= 1;
3535+
if (link->discovery.notify_retries_left == 0) {
3536+
warnx("failed to send discovery notify after all retries");
3537+
sd_event_source_disable_unref(source);
3538+
} else {
3539+
sd_event_source_set_time_relative(
3540+
source, link->discovery.notify_retry_delay);
3541+
}
3542+
return 0;
3543+
}
3544+
34633545
static int bus_link_set_prop(sd_bus *bus, const char *path,
34643546
const char *interface, const char *property,
34653547
sd_bus_message *value, void *userdata,
@@ -4279,7 +4361,7 @@ static int add_interface(struct ctx *ctx, int ifindex)
42794361
if (!link)
42804362
return -ENOMEM;
42814363

4282-
link->discovered = DISCOVERY_UNSUPPORTED;
4364+
link->discovery.flag = DISCOVERY_UNSUPPORTED;
42834365
link->published = false;
42844366
link->ifindex = ifindex;
42854367
link->ctx = ctx;
@@ -4309,7 +4391,29 @@ static int add_interface(struct ctx *ctx, int ifindex)
43094391
}
43104392

43114393
if (phys_binding == MCTP_PHYS_BINDING_PCIE_VDM) {
4312-
link->discovered = DISCOVERY_UNDISCOVERED;
4394+
link->discovery.flag = DISCOVERY_UNDISCOVERED;
4395+
// TODO: These numbers are respectively MN1 and MT4, specified in DSP0239
4396+
// control message timing.
4397+
//
4398+
// Might need to extract these to macros like MCTP_I2C_TSYM_* in this file,
4399+
// or a commit to actually centralize those timing at one place, now that
4400+
// we have support for detecting link binding type.
4401+
link->discovery.notify_retries_left = 2;
4402+
link->discovery.notify_retry_delay = 5000000;
4403+
4404+
// For PCIe-VDM, we want an all zeroes address for Route-to-Root-Complex.
4405+
mctp_nl_hwaddr_len_byindex(
4406+
ctx->nl, ifindex,
4407+
&link->discovery.notify_dest.hwaddr_len);
4408+
memset(link->discovery.notify_dest.hwaddr, 0,
4409+
link->discovery.notify_dest.hwaddr_len);
4410+
link->discovery.notify_dest.ifindex = ifindex;
4411+
4412+
sd_event_add_time_relative(ctx->event,
4413+
&link->discovery.notify_source,
4414+
CLOCK_MONOTONIC, 0, 0,
4415+
link_discovery_notify_callback,
4416+
link);
43134417
}
43144418

43154419
link->published = true;

tests/test_mctpd_endpoint.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ async def iface():
2222

2323

2424
@pytest.fixture
25-
async def sysnet(iface):
25+
async def bo(iface):
26+
return Endpoint(iface, bytes([0x10]), eid=8)
27+
28+
29+
@pytest.fixture
30+
async def sysnet(iface, bo):
2631
system = System()
2732
await system.add_interface(iface)
2833
network = Network()
29-
network.add_endpoint(Endpoint(iface, bytes([0x10]), eid=8))
34+
network.add_endpoint(bo)
3035
return Sysnet(system, network)
3136

3237

@@ -113,12 +118,37 @@ class TestDiscovery:
113118
async def iface(self):
114119
return System.Interface("mctp0", 1, 1, bytes([0x1D]), 68, 254, True, PhysicalBinding.PCIE_VDM)
115120

121+
@pytest.fixture
122+
async def bo(self, iface):
123+
return TestDiscovery.BusOwnerEndpoint(iface, bytes([0x00]), eid=8)
124+
125+
126+
class BusOwnerEndpoint(Endpoint):
127+
def __init__(self, *args, **kwargs):
128+
super().__init__(*args, **kwargs)
129+
self.sem = trio.Semaphore(initial_value=0)
130+
131+
async def handle_mctp_control(self, sock, addr, data):
132+
print(addr, data)
133+
flags, opcode = data[0:2]
134+
if opcode != 0x0D:
135+
return await super().handle_mctp_control(sock, addr, data)
136+
dst_addr = MCTPSockAddr.for_ep_resp(self, addr, sock.addr_ext)
137+
await sock.send(dst_addr, bytes([flags & 0x1F, opcode, 0x00]))
138+
self.sem.release()
139+
140+
116141
""" Test simple Discovery sequence """
117142
async def test_simple_discovery_sequence(self, dbus, mctpd):
118143
bo = mctpd.network.endpoints[0]
119144

120145
assert len(mctpd.system.addresses) == 0
121146

147+
# BMC should send a Discovery Notify message
148+
with trio.move_on_after(5) as expected:
149+
await bo.sem.acquire()
150+
assert not expected.cancelled_caught
151+
122152
# no EID yet
123153
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x02))
124154
assert rsp.hex(' ') == '00 02 00 00 02 00'

0 commit comments

Comments
 (0)