Skip to content

Commit 686395a

Browse files
Add Allocate Endpoint ID support for MCTP Bridge
* New mctpd method to send Allocate Endpoint ID mctp control message * Timer for MCTP Bridge to settle ( observed it takes sometime for Bridges like FPGA to allocate downstream eids to endpoints during which any request on the downstream endpoint fails) * update AssignEndpoint and AssignEndpointStatic method to consider Endpoint nature (MCTP bridge based on pool size received) * Check for presence of contiguous available EIDs of pool size. * Pytest framework change > Introduced new Endpoint of MCTP Bridge type (pool size =2) > New test method to validate endpoint_allocate_eid() > update existing pytest method to accomodate for new endpoint in present network ''' System contains MCTP Bridge (FPGA) over USB which has downstream endpoints such as EROTS, IROTS. MCTP Bridge is one bus usb1-1 populating as mctpusb0 interface. USBMON : ================== cat /sys/kernel/debug/usb/usbmon/1u 866e6900 886711482 S Bo:1:002:1 -115 13 = 1ab4000d 010008c8 00800100 0c -> SET EID 0xc 866e6900 886711719 C Bo:1:002:1 0 13 > 82a05f00 886711737 C Bi:1:002:2 0 15 = 1ab4000f 01080cc0 00000100 120c0f -> Bridge size 0xf 82a05f00 886711753 S Bi:1:002:2 -115 512 < 866e6200 886712339 S Bo:1:002:1 -115 11 = 1ab4000b 010c08c8 008105 -> GET MSSG TYPE (eid : 0xc) 866e6200 886712449 C Bo:1:002:1 0 11 > 82a05f00 886712461 C Bi:1:002:2 0 14 = 1ab4000e 01080cc0 00010500 017e 82a05f00 886712474 S Bi:1:002:2 -115 512 < 866e6900 886712862 S Bo:1:002:1 -115 11 = 1ab4000b 010c08c8 008203 -> GET UUID (eid : 0xc) 866e6900 886712961 C Bo:1:002:1 0 11 > 82a05f00 886712975 C Bi:1:002:2 0 28 = 1ab4001c 01080cc0 00020300 xxxx xxxx xxxx xxxx 82a05f00 886712993 S Bi:1:002:2 -115 512 < 866e6200 886714375 S Bo:1:002:1 -115 14 = 1ab4000e 010c08c8 00830800 0f0d -> ALLOCATE EID 0xc, bridge size 0xf, start eid 0xd 866e6200 886714455 C Bo:1:002:1 0 14 > 82a05f00 886714475 C Bi:1:002:2 0 15 = 1ab4000f 01080cc0 00030800 010f0d 82a05f00 886714490 S Bi:1:002:2 -115 512 < 85e6ab80 890712851 S Bo:1:002:1 -115 11 = 1ab4000b 010d08c8 008405 -> GET MSSG TYPE (eid : 0xd) 85e6ab80 890713119 C Bo:1:002:1 0 11 > 82a05f00 890713452 C Bi:1:002:2 0 17 = 1ab40011 01080dc0 00040500 0401057e 7f 82a05f00 890713487 S Bi:1:002:2 -115 512 < 85e6a780 890713984 S Bo:1:002:1 -115 11 = 1ab4000b 010d08c8 008503 -> GET UUID (eid : 0xd) 85e6a780 890714073 C Bo:1:002:1 0 11 > 82a05f00 890714451 C Bi:1:002:2 0 28 = 1ab4001c 01080dc0 00050300 xxxx xxxx xxxx xxxx 82a05f00 890714496 S Bi:1:002:2 -115 512 < 85e6a180 890718152 S Bo:1:002:1 -115 11 = 1ab4000b 010e08c8 008605 -> GET MSSG TYPE (eid : 0xe) (Timedout) 85e6a180 890718331 C Bo:1:002:1 0 11 > 86654980 891215635 S Bo:1:002:1 -115 11 = 1ab4000b 010e08c8 008703 -> GET UUID (eid : 0xe) (Timedout) 86654980 891215839 C Bo:1:002:1 0 11 > 86654e00 891712957 S Bo:1:002:1 -115 11 = 1ab4000b 010f08c8 008805 -> GET MSSG TYPE (eid : 0xf) 86654e00 891713082 C Bo:1:002:1 0 11 > 82a05f00 891713576 C Bi:1:002:2 0 17 = 1ab40011 01080fc0 00080500 0401057e 7f 82a05f00 891713615 S Bi:1:002:2 -115 512 < 85e6a400 891715076 S Bo:1:002:1 -115 11 = 1ab4000b 010f08c8 008903 85e6a400 891715199 C Bo:1:002:1 0 11 > MCTPD Traces ======================= busctl call au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1/interfaces/mctpusb0 au.com.codeconstruct.MCTP.BusOwner1 AssignEndpoint ay 0 yisb 12 1 "/au/com/codeconstruct/mctp1/networks/1/endpoints/12" true mctpd: read_message got from sockaddr_mctp_ext eid 12 net 1 type 0x00 if 3 hw len 0 0x len 6 mctpd: physaddr if 3 hw len 0 0x requested allocation of pool size = 15 mctpd: emit_endpoint_added: /au/com/codeconstruct/mctp1/networks/1/endpoints/12 endpoint_allocate_eid Asking for contiguous EIDs for pool with start eid : 13 mctpd: endpoint_send_allocate_endpoint_id Allocation was rejected as it was Allocated by other bus endpoint_send_allocate_endpoint_id Allocated size of 15, starting from EID 13 Bridge Time expired, set pool eids mctpd: emit_endpoint_added: /au/com/codeconstruct/mctp1/networks/1/endpoints/13 mctpd: Error getting endpoint types for peer eid 14 net 1 phys physaddr if 3 hw len 0 0x state 1. Ignoring error -110 Connection timed out mctpd: Error getting UUID for peer eid 14 net 1 phys physaddr if 3 hw len 0 0x state 1. Ignoring error -110 Connection timed out mctpd: emit_endpoint_added: /au/com/codeconstruct/mctp1/networks/1/endpoints/14 mctpd: emit_endpoint_added: /au/com/codeconstruct/mctp1/networks/1/endpoints/15 =============================================================================== mctp addr show eid 8 net 1 dev mctpusb0 busctl tree au.com.codeconstruct.MCTP1 `- /au `- /au/com `- /au/com/codeconstruct `- /au/com/codeconstruct/mctp1 |- /au/com/codeconstruct/mctp1/interfaces | |- /au/com/codeconstruct/mctp1/interfaces/lo \ | `- /au/com/codeconstruct/mctp1/interfaces/mctpusb0 `- /au/com/codeconstruct/mctp1/networks `- /au/com/codeconstruct/mctp1/networks/1 `- /au/com/codeconstruct/mctp1/networks/1/endpoints |- /au/com/codeconstruct/mctp1/networks/1/endpoints/12 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/13 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/14 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/15 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/16 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/17 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/18 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/19 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/20 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/21 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/22 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/23 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/24 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/25 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/26 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/27 |- /au/com/codeconstruct/mctp1/networks/1/endpoints/8 ========================================================================== PYTEST ninja -C obj test ninja: Entering directory `obj' [0/1] Running all tests. 1/1 test-mctpd OK 21.17s 20 subtests passed Ok: 1 Expected Fail: 0 Fail: 0 Unexpected Pass: 0 Skipped: 0 Timeout: 0 ''' Signed-off-by: Faizan Ali <[email protected]>
1 parent 3f9ec21 commit 686395a

