Skip to content

Commit 679e177

Browse files
Add interface au.com.codeconstruct.MCTP.Bridge1
New endpoint object interface au.com.codeconstruct.MCTP.Bridge1 which will capture details of bridge type endpoint such as pool start, pool end. Update test framework with new test methods to validate bridge pool assignemnt. Signed-off-by: Faizan Ali <[email protected]>
1 parent 28fecd9 commit 679e177

File tree

3 files changed

+189
-0
lines changed

3 files changed

+189
-0
lines changed

docs/mctpd.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,17 @@ busctl call au.com.codeconstruct.MCTP1 \
219219

220220
Removes the MCTP endpoint from `mctpd`, and deletes routes and neighbour entries.
221221

222+
For any endpoint which also happens to be an MCTP Bridge, if dynamic eid is assgined to it via d-bus method `.AssignEndpoint`,
223+
such endpoint's pool allocation details would be reflected into `au.com.codeconstruct.MCTP.Bridge1` interface of bridge's endpoint object.
224+
225+
### `.PoolEnd`: `y`
226+
227+
A constant property representing last EID in the contiguous range allocated for downstream endpoints.
228+
229+
### `.PoolStart`: `y`
230+
231+
A constant property representing first EID in the contiguous range allocated for downstream endpoints.
232+
222233
## Configuration
223234

224235
`mctpd` reads configuration data from a TOML file, typically `/etc/mctpd.conf`.

src/mctpd.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#define MCTP_DBUS_PATH_LINKS "/au/com/codeconstruct/mctp1/interfaces"
4646
#define CC_MCTP_DBUS_IFACE_BUSOWNER "au.com.codeconstruct.MCTP.BusOwner1"
4747
#define CC_MCTP_DBUS_IFACE_ENDPOINT "au.com.codeconstruct.MCTP.Endpoint1"
48+
#define CC_MCTP_DBUS_IFACE_BRIDGE "au.com.codeconstruct.MCTP.Bridge1"
4849
#define CC_MCTP_DBUS_IFACE_TESTING "au.com.codeconstruct.MCTPTesting"
4950
#define MCTP_DBUS_NAME "au.com.codeconstruct.MCTP1"
5051
#define MCTP_DBUS_IFACE_ENDPOINT "xyz.openbmc_project.MCTP.Endpoint"
@@ -151,6 +152,7 @@ struct peer {
151152
bool published;
152153
sd_bus_slot *slot_obmc_endpoint;
153154
sd_bus_slot *slot_cc_endpoint;
155+
sd_bus_slot *slot_bridge;
154156
sd_bus_slot *slot_uuid;
155157
char *path;
156158

@@ -256,6 +258,7 @@ static int endpoint_allocate_eid(struct peer *peer);
256258

257259
static const sd_bus_vtable bus_endpoint_obmc_vtable[];
258260
static const sd_bus_vtable bus_endpoint_cc_vtable[];
261+
static const sd_bus_vtable bus_endpoint_bridge[];
259262
static const sd_bus_vtable bus_endpoint_uuid_vtable[];
260263

261264
__attribute__((format(printf, 1, 2))) static void bug_warn(const char *fmt, ...)
@@ -1586,6 +1589,7 @@ static void free_peers(struct ctx *ctx)
15861589
free(peer->path);
15871590
sd_bus_slot_unref(peer->slot_obmc_endpoint);
15881591
sd_bus_slot_unref(peer->slot_cc_endpoint);
1592+
sd_bus_slot_unref(peer->slot_bridge);
15891593
sd_bus_slot_unref(peer->slot_uuid);
15901594
free(peer);
15911595
}
@@ -2674,6 +2678,8 @@ static int unpublish_peer(struct peer *peer)
26742678
peer->slot_obmc_endpoint = NULL;
26752679
sd_bus_slot_unref(peer->slot_cc_endpoint);
26762680
peer->slot_cc_endpoint = NULL;
2681+
sd_bus_slot_unref(peer->slot_bridge);
2682+
peer->slot_bridge = NULL;
26772683
sd_bus_slot_unref(peer->slot_uuid);
26782684
peer->slot_uuid = NULL;
26792685
peer->published = false;
@@ -3058,6 +3064,28 @@ static int bus_endpoint_get_prop(sd_bus *bus, const char *path,
30583064
return rc;
30593065
}
30603066

