Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ configuring remote endpoints on that bus:
au.com.codeconstruct.MCTP.Interface1 interface - - -
.AssignEndpoint method ay yisb -
.AssignEndpointStatic method ayy yisb -
.AssignEndpointPreferred method ayy yisb -
.LearnEndpoint method ay yisb -
.SetupEndpoint method ay yisb -

Expand Down
2 changes: 2 additions & 0 deletions docs/endpoint-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ root@cc-nvme-mi:~# busctl introspect au.com.codeconstruct.MCTP1 /au/com/codecons
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
au.com.codeconstruct.Interface1 interface - - -
.AssignEndpoint method ay yisb -
.AssignEndpointStatic method ayy yisb -
.AssignEndpointPreferred method ayy yisb -
.LearnEndpoint method ay yisb -
.SetupEndpoint method ay yisb -
org.freedesktop.DBus.Introspectable interface - - -
Expand Down
15 changes: 15 additions & 0 deletions docs/mctpd.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ au.com.codeconstruct.MCTP.Interface1 interface - - -
au.com.codeconstruct.MCTP.BusOwner1 interface - - -
.AssignEndpoint method ay yisb -
.AssignEndpointStatic method ayy yisb -
.AssignEndpointPreferred method ayy yisb -
.LearnEndpoint method ay yisb -
.SetupEndpoint method ay yisb -
```
Expand Down Expand Up @@ -203,6 +204,20 @@ This call will fail if the endpoint already has an EID, and that EID is
different from `static-EID`, or if `static-EID` is already assigned to another
endpoint.

#### `.AssignEndpointPreferred`: `ayy` → `yisb`

Similar to AssignEndpointStatic, but takes the additional EID argument as a
preferred EID rather than a strict static assignment:

```
AssignEndpointPreferred <hwaddr> <preferred-EID>
```

If `<preferred-EID>` is available, it will be assigned to the endpoint. If that
EID is already assigned to another endpoint, `mctpd` falls back to dynamic EID
allocation. If the endpoint is already known to `mctpd`, the existing endpoint
record is returned.

#### `.LearnEndpoint`: `ay` → `yisb`

Like SetupEndpoint but will not assign EIDs, will only query endpoints for a
Expand Down
90 changes: 90 additions & 0 deletions src/mctpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -3126,6 +3126,84 @@ static int method_assign_endpoint_static(sd_bus_message *call, void *data,
return rc;
}

static int method_assign_endpoint_preferred(sd_bus_message *call, void *data,
sd_bus_error *berr)
{
dest_phys desti, *dest = &desti;
const char *peer_path = NULL;
struct peer *peer = NULL;
struct link *link = data;
struct ctx *ctx = link->ctx;
uint8_t eid;
int rc;

dest->ifindex = link->ifindex;
if (dest->ifindex <= 0)
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
"Unknown MCTP interface");

rc = message_read_hwaddr(call, dest);
if (rc < 0)
goto err;

rc = sd_bus_message_read(call, "y", &eid);
if (rc < 0)
goto err;

rc = validate_dest_phys(ctx, dest);
if (rc < 0)
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
"Bad physaddr");

peer = find_peer_by_phys(ctx, dest);
if (peer) {
// Return existing record, even if it differs from the preferred EID.
peer_path = path_from_peer(peer);
if (!peer_path)
goto err;

return sd_bus_reply_method_return(call, "yisb", peer->eid,
peer->net, peer_path, 0);
} else {
uint32_t netid;
struct net *net;

netid = mctp_nl_net_byindex(ctx->nl, dest->ifindex);
net = lookup_net(ctx, netid);
peer = find_peer_by_addr(ctx, eid, netid);
if (peer || (net && is_eid_in_bridge_pool(net, ctx, eid))) {
if (peer) {
warnx("Preferred EID %d already in use by %s, using dynamic EID for %s",
eid, peer_tostr(peer),
dest_phys_tostr(dest));
} else {
warnx("Preferred EID %d is in a bridge pool, using dynamic EID for %s",
eid, dest_phys_tostr(dest));
}
rc = endpoint_assign_eid(ctx, berr, dest, &peer, 0,
true);
} else {
rc = endpoint_assign_eid(ctx, berr, dest, &peer, eid,
false);
}
if (rc < 0)
goto err;
}

if (peer->pool_size > 0)
endpoint_allocate_eids(peer);

peer_path = path_from_peer(peer);
if (!peer_path)
goto err;

return sd_bus_reply_method_return(call, "yisb", peer->eid, peer->net,
peer_path, 1);
err:
set_berr(ctx, rc, berr);
return rc;
}

static int method_learn_endpoint(sd_bus_message *call, void *data,
sd_bus_error *berr)
{
Expand Down Expand Up @@ -4055,6 +4133,18 @@ static const sd_bus_vtable bus_link_owner_vtable[] = {
method_assign_endpoint_static,
0),

SD_BUS_METHOD_WITH_NAMES("AssignEndpointPreferred",
"ayy",
SD_BUS_PARAM(physaddr)
SD_BUS_PARAM(eid),
"yisb",
SD_BUS_PARAM(eid)
SD_BUS_PARAM(net)
SD_BUS_PARAM(path)
SD_BUS_PARAM(new),
method_assign_endpoint_preferred,
0),

SD_BUS_METHOD_WITH_NAMES("LearnEndpoint",
"ay",
SD_BUS_PARAM(physaddr),
Expand Down
41 changes: 41 additions & 0 deletions tests/test_mctpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,47 @@ async def test_assign_endpoint_static_conflict(dbus, mctpd):
assert str(ex.value) == "Address in use"


async def test_assign_endpoint_preferred_static(dbus, mctpd):
"""Test that preferred assignment uses the requested EID when available"""
iface = mctpd.system.interfaces[0]
mctp = await mctpd_mctp_iface_obj(dbus, iface)
dev = mctpd.network.endpoints[0]
preferred_eid = 12

(eid, _, _, new) = await mctp.call_assign_endpoint_preferred(
dev.lladdr, preferred_eid
)

assert eid == preferred_eid
assert dev.eid == preferred_eid
assert new


async def test_assign_endpoint_preferred_conflict_falls_back(dbus, mctpd):
"""Test that preferred assignment falls back to dynamic EID on conflict"""
iface = mctpd.system.interfaces[0]
mctp = await mctpd_mctp_iface_obj(dbus, iface)
dev1 = mctpd.network.endpoints[0]
dev2 = Endpoint(iface, bytes([0x1E]))
preferred_eid = 12

mctpd.network.add_endpoint(dev2)

(eid1, _, _, new1) = await mctp.call_assign_endpoint_static(
dev1.lladdr, preferred_eid
)
assert eid1 == preferred_eid
assert new1

(eid2, _, _, new2) = await mctp.call_assign_endpoint_preferred(
dev2.lladdr, preferred_eid
)

assert eid2 != preferred_eid
assert dev2.eid == eid2
assert new2


async def test_assign_endpoint_static_varies(dbus, mctpd):
"""Test that we cannot re-assign a static EID to an endpoint that already
has a different EID allocated
Expand Down
Loading