Skip to content

Commit

Permalink
Merge branch 'static'
Browse files Browse the repository at this point in the history
  • Loading branch information
jk-ozlabs committed Feb 1, 2024
2 parents 0070bc0 + fcd00ee commit 27cb8da
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1. mctpd: Add support for endpoint recovery
2. mctpd: Allow recovery of devices reporting a nil UUID for development
3. mctpd: Allow configuring .Connectivity as writable for development
4. mctpd: Add AssignEndpointStatic for static EID allocations

### Changed

Expand Down
14 changes: 14 additions & 0 deletions docs/mctpd.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ busctl call xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp \
Similar to SetupEndpoint, but will always assign an EID rather than querying for existing ones.
Will return `new = false` when an endpoint is already known to `mctpd`.

### `.AssignEndpointStatic`

Similar to AssignEndpoint, but takes an additional EID argument:

```
AssignEndpointStatic <interface name> <hwaddr> <static-EID>
```

to assign `<static-EID>` to the endpoint with hardware address `hwaddr`.

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.

### `.LearnEndpoint`

Like SetupEndpoint but will not assign EIDs, will only query endpoints for a current EID.
Expand Down
133 changes: 116 additions & 17 deletions src/mctpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,7 @@ static int peer_set_mtu(ctx *ctx, peer *peer, uint32_t mtu) {
}

static int endpoint_assign_eid(ctx *ctx, sd_bus_error *berr, const dest_phys *dest,
peer **ret_peer)
peer **ret_peer, mctp_eid_t static_eid)
{
mctp_eid_t e, new_eid;
net_det *n = NULL;
Expand All @@ -1359,20 +1359,28 @@ static int endpoint_assign_eid(ctx *ctx, sd_bus_error *berr, const dest_phys *de
return -EPROTO;
}

/* Find an unused EID */
for (e = eid_alloc_min; e <= eid_alloc_max; e++) {
if (n->peeridx[e] == -1) {
rc = add_peer(ctx, dest, e, net, &peer);
if (rc < 0)
return rc;
break;
if (static_eid) {
rc = add_peer(ctx, dest, static_eid, net, &peer);
if (rc < 0)
return rc;

new_eid = static_eid;
} else {
/* Find an unused EID */
for (e = eid_alloc_min; e <= eid_alloc_max; e++) {
if (n->peeridx[e] == -1) {
rc = add_peer(ctx, dest, e, net, &peer);
if (rc < 0)
return rc;
break;
}
}
if (e > eid_alloc_max) {
warnx("Ran out of EIDs for net %d, allocating %s", net, dest_phys_tostr(dest));
sd_bus_error_setf(berr, SD_BUS_ERROR_FAILED,
"Ran out of EIDs");
return -EADDRNOTAVAIL;
}
}
if (e > eid_alloc_max) {
warnx("Ran out of EIDs for net %d, allocating %s", net, dest_phys_tostr(dest));
sd_bus_error_setf(berr, SD_BUS_ERROR_FAILED,
"Ran out of EIDs");
return -EADDRNOTAVAIL;
}

rc = endpoint_send_set_endpoint_id(peer, &new_eid);
Expand Down Expand Up @@ -1794,7 +1802,7 @@ static int method_setup_endpoint(sd_bus_message *call, void *data, sd_bus_error
}

/* Set Endpoint ID */
rc = endpoint_assign_eid(ctx, berr, dest, &peer);
rc = endpoint_assign_eid(ctx, berr, dest, &peer, 0);
if (rc < 0)
goto err;

Expand Down Expand Up @@ -1851,7 +1859,7 @@ static int method_assign_endpoint(sd_bus_message *call, void *data, sd_bus_error
peer->eid, peer->net, peer_path, 0);
}

rc = endpoint_assign_eid(ctx, berr, dest, &peer);
rc = endpoint_assign_eid(ctx, berr, dest, &peer, 0);
if (rc < 0)
goto err;

Expand All @@ -1867,6 +1875,84 @@ static int method_assign_endpoint(sd_bus_message *call, void *data, sd_bus_error
return rc;
}

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

rc = sd_bus_message_read(call, "s", &ifname);
if (rc < 0)
goto err;

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

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

dest->ifindex = mctp_nl_ifindex_byname(ctx->nl, ifname);
if (dest->ifindex <= 0)
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
"Unknown MCTP ifname '%s'", ifname);

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) {
if (peer->eid != eid) {
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
"Already assigned a different EID");
}

// Return existing record.
rc = path_from_peer(peer, &peer_path);
if (rc < 0)
goto err;
dfree(peer_path);

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

