Skip to content

Commit 4e4db2c

Browse files
mctpd: support discovery requests
This adds support for the Discovered flag and discovery requests, as described in DSP0236 12.14 Prepare for Endpoint Discovery and 12.15 Endpoint Discovery. Signed-off-by: Khang D Nguyen <[email protected]>
1 parent df4c901 commit 4e4db2c

File tree

4 files changed

+188
-1
lines changed

4 files changed

+188
-1
lines changed

src/mctp-netlink.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,16 @@ int mctp_nl_hwaddr_len_byindex(const mctp_nl *nl, int index,
10751075
return 0;
10761076
}
10771077

1078+
enum mctp_phys_binding mctp_nl_phys_binding_byindex(const mctp_nl *nl,
1079+
int index)
1080+
{
1081+
struct linkmap_entry *entry = entry_byindex(nl, index);
1082+
if (!entry) {
1083+
return MCTP_PHYS_BINDING_UNSPEC;
1084+
}
1085+
return entry->phys_binding;
1086+
}
1087+
10781088
mctp_eid_t *mctp_nl_addrs_byindex(const mctp_nl *nl, int index, size_t *ret_num)
10791089
{
10801090
struct linkmap_entry *entry = entry_byindex(nl, index);

src/mctp-netlink.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/if.h>
77
#include <linux/rtnetlink.h>
88

9+
#include "mctp-control-spec.h"
910
#include "mctp.h"
1011

1112
struct mctp_nl;
@@ -83,6 +84,9 @@ uint32_t mctp_nl_max_mtu_byindex(const mctp_nl *nl, int index);
8384
/* Returns negative errno on failure */
8485
int mctp_nl_hwaddr_len_byindex(const mctp_nl *nl, int index,
8586
size_t *ret_hwaddr_len);
87+
/* Returns interface physical binding, or MCTP_PHYS_BINDING_UNSPEC if bad index */
88+
enum mctp_phys_binding mctp_nl_phys_binding_byindex(const mctp_nl *nl,
89+
int index);
8690
/* Caller to free */
8791
mctp_eid_t *mctp_nl_addrs_byindex(const mctp_nl *nl, int index,
8892
size_t *ret_num);

src/mctpd.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,14 @@ static const struct role roles[] = {
117117
},
118118
};
119119