File tree

3 files changed

+234
-6
lines changed

3 files changed

+234
-6
lines changed

src/mctpd.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#define CC_MCTP_DBUS_IFACE_INTERFACE "au.com.codeconstruct.MCTP.Interface1"
5454
#define CC_MCTP_DBUS_NETWORK_INTERFACE "au.com.codeconstruct.MCTP.Network1"
5555

56+
#define BRIDGE_SETTLE_DELAY_SEC 4
5657
// an arbitrary constant for use with sd_id128_get_machine_app_specific()
5758
static const char* mctpd_appid = "67369c05-4b97-4b7e-be72-65cfd8639f10";
5859

@@ -243,6 +244,7 @@ static int add_local_eid(ctx *ctx, int net, int eid);
243244
static int del_local_eid(ctx *ctx, int net, int eid);
244245
static int add_net(ctx *ctx, int net);
245246
static int add_interface(ctx *ctx, int ifindex);
247+
static int endpoint_allocate_eid(peer *peer);
246248

247249
mctp_eid_t local_addr(const ctx *ctx, int ifindex) {
248250
mctp_eid_t *eids, ret = 0;
@@ -2107,6 +2109,16 @@ static int method_assign_endpoint(sd_bus_message *call, void *data, sd_bus_error
21072109
goto err;
21082110
dfree(peer_path);
21092111

2112+
/* MCTP Bridge Support */
2113+
/* Allocate Endopint EID while looking for pool start eid
2114+
* Update pool endpoints to dbus */
2115+
2116+
if(peer->pool_size > 0) {
2117+
/* new start eid will be assigned before MCTP Allocate eid control command */
2118+
peer->pool_start = peer->eid + 1;
2119+
rc = endpoint_allocate_eid(peer);
2120+
}
2121+
21102122
return sd_bus_reply_method_return(call, "yisb",
21112123
peer->eid, peer->net, peer_path, 1);
21122124
err:
@@ -2185,8 +2197,11 @@ static int method_assign_endpoint_static(sd_bus_message *call, void *data,
21852197
dfree(peer_path);
21862198

21872199
/* MCTP Bridge Support */
2200+
/* Allocate Endopint EID
2201+
* Update pool endpoints to dbus */
21882202
if(peer->pool_size > 0) {
21892203
peer->pool_start = start_eid;
2204+
rc = endpoint_allocate_eid(peer);
21902205
}
21912206

21922207
return sd_bus_reply_method_return(call, "yisb",
@@ -4494,6 +4509,160 @@ static void setup_config_defaults(ctx *ctx)
44944509
ctx->default_role = ENDPOINT_ROLE_BUS_OWNER;
44954510
}
44964511

4512+
static int endpoint_send_allocate_endpoint_id(peer *peer,
4513+
mctp_eid_t eid_start, uint8_t eid_pool_size, mctp_ctrl_cmd_alloc_eid_op oper,
4514+
uint8_t *allocated_pool_size, mctp_eid_t *allocated_pool_start)
4515+
{
4516+
struct sockaddr_mctp_ext addr;
4517+
struct mctp_ctrl_cmd_alloc_eid req = {0};
4518+
struct mctp_ctrl_resp_alloc_eid *resp = NULL;
4519+
uint8_t *buf = NULL;
4520+
size_t buf_size;
4521+
uint8_t iid, stat;
4522+
int rc;
4523+
4524+
iid = mctp_next_iid(peer->ctx);
4525+
req.ctrl_hdr.rq_dgram_inst = RQDI_REQ | iid;
4526+
req.ctrl_hdr.command_code = MCTP_CTRL_CMD_ALLOCATE_ENDPOINT_IDS;
4527+
req.alloc_eid_op = alloc_eid;
4528+
req.pool_size = eid_pool_size;
4529+
req.start_eid = eid_start;
4530+
rc = endpoint_query_peer(peer, MCTP_CTRL_HDR_MSG_TYPE, &req, sizeof(req),
4531+
&buf, &buf_size, &addr);
4532+
if (rc < 0)
4533+
goto out;
4534+
4535+
rc = mctp_ctrl_validate_response(buf, buf_size, sizeof(*resp),
4536+
peer_tostr_short(peer), iid,
4537+
MCTP_CTRL_CMD_ALLOCATE_ENDPOINT_IDS);
4538+
4539+
if (rc)
4540+
goto out;
4541+
4542+
resp = (void *)buf;
4543+
if (!resp) {
4544+
warnx("%s Invalid response Buffer\n", __func__);
4545+
return -ENOMEM;
4546+
}
4547+
4548+
stat = resp->status & 0x03;
4549+
if (stat == 0x00) {
4550+
if(peer->ctx->verbose) {
4551+
fprintf(stderr, "%s Allocation Accepted \n", __func__);
4552+
}
4553+
}
4554+
else if (stat == 0x1) {
4555+
warnx("%s Allocation was rejected as it was Allocated by other bus \n", __func__);
4556+
}
4557+
4558+
*allocated_pool_size = resp->eid_pool_size;
4559+
*allocated_pool_start = resp->eid_set;
4560+
if(peer->ctx->verbose) {
4561+
fprintf(stderr, "%s Allocated size of %d, starting from EID %d\n", __func__,
4562+
resp->eid_pool_size, resp->eid_set);
4563+
}
4564+
4565+
return 0;
4566+
out:
4567+
free(buf);
4568+
return rc;
4569+
}
4570+
static int cb_populate_pool_eids(sd_event_source *s, uint64_t t, void* data)
4571+
{
4572+
peer *peer = data;
4573+
int net = peer->net;
4574+
struct peer *allocated_peer = NULL;
4575+
dest_phys dest = peer->phys;
4576+
int rc;
4577+
4578+
fprintf (stderr, "Bridge Time expired, set pool eids\n");
4579+
for (mctp_eid_t eid = peer->pool_start;
4580+
eid < peer->pool_start + peer->pool_size; eid++) {
4581+
rc = add_peer(peer->ctx, &dest, eid, net, &allocated_peer);
4582+
if (rc < 0) {
4583+
warnx("%s failed to find peer for allocated eid %d\n",
4584+
__func__, eid);
4585+
continue;
4586+
}
4587+
4588+
rc = setup_added_peer(allocated_peer);
4589+
if (rc < 0) {
4590+
warnx("%s failed to setup peer for allocated eid %d\n",
4591+
__func__, eid);
4592+
continue;
4593+
}
4594+
}
4595+
4596+
return 0;
4597+
}
4598+
4599+
static mctp_eid_t get_pool_start (peer *peer, mctp_eid_t eid_start, uint8_t pool_size)
4600+
{
4601+
uint8_t count = 0;
4602+
mctp_eid_t pool_start = eid_alloc_max;
4603+
net_det *n = lookup_net(peer->ctx, peer->net);
4604+
4605+
if (!n) {
4606+
warnx("BUG: Unknown net %d : failed to get pool start\n", peer->net);
4607+
return eid_alloc_max;
4608+
}
4609+
4610+
for (mctp_eid_t e = eid_start; e <= eid_alloc_max; e++) {
4611+
if (n->peeridx[e] == -1) {
4612+
if(pool_start == eid_alloc_max) {
4613+
pool_start = e;
4614+
}
4615+
count++;
4616+
if (count == pool_size) return pool_start;
4617+
} else {
4618+
pool_start = eid_alloc_max;
4619+
count = 0;
4620+
}
4621+
}
4622+
4623+
return eid_alloc_max;
4624+
}
4625+
4626+
static int endpoint_allocate_eid(peer* peer)
4627+
{
4628+
uint8_t allocated_pool_size = 0;
4629+
mctp_eid_t allocated_pool_start = 0;
4630+
4631+
/* Find pool sized contiguous unused eids to allocate on the bridge. */
4632+
peer->pool_start = get_pool_start(peer, peer->pool_start, peer->pool_size);
4633+
if(peer->pool_start == eid_alloc_max) {
4634+
warnx("%s failed to find contiguous EIDs of required size", __func__);
4635+
return 0;
4636+
} else {
4637+
if(peer->ctx->verbose)
4638+
fprintf(stderr, "%s Asking for contiguous EIDs for pool with start eid : %d\n", __func__, peer->pool_start);
4639+
}
4640+
4641+
int rc = endpoint_send_allocate_endpoint_id(peer, peer->pool_start, peer->pool_size,
4642+
alloc_eid, &allocated_pool_size, &allocated_pool_start);
4643+
if (rc) {
4644+
warnx("%s failed to allocate endpoints, returned %s %d\n",
4645+
__func__, strerror(-rc), rc);
4646+
} else {
4647+
peer->pool_size = allocated_pool_size;
4648+
peer->pool_start = allocated_pool_start;
4649+
4650+
//delay for settling MCTP Bridge after allocation of downstream eid
4651+
uint64_t now_usec, timer_usec;
4652+
// Get the current time in microseconds
4653+
if (sd_event_now(peer->ctx->event, CLOCK_MONOTONIC, &now_usec) < 0) {
4654+
warnx("Failed to get current time");
4655+
return -1;
4656+
}
4657+
timer_usec = now_usec + BRIDGE_SETTLE_DELAY_SEC * 1000000ULL;
4658+
rc = sd_event_add_time(peer->ctx->event, NULL,
4659+
CLOCK_MONOTONIC, timer_usec, 0,
4660+
cb_populate_pool_eids, peer);
4661+
}
4662+
4663+
return 0;
4664+
}
4665+
44974666
int main(int argc, char **argv)
44984667
{
44994668
int rc;

tests/conftest.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@ async def handle_mctp_control(self, sock, addr, data):
314314
data = bytes(hdr + [0x00, len(types)] + types)
315315
await sock.send(raddr, data)
316316

317+
elif opcode == 8:
318+
# Allocate Enpoint IDs
319+
(_, pool_st) = data[3:]
320+
data = bytes(hdr + [0x00, 0x00, self.pool_size, pool_st])
321+
await sock.send(raddr, data)
322+
317323
else:
318324
await sock.send(raddr, bytes(hdr + [0x05])) # unsupported command
319325

@@ -348,9 +354,9 @@ def __init__(self):
348354
def add_endpoint(self, endpoint):
349355
self.endpoints.append(endpoint)
350356

351-
def lookup_endpoint(self, iface, lladdr):
357+
def lookup_endpoint(self, iface, lladdr, eid):
352358
for ep in self.endpoints:
353-
if ep.iface == iface and ep.lladdr == lladdr:
359+
if ep.iface == iface and ep.lladdr == lladdr and (eid == ep.eid or not eid):
354360
return ep
355361
return None
356362

@@ -570,7 +576,7 @@ async def handle_send(self, addr, data):
570576
if phys is None:
571577
return
572578

573-
ep = self.network.lookup_endpoint(*phys)
579+
ep = self.network.lookup_endpoint(*phys, a.eid)
574580
if ep is None:
575581
return
576582

@@ -1031,8 +1037,8 @@ def name_owner_changed(name, new_owner, old_owner):
10311037

10321038
"""Simple system & network.
10331039
1034-
Contains one interface (lladdr 0x10, local EID 8), and one endpoint (lladdr
1035-
0x1d), that reports support for MCTP control and PLDM.
1040+
Contains two interface (lladdr 0x10, local EID 8), (lladdr 0x11, local EID 10) with one endpoint (lladdr
1041+
0x1d), and MCTP bridge (lladdr 0x1e, pool size 2), that reports support for MCTP control and PLDM.
10361042
"""
10371043
@pytest.fixture
10381044
async def sysnet():
@@ -1044,6 +1050,12 @@ async def sysnet():
10441050
network = Network()
10451051
network.add_endpoint(Endpoint(iface, bytes([0x1d]), types = [0, 1]))
10461052

1053+
# new interface for MCTP Bridge device
1054+
bridge_iface = System.Interface('mctp1', 2, 2, bytes([0x11]), 68, 254, True)
1055+
await system.add_interface(bridge_iface)
1056+
await system.add_address(System.Address(bridge_iface, 10))
1057+
network.add_endpoint(Endpoint(bridge_iface, bytes([0x1e]), types=[0, 1], pool_size= 0x2))
1058+
10471059
return Sysnet(system, network)
10481060

10491061
@pytest.fixture

tests/test_mctpd.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ def ep_removed(ep_path, interfaces):
531531
# Delete the endpoint from the network so its recovery will fail after
532532
# timeout. Note we delete at the split index as the network was already
533533
# populated with the default endpoint
534-
del mctpd.network.endpoints[split]
534+
del mctpd.network.endpoints[split + 1]
535535

536536
# Begin recovery for the endpoint ...
537537
ep_ep = await ep.get_interface(MCTPD_ENDPOINT_I)
@@ -555,3 +555,50 @@ def ep_removed(ep_path, interfaces):
555555
with trio.move_on_after(2 * MCTPD_TRECLAIM) as expected:
556556
await removed.acquire()
557557
assert not expected.cancelled_caught
558+
559+
""" Test that we allocate Eids to MCTP Bridge Endpoints"""
560+
async def test_endpoint_allocate_eid(dbus, mctpd):
561+
bridge = mctpd.network.endpoints[1]
562+
ep_types = [0, 1, 5]
563+
bridge.types = ep_types
564+
static_eid = 35
565+
start_eid = 36
566+
567+
# mimicing MCTP Bridge by adding Bridg's Endpoints to same network and physcial address
568+
for eid in range(start_eid, start_eid + bridge.pool_size + 1):
569+
mctpd.network.add_endpoint(Endpoint(bridge.iface, bridge.lladdr, types = [0,1,2,3], eid= eid))
570+
571+
# first assign enpoint to MCTP Bridge and later involk allocate endpoint ids
572+
# this will add Brige's enpoints routes and neigh and update dbus
573+
mctp = await mctpd_mctp_iface_obj(dbus, bridge.iface)
574+
(eid, _, path, _) = await mctp.call_assign_endpoint_static(
575+
bridge.lladdr,
576+
static_eid,
577+
start_eid
578+
)
579+
580+
# non blocking sleep for Allocate Eid timer expiry
581+
await trio.sleep(5)
582+
assert eid == static_eid
583+
# check if networks neighbours are reflecting the mctpd added bridge's neighbours
584+
assert len(mctpd.system.neighbours) == (1 + bridge.pool_size)
585+
586+
neigh = mctpd.system.neighbours[0]
587+
assert neigh.lladdr == bridge.lladdr
588+
assert neigh.eid == static_eid
589+
590+
neigh = mctpd.system.neighbours[1]
591+
assert neigh.lladdr == bridge.lladdr
592+
assert neigh.eid == start_eid
593+
594+
neigh = mctpd.system.neighbours[2]
595+
assert neigh.lladdr == bridge.lladdr
596+
assert neigh.eid == start_eid + 1
597+
598+
# check one of Bridge's endpoint types per dbus property
599+
path = path.rsplit('/endpoints', 1)[0]
600+
path = path + f"/endpoints/{mctpd.network.endpoints[2].eid}"
601+
ep = await mctpd_mctp_endpoint_common_obj(dbus, path)
602+
query_types = list(await ep.get_supported_message_types())
603+
print(mctpd.network.endpoints[2].types)
604+
assert (query_types == mctpd.network.endpoints[2].types)

0 commit comments

Comments
 (0)