3067+
static int bus_bridge_get_prop(sd_bus *bus, const char *path,
3068+
const char *interface, const char *property,
3069+
sd_bus_message *reply, void *userdata,
3070+
sd_bus_error *berr)
3071+
{
3072+
struct peer *peer = userdata;
3073+
int rc;
3074+
3075+
if (strcmp(property, "PoolStart") == 0) {
3076+
rc = sd_bus_message_append(reply, "y", peer->pool_start);
3077+
} else if (strcmp(property, "PoolEnd") == 0) {
3078+
uint8_t pool_end = peer->pool_start + peer->pool_size - 1;
3079+
rc = sd_bus_message_append(reply, "y", pool_end);
3080+
} else {
3081+
warnx("Unknown bridge property '%s' for %s iface %s", property,
3082+
path, interface);
3083+
rc = -ENOENT;
3084+
}
3085+
3086+
return rc;
3087+
}
3088+
30613089
static int bus_network_get_prop(sd_bus *bus, const char *path,
30623090
const char *interface, const char *property,
30633091
sd_bus_message *reply, void *userdata,
@@ -3257,6 +3285,21 @@ static const sd_bus_vtable bus_endpoint_cc_vtable[] = {
32573285
SD_BUS_VTABLE_END
32583286
};
32593287

3288+
static const sd_bus_vtable bus_endpoint_bridge[] = {
3289+
SD_BUS_VTABLE_START(0),
3290+
SD_BUS_PROPERTY("PoolStart",
3291+
"y",
3292+
bus_bridge_get_prop,
3293+
0,
3294+
SD_BUS_VTABLE_PROPERTY_CONST),
3295+
SD_BUS_PROPERTY("PoolEnd",
3296+
"y",
3297+
bus_bridge_get_prop,
3298+
0,
3299+
SD_BUS_VTABLE_PROPERTY_CONST),
3300+
SD_BUS_VTABLE_END
3301+
};
3302+
32603303
static const sd_bus_vtable bus_link_vtable[] = {
32613304
SD_BUS_VTABLE_START(0),
32623305
SD_BUS_WRITABLE_PROPERTY("Role",
@@ -4352,6 +4395,18 @@ static int endpoint_allocate_eid(struct peer *peer)
43524395
return rc;
43534396
}
43544397
}
4398+
sd_bus_add_object_vtable(peer->ctx->bus,
4399+
&peer->slot_bridge, peer->path,
4400+
CC_MCTP_DBUS_IFACE_BRIDGE,
4401+
bus_endpoint_bridge, peer);
4402+
rc = sd_bus_emit_interfaces_added(
4403+
peer->ctx->bus, peer->path,
4404+
CC_MCTP_DBUS_IFACE_BRIDGE, NULL);
4405+
if (rc) {
4406+
warnx("Failed to emit add %s signal for endpoint %d : %s",
4407+
CC_MCTP_DBUS_IFACE_BRIDGE, peer->eid,
4408+
strerror(-rc));
4409+
}
43554410
// TODO: Polling logic for downstream EID
43564411
}
43574412
}

tests/test_mctpd.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
MCTPD_MCTP_P = '/au/com/codeconstruct/mctp1'
2121
MCTPD_MCTP_I = 'au.com.codeconstruct.MCTP.BusOwner1'
2222
MCTPD_ENDPOINT_I = 'au.com.codeconstruct.MCTP.Endpoint1'
23+
MCTPD_ENDPOINT_BRIDGE_I = 'au.com.codeconstruct.MCTP.Bridge1'
2324
DBUS_OBJECT_MANAGER_I = 'org.freedesktop.DBus.ObjectManager'
2425
DBUS_PROPERTIES_I = 'org.freedesktop.DBus.Properties'
2526