// is the requested EID already in use? if so, reject
netid = mctp_nl_net_byindex(ctx->nl, dest->ifindex);
peer = find_peer_by_addr(ctx, eid, netid);
if (peer) {
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
"Address in use");
}
}

rc = endpoint_assign_eid(ctx, berr, dest, &peer, eid);
if (rc < 0) {
goto err;
}

rc = path_from_peer(peer, &peer_path);
if (rc < 0) {
goto err;
}
dfree(peer_path);

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)
{
int rc;
Expand Down Expand Up @@ -2325,7 +2411,7 @@ peer_endpoint_recover(sd_event_source *s, uint64_t usec, void *userdata)
* after which we immediately return as there's no old peer state left to
* maintain.
*/
return endpoint_assign_eid(ctx, NULL, &phys, &peer);
return endpoint_assign_eid(ctx, NULL, &phys, &peer, 0);
}

/* Confirmation of the same device, apply its already allocated EID */
Expand Down Expand Up @@ -2542,6 +2628,19 @@ static const sd_bus_vtable bus_mctpd_vtable[] = {
method_assign_endpoint,
0),

SD_BUS_METHOD_WITH_NAMES("AssignEndpointStatic",
"sayy",
SD_BUS_PARAM(ifname)
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_static,
0),

SD_BUS_METHOD_WITH_NAMES("LearnEndpoint",
"say",
SD_BUS_PARAM(ifname)
Expand Down
96 changes: 96 additions & 0 deletions tests/test_mctpd.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
import trio
import uuid
import asyncdbus

from mctp_test_utils import mctpd_mctp_obj, mctpd_mctp_endpoint_obj
from conftest import Endpoint
Expand Down Expand Up @@ -272,3 +273,98 @@ def ep_added(ep_path, content):
await degraded.acquire()

assert not expected.cancelled_caught

""" Test that we get the correct EID allocated (and the usual route/neigh setup)
on an AssignEndpointStatic call """
async def test_assign_endpoint_static(dbus, mctpd):
iface = mctpd.system.interfaces[0]
dev = mctpd.network.endpoints[0]
mctp = await mctpd_mctp_obj(dbus)
static_eid = 12

(eid, _, _, new) = await mctp.call_assign_endpoint_static(
iface.name,
dev.lladdr,
static_eid
)

assert eid == static_eid
assert new

assert len(mctpd.system.neighbours) == 1
neigh = mctpd.system.neighbours[0]
assert neigh.lladdr == dev.lladdr
assert neigh.eid == static_eid
assert len(mctpd.system.routes) == 2

""" Test that we can repeat an AssignEndpointStatic call with the same static
EID"""
async def test_assign_endpoint_static_allocated(dbus, mctpd):
iface = mctpd.system.interfaces[0]
mctp = await mctpd_mctp_obj(dbus)
dev = mctpd.network.endpoints[0]
static_eid = 12

(eid, _, _, new) = await mctp.call_assign_endpoint_static(
iface.name,
dev.lladdr,
static_eid,
)

assert eid == static_eid
assert new

# repeat, same EID
(eid, _, _, new) = await mctp.call_assign_endpoint_static(
iface.name,
dev.lladdr,
static_eid,
)

assert eid == static_eid
assert not new

""" Test that we cannot assign a conflicting static EID """
async def test_assign_endpoint_static_conflict(dbus, mctpd):
iface = mctpd.system.interfaces[0]
mctp = await mctpd_mctp_obj(dbus)
dev1 = mctpd.network.endpoints[0]

dev2 = Endpoint(iface, bytes([0x1e]))
mctpd.network.add_endpoint(dev2)

# dynamic EID assigment for dev1
(eid, _, _, new) = await mctp.call_assign_endpoint(
iface.name,
dev1.lladdr,
)

assert new

# try to assign dev2 with the dev1's existing EID
with pytest.raises(asyncdbus.errors.DBusError) as ex:
await mctp.call_assign_endpoint_static(iface.name, dev2.lladdr, eid)

assert str(ex.value) == "Address in use"

""" Test that we cannot re-assign a static EID to an endpoint that already has
a different EID allocated"""
async def test_assign_endpoint_static_varies(dbus, mctpd):
iface = mctpd.system.interfaces[0]
dev = mctpd.network.endpoints[0]
mctp = await mctpd_mctp_obj(dbus)
static_eid = 12

(eid, _, _, new) = await mctp.call_assign_endpoint_static(
iface.name,
dev.lladdr,
static_eid
)

assert eid == static_eid
assert new

with pytest.raises(asyncdbus.errors.DBusError) as ex:
await mctp.call_assign_endpoint_static(iface.name, dev.lladdr, 13)

assert str(ex.value) == "Already assigned a different EID"

0 comments on commit 27cb8da

Please sign in to comment.