120+
enum discovery_state {
121+
DISCOVERY_UNSUPPORTED,
122+
DISCOVERY_DISCOVERED,
123+
DISCOVERY_UNDISCOVERED,
124+
};
125+
120126
struct link {
127+
enum discovery_state discovered;
121128
bool published;
122129
int ifindex;
123130
enum endpoint_role role;
@@ -777,6 +784,9 @@ static int handle_control_set_endpoint_id(struct ctx *ctx, int sd,
777784
warnx("ERR: cannot add bus owner to object lists");
778785
}
779786

787+
if (link_data->discovered != DISCOVERY_UNSUPPORTED) {
788+
link_data->discovered = DISCOVERY_DISCOVERED;
789+
}
780790
resp->status =
781791
SET_MCTP_EID_ASSIGNMENT_STATUS(MCTP_SET_EID_ACCEPTED) |
782792
SET_MCTP_EID_ALLOCATION_STATUS(MCTP_SET_EID_POOL_NONE);
@@ -786,6 +796,20 @@ static int handle_control_set_endpoint_id(struct ctx *ctx, int sd,
786796
return reply_message(ctx, sd, resp, resp_len, addr);
787797

788798
case MCTP_SET_EID_DISCOVERED:
799+
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
800+
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
801+
resp_len = sizeof(struct mctp_ctrl_resp);
802+
return reply_message(ctx, sd, resp, resp_len, addr);
803+
}
804+
805+
link_data->discovered = DISCOVERY_DISCOVERED;
806+
resp->status =
807+
SET_MCTP_EID_ASSIGNMENT_STATUS(MCTP_SET_EID_REJECTED) |
808+
SET_MCTP_EID_ALLOCATION_STATUS(MCTP_SET_EID_POOL_NONE);
809+
resp->eid_set = req->eid;
810+
resp->eid_pool_size = 0;
811+
return reply_message(ctx, sd, resp, resp_len, addr);
812+
789813
case MCTP_SET_EID_RESET:
790814
// unsupported
791815
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
@@ -948,6 +972,97 @@ handle_control_resolve_endpoint_id(struct ctx *ctx, int sd,
948972
return reply_message(ctx, sd, resp, resp_len, addr);
949973
}
950974

975+
static int handle_control_prepare_endpoint_discovery(
976+
struct ctx *ctx, int sd, const struct sockaddr_mctp_ext *addr,
977+
const uint8_t *buf, const size_t buf_size)
978+
{
979+
struct mctp_ctrl_msg_hdr *req = NULL;
980+
struct mctp_ctrl_resp_prepare_discovery respi = { 0 }, *resp = &respi;
981+
struct link *link_data;
982+
983+
if (buf_size < sizeof(*req)) {
984+
warnx("short Prepare for Endpoint Discovery message");
985+
return -ENOMSG;
986+
}
987+
988+
link_data = mctp_nl_get_link_userdata(ctx->nl, addr->smctp_ifindex);
989+
if (!link_data) {
990+
bug_warn("unconfigured interface %d", addr->smctp_ifindex);
991+
return -ENOENT;
992+
}
993+
994+
if (link_data->role == ENDPOINT_ROLE_BUS_OWNER) {
995+
// ignore message if we are bus owner
996+
return 0;
997+
}
998+
999+
req = (void *)buf;
1000+
resp = (void *)resp;
1001+
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, *req);
1002+
1003+
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
1004+
warnx("received prepare for discovery request to unsupported interface %d",
1005+
addr->smctp_ifindex);
1006+
resp->completion_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
1007+
return reply_message_phys(ctx, sd, resp,
1008+
sizeof(struct mctp_ctrl_resp), addr);
1009+
}
1010+
1011+
if (link_data->discovered == DISCOVERY_DISCOVERED) {
1012+
link_data->discovered = DISCOVERY_UNDISCOVERED;
1013+
warnx("clear discovered flag of interface %d",
1014+
addr->smctp_ifindex);
1015+
}
1016+
1017+
// we need to send using physical addressing, no entry in routing table yet
1018+
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
1019+
return reply_message_phys(ctx, sd, resp, sizeof(*resp), addr);
1020+
}
1021+
1022+
static int
1023+
handle_control_endpoint_discovery(struct ctx *ctx, int sd,
1024+
const struct sockaddr_mctp_ext *addr,
1025+
const uint8_t *buf, const size_t buf_size)
1026+
{
1027+
struct mctp_ctrl_msg_hdr *req = NULL;
1028+
struct mctp_ctrl_resp_endpoint_discovery respi = { 0 }, *resp = &respi;
1029+
struct link *link_data;
1030+
1031+
if (buf_size < sizeof(*req)) {
1032+
warnx("short Endpoint Discovery message");
1033+
return -ENOMSG;
1034+
}
1035+
1036+
link_data = mctp_nl_get_link_userdata(ctx->nl, addr->smctp_ifindex);
1037+
if (!link_data) {
1038+
bug_warn("unconfigured interface %d", addr->smctp_ifindex);
1039+
return -ENOENT;
1040+
}
1041+
1042+
if (link_data->role == ENDPOINT_ROLE_BUS_OWNER) {
1043+
// ignore message if we are bus owner
1044+
return 0;
1045+
}
1046+
1047+
if (link_data->discovered == DISCOVERY_UNSUPPORTED) {
1048+
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
1049+
return reply_message(ctx, sd, resp,
1050+
sizeof(struct mctp_ctrl_resp), addr);
1051+
}
1052+
1053+
if (link_data->discovered == DISCOVERY_DISCOVERED) {
1054+
// if we are already discovered (i.e, assigned an EID), then no reply
1055+
return 0;
1056+
}
1057+
1058+
req = (void *)buf;
1059+
resp = (void *)resp;
1060+
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, *req);
1061+
1062+
// we need to send using physical addressing, no entry in routing table yet
1063+
return reply_message_phys(ctx, sd, resp, sizeof(*resp), addr);
1064+
}
1065+
9511066
static int handle_control_unsupported(struct ctx *ctx, int sd,
9521067
const struct sockaddr_mctp_ext *addr,
9531068
const uint8_t *buf, const size_t buf_size)
@@ -1030,6 +1145,14 @@ static int cb_listen_control_msg(sd_event_source *s, int sd, uint32_t revents,
10301145
rc = handle_control_resolve_endpoint_id(ctx, sd, &addr, buf,
10311146
buf_size);
10321147
break;
1148+
case MCTP_CTRL_CMD_PREPARE_ENDPOINT_DISCOVERY:
1149+
rc = handle_control_prepare_endpoint_discovery(ctx, sd, &addr,
1150+
buf, buf_size);
1151+
break;
1152+
case MCTP_CTRL_CMD_ENDPOINT_DISCOVERY:
1153+
rc = handle_control_endpoint_discovery(ctx, sd, &addr, buf,
1154+
buf_size);
1155+
break;
10331156
default:
10341157
if (ctx->verbose) {
10351158
warnx("Ignoring unsupported command code 0x%02x",
@@ -3905,10 +4028,14 @@ static int add_interface(struct ctx *ctx, int ifindex)
39054028
return -ENOENT;
39064029
}
39074030

4031+
enum mctp_phys_binding phys_binding =
4032+
mctp_nl_phys_binding_byindex(ctx->nl, ifindex);
4033+
39084034
struct link *link = calloc(1, sizeof(*link));
39094035
if (!link)
39104036
return -ENOMEM;
39114037

4038+
link->discovered = DISCOVERY_UNSUPPORTED;
39124039
link->published = false;
39134040
link->ifindex = ifindex;
39144041
link->ctx = ctx;
@@ -3937,6 +4064,11 @@ static int add_interface(struct ctx *ctx, int ifindex)
39374064
bus_link_owner_vtable, link);
39384065
}
39394066

