From fd3dd4701c847f537fd12e37214fba3a518e6534 Mon Sep 17 00:00:00 2001 From: Thu Nguyen Date: Thu, 16 May 2024 01:05:39 +0000 Subject: [PATCH] mctpd: add MCTP Interface D-Bus object 1. Create the MCTP interfaces D-Bus objects for the existing MCTP links at `/xyz/openbmc_project/mctp1/interfaces/`. When the MCTP links is removed from/added to the system, the D-Bus object will also be removed/added. 2. Create the au.com.CodeConstruct.MCTP.Link1 D-Bus interface for MCTP interface D-Bus objects. The D-Bus interface includes the `Role` property which reports BMC roles in the MCTP link. The possible value of `Role` are `BusOwner`, `Endpoint` and `Unknown`. 3. Because the BMC `Role` in the MCTP interface is fixed. The `Role` property is changeable value but it can only be changed when the current configured value is `Unknown`. Ex: ``` busctl tree au.com.codeconstruct.MCTP1 `- /au `- /au/com `- /au/com/codeconstruct `- /au/com/codeconstruct/mctp1 |- /au/com/codeconstruct/mctp1/interfaces | |- /au/com/codeconstruct/mctp1/interfaces/lo | `- /au/com/codeconstruct/mctp1/interfaces/mctpi2c3 `- /au/com/codeconstruct/mctp1/networks `- /au/com/codeconstruct/mctp1/networks/1 `- /au/com/codeconstruct/mctp1/networks/1/endpoints `- /au/com/codeconstruct/mctp1/networks/1/endpoints/8 busctl introspect au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1/interfaces/mctpi2c3 NAME TYPE SIGNATURE RESULT/VALUE FLAGS au.com.CodeConstruct.MCTP.Link1 interface - - - .Role property s "Endpoint" emits-change writable org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - busctl set-property au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1/interfaces/mctpi2c3 au.com.CodeConstruct.MCTP.Link1 Role s BusOwner busctl get-property au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1/interfaces/mctpi2c3 au.com.CodeConstruct.MCTP.Link1 Role s "BusOwner" ``` Signed-off-by: Thu Nguyen --- CHANGELOG.md | 1 + conf/mctpd.conf | 6 +- docs/mctpd.md | 10 +- src/mctp-netlink.h | 8 + src/mctpd.c | 466 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 474 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07fdc1e..5e6f5ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 3. mctpd: Allow configuring .Connectivity as writable for development 4. mctpd: Add AssignEndpointStatic for static EID allocations 5. mctpd: Add a configuration file facility, defaulting to /etc/mctpd.conf. +6. mctpd: Add mctp/interfaces/ D-Bus object ### Changed diff --git a/conf/mctpd.conf b/conf/mctpd.conf index 82b5546..e5ea2c0 100644 --- a/conf/mctpd.conf +++ b/conf/mctpd.conf @@ -1,7 +1,7 @@ -# Mode: either bus-owner or endpoint -mode = "bus-owner" +# Mode: either BusOwner, Endpoint or Unknown +mode = "BusOwner" -# MCTP protocol configuration. Used for both endpoint and bus-owner modes. +# MCTP protocol configuration. Used for both endpoint and BusOwner modes. [mctp] message_timeout_ms = 30 diff --git a/docs/mctpd.md b/docs/mctpd.md index 3cc65da..a82372a 100644 --- a/docs/mctpd.md +++ b/docs/mctpd.md @@ -1,6 +1,6 @@ # `mctpd` -## D-Bus +## D-Bus /xyz/openbmc_project/mctp1//endpoints/ `mctpd` provides a D-Bus service named `au.com.codeconstruct.MCTP1`, and a base object path of `/au/com/codeconstruct/mctp1`. For each known MCTP endpoint, @@ -104,3 +104,11 @@ busctl call au.com.codeconstruct.MCTP1 \ Removes the MCTP endpoint from `mctpd`, and deletes routes and neighbour entries. +## D-Bus /xyz/openbmc_project/mctp1/interfaces/ + +`mctpd` provides a D-Bus path of `/xyz/openbmc_project/mctp1/interfaces`. +For each known MCTP interfaces, `mctpd` will populate an object `/xyz/openbmc_project/mctp1/interfaces/`. The D-Bus objects have interface `au.com.CodeConstruct.MCTP.Link1`. The D-Bus interface includes the `Role` property which reports +BMC roles in the link. The possible value of `Role` are `BusOwner`, `Endpoint` and `Unknown`. +Because the BMC `Role` in the MCTP link is fixed. The `Role` property is changeable value but it can only be changed +when the current configured value is `Unknown`. +The D-Bus `mctp1/interfaces/` objects also includes an au.com.codeconstruct.MCTP.BusOwner1 which exposes bus-owner level functions. \ No newline at end of file diff --git a/src/mctp-netlink.h b/src/mctp-netlink.h index deb0680..5744296 100644 --- a/src/mctp-netlink.h +++ b/src/mctp-netlink.h @@ -8,11 +8,19 @@ #include "mctp.h" +enum endpoint_role { + ENDPOINT_ROLE_UNKNOWN, + ENDPOINT_ROLE_BUS_OWNER, + ENDPOINT_ROLE_ENDPOINT, +}; + struct linkmap_entry { int ifindex; char ifname[IFNAMSIZ+1]; int net; bool up; + bool published; + enum endpoint_role role; mctp_eid_t *local_eids; size_t num_local; diff --git a/src/mctpd.c b/src/mctpd.c index 5049914..319ec20 100644 --- a/src/mctpd.c +++ b/src/mctpd.c @@ -42,12 +42,14 @@ #define MCTP_DBUS_PATH "/au/com/codeconstruct/mctp1" #define MCTP_DBUS_PATH_NETWORKS "/au/com/codeconstruct/mctp1/networks" +#define MCTP_DBUS_PATH_LINKS "/au/com/codeconstruct/mctp1/interfaces" #define CC_MCTP_DBUS_IFACE_BUSOWNER "au.com.codeconstruct.MCTP.BusOwner1.DRAFT" #define CC_MCTP_DBUS_IFACE_ENDPOINT "au.com.codeconstruct.MCTP.Endpoint1" #define CC_MCTP_DBUS_IFACE_TESTING "au.com.codeconstruct.MCTPTesting" #define MCTP_DBUS_NAME "au.com.codeconstruct.MCTP1" #define MCTP_DBUS_IFACE_ENDPOINT "xyz.openbmc_project.MCTP.Endpoint" #define OPENBMC_IFACE_COMMON_UUID "xyz.openbmc_project.Common.UUID" +#define CC_MCTP_DBUS_IFACE_LINK "au.com.CodeConstruct.MCTP.Link1" // an arbitrary constant for use with sd_id128_get_machine_app_specific() static const char* mctpd_appid = "67369c05-4b97-4b7e-be72-65cfd8639f10"; @@ -83,12 +85,6 @@ struct ctx; // all local peers have the same phys static const dest_phys local_phys = { .ifindex = 0 }; -enum endpoint_role { - ENDPOINT_ROLE_UNKNOWN, - ENDPOINT_ROLE_BUS_OWNER, - ENDPOINT_ROLE_ENDPOINT, -}; - struct role { enum endpoint_role role; const char *conf_val; @@ -97,14 +93,15 @@ struct role { static const struct role roles[] = { [ENDPOINT_ROLE_UNKNOWN] = { .role = ENDPOINT_ROLE_UNKNOWN, + .conf_val = "Unknown", }, [ENDPOINT_ROLE_BUS_OWNER] = { .role = ENDPOINT_ROLE_BUS_OWNER, - .conf_val = "bus-owner", + .conf_val = "BusOwner", }, [ENDPOINT_ROLE_ENDPOINT] = { .role = ENDPOINT_ROLE_ENDPOINT, - .conf_val = "endpoint", + .conf_val = "Endpoint", }, }; @@ -176,8 +173,8 @@ struct ctx { // Second instance for sending mctp socket requests. State is unused. mctp_nl *nl_query; - // Whether we are running as the bus owner - bool bus_owner; + // Default BMC role in All of MCTP medium interface + size_t default_role; // An allocated array of peers, changes address (reallocated) during runtime peer *peers; @@ -186,6 +183,9 @@ struct ctx { struct net_det *nets; size_t num_nets; + struct linkmap_entry *linkmap; + size_t linkmap_count; + // Timeout in usecs for a MCTP response uint64_t mctp_timeout; @@ -199,6 +199,8 @@ typedef struct ctx ctx; static int emit_endpoint_added(const peer *peer); static int emit_endpoint_removed(const peer *peer); +static int emit_interface_added(ctx *ctx, int ifindex); +static int emit_interface_removed(ctx *ctx, int ifindex); static int emit_net_added(ctx *ctx, int net); static int emit_net_removed(ctx *ctx, int net); static int query_peer_properties(peer *peer); @@ -215,6 +217,7 @@ static int change_net_interface(ctx *ctx, int ifindex, int old_net); static int add_local_eid(ctx *ctx, int net, int eid); static int del_local_eid(ctx *ctx, int net, int eid); static int add_net(ctx *ctx, int net); +static int add_interface(ctx *ctx, int ifindex); mctp_eid_t local_addr(const ctx *ctx, int ifindex) { mctp_eid_t *eids, ret = 0; @@ -238,6 +241,24 @@ static net_det *lookup_net(ctx *ctx, int net) return NULL; } +static linkmap_entry * find_link_by_ifindex(ctx *ctx, int ifindex) +{ + for (size_t i = 0; i < ctx->linkmap_count; i++) { + if (ctx->linkmap[i].ifindex == ifindex) + return &ctx->linkmap[i]; + } + return NULL; +} + +static linkmap_entry * find_link_by_name(ctx *ctx, const char* ifname) +{ + for (size_t i = 0; i < ctx->linkmap_count; i++) { + if (strcmp(ctx->linkmap[i].ifname, ifname) == 0) + return &ctx->linkmap[i]; + } + return NULL; +} + static bool match_phys(const dest_phys *d1, const dest_phys *d2) { return d1->ifindex == d2->ifindex && d1->hwaddr_len == d2->hwaddr_len && @@ -442,6 +463,20 @@ static int path_from_peer(const peer *peer, char ** ret_path) { return 0; } +static int get_role(const char *mode, struct role *role) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(roles); i++) { + if (roles[i].conf_val && (strcmp(roles[i].conf_val, mode) == 0)) + { + memcpy(role, &roles[i], sizeof(struct role)); + return 0; + } + } + + return -1; +} /* Returns the message from a socket. ret_buf is allocated, should be freed by the caller */ @@ -625,7 +660,7 @@ static int handle_control_get_endpoint_id(ctx *ctx, resp->ctrl_hdr.rq_dgram_inst = RQDI_RESP; resp->eid = local_addr(ctx, addr->smctp_ifindex); - if (ctx->bus_owner) + if (ctx->default_role == ENDPOINT_ROLE_BUS_OWNER) SET_ENDPOINT_TYPE(resp->eid_type, MCTP_BUS_OWNER_BRIDGE); // 10b = 2 = static EID supported, matches currently assigned. SET_ENDPOINT_ID_TYPE(resp->eid_type, 2); @@ -2733,6 +2768,53 @@ static const sd_bus_vtable testing_vtable[] = { SD_BUS_VTABLE_END }; +static bool is_endpoint_path(const char *path) +{ + char *netstr = NULL, *eidstr = NULL; + uint32_t tmp, net; + int rc; + + rc = sd_bus_path_decode_many(path, + MCTP_DBUS_PATH "/networks/%/endpoints/%", + &netstr, &eidstr); + + if (rc == 0) + return false; + if (rc < 0) + return false; + + dfree(netstr); + dfree(eidstr); + + if (parse_uint32(eidstr, &tmp) < 0 || tmp > 0xff) + return false; + + if (parse_uint32(netstr, &net) < 0) + return false; + + return true; +} + +static bool is_interfaces_path(const char *path) +{ + char *intfName = NULL; + int rc; + + rc = sd_bus_path_decode_many(path, + MCTP_DBUS_PATH "/interfaces/%", + &intfName); + + if (rc == 0) + return false; + + if (rc < 0) + return false; + + dfree(intfName); + + return true; +} + static int bus_endpoint_get_prop(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *berr) @@ -2740,6 +2822,10 @@ static int bus_endpoint_get_prop(sd_bus *bus, peer *peer = userdata; int rc; + if (!is_endpoint_path(path)) { + return -ENOENT; + } + if (strcmp(property, "NetworkId") == 0) { rc = sd_bus_message_append(reply, "u", peer->net); } else if (strcmp(property, "EID") == 0) { @@ -2760,6 +2846,121 @@ static int bus_endpoint_get_prop(sd_bus *bus, return rc; } +static int bus_link_get_prop(sd_bus *bus, + const char *path, const char *interface, const char *property, + sd_bus_message *reply, void *userdata, sd_bus_error *berr) +{ + ctx *ctx = userdata; + char *tmpstr = NULL; + char *link_name = NULL; + linkmap_entry *lm = NULL; + int rc = 0; + + if (!is_interfaces_path(path)) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + goto out; + } + + rc = sd_bus_path_decode_many(path, MCTP_DBUS_PATH "/%/%", &tmpstr, + &link_name); + if (rc <= 0) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + goto out; + } + + lm = find_link_by_name(ctx, link_name); + if (!lm) { + rc = -ENOENT; + goto out; + } + dfree(tmpstr); + dfree(link_name); + + if (lm->published && strcmp(property, "Role") == 0) { + rc = sd_bus_message_append(reply, "s", roles[lm->role].conf_val); + } else { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Unknown property."); + rc = -ENOENT; + } + +out: + set_berr(ctx, rc, berr); + return rc; +} + +static int bus_link_set_prop(sd_bus *bus, + const char *path, const char *interface, const char *property, + sd_bus_message *value, void *userdata, sd_bus_error *berr) +{ + ctx *ctx = userdata; + const char *state; + char *tmpstr = NULL; + char *link_name = NULL; + linkmap_entry *lm; + int rc; + struct role role; + + if (!is_interfaces_path(path)) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + goto out; + } + + rc = sd_bus_path_decode_many(path, MCTP_DBUS_PATH "/%/%", &tmpstr, + &link_name); + if (rc <= 0) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + goto out; + } + + lm = find_link_by_name(ctx, link_name); + if (!lm) { + rc = -ENOENT; + goto out; + } + + dfree(tmpstr); + dfree(link_name); + + + if (strcmp(property, "Role") != 0) { + printf("Unknown property '%s' for %s iface %s\n", property, path, interface); + rc = -ENOENT; + goto out; + } + + if (lm->role != ENDPOINT_ROLE_UNKNOWN) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Role is already set."); + rc = -ENOENT; + goto out; + } + + rc = sd_bus_message_read(value, "s", &state); + if (rc < 0) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Unknown Role. Only Support BusOwner/EndPoint."); + goto out; + } + + rc = get_role(state, &role); + if (rc < 0) { + printf("Invalid property value '%s' for property '%s' from interface '%s' on object '%s'\n", + state, property, interface, path); + rc = -EINVAL; + goto out; + } + lm->role = role.role; + +out: + set_berr(ctx, rc, berr); + return rc; +} + __attribute__((unused)) static int bus_endpoint_set_prop(sd_bus *bus, const char *path, const char *interface, @@ -2773,6 +2974,11 @@ static int bus_endpoint_set_prop(sd_bus *bus, const char *path, ctx *ctx = peer->ctx; int rc; + if (!is_endpoint_path(path)) { + rc = -ENOENT; + goto out; + } + if (strcmp(property, "Connectivity") == 0) { bool previously = peer->degraded; rc = sd_bus_message_read(value, "s", &connectivity); @@ -2833,6 +3039,17 @@ static const sd_bus_vtable bus_endpoint_uuid_vtable[] = { SD_BUS_VTABLE_END }; +static const sd_bus_vtable bus_endpoint_link_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_WRITABLE_PROPERTY("Role", + "s", + bus_link_get_prop, + bus_link_set_prop, + 0, + SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; + static const sd_bus_vtable bus_endpoint_cc_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD_WITH_ARGS("SetMTU", @@ -2874,6 +3091,9 @@ static int bus_endpoint_find(sd_bus *bus, const char *path, ctx *ctx = userdata; peer *peer = NULL; int rc; + if (!is_endpoint_path(path)) { + return 0; + } rc = peer_from_path(ctx, path, &peer); if (rc >= 0 && peer->published) { @@ -2891,6 +3111,9 @@ static int bus_endpoint_find_uuid(sd_bus *bus, const char *path, ctx *ctx = userdata; peer *peer = NULL; int rc; + if (!is_endpoint_path(path)) { + return 0; + } rc = peer_from_path(ctx, path, &peer); if (rc >= 0 && peer->published) { @@ -2916,6 +3139,45 @@ static char* root_endpoints_path(int net) return buf; } +/* au.com.CodeConstruct.MCTP.Link1 interface */ +static int bus_mctp_link_find(sd_bus *bus, const char *path, + const char *interface, void *userdata, void **ret_found, + sd_bus_error *ret_error) +{ + ctx *ctx = userdata; + char *tmpstr = NULL; + char *link_name = NULL; + linkmap_entry *lm = NULL; + int rc = 0; + + if (!is_interfaces_path(path)) { + return 0; + } + + rc = sd_bus_path_decode_many(path, MCTP_DBUS_PATH "/%/%", &tmpstr, + &link_name); + if (rc == 0) + return -ENOENT; + if (rc < 0) + return rc; + + lm = find_link_by_name(ctx, link_name); + if (!lm) { + warnx("Linkmap entry of link %s is not existing\n", link_name); + return -ENOMEM; + } + + dfree(tmpstr); + dfree(link_name); + + if (lm->published) { + *ret_found = ctx; + return 1; + } + + return 0; +} + static char* net_path(int net) { size_t l; @@ -2932,6 +3194,21 @@ static char* net_path(int net) return buf; } +static char* interface_path(const char* link_name) +{ + size_t l; + char *buf = NULL; + + l = strlen(MCTP_DBUS_PATH) + 30; + buf = malloc(l); + if (!buf) { + return NULL; + } + + snprintf(buf, l, "%s/interfaces/%s", MCTP_DBUS_PATH, link_name); + return buf; +} + static int emit_endpoint_added(const peer *peer) { char *path = NULL; int rc; @@ -2977,6 +3254,30 @@ static int emit_net_added(ctx *ctx, int net) { return rc; } +static int emit_interface_added(ctx *ctx, int ifindex) { + const char* ifname = NULL; + char *path = NULL, *links = NULL; + size_t l; + int rc; + + ifname = mctp_nl_if_byindex(ctx->nl, ifindex); + if (!ifname) { + warnx("BUG %s: no interface for ifindex %d", __func__, ifindex); + return -EPROTO; + } + + path = interface_path(ifname); + if (path == NULL) { + warnx("%s: out of memory", __func__); + return -ENOMEM; + } + rc = sd_bus_emit_object_added(ctx->bus, dfree(path)); + if (rc < 0) + warnx("%s: error emitting, %s", __func__, strerror(-rc)); + + return rc; +} + static int emit_net_removed(ctx *ctx, int net) { char *path = NULL; int rc; @@ -2992,6 +3293,31 @@ static int emit_net_removed(ctx *ctx, int net) { return rc; } +static int emit_interface_removed(ctx *ctx, int ifindex) { + const char* ifname = NULL; + char *path = NULL, *links = NULL; + size_t l; + int rc; + + ifname = mctp_nl_if_byindex(ctx->nl_query, ifindex); + if (!ifname) { + warnx("BUG %s: no interface for ifindex %d", __func__, ifindex); + return -EPROTO; + } + + path = interface_path(ifname); + if (path == NULL) { + warnx("%s: out of memory", __func__); + return -ENOMEM; + } + + rc = sd_bus_emit_object_removed(ctx->bus, dfree(path)); + if (rc < 0) + warnx("%s: error emitting, %s", __func__, strerror(-rc)); + + return rc; +} + static int bus_mctpd_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error) @@ -3036,6 +3362,17 @@ static int mctpd_dbus_enumerate(sd_bus *bus, const char* path, if (ctx->peers[i].published) num_nodes++; + // .../mctp1/interfaces object + num_nodes++; + + // .../mctp1/interface/ + for (i = 0; i < ctx->linkmap_count; i++) { + linkmap_entry *entry = &ctx->linkmap[i]; + if (entry->published) { + num_nodes++; + } + } + nodes = malloc(sizeof(*nodes) * num_nodes); if (!nodes) { rc = -ENOMEM; @@ -3097,6 +3434,28 @@ static int mctpd_dbus_enumerate(sd_bus *bus, const char* path, j++; } + // .../mctp1/interfaces object + nodes[j] = strdup(MCTP_DBUS_PATH_LINKS); + if (!nodes[j]) { + rc = -ENOMEM; + goto out; + } + j++; + + // interfaces + for (i = 0; i < ctx->linkmap_count; i++) { + linkmap_entry *entry = &ctx->linkmap[i]; + if (!entry->published) + continue; + + nodes[j] = interface_path(entry->ifname); + if (nodes[j] == NULL) { + rc = -ENOMEM; + goto out; + } + j++; + } + // NULL terminator nodes[j] = NULL; j++; @@ -3202,6 +3561,17 @@ static int setup_bus(ctx *ctx) goto out; } + rc = sd_bus_add_fallback_vtable(ctx->bus, NULL, + MCTP_DBUS_PATH, + CC_MCTP_DBUS_IFACE_LINK, + bus_endpoint_link_vtable, + bus_mctp_link_find, + ctx); + if (rc < 0) { + warnx("Failed adding link D-Bus interface: %s", strerror(-rc)); + goto out; + } + rc = sd_bus_add_object_manager(ctx->bus, NULL, MCTP_DBUS_PATH); if (rc < 0) { warnx("Adding object manager failed: %s", strerror(-rc)); @@ -3304,6 +3674,32 @@ static int prune_old_nets(ctx *ctx) return 0; } +// Remove nets that have no interfaces +static int del_dbus_link(ctx *ctx) +{ + size_t i, j; + int ifindex; + + // iterate and discard unused nets + for (i = 0, j = 0; i < ctx->linkmap_count; i++) { + bool found = false; + for (size_t n = 0; n < ctx->nl->linkmap_count && !found; n++) + if (ctx->nl->linkmap[n].ifindex == ctx->linkmap[i].ifindex) + found = true; + if (found) { + // isn't stale + if (j != i) + memmove(&ctx->linkmap[j], &ctx->linkmap[i], + sizeof(*ctx->linkmap)); + j++; + } else { + emit_interface_removed(ctx, ctx->linkmap[i].ifindex); + } + } + ctx->linkmap_count = j; + return 0; +} + // Removes remote peers associated with an old interface. // Note that this old_ifindex has already been removed from ctx->nl */ static int del_interface(ctx *ctx, int old_ifindex) @@ -3317,6 +3713,7 @@ static int del_interface(ctx *ctx, int old_ifindex) remove_peer(p); } } + del_dbus_link(ctx); prune_old_nets(ctx); return 0; } @@ -3454,6 +3851,7 @@ static int add_local_eid(ctx *ctx, int net, int eid) static int add_interface_local(ctx *ctx, int ifindex) { mctp_eid_t *eids = NULL; + linkmap_entry *lm = NULL; size_t num; int net; int rc; @@ -3467,6 +3865,13 @@ static int add_interface_local(ctx *ctx, int ifindex) warnx("Warning, interface %s is down", mctp_nl_if_byindex(ctx->nl, ifindex)); + // Add new link if required + lm = find_link_by_ifindex(ctx, ifindex); + if (!lm) { + rc = add_interface(ctx, ifindex); + if (rc < 0) + return rc; + } net = mctp_nl_net_byindex(ctx->nl, ifindex); if (net == 0) { warnx("No net for ifindex %d", ifindex); @@ -3514,6 +3919,41 @@ static int add_net(ctx *ctx, int net) return 0; } +static int add_interface(ctx *ctx, int ifindex) +{ + linkmap_entry *m = NULL, *tmp = NULL; + int rc; + + tmp = realloc(ctx->linkmap, + sizeof(linkmap_entry) * (ctx->linkmap_count + 1)); + if (!tmp) { + warnx("Out of memory"); + return -ENOMEM; + } + ctx->linkmap = tmp; + ctx->linkmap_count ++; + + // Initialise the new entry + memcpy(&ctx->linkmap[ctx->linkmap_count-1], + &ctx->nl->linkmap[ctx->linkmap_count-1], sizeof(linkmap_entry)); + + m = find_link_by_ifindex(ctx, ifindex); + if (!m) { + warnx("Can't find link %d\n", ifindex); + return -ENOMEM; + } + /* Use the `mode` setting in conf/mctp.conf */ + m->role = ctx->default_role; + + rc = emit_interface_added(ctx, ifindex); + if (rc) + { + m->published = true; + } + + return rc; +} + static int setup_nets(ctx *ctx) { size_t num_ifs; @@ -3675,7 +4115,7 @@ static int parse_config_mode(ctx *ctx, const char *mode) if (!role->conf_val || strcmp(role->conf_val, mode)) continue; - ctx->bus_owner = role->role == ENDPOINT_ROLE_BUS_OWNER; + ctx->default_role = role->role; return 0; } @@ -3798,7 +4238,7 @@ static int parse_config(ctx *ctx) static void setup_config_defaults(ctx *ctx) { ctx->mctp_timeout = 250000; // 250ms - ctx->bus_owner = true; + ctx->default_role = ENDPOINT_ROLE_BUS_OWNER; } int main(int argc, char **argv)