From 64f4f5329aed5f7821a9921dc3b001e3f30237a8 Mon Sep 17 00:00:00 2001 From: Khang Nguyen Date: Mon, 15 Jul 2024 15:37:40 +0700 Subject: [PATCH 1/2] mctp-netlink: Store interface physical address in linkmap Normally, extended addressing is used to respond to requests. We can take the physical address len from the requester's sockaddr. However, when we want to send extended address on an interface, we do not have that information in linkmap. This stores interface address from netlink inside linkmap. Tested: Discovery Notify message is filled with correct address (see next commit) Signed-off-by: Khang Nguyen Duy --- src/mctp-netlink.c | 40 ++++++++++++++++++++++++++++++++++------ src/mctp-netlink.h | 1 + 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/mctp-netlink.c b/src/mctp-netlink.c index dfbe042..031b407 100644 --- a/src/mctp-netlink.c +++ b/src/mctp-netlink.c @@ -23,6 +23,8 @@ struct linkmap_entry { int ifindex; char ifname[IFNAMSIZ+1]; + uint8_t ifaddr[MAX_ADDR_LEN]; + size_t ifaddr_len; int net; bool up; @@ -53,8 +55,9 @@ static int fill_local_addrs(mctp_nl *nl); static int fill_linkmap(mctp_nl *nl); static void sort_linkmap(mctp_nl *nl); static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, - const char *ifname, size_t ifname_len, int net, - bool up); + const char *ifname, size_t ifname_len, + uint8_t *ifaddr, size_t ifaddr_len, int net, + bool up); static struct linkmap_entry *entry_byindex(const mctp_nl *nl, int index); @@ -679,8 +682,9 @@ static int parse_getlink_dump(mctp_nl *nl, struct nlmsghdr *nlh, uint32_t len) for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { struct rtattr *rta, *rt_nest, *rt_mctp; + uint8_t *ifaddr; char *ifname; - size_t ifname_len, rlen, nlen, mlen; + size_t ifname_len, ifaddr_len, rlen, nlen, mlen; uint32_t net; bool up; @@ -722,8 +726,13 @@ static int parse_getlink_dump(mctp_nl *nl, struct nlmsghdr *nlh, uint32_t len) continue; } ifname_len = strnlen(ifname, ifname_len); + + ifaddr = mctp_get_rtnlmsg_attr(IFLA_ADDRESS, rta, rlen, + &ifaddr_len); + up = info->ifi_flags & IFF_UP; - linkmap_add_entry(nl, info, ifname, ifname_len, net, up); + linkmap_add_entry(nl, info, ifname, ifname_len, ifaddr, + ifaddr_len, net, up); } // Not done. return 1; @@ -927,6 +936,16 @@ const char* mctp_nl_if_byindex(const mctp_nl *nl, int index) return NULL; } +uint8_t *mctp_nl_ifaddr_byindex(const mctp_nl *nl, int index, size_t *ret_len) +{ + struct linkmap_entry *entry = entry_byindex(nl, index); + if (entry) { + *ret_len = entry->ifaddr_len; + return entry->ifaddr; + } + return NULL; +} + int mctp_nl_net_byindex(const mctp_nl *nl, int index) { struct linkmap_entry *entry = entry_byindex(nl, index); @@ -1054,8 +1073,9 @@ int *mctp_nl_if_list(const mctp_nl *nl, size_t *ret_num_ifs) } static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, - const char *ifname, size_t ifname_len, int net, - bool up) + const char *ifname, size_t ifname_len, + uint8_t *ifaddr, size_t ifaddr_len, int net, + bool up) { struct linkmap_entry *entry; size_t newsz; @@ -1067,6 +1087,12 @@ static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, return -1; } + if (ifaddr_len > MAX_ADDR_LEN) { + warnx("linkmap, too long ifaddr (%zu bytes long, expected max %d bytes)", + ifaddr_len, MAX_ADDR_LEN); + return -1; + } + if (net <= 0) { warnx("Bad network ID %d for %*s", net, (int)ifname_len, ifname); return -1; @@ -1088,6 +1114,8 @@ static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, entry = &nl->linkmap[idx]; memset(entry, 0, sizeof(*entry)); snprintf(entry->ifname, IFNAMSIZ, "%*s", (int)ifname_len, ifname); + memcpy(entry->ifaddr, ifaddr, ifaddr_len); + entry->ifaddr_len = ifaddr_len; entry->ifindex = info->ifi_index; entry->net = net; entry->up = up; diff --git a/src/mctp-netlink.h b/src/mctp-netlink.h index 52847c9..10f7e0e 100644 --- a/src/mctp-netlink.h +++ b/src/mctp-netlink.h @@ -62,6 +62,7 @@ int mctp_nl_recv_all(mctp_nl *nl, int sd, /* Lookup MCTP interfaces */ int mctp_nl_ifindex_byname(const mctp_nl *nl, const char *ifname); const char* mctp_nl_if_byindex(const mctp_nl *nl, int index); +uint8_t *mctp_nl_ifaddr_byindex(const mctp_nl *nl, int index, size_t *ret_len); int mctp_nl_net_byindex(const mctp_nl *nl, int index); bool mctp_nl_up_byindex(const mctp_nl *nl, int index); /* Caller to free */ From 73e256730eb7e52572b370946795be2ffa935211 Mon Sep 17 00:00:00 2001 From: Khang Nguyen Date: Mon, 15 Jul 2024 15:45:44 +0700 Subject: [PATCH 2/2] mctpd: Send Discovery Notify on Endpoint role set Implement the first step of partial discovery, which is notifying the bus owner of our presence on the bus. Tested: Discovery Notify message is sent when setting role on interface. Jul 15 08:33:42 evb-endpoint mctpd[3322]: mctpd: read_message got from sockaddr_mctp_ext eid 8 net 1 type 0x00 if 2 hw len 2 0x80:08 len 3 Jul 15 08:33:42 evb-endpoint mctpd[3322]: mctpd: Failure completion code 0x05 from physaddr if 2 hw len 2 0x00:00 Jul 15 08:33:42 evb-endpoint mctpd[3322]: mctpd: Warning: discovery notify on interface 'mctppcie0' failed: Connection refused (My Root Complex does not handle Discovery Notify message yet, but can confirm that the message is sent) Signed-off-by: Khang Nguyen Duy --- CHANGELOG.md | 1 + src/mctpd.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20a20a0..a1dfa60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 5. mctpd: New test infrastructure for control procotol messaging to mctpd 6. mctpd: Add a configuration file facility, defaulting to /etc/mctpd.conf. 7. mctpd: Add mctp/interfaces/ D-Bus object +8. mctpd: Send Discovery Notify on Endpoint role set ### Changed diff --git a/src/mctpd.c b/src/mctpd.c index b16e456..f9848ec 100644 --- a/src/mctpd.c +++ b/src/mctpd.c @@ -2895,6 +2895,48 @@ static int bus_link_get_prop(sd_bus *bus, return rc; } +static int notify_discovery(ctx *ctx, int ifindex) +{ + int rc = 0; + dest_phys desti = { 0 }, *dest = &desti; + struct mctp_ctrl_cmd_discovery_notify req = { 0 }; + struct mctp_ctrl_resp_discovery_notify *resp; + uint8_t *buf; + size_t buf_size; + struct sockaddr_mctp_ext resp_addr; + + dest->ifindex = ifindex; + mctp_nl_ifaddr_byindex(ctx->nl, dest->ifindex, &dest->hwaddr_len); + memset(dest->hwaddr, 0, sizeof dest->hwaddr); + + req.ctrl_hdr.command_code = MCTP_CTRL_CMD_DISCOVERY_NOTIFY; + req.ctrl_hdr.rq_dgram_inst = RQDI_REQ; + + rc = endpoint_query_phys(ctx, dest, MCTP_CTRL_HDR_MSG_TYPE, &req, + sizeof(req), &buf, &buf_size, &resp_addr); + if (rc < 0) + goto free_buf; + + if (buf_size != sizeof(*resp)) { + warnx("%s: wrong reply length %zu bytes. dest %s", __func__, + buf_size, dest_phys_tostr(dest)); + rc = -ENOMSG; + goto free_buf; + } + resp = (void *)buf; + + if (resp->completion_code != 0) { + // TODO: make this a debug message? + warnx("Failure completion code 0x%02x from %s", + resp->completion_code, dest_phys_tostr(dest)); + rc = -ECONNREFUSED; + goto free_buf; + } +free_buf: + free(buf); + 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) @@ -2906,6 +2948,7 @@ static int bus_link_set_prop(sd_bus *bus, link_userdata *lmUserData; int rc; struct role role; + int ifindex; if (!is_interfaces_path(path)) { sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, @@ -2921,11 +2964,13 @@ static int bus_link_set_prop(sd_bus *bus, goto out; } - lmUserData = mctp_nl_get_link_userdata_byname(ctx->nl, link_name); - if (!lmUserData) { + ifindex = mctp_nl_ifindex_byname(ctx->nl, link_name); + if (!ifindex) { rc = -ENOENT; goto out; } + lmUserData = mctp_nl_get_link_userdata(ctx->nl, ifindex); + assert(lmUserData); if (strcmp(property, "Role") != 0) { printf("Unknown property '%s' for %s iface %s\n", property, path, interface); @@ -2956,6 +3001,16 @@ static int bus_link_set_prop(sd_bus *bus, } lmUserData->role = role.role; + // Announce on the bus we are endpoint, print warning and ignore error if failed + if (lmUserData->role == ENDPOINT_ROLE_ENDPOINT) { + rc = notify_discovery(ctx, ifindex); + if (rc) { + warnx("Warning: discovery notify on interface '%s' failed: %s", link_name, + strerror(-rc)); + rc = 0; + } + } + out: set_berr(ctx, rc, berr); return rc;