4067+
if (phys_binding == MCTP_PHYS_BINDING_PCIE_VDM ||
4068+
phys_binding == MCTP_PHYS_BINDING_I3C) {
4069+
link->discovered = DISCOVERY_UNDISCOVERED;
4070+
}
4071+
39404072
link->published = true;
39414073
rc = emit_interface_added(link);
39424074
if (rc < 0) {

tests/test_mctpd_endpoint.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def config():
1818
@pytest.fixture
1919
async def sysnet():
2020
system = System()
21-
iface = System.Interface("mctp0", 1, 1, bytes([0x1D]), 68, 254, True)
21+
iface = System.Interface("mctp0", 1, 1, bytes([0x1D]), 68, 254, True, PhysicalBinding.PCIE_VDM)
2222
await system.add_interface(iface)
2323
network = Network()
2424
network.add_endpoint(Endpoint(iface, bytes([0x10]), eid=8))
@@ -101,3 +101,44 @@ async def test_accept_multiple_set_eids_for_single_interface(dbus, mctpd):
101101

102102
# expect new EID on D-Bus
103103
assert await mctpd_mctp_endpoint_control_obj(dbus, f"/au/com/codeconstruct/mctp1/networks/1/endpoints/{second_eid}")
104+
105+
106+
""" Test simple Discovery sequence """
107+
async def test_simple_discovery_sequence(dbus, mctpd):
108+
bo = mctpd.network.endpoints[0]
109+
110+
assert len(mctpd.system.addresses) == 0
111+
112+
# no EID yet
113+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x02))
114+
assert rsp.hex(' ') == '00 02 00 00 02 00'
115+
116+
# BMC response to Prepare for Discovery
117+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x0B))
118+
assert rsp.hex(' ') == '00 0b 00'
119+
120+
# BMC response to Endpoint Discovery
121+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x0C))
122+
assert rsp.hex(' ') == '00 0c 00'
123+
124+
# set EID = 42
125+
eid = 42
126+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x01, bytes([0x00, eid])))
127+
assert rsp.hex(' ') == f'00 01 00 00 {eid:02x} 00'
128+
129+
# BMC should contains two object paths: bus owner and itself
130+
assert await mctpd_mctp_endpoint_control_obj(dbus, f"/au/com/codeconstruct/mctp1/networks/1/endpoints/{bo.eid}")
131+
assert await mctpd_mctp_endpoint_control_obj(dbus, f"/au/com/codeconstruct/mctp1/networks/1/endpoints/{eid}")
132+
133+
134+
""" Discovery command on unsupported interface """
135+
async def test_discovery_on_unsupported_interface(dbus, mctpd):
136+
iface = System.Interface("mctp1", 2, 1, bytes([0x1D]), 68, 254, True, PhysicalBinding.SMBUS)
137+
await mctpd.system.add_interface(iface)
138+
139+
bo = Endpoint(iface, bytes([0x10]), eid=10)
140+
mctpd.network.add_endpoint(bo)
141+
142+
# BMC response ERROR_UNSUPPORTED_CMD to Prepare for Discovery
143+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x0B))
144+
assert rsp.hex(' ') == '00 0b 05'

0 commit comments

Comments
 (0)