From nobody Fri May 3 00:16:12 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VVrv11cLFz5KK7d; Fri, 3 May 2024 00:16:13 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VVrv03pb4z4RGg; Fri, 3 May 2024 00:16:12 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714695372; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YzxYP9ukcJrNPiTjqbgseh7vl3xypfAICSnLNHMF4fU=; b=S0fj0xQTD3BXBg6/8/xsX7BPCHbye/j2Q8nl0l/L8lxv4YUmgxwVcRQwl+myti/5itj2zf I1DE6Feaw/3e6zAier4BwG4m1/gcOGLHaHABTwmj2QtvlOd7PblOW1ZJi3Ly4fHD+Jn83H WZi6e3KmOFfdp278bOooPOYVHp9hX6cRkyoI2vPNQzD9kzgW019Awb3opeTKKvD9mKR+tZ dsWVHIb4B3vfxLsfw0pZkBy7RANKanH65Vo2DpI1Qs5y1LqMy7G6DXhv8gL3JrZOwijipd w60f3pkbl9lnKERvTJlpdq7MaVPoutqHEL/j478cgR5HeTSr1I4aYAhiuour3Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1714695372; a=rsa-sha256; cv=none; b=n9/2EK8qKxqbrY0hgRwnlAy1uxAvdykCcpg2NP0rmKGwdb4EzxahWlX2gTvRW41A/bbsn9 09o7JEwEhXcKZHDHu0Dmr0XBD7U+FYjxFjyGtQZcGpVr2nPnQ3hnctgbOgiXn2W846iUTB tK2VyTGX08P/irvSmW8LPhEoogNxbKu53LYQkQjSYXLOoCoryqApKfw2ugQzHDv6Vp+yx+ NAgFwOjAJ/IIVGTycyxOpWoq5qgegdfb6PgDKDxb6zKJG1epJ9T2gMscqfbBmpDx2x4tas oQN/br1oDx0h+VbIwIGpzVPfOOU4MgUDCQ99Sc5M7oWfhtoXXKonPWI1ZhOZVw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714695372; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YzxYP9ukcJrNPiTjqbgseh7vl3xypfAICSnLNHMF4fU=; b=QRl4XLHyDfW8WFA1vgarL5GTd0Wc2nY5tP8w1VT9OXQcS3m0Gyi9jDsCFeMQNjsCfbR1ob B3mJBR9TA7bezhU7jM5ADuPa7ebsPSw8xFNgu+J/iqnv9HZxiy52XCt+6EXnJTrQ2ySZIW VK4e/Xtp1sR3zP3AkK7gWhE3LsqjOjLU4U38tnS65sQxWHZE0hmOmSyDT87Z0Al2PZsVso Q8mC75rk8uwHmt462aliSQrQkd6ucuSM9yPZTnIkXbLQ23bD1o4oZ40b3lRXgBW6Zvpb3i wjkgKDvd7zSyIu5aZ84X2cVLkIVbVKqp6uwbCLhG8o2RtcSIxXb7JFBKRpNZKA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VVrv03Q01zP3F; Fri, 3 May 2024 00:16:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 4430GCHd080251; Fri, 3 May 2024 00:16:12 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 4430GC8b080248; Fri, 3 May 2024 00:16:12 GMT (envelope-from git) Date: Fri, 3 May 2024 00:16:12 GMT Message-Id: <202405030016.4430GC8b080248@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: John Baldwin Subject: git: 4f9fa31c5c2c - main - ctladm: Add nvlist command to list active NVMeoF associations List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jhb X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 4f9fa31c5c2ce78482677331e396cf104ae9b33f Auto-Submitted: auto-generated The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=4f9fa31c5c2ce78482677331e396cf104ae9b33f commit 4f9fa31c5c2ce78482677331e396cf104ae9b33f Author: John Baldwin AuthorDate: 2024-05-02 23:35:02 +0000 Commit: John Baldwin CommitDate: 2024-05-02 23:38:39 +0000 ctladm: Add nvlist command to list active NVMeoF associations Reviewed by: imp Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D44728 --- usr.sbin/ctladm/ctladm.8 | 17 +++- usr.sbin/ctladm/ctladm.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 269 insertions(+), 2 deletions(-) diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8 index ba2712cb278c..6e084c30de36 100644 --- a/usr.sbin/ctladm/ctladm.8 +++ b/usr.sbin/ctladm/ctladm.8 @@ -35,7 +35,7 @@ .\" .\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $ .\" -.Dd December 27, 2023 +.Dd May 2, 2024 .Dt CTLADM 8 .Os .Sh NAME @@ -198,6 +198,10 @@ .Ic isterminate .Aq Fl a | Fl c Ar connection-id | Fl i Ar name | Fl p Ar portal .Nm +.Ic nvlist +.Op Fl v +.Op Fl x +.Nm .Ic help .Sh DESCRIPTION The @@ -861,6 +865,17 @@ Specify initiator name. .It Fl p Specify initiator portal (hostname or IP address). .El +.It Ic nvlist +Get a list of currently running NVMeoF associations. +This includes host and controller names and the unique controller IDs. +.Bl -tag -width 11n +.It Fl v +Verbose mode. +.It Fl x +Dump the raw XML. +The sessions list information from the kernel comes in XML format, and this +option allows the display of the raw XML data. +.El .It Ic help Display .Nm diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index 36cedf548ae5..d0456986fd12 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #include #include "ctladm.h" @@ -113,7 +114,8 @@ typedef enum { CTLADM_CMD_ISLIST, CTLADM_CMD_ISLOGOUT, CTLADM_CMD_ISTERMINATE, - CTLADM_CMD_LUNMAP + CTLADM_CMD_LUNMAP, + CTLADM_CMD_NVLIST } ctladm_cmdfunction; typedef enum { @@ -179,6 +181,7 @@ static struct ctladm_opts option_table[] = { {"lunmap", CTLADM_CMD_LUNMAP, CTLADM_ARG_NONE, "p:l:L:"}, {"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"}, {"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:o:s:"}, + {"nvlist", CTLADM_CMD_NVLIST, CTLADM_ARG_NONE, "vx"}, {"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:O:d:crp:qt:w:W:x"}, {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ilp:qvx"}, {"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"}, @@ -3818,6 +3821,251 @@ cctl_lunmap(int fd, int argc, char **argv, char *combinedopt) return (retval); } +struct cctl_nvlist_conn { + int connection_id; + char *hostnqn; + char *subnqn; + int trtype; + STAILQ_ENTRY(cctl_nvlist_conn) links; +}; + +struct cctl_nvlist_data { + int num_conns; + STAILQ_HEAD(,cctl_nvlist_conn) conn_list; + struct cctl_nvlist_conn *cur_conn; + u_int level; + struct sbuf *cur_sb[32]; +}; + +static void +cctl_nvlist_start_element(void *user_data, const char *name, const char **attr) +{ + int i; + struct cctl_nvlist_data *nvlist; + struct cctl_nvlist_conn *cur_conn; + + nvlist = (struct cctl_nvlist_data *)user_data; + cur_conn = nvlist->cur_conn; + nvlist->level++; + if ((u_int)nvlist->level >= nitems(nvlist->cur_sb)) + errx(1, "%s: too many nesting levels, %zd max", __func__, + nitems(nvlist->cur_sb)); + + nvlist->cur_sb[nvlist->level] = sbuf_new_auto(); + if (nvlist->cur_sb[nvlist->level] == NULL) + err(1, "%s: Unable to allocate sbuf", __func__); + + if (strcmp(name, "connection") == 0) { + if (cur_conn != NULL) + errx(1, "%s: improper connection element nesting", + __func__); + + cur_conn = calloc(1, sizeof(*cur_conn)); + if (cur_conn == NULL) + err(1, "%s: cannot allocate %zd bytes", __func__, + sizeof(*cur_conn)); + + nvlist->num_conns++; + nvlist->cur_conn = cur_conn; + + STAILQ_INSERT_TAIL(&nvlist->conn_list, cur_conn, links); + + for (i = 0; attr[i] != NULL; i += 2) { + if (strcmp(attr[i], "id") == 0) { + cur_conn->connection_id = + strtoull(attr[i+1], NULL, 0); + } else { + errx(1, + "%s: invalid connection attribute %s = %s", + __func__, attr[i], attr[i+1]); + } + } + } +} + +static void +cctl_nvlist_end_element(void *user_data, const char *name) +{ + struct cctl_nvlist_data *nvlist; + struct cctl_nvlist_conn *cur_conn; + char *str; + + nvlist = (struct cctl_nvlist_data *)user_data; + cur_conn = nvlist->cur_conn; + + if ((cur_conn == NULL) && (strcmp(name, "ctlnvmflist") != 0)) + errx(1, "%s: cur_conn == NULL! (name = %s)", __func__, name); + + if (nvlist->cur_sb[nvlist->level] == NULL) + errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, + nvlist->level, name); + + sbuf_finish(nvlist->cur_sb[nvlist->level]); + str = strdup(sbuf_data(nvlist->cur_sb[nvlist->level])); + if (str == NULL) + err(1, "%s can't allocate %zd bytes for string", __func__, + sbuf_len(nvlist->cur_sb[nvlist->level])); + + sbuf_delete(nvlist->cur_sb[nvlist->level]); + nvlist->cur_sb[nvlist->level] = NULL; + nvlist->level--; + + if (strcmp(name, "hostnqn") == 0) { + cur_conn->hostnqn = str; + str = NULL; + } else if (strcmp(name, "subnqn") == 0) { + cur_conn->subnqn = str; + str = NULL; + } else if (strcmp(name, "trtype") == 0) { + cur_conn->trtype = atoi(str); + str = NULL; + } else if (strcmp(name, "connection") == 0) { + nvlist->cur_conn = NULL; + } else if (strcmp(name, "ctlnvmflist") == 0) { + /* Nothing. */ + } else { + /* + * Unknown element; ignore it for forward compatibility. + */ + } + + free(str); +} + +static void +cctl_nvlist_char_handler(void *user_data, const XML_Char *str, int len) +{ + struct cctl_nvlist_data *nvlist; + + nvlist = (struct cctl_nvlist_data *)user_data; + + sbuf_bcat(nvlist->cur_sb[nvlist->level], str, len); +} + +static const char * +nvmf_transport_descr(u_int trtype) +{ + static char buf[16]; + + switch (trtype) { + case NVMF_TRTYPE_RDMA: + return ("RDMA"); + case NVMF_TRTYPE_FC: + return ("Fibre Channel"); + case NVMF_TRTYPE_TCP: + return ("TCP"); + default: + snprintf(buf, sizeof(buf), "%#x", trtype); + return (buf); + } +} + +static int +cctl_nvlist(int fd, int argc, char **argv, char *combinedopt) +{ + struct ctl_nvmf req; + struct cctl_nvlist_data nvlist; + struct cctl_nvlist_conn *conn; + XML_Parser parser; + char *conn_str; + int conn_len; + int dump_xml = 0; + int c, retval, verbose = 0; + + retval = 0; + conn_len = 4096; + + bzero(&nvlist, sizeof(nvlist)); + STAILQ_INIT(&nvlist.conn_list); + + while ((c = getopt(argc, argv, combinedopt)) != -1) { + switch (c) { + case 'v': + verbose = 1; + break; + case 'x': + dump_xml = 1; + break; + default: + break; + } + } + +retry: + conn_str = malloc(conn_len); + + bzero(&req, sizeof(req)); + req.type = CTL_NVMF_LIST; + req.data.list.alloc_len = conn_len; + req.data.list.conn_xml = conn_str; + + if (ioctl(fd, CTL_NVMF, &req) == -1) { + warn("%s: error issuing CTL_NVMF ioctl", __func__); + retval = 1; + goto bailout; + } + + if (req.status == CTL_NVMF_ERROR) { + warnx("%s: error returned from CTL_NVMF ioctl:\n%s", + __func__, req.error_str); + } else if (req.status == CTL_NVMF_LIST_NEED_MORE_SPACE) { + conn_len = conn_len << 1; + goto retry; + } + + if (dump_xml != 0) { + printf("%s", conn_str); + goto bailout; + } + + parser = XML_ParserCreate(NULL); + if (parser == NULL) { + warn("%s: Unable to create XML parser", __func__); + retval = 1; + goto bailout; + } + + XML_SetUserData(parser, &nvlist); + XML_SetElementHandler(parser, cctl_nvlist_start_element, + cctl_nvlist_end_element); + XML_SetCharacterDataHandler(parser, cctl_nvlist_char_handler); + + retval = XML_Parse(parser, conn_str, strlen(conn_str), 1); + if (retval != 1) { + warnx("%s: Unable to parse XML: Error %d", __func__, + XML_GetErrorCode(parser)); + XML_ParserFree(parser); + retval = 1; + goto bailout; + } + retval = 0; + XML_ParserFree(parser); + + if (verbose != 0) { + STAILQ_FOREACH(conn, &nvlist.conn_list, links) { + printf("%-25s %d\n", "Controller ID:", conn->connection_id); + printf("%-25s %s\n", "Host NQN:", conn->hostnqn); + printf("%-25s %s\n", "Subsystem NQN:", conn->subnqn); + printf("%-25s %s\n", "Transport:", + nvmf_transport_descr(conn->trtype)); + printf("\n"); + } + } else { + printf("%4s %-16s %-36s %-36s\n", "ID", "Transport", "HostNQN", + "SubNQN"); + STAILQ_FOREACH(conn, &nvlist.conn_list, links) { + printf("%4u %-16s %-36s %-36s\n", + conn->connection_id, + nvmf_transport_descr(conn->trtype), + conn->hostnqn, conn->subnqn); + } + } +bailout: + free(conn_str); + + return (retval); +} + void usage(int error) { @@ -3864,6 +4112,7 @@ usage(int error) " ctladm islist [-v | -x]\n" " ctladm islogout <-a | -c connection-id | -i name | -p portal>\n" " ctladm isterminate <-a | -c connection-id | -i name | -p portal>\n" +" ctladm nvlist [-v | -x]\n" " ctladm dumpooa\n" " ctladm dumpstructs\n" " ctladm help\n" @@ -4260,6 +4509,9 @@ main(int argc, char **argv) case CTLADM_CMD_ISTERMINATE: retval = cctl_isterminate(fd, argc, argv, combinedopt); break; + case CTLADM_CMD_NVLIST: + retval = cctl_nvlist(fd, argc, argv, combinedopt); + break; case CTLADM_CMD_HELP: default: usage(retval);