@@ -971,3 +972,125 @@ async def test_assign_dynamic_bridge_eid(dbus, mctpd):
971972
assert ep.eid < br_ep.eid <= ep.eid + ep.allocated_pool_size
972973
(_, new) = await net.call_learn_endpoint(br_ep.eid)
973974
assert new
975+
976+
""" Test that we truncate the requested pool size to
977+
the max_pool_size config """
978+
async def test_assign_dynamic_eid_limited_pool(nursery, dbus, sysnet):
979+
max_pool_size = 1
980+
config = f"""
981+
[bus-owner]
982+
max_pool_size = {max_pool_size}
983+
"""
984+
985+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
986+
await mctpd.start_mctpd(nursery)
987+
988+
iface = mctpd.system.interfaces[0]
989+
ep = mctpd.network.endpoints[0]
990+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
991+
992+
# Set up bridged endpoints as undiscovered EID 0
993+
for i in range(0, 2):
994+
br_ep = Endpoint(iface, bytes(), types=[0, 2])
995+
ep.add_bridged_ep(br_ep)
996+
mctpd.network.add_endpoint(br_ep)
997+
998+
# dynamic EID assigment for dev1
999+
(eid, _, path, new) = await mctp.call_assign_endpoint(
1000+
ep.lladdr,
1001+
)
1002+
1003+
assert new
1004+
1005+
bridge_obj = await dbus.get_proxy_object(MCTPD_C, path)
1006+
props_iface = await bridge_obj.get_interface(DBUS_PROPERTIES_I)
1007+
pool_end = await props_iface.call_get(MCTPD_ENDPOINT_BRIDGE_I, "PoolEnd")
1008+
pool_size = pool_end.value - eid
1009+
assert pool_size == max_pool_size
1010+
1011+
res = await mctpd.stop_mctpd()
1012+
assert res == 0
1013+
1014+
""" Test that no pool is assigned for requested pool size from
1015+
unavailable pool space"""
1016+
async def test_assign_dynamic_unavailable_pool(nursery, dbus, sysnet):
1017+
(min_dyn_eid, max_dyn_eid) = (8, 12)
1018+
config = f"""
1019+
[bus-owner]
1020+
dynamic_eid_range = [{min_dyn_eid}, {max_dyn_eid}]
1021+
"""
1022+
1023+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1024+
await mctpd.start_mctpd(nursery)
1025+
1026+
iface = mctpd.system.interfaces[0]
1027+
ep = mctpd.network.endpoints[0]
1028+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1029+
1030+
# Set up bridged endpoints as undiscovered EID 0
1031+
for i in range(0, 2):
1032+
br_ep = Endpoint(iface, bytes(), types=[0, 2])
1033+
ep.add_bridged_ep(br_ep)
1034+
mctpd.network.add_endpoint(br_ep)
1035+
1036+
# consume middle eid from the range to dev2
1037+
dev2 = Endpoint(iface, bytes([0x09]))
1038+
mctpd.network.add_endpoint(dev2)
1039+
(eid, _, path, new) = await mctp.call_assign_endpoint_static(
1040+
dev2.lladdr,
1041+
10
1042+
)
1043+
assert new
1044+
1045+
# dynamic EID assigment for dev1
1046+
(eid, _, path, new) = await mctp.call_assign_endpoint(
1047+
ep.lladdr,
1048+
)
1049+
assert new
1050+
# Interface should not be present for unavailable pool space
1051+
with pytest.raises(asyncdbus.errors.InterfaceNotFoundError):
1052+
bridge_obj = await dbus.get_proxy_object(MCTPD_C, path)
1053+
await bridge_obj.get_interface(MCTPD_ENDPOINT_BRIDGE_I)
1054+
1055+
res = await mctpd.stop_mctpd()
1056+
assert res == 0
1057+
1058+
"""During Allocate Endpoint ID exchange, return completion code failure
1059+
to indicate no pool has been assigned to the bridge"""
1060+
async def test_assign_dynamic_eid_allocation_failure(dbus, mctpd):
1061+
class BridgeEndpoint(Endpoint):
1062+
async def handle_mctp_control(self, sock, src_addr, msg):
1063+
flags, opcode = msg[0:2]
1064+
if opcode != 0x8:
1065+
return await super().handle_mctp_control(sock, src_addr, msg)
1066+
dst_addr = MCTPSockAddr.for_ep_resp(self, src_addr, sock.addr_ext)
1067+
1068+
msg = bytes([
1069+
flags & 0x1f, # Rsp
1070+
0x08, # opcode: Allocate Endpoint ID
1071+
0x01, # cc: failure
1072+
0x01, # allocation rejected
1073+
0x00, # pool size
1074+
0x00, # pool start
1075+
])
1076+
await sock.send(dst_addr, msg)
1077+
1078+
iface = mctpd.system.interfaces[0]
1079+
ep = BridgeEndpoint(iface, bytes([0x1e]))
1080+
mctpd.network.add_endpoint(ep)
1081+
# Set up downstream endpoints as undiscovered EID 0
1082+
for i in range(0, 2):
1083+
br_ep = Endpoint(iface, bytes(), types=[0, 2])
1084+
ep.add_bridged_ep(br_ep)
1085+
mctpd.network.add_endpoint(br_ep)
1086+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1087+
1088+
# dynamic EID assigment for dev1
1089+
(eid, _, path, new) = await mctp.call_assign_endpoint(
1090+
ep.lladdr,
1091+
)
1092+
assert new
1093+
# Interface should not be present for failed pool allocation
1094+
with pytest.raises(asyncdbus.errors.InterfaceNotFoundError):
1095+
bridge_obj = await dbus.get_proxy_object(MCTPD_C, path)
1096+
await bridge_obj.get_interface(MCTPD_ENDPOINT_BRIDGE_I)

0 commit comments

Comments
 (0)