Skip to content

Commit 7ab1b57

Browse files
mctpd: implement routing table polling
As discussed on OpenBMC Discord [1], according to the DSP0236 spec, there is no good way to discover all active endpoints aside from polling/scanning the entire network. This adds an initial routing table polling mechanism. For each bridge, mctpd will send Get Routing Table and add the endpoints to D-Bus. If some of the endpoints are bridges, mctpd recursively enables polling for those bridges. To kick start the process, mctpd will enable polling on its bus owner, discovered when mctpd receives the Set Endpoint ID message. mctp.routing_table_polling_interval_ms config can be used to tweak the delay between pollings. Config files have been updated accordingly, we want a reasonable delay in the default config file, and a shorter delay in the test config file for running tests. Tested: For the following topology: ┌───────┐ ┌───────┐ │ ┼──► EID 9 │ │ │ └───────┘ │ │ │ │ │ EID 8 │ │ │ ┌────────┐ ┌──────┐ │ │ │ ┼──►EID 11│ │ │ │ │ └──────┘ │ ┼──► EID 10 │ │ │ │ │ ┌──────┐ │ │ │ ├──►EID 12│ └───────┘ └────────┘ └──────┘ The result D-Bus object tree should contain: - /au/com/codeconstruct/mctp1/networks/1/endpoints/8 - /au/com/codeconstruct/mctp1/networks/1/endpoints/9 - /au/com/codeconstruct/mctp1/networks/1/endpoints/10 - /au/com/codeconstruct/mctp1/networks/1/endpoints/11 - /au/com/codeconstruct/mctp1/networks/1/endpoints/12 [1] https://discord.com/channels/775381525260664832/778790638563885086/1282947932093415446 Signed-off-by: Khang D Nguyen <[email protected]>
1 parent 7d9c672 commit 7ab1b57

File tree

4 files changed

+478
-0
lines changed

4 files changed

+478
-0
lines changed

conf/mctpd.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ mode = "bus-owner"
55
[mctp]
66
message_timeout_ms = 30
77

8+
# Delay between each Get Routing Table message.
9+
routing_table_polling_interval_ms = 1000
10+
811
# Specify a UUID: not generally required - mctpd will query the system UUID
912
# where available.
1013
# uuid = "21f0f554-7f7c-4211-9ca1-6d0f000ea9e7"

src/mctp-control-spec.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,11 @@ enum mctp_phys_binding {
413413
MCTP_PHYS_BINDING_UCIE = 0x09,
414414
MCTP_PHYS_BINDING_VENDOR = 0xFF,
415415
};
416+
417+
#define MCTP_GET_ROUTING_TABLE_MSG_PHYSICAL_ADDRESS(entryh) \
418+
((void *)((char *)(entryh) + sizeof(struct get_routing_table_entry)))
419+
#define MCTP_GET_ROUTING_TABLE_MSG_NEXT(entryh) \
420+
((struct get_routing_table_entry \
421+
*)((char *)(entryh) + \
422+
sizeof(struct get_routing_table_entry) + \
423+
(entryh)->phys_address_size))

src/mctpd.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ struct peer {
206206
// Pool size
207207
uint8_t pool_size;
208208
uint8_t pool_start;
209+
210+
struct {
211+
sd_event_source *source;
212+
} routing_table_polling;
209213
};
210214

