From e280eed49e98773af84f6f0e239d3c07ae6e2ec9 Mon Sep 17 00:00:00 2001 From: Thu Nguyen Date: Thu, 16 May 2024 01:05:39 +0000 Subject: [PATCH] mctpd: Add `mctp/links/` D-Bus object 1. Create the MCTP Link D-Bus objects for the existing MCTP links at `/xyz/openbmc_project/mctp/links/`. 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.Link D-Bus interface for MCTP Link D-Bus objects. The interface includes the `Role` property which reports BMC roles in the link. The possible value of `Role` are `BusOwner`, `Endpoint` and `Unknown`. 3. 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`. Ex: ``` ~# busctl tree xyz.openbmc_project.MCTP `- /xyz `- /xyz/openbmc_project `- /xyz/openbmc_project/mctp |- /xyz/openbmc_project/mctp/1 | `- /xyz/openbmc_project/mctp/1/8 `- /xyz/openbmc_project/mctp/links |- /xyz/openbmc_project/mctp/links/lo `- /xyz/openbmc_project/mctp/links/mctpi2c3 ~# busctl introspect xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp/links NAME TYPE SIGNATURE RESULT/VALUE FLAGS 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 introspect xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp/links/mctpi2c3 NAME TYPE SIGNATURE RESULT/VALUE FLAGS au.com.CodeConstruct.MCTP.Link interface - - - .Role property s "Unknown" 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 xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp/links/mctpi2c3 au.com.CodeConstruct.MCTP.Link Role s BusOwner ~# busctl set-property xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp/links/mctpi2c3 au.com.CodeConstruct.MCTP.Link Role s "BusOwner" ``` Signed-off-by: Thu Nguyen --- CHANGELOG.md | 1 + docs/mctpd.md | 10 +- src/mctp-netlink.c | 28 --- src/mctp-netlink.h | 43 ++++- src/mctpd.c | 458 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 510 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 211d94f..b194df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 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 +5. mctpd: Add mctp/links/ D-Bus object ### Changed diff --git a/docs/mctpd.md b/docs/mctpd.md index 0ff827b..2d618a6 100644 --- a/docs/mctpd.md +++ b/docs/mctpd.md @@ -1,6 +1,6 @@ # `mctpd` -## D-Bus +## D-Bus /xyz/openbmc_project/mctp// `mctpd` provides a D-Bus path of `/xyz/openbmc_project/mctp`. For each known MCTP endpoint, `mctpd` will populate an object `/xyz/openbmc_project/mctp//`. The objects have interface @@ -89,5 +89,13 @@ busctl call xyz.openbmc_project.MCTP /xyz/openbmc_project/mctp/1/11 \ Removes the MCTP endpoint from `mctpd`, and deletes routes and neighbour entries. +## D-Bus /xyz/openbmc_project/mctp/links/ + +`mctpd` provides a D-Bus path of `/xyz/openbmc_project/mctp/links`. For each known MCTP interfaces, `mctpd` +will populate an object `/xyz/openbmc_project/mctp/links/`. +The objects have interface `au.com.CodeConstruct.MCTP.Link`. The 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`. diff --git a/src/mctp-netlink.c b/src/mctp-netlink.c index 56f620d..bc25c16 100644 --- a/src/mctp-netlink.c +++ b/src/mctp-netlink.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -20,33 +19,6 @@ #include "mctp-util.h" #include "mctp-ops.h" -struct linkmap_entry { - int ifindex; - char ifname[IFNAMSIZ+1]; - int net; - bool up; - - mctp_eid_t *local_eids; - size_t num_local; -}; - -struct mctp_nl { - // socket for queries - int sd; - // socket for monitor - int sd_monitor; - - struct linkmap_entry *linkmap; - size_t linkmap_count; - size_t linkmap_alloc; - bool verbose; - - // allows callers to silence printf of EEXIST returns. - // TODO: this is a workaround, if more are required we should - // rework how error messages are returned to callers. - bool quiet_eexist; -}; - #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) diff --git a/src/mctp-netlink.h b/src/mctp-netlink.h index 31ee6b6..91aaa15 100644 --- a/src/mctp-netlink.h +++ b/src/mctp-netlink.h @@ -3,12 +3,53 @@ #include #include #include +#include #include #include "mctp.h" -struct mctp_nl; +struct linkmap_entry { + int ifindex; + char ifname[IFNAMSIZ+1]; + int net; + bool up; + bool published; + enum { + MCTP_ENTITY_ROLE_BUS_OWNER, + MCTP_ENTITY_ROLE_ENDPOINT, + MCTP_ENTITY_ROLE_UNKNOWN + } role; + + mctp_eid_t *local_eids; + size_t num_local; +}; + +#define MCTP_ENTITY_ROLE_COUNT 3 +static const char * const role_name[] = { + [MCTP_ENTITY_ROLE_BUS_OWNER] = "BusOwner", + [MCTP_ENTITY_ROLE_ENDPOINT] = "EndPoint", + [MCTP_ENTITY_ROLE_UNKNOWN] = "Unknown" +}; + +struct mctp_nl { + // socket for queries + int sd; + // socket for monitor + int sd_monitor; + + struct linkmap_entry *linkmap; + size_t linkmap_count; + size_t linkmap_alloc; + bool verbose; + + // allows callers to silence printf of EEXIST returns. + // TODO: this is a workaround, if more are required we should + // rework how error messages are returned to callers. + bool quiet_eexist; +}; + typedef struct mctp_nl mctp_nl; +typedef struct linkmap_entry linkmap_entry; struct mctp_nl_change { #define MCTP_NL_OP_COUNT 6 diff --git a/src/mctpd.c b/src/mctpd.c index db6f4f2..efd72e2 100644 --- a/src/mctpd.c +++ b/src/mctpd.c @@ -39,8 +39,10 @@ #define min(a, b) ((a) < (b) ? (a) : (b)) #define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp" +#define MCTP_DBUS_PATH_LINKS "/xyz/openbmc_project/mctp/links" #define CC_MCTP_DBUS_IFACE "au.com.CodeConstruct.MCTP" #define CC_MCTP_DBUS_IFACE_ENDPOINT "au.com.CodeConstruct.MCTP.Endpoint" +#define CC_MCTP_DBUS_IFACE_LINK "au.com.CodeConstruct.MCTP.Link" #define CC_MCTP_DBUS_IFACE_TESTING "au.com.CodeConstruct.MCTPTesting" #define MCTP_DBUS_IFACE "xyz.openbmc_project.MCTP" #define MCTP_DBUS_IFACE_ENDPOINT "xyz.openbmc_project.MCTP.Endpoint" @@ -152,6 +154,10 @@ struct ctx { struct net_det *nets; size_t num_nets; + struct linkmap_entry *linkmap; + size_t linkmap_count; + bool publish_links; + // Timeout in usecs for a MCTP response uint64_t mctp_timeout; @@ -165,6 +171,8 @@ typedef struct ctx ctx; static int emit_endpoint_added(const peer *peer); static int emit_endpoint_removed(const peer *peer); +static int emit_link_added(ctx *ctx, int ifindex); +static int emit_link_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); @@ -181,6 +189,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_link(ctx *ctx, int ifindex); mctp_eid_t local_addr(const ctx *ctx, int ifindex) { mctp_eid_t *eids, ret = 0; @@ -204,6 +213,24 @@ static net_det *lookup_net(ctx *ctx, int net) return NULL; } +static linkmap_entry * find_link_entry_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_entry_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 && @@ -2150,6 +2177,7 @@ static int publish_peer(peer *peer, bool add_route) /* removes route, neigh, dbus entry for the peer */ static int unpublish_peer(peer *peer) { int rc; + if (peer->have_neigh) { if (peer->ctx->verbose) { fprintf(stderr, "Deleting neigh to %s\n", peer_tostr(peer)); @@ -2705,6 +2733,10 @@ static int bus_endpoint_get_prop(sd_bus *bus, peer *peer = userdata; int rc; + if (strstr(path, "links") != NULL) { + return -ENOENT; + } + if (strcmp(property, "NetworkId") == 0) { rc = sd_bus_message_append(reply, "u", peer->net); } else if (strcmp(property, "EID") == 0) { @@ -2725,6 +2757,144 @@ 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 (strstr(path, "links") == NULL) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + rc = -ENOENT; + goto out; + } + + if (strcmp(path, MCTP_DBUS_PATH_LINKS) == 0) { + rc = 0; + 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_entry_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", role_name[lm->role]); + } 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; + bool found = false; + size_t i; + int rc; + + if (strstr(path, "links") == NULL) { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Invalid Object Path"); + rc = -ENOENT; + goto out; + } + + if (strcmp(path, MCTP_DBUS_PATH_LINKS) == 0) { + rc = 0; + 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_entry_by_name(ctx, link_name); + if (!lm) { + rc = -ENOENT; + goto out; + } + dfree(tmpstr); + dfree(link_name); + + if (strcmp(property, "Role") == 0) { + if (lm->role != MCTP_ENTITY_ROLE_UNKNOWN) + { + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Can't change the none \"Unknown\" BMC Role."); + 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, + "Failed to get the setting Role."); + goto out; + } + + for (i = 0; i < MCTP_ENTITY_ROLE_COUNT; i++) + { + if (strcmp(state, role_name[i]) == 0) + { + found = true; + break; + } + } + if (!found) + { + printf("Invalid property value '%s' for property '%s' from interface '%s' on object '%s'\n", + state, property, interface, path); + sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, + "Unknown Role. Only Support BusOwner/EndPoint."); + rc = -EINVAL; + goto out; + + } + + lm->role = i; + } else { + printf("Unknown property '%s' for %s iface %s\n", property, path, interface); + rc = -ENOENT; + } + +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, @@ -2738,6 +2908,11 @@ static int bus_endpoint_set_prop(sd_bus *bus, const char *path, ctx *ctx = peer->ctx; int rc; + if (strstr(path, "links") != NULL) { + rc = -ENOENT; + goto out; + } + if (strcmp(property, "Connectivity") == 0) { bool previously = peer->degraded; rc = sd_bus_message_read(value, "s", &connectivity); @@ -2798,6 +2973,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", @@ -2840,6 +3026,10 @@ static int bus_endpoint_find(sd_bus *bus, const char *path, peer *peer = NULL; int rc; + if (strstr(path, "links") != NULL) { + return 0; + } + rc = peer_from_path(ctx, path, &peer); if (rc >= 0 && peer->published) { *ret_found = peer; @@ -2857,6 +3047,10 @@ static int bus_endpoint_find_uuid(sd_bus *bus, const char *path, peer *peer = NULL; int rc; + if (strstr(path, "links") != NULL) { + return 0; + } + rc = peer_from_path(ctx, path, &peer); if (rc >= 0 && peer->published) { if (peer->uuid) { @@ -2867,6 +3061,47 @@ static int bus_endpoint_find_uuid(sd_bus *bus, const char *path, return 0; } +/* au.com.CodeConstruct.MCTP.Link 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 (strstr(path, "links") == NULL) { + return 0; + } + if (strcmp(path, MCTP_DBUS_PATH_LINKS) == 0) { + 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_entry_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; @@ -2883,6 +3118,26 @@ static char* net_path(int net) return buf; } +static char* link_path(const char* link_name) +{ + size_t l; + char *buf = NULL; + + l = strlen(MCTP_DBUS_PATH_LINKS) + 30; + buf = malloc(l); + if (!buf) { + return NULL; + } + /* can't use sd_bus_path_encode_many() since it escapes + leading digits */ + if (strcmp(link_name, "") == 0) + snprintf(buf, l, "%s", MCTP_DBUS_PATH_LINKS); + else + snprintf(buf, l, "%s/%s", MCTP_DBUS_PATH_LINKS, link_name); + + return buf; +} + static int emit_endpoint_added(const peer *peer) { char *path = NULL; int rc; @@ -2928,6 +3183,45 @@ static int emit_net_added(ctx *ctx, int net) { return rc; } +static int emit_link_added(ctx *ctx, int ifindex) { + const char* ifname = NULL; + char *path = NULL, *links = NULL; + int rc; + + if (!ctx->publish_links) + { + links = link_path(""); + if (links == NULL) { + warnx("%s: out of memory", __func__); + return -ENOMEM; + } + + rc = sd_bus_emit_object_added(ctx->bus, dfree(links)); + if (rc < 0) { + warnx("%s: error emitting, %s", __func__, strerror(-rc)); + return -ENOMEM; + } + ctx->publish_links = true; + } + + ifname = mctp_nl_if_byindex(ctx->nl, ifindex); + if (!ifname) { + warnx("BUG %s: no interface for ifindex %d", __func__, ifindex); + return -EPROTO; + } + + path = link_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; @@ -2943,6 +3237,47 @@ static int emit_net_removed(ctx *ctx, int net) { return rc; } +static int emit_link_removed(ctx *ctx, int ifindex) { + const char* ifname = NULL; + char *path = NULL, *links = NULL; + int rc; + + + if (ifindex == -1) + { + links = link_path(""); + if (links == NULL) { + warnx("%s: out of memory", __func__); + return -ENOMEM; + } + + rc = sd_bus_emit_object_removed(ctx->bus, dfree(links)); + if (rc < 0) { + warnx("%s: error emitting, %s", __func__, strerror(-rc)); + return -ENOMEM; + } + ctx->publish_links = false; + } + + ifname = mctp_nl_if_byindex(ctx->nl_query, ifindex); + if (!ifname) { + warnx("BUG %s: no interface for ifindex %d", __func__, ifindex); + return -EPROTO; + } + + path = link_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) @@ -2973,6 +3308,16 @@ static int mctpd_dbus_enumerate(sd_bus *bus, const char* path, num_nodes += ctx->num_nets; + // .../mctp/links object + num_nodes++; + + 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; @@ -3010,6 +3355,28 @@ static int mctpd_dbus_enumerate(sd_bus *bus, const char* path, j++; } + // .../mctp/links object + nodes[j] = strdup(MCTP_DBUS_PATH_LINKS); + if (!nodes[j]) { + rc = -ENOMEM; + goto out; + } + j++; + + // Links + for (i = 0; i < ctx->linkmap_count; i++) { + linkmap_entry *entry = &ctx->linkmap[i]; + if (!entry->published) + continue; + + nodes[j] = link_path(entry->ifname); + if (nodes[j] == NULL) { + rc = -ENOMEM; + goto out; + } + j++; + } + // NULL terminator nodes[j] = NULL; j++; @@ -3115,6 +3482,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)); @@ -3214,6 +3592,40 @@ static int prune_old_nets(ctx *ctx) return 0; } +// Remove nets that have no interfaces +static int del_dbus_links(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_link_removed(ctx, ctx->linkmap[i].ifindex); + } + } + ctx->linkmap_count = j; + + /* Remove mctp/links path */ + if (ctx->linkmap_count == 0) + { + emit_link_removed(ctx, -1); + ctx->publish_links = false; + } + + 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) @@ -3302,6 +3714,7 @@ static int change_net_interface(ctx *ctx, int ifindex, int old_net) publish_peer(peer, true); } + del_dbus_links(ctx); prune_old_nets(ctx); return 0; } @@ -3364,6 +3777,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; @@ -3377,6 +3791,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_entry_by_ifindex(ctx, ifindex); + if (!lm) { + rc = add_link(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); @@ -3401,6 +3822,7 @@ static int add_interface_local(ctx *ctx, int ifindex) static int add_net(ctx *ctx, int net) { net_det *n, *tmp; + if (lookup_net(ctx, net) != NULL) { warnx("BUG: add_net for existing net %d", net); return -EEXIST; @@ -3424,6 +3846,41 @@ static int add_net(ctx *ctx, int net) return 0; } +static int add_link(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_entry_by_ifindex(ctx, ifindex); + if (!m) { + warnx("Can't find link %d\n", ifindex); + return -ENOMEM; + } + m->role = MCTP_ENTITY_ROLE_UNKNOWN; + + + rc = emit_link_added(ctx, ifindex); + if (rc) + { + m->published = true; + } + + return rc; +} + static int setup_nets(ctx *ctx) { size_t num_ifs; @@ -3622,6 +4079,7 @@ int main(int argc, char **argv) } ctx->nl = mctp_nl_new(false); + ctx->verbose = true; if (!ctx->nl) { warnx("Failed creating netlink object"); return 1;