Skip to content

Commit 7bdb6d7

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 b4ac97f commit 7bdb6d7

File tree

3 files changed

+195
-1
lines changed

3 files changed

+195
-1
lines changed

docs/mctpd.md

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

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

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

224240
`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
}
@@ -2668,6 +2672,8 @@ static int unpublish_peer(struct peer *peer)
26682672
peer->slot_obmc_endpoint = NULL;
26692673
sd_bus_slot_unref(peer->slot_cc_endpoint);
26702674
peer->slot_cc_endpoint = NULL;
2675+
sd_bus_slot_unref(peer->slot_bridge);
2676+
peer->slot_bridge = NULL;
26712677
sd_bus_slot_unref(peer->slot_uuid);
26722678
peer->slot_uuid = NULL;
26732679
peer->published = false;
@@ -3052,6 +3058,28 @@ static int bus_endpoint_get_prop(sd_bus *bus, const char *path,
30523058
return rc;
30533059
}
30543060

3061+
static int bus_bridge_get_prop(sd_bus *bus, const char *path,
3062+
const char *interface, const char *property,
3063+
sd_bus_message *reply, void *userdata,
3064+
sd_bus_error *berr)
3065+
{
3066+
struct peer *peer = userdata;
3067+
int rc;
3068+
3069+
if (strcmp(property, "PoolStart") == 0) {
3070+
rc = sd_bus_message_append(reply, "y", peer->pool_start);
3071+
} else if (strcmp(property, "PoolEnd") == 0) {
3072+
uint8_t pool_end = peer->pool_start + peer->pool_size - 1;
3073+
rc = sd_bus_message_append(reply, "y", pool_end);
3074+
} else {
3075+
warnx("Unknown bridge property '%s' for %s iface %s", property,
3076+
path, interface);
3077+
rc = -ENOENT;
3078+
}
3079+
3080+
return rc;
3081+
}
3082+
30553083
static int bus_network_get_prop(sd_bus *bus, const char *path,
30563084
const char *interface, const char *property,
30573085
sd_bus_message *reply, void *userdata,
@@ -3251,6 +3279,21 @@ static const sd_bus_vtable bus_endpoint_cc_vtable[] = {
32513279
SD_BUS_VTABLE_END
32523280
};
32533281

3282+
static const sd_bus_vtable bus_endpoint_bridge[] = {
3283+
SD_BUS_VTABLE_START(0),
3284+
SD_BUS_PROPERTY("PoolStart",
3285+
"y",
3286+
bus_bridge_get_prop,
3287+
0,
3288+
SD_BUS_VTABLE_PROPERTY_CONST),
3289+
SD_BUS_PROPERTY("PoolEnd",
3290+
"y",
3291+
bus_bridge_get_prop,
3292+
0,
3293+
SD_BUS_VTABLE_PROPERTY_CONST),
3294+
SD_BUS_VTABLE_END
3295+
};
3296+
32543297
static const sd_bus_vtable bus_link_vtable[] = {
32553298
SD_BUS_VTABLE_START(0),
32563299
SD_BUS_WRITABLE_PROPERTY("Role",
@@ -4346,6 +4389,18 @@ static int endpoint_allocate_eid(struct peer *peer)
43464389
return rc;
43474390
}
43484391
}
4392+
sd_bus_add_object_vtable(peer->ctx->bus,
4393+
&peer->slot_bridge, peer->path,
4394+
CC_MCTP_DBUS_IFACE_BRIDGE,
4395+
bus_endpoint_bridge, peer);
4396+
rc = sd_bus_emit_interfaces_added(
4397+
peer->ctx->bus, peer->path,
4398+
CC_MCTP_DBUS_IFACE_BRIDGE, NULL);
4399+
if (rc < 0) {
4400+
warnx("Failed to emit add %s signal for endpoint %d : %s",
4401+
CC_MCTP_DBUS_IFACE_BRIDGE, peer->eid,
4402+
strerror(-rc));
4403+
}
43494404
// TODO: Polling logic for downstream EID
43504405
}
43514406
}

tests/test_mctpd.py

Lines changed: 124 additions & 1 deletion
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

@@ -964,4 +965,126 @@ async def test_assign_dynamic_bridge_eid(dbus, mctpd):
964965
with pytest.raises(asyncdbus.errors.DBusError) as ex:
965966
await mctp.call_assign_endpoint_static(dev2.lladdr, ep.eid + 1)
966967

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

0 commit comments

Comments
 (0)