211215
struct msg_type_support {
@@ -241,6 +245,9 @@ struct ctx {
241245
// Timeout in usecs for a MCTP response
242246
uint64_t mctp_timeout;
243247

248+
// Interval in usecs between routing table requests
249+
uint64_t routing_table_polling_interval;
250+
244251
// Next IID to use
245252
uint8_t iid;
246253

@@ -276,6 +283,7 @@ static int publish_peer(struct peer *peer);
276283
static int unpublish_peer(struct peer *peer);
277284
static int peer_route_update(struct peer *peer, uint16_t type);
278285
static int peer_neigh_update(struct peer *peer, uint16_t type);
286+
static int peer_routing_table_polling_enable(struct peer *peer);
279287

280288
static int add_interface_local(struct ctx *ctx, int ifindex);
281289
static int del_interface(struct link *link);
@@ -815,6 +823,10 @@ static int handle_control_set_endpoint_id(struct ctx *ctx, int sd,
815823
if (link_data->discovery.flag != DISCOVERY_UNSUPPORTED) {
816824
link_data->discovery.flag = DISCOVERY_DISCOVERED;
817825
}
826+
rc = peer_routing_table_polling_enable(peer);
827+
if (rc) {
828+
warnx("failed to setup routing table polling for bus owner");
829+
}
818830
resp->status =
819831
SET_MCTP_EID_ASSIGNMENT_STATUS(MCTP_SET_EID_ACCEPTED) |
820832
SET_MCTP_EID_ALLOCATION_STATUS(MCTP_SET_EID_POOL_NONE);
@@ -1909,6 +1921,8 @@ static int remove_peer(struct peer *peer)
19091921
sd_event_source_unref(peer->recovery.source);
19101922
}
19111923

1924+
sd_event_source_disable_unref(peer->routing_table_polling.source);
1925+
19121926
n->peers[peer->eid] = NULL;
19131927
free(peer->message_types);
19141928
free(peer->uuid);
@@ -2291,6 +2305,62 @@ static int query_get_endpoint_id(struct ctx *ctx, const dest_phys *dest,
22912305
return rc;
22922306
}
22932307

2308+
static int query_get_routing_table(struct ctx *ctx, struct peer *peer,
2309+
uint8_t handle,
2310+
struct get_routing_table_entry **entries,
2311+
size_t *entries_count, uint8_t *next_handle)
2312+
{
2313+
struct sockaddr_mctp_ext addr;
2314+
struct mctp_ctrl_cmd_get_routing_table req = { 0 };
2315+
struct mctp_ctrl_resp_get_routing_table *resp = NULL;
2316+
uint8_t *buf = NULL;
2317+
size_t buf_size;
2318+
uint8_t iid;
2319+
int rc;
2320+
2321+
iid = mctp_next_iid(ctx);
2322+
2323+
req.ctrl_hdr.rq_dgram_inst = RQDI_REQ | iid;
2324+
req.ctrl_hdr.command_code = MCTP_CTRL_CMD_GET_ROUTING_TABLE_ENTRIES;
2325+
2326+
req.entry_handle = handle;
2327+
2328+
rc = endpoint_query_peer(peer, MCTP_CTRL_HDR_MSG_TYPE, &req,
2329+
sizeof(req), &buf, &buf_size, &addr);
2330+
if (rc < 0)
2331+
goto out;
2332+
2333+
rc = mctp_ctrl_validate_response(
2334+
buf, buf_size, sizeof(*resp), peer_tostr_short(peer), iid,
2335+
MCTP_CTRL_CMD_GET_ROUTING_TABLE_ENTRIES);
2336+
if (rc)
2337+
goto out;
2338+
2339+
resp = (void *)buf;
2340+
2341+
*next_handle = resp->next_entry_handle;
2342+
*entries_count = resp->number_of_entries;
2343+
if (*entries_count == 0) {
2344+
*entries = NULL;
2345+
goto out;
2346+
}
2347+
2348+
*entries = malloc(resp->number_of_entries *
2349+
sizeof(struct get_routing_table_entry) +
2350+
1024);
2351+
if (*entries == NULL) {
2352+
rc = -ENOMEM;
2353+
goto out;
2354+
}
2355+
2356+
memcpy(*entries, resp + 1,
2357+
resp->number_of_entries *
2358+
sizeof(struct get_routing_table_entry));
2359+
out:
2360+
free(buf);
2361+
return rc;
2362+
}
2363+
22942364
/* Returns 0, and ret_peer associated with the endpoint.
22952365
* Returns 0, ret_peer=NULL if the endpoint successfully replies "not yet assigned".
22962366
* Returns negative error code on failure.
@@ -3347,6 +3417,107 @@ static int method_endpoint_set_mtu(sd_bus_message *call, void *data,
33473417
return rc;
33483418
}
33493419

3420+
static int peer_routing_table_polling_callback(sd_event_source *source,
3421+
uint64_t time, void *userdata)
3422+
{
3423+
struct peer *peer = userdata;
3424+
struct peer *remote_peer = NULL;
3425+
struct get_routing_table_entry *entry = NULL;
3426+
size_t entries_count = 0;
3427+
uint8_t handle = 0x00;
3428+
size_t i;
3429+
int rc;
3430+
3431+
assert(peer->routing_table_polling.source == source);
3432+
3433+
while (handle != 0xFF) {
3434+
rc = query_get_routing_table(peer->ctx, peer, handle, &entry,
3435+
&entries_count, &handle);
3436+
if (rc < 0) {
3437+
warnx("failed to fetch routing table from peer %s",
3438+
peer_tostr(peer));
3439+
return 0;
3440+
}
3441+
dfree(entry);
3442+
3443+
for (i = 0; i < entries_count;
3444+
i++, entry = MCTP_GET_ROUTING_TABLE_MSG_NEXT(entry)) {
3445+
// Add Bridge/Endpoint to routing table
3446+
3447+
switch (GET_ROUTING_ENTRY_TYPE(entry->entry_type)) {
3448+
case MCTP_ROUTING_ENTRY_ENDPOINT:
3449+
case MCTP_ROUTING_ENTRY_BRIDGE:
3450+
case MCTP_ROUTING_ENTRY_BRIDGE_AND_ENDPOINTS:
3451+
rc = add_peer(peer->ctx, &peer->phys,
3452+
entry->starting_eid, peer->net,
3453+
&remote_peer, true);
3454+
if (rc == -EEXIST) {
3455+
continue;
3456+
} else if (rc < 0) {
3457+
warnx("failed to add new peer: %s",
3458+
strerror(-rc));
3459+
continue;
3460+
}
3461+
3462+
rc = setup_added_peer(remote_peer);
3463+
if (rc < 0) {
3464+
warnx("failed to set up new peer: %s",
3465+
strerror(-rc));
3466+
continue;
3467+
}
3468+
3469+
// TODO: port?
3470+
3471+
break;
3472+
};
3473+
3474+
// For bridge, enable routing table polling recursively
3475+
3476+
switch (GET_ROUTING_ENTRY_TYPE(entry->entry_type)) {
3477+
case MCTP_ROUTING_ENTRY_BRIDGE:
3478+
case MCTP_ROUTING_ENTRY_BRIDGE_AND_ENDPOINTS:
3479+
rc = peer_routing_table_polling_enable(
3480+
remote_peer);
3481+
if (rc < 0) {
3482+
warnx("failed to enable routing table polling on bridge: %s",
3483+
strerror(-rc));
3484+
continue;
3485+
}
3486+
3487+
break;
3488+
}
3489+
}
3490+
}
3491+
3492+
// rearm timer
3493+
rc = mctp_ops.sd_event.source_set_time_relative(
3494+
source, peer->ctx->routing_table_polling_interval);
3495+
if (rc) {
3496+
warn("failed to rearm timer");
3497+
}
3498+
3499+
return 0;
3500+
}
3501+
3502+
static int peer_routing_table_polling_enable(struct peer *peer)
3503+
{
3504+
int rc = 0;
3505+
3506+
if (peer->routing_table_polling.source != NULL) {
3507+
return 0;
3508+
}
3509+
3510+
rc = mctp_ops.sd_event.add_time_relative(
3511+
peer->ctx->event, &peer->routing_table_polling.source,
3512+
CLOCK_MONOTONIC, peer->ctx->routing_table_polling_interval, 0,
3513+
peer_routing_table_polling_callback, peer);
3514+
3515+
rc = sd_event_source_set_enabled(peer->routing_table_polling.source,
3516+
SD_EVENT_ON);
3517+
3518+
return rc;
3519+
}
3520+
33503521
static int method_net_learn_endpoint(sd_bus_message *call, void *data,
33513522
sd_bus_error *berr)
33523523
{
@@ -4798,6 +4969,16 @@ static int parse_config_mctp(struct ctx *ctx, toml_table_t *mctp_tab)
47984969
ctx->mctp_timeout = i * 1000;
47994970
}
48004971

4972+
val = toml_int_in(mctp_tab, "routing_table_polling_interval_ms");
4973+
if (val.ok) {
4974+
int64_t i = val.u.i;
4975+
if (i <= 0 || i > 100 * 1000) {
4976+
warnx("invalid routing_table_polling_interval_ms value");
4977+
return -1;
4978+
}
4979+
ctx->routing_table_polling_interval = i * 1000;
4980+
}
4981+
48014982
val = toml_string_in(mctp_tab, "uuid");
48024983
if (val.ok) {
48034984
rc = sd_id128_from_string(val.u.s, (void *)&ctx->uuid);
@@ -4974,6 +5155,7 @@ static void setup_config_defaults(struct ctx *ctx)
49745155
{
49755156
ctx->mctp_timeout = 250000; // 250ms
49765157
ctx->default_role = ENDPOINT_ROLE_BUS_OWNER;
5158+
ctx->routing_table_polling_interval = 1000000; // 1s
49775159
ctx->max_pool_size = 15;
49785160
ctx->dyn_eid_min = eid_alloc_min;
49795161
ctx->dyn_eid_max = eid_alloc_max;

0 commit comments

Comments
 (0)