From 675c5592e7a8e826949fca5d4b4cf3f5fb3cf183 Mon Sep 17 00:00:00 2001 From: Seth Howell Date: Tue, 4 Dec 2018 15:09:31 -0700 Subject: [PATCH] nvme_bdev: add parsing for hostaddr and hostsvcid This allows us to specify the host-side configuration for each controller to which we connect. Change-Id: Iac2aed3934d4a326f45546f2f541e374308e2589 Signed-off-by: Seth Howell Reviewed-on: https://review.gerrithub.io/436219 Tested-by: SPDK CI Jenkins Chandler-Test-Pool: SPDK Automated Test System Reviewed-by: Ben Walker Reviewed-by: Jim Harris --- CHANGELOG.md | 3 ++ etc/spdk/nvmf.conf.in | 1 + include/spdk/nvme.h | 54 +++++++++++++++++++++++++++++ lib/bdev/nvme/bdev_nvme.c | 16 +++++++++ lib/nvme/nvme.c | 63 ++++++++++++++++++++++++++++++++++ test/nvmf/shutdown/shutdown.sh | 2 +- 6 files changed, 138 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a43d32e9..7031f74fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ same TCP/IP support. Added API, spdk_nvme_ctrlr_is_discovery(), to indicate whether the ctrlr arg refers to a Discovery Controller or not. +Added an API function `spdk_nvme_host_id_parse` and corresponding object `spdk_nvme_host_id` +for parsing host address and host service ID arguments on a per connection basis. + ### NVMe-oF Target The `spdk_nvmf_tgt_opts` struct has been deprecated in favor of `spdk_nvmf_transport_opts`. diff --git a/etc/spdk/nvmf.conf.in b/etc/spdk/nvmf.conf.in index 811d3e48f..8b13bbaa0 100644 --- a/etc/spdk/nvmf.conf.in +++ b/etc/spdk/nvmf.conf.in @@ -102,6 +102,7 @@ TransportID "trtype:PCIe traddr:0000:01:00.0" Nvme1 TransportID "trtype:PCIe traddr:0000:02:00.0" Nvme2 TransportID "trtype:PCIe traddr:0000:03:00.0" Nvme3 + TransportID "trtypr:RDMA traddr:192.168.100.8 trsvcid:4420 hostaddr:192.168.100.9" Nvme4 # The number of attempts per I/O when an I/O fails. Do not include # this key to get the default behavior. diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index c212f5d1a..0252cfb5e 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -279,6 +279,35 @@ struct spdk_nvme_transport_id { char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1]; }; +/** + * NVMe host identifier + * + * Used for defining the host identity for an NVMe-oF connection. + * + * In terms of configuration, this object can be considered a subtype of TransportID + * Please see etc/spdk/nvmf.conf.in for more details. + * + * A string representation of this type may be converted to this type using + * spdk_nvme_host_id_parse(). + */ +struct spdk_nvme_host_id { + /** + * Transport address to be used by the host when connecting to the NVMe-oF endpoint. + * May be an IP address or a zero length string for transports which + * use IP addressing (e.g. RDMA). + * For PCIe and FC this is always a zero length string. + */ + char hostaddr[SPDK_NVMF_TRADDR_MAX_LEN + 1]; + + /** + * Transport service ID used by the host when connecting to the NVMe. + * May be a port number or a zero length string for transports which + * use IP addressing (e.g. RDMA). + * For PCIe and FC this is always a zero length string. + */ + char hostsvcid[SPDK_NVMF_TRSVCID_MAX_LEN + 1]; +}; + /** * Parse the string representation of a transport ID. * @@ -304,6 +333,31 @@ struct spdk_nvme_transport_id { */ int spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str); +/** + * Parse the string representation of a host ID. + * + * \param hostid Output host ID structure (must be allocated and initialized by caller). + * \param str Input string representation of a transport ID to parse (hostid is a sub-configuration). + * + * str must be a zero-terminated C string containing one or more key:value pairs + * separated by whitespace. + * + * Key | Value + * -------------- | ----- + * hostaddr | Transport address (e.g. 192.168.100.8 for RDMA) + * hostsvcid | Transport service identifier (e.g. 4420) + * + * Unspecified fields of trid are left unmodified, so the caller must initialize + * hostid (for example, memset() to 0) before calling this function. + * + * This function should not be used with Fiber Channel or PCIe as these transports + * do not require host information for connections. + * + * \return 0 if parsing was successful and hostid is filled out, or negated errno + * values on failure. + */ +int spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str); + /** * Parse the string representation of a transport ID tranport type. * diff --git a/lib/bdev/nvme/bdev_nvme.c b/lib/bdev/nvme/bdev_nvme.c index 99bf6f399..591caac24 100644 --- a/lib/bdev/nvme/bdev_nvme.c +++ b/lib/bdev/nvme/bdev_nvme.c @@ -90,6 +90,7 @@ enum data_direction { struct nvme_probe_ctx { size_t count; struct spdk_nvme_transport_id trids[NVME_MAX_CONTROLLERS]; + struct spdk_nvme_host_id hostids[NVME_MAX_CONTROLLERS]; const char *names[NVME_MAX_CONTROLLERS]; const char *hostnqn; }; @@ -1384,6 +1385,13 @@ bdev_nvme_library_init(void) goto end; } + rc = spdk_nvme_host_id_parse(&probe_ctx->hostids[i], val); + if (rc < 0) { + SPDK_ERRLOG("Unable to parse HostID: %s\n", val); + rc = -1; + goto end; + } + val = spdk_conf_section_get_nmval(sp, "TransportID", i, 1); if (val == NULL) { SPDK_ERRLOG("No name provided for TransportID\n"); @@ -1417,6 +1425,14 @@ bdev_nvme_library_init(void) snprintf(opts.hostnqn, sizeof(opts.hostnqn), "%s", probe_ctx->hostnqn); } + if (probe_ctx->hostids[i].hostaddr[0] != '\0') { + snprintf(opts.src_addr, sizeof(opts.src_addr), "%s", probe_ctx->hostids[i].hostaddr); + } + + if (probe_ctx->hostids[i].hostsvcid[0] != '\0') { + snprintf(opts.src_svcid, sizeof(opts.src_svcid), "%s", probe_ctx->hostids[i].hostsvcid); + } + ctrlr = spdk_nvme_connect(&probe_ctx->trids[i], &opts, sizeof(opts)); if (ctrlr == NULL) { SPDK_ERRLOG("Unable to connect to provided trid (traddr: %s)\n", diff --git a/lib/nvme/nvme.c b/lib/nvme/nvme.c index b2da4527d..9f4781742 100644 --- a/lib/nvme/nvme.c +++ b/lib/nvme/nvme.c @@ -828,6 +828,10 @@ spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *st return -EINVAL; } memcpy(trid->subnqn, val, val_len + 1); + } else if (strcasecmp(key, "hostaddr") == 0) { + continue; + } else if (strcasecmp(key, "hostsvcid") == 0) { + continue; } else if (strcasecmp(key, "ns") == 0) { /* * Special case. The namespace id parameter may @@ -848,6 +852,65 @@ spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *st return 0; } +int +spdk_nvme_host_id_parse(struct spdk_nvme_host_id *hostid, const char *str) +{ + + size_t key_size = 32; + size_t val_size = 1024; + size_t val_len; + char key[key_size]; + char val[val_size]; + + if (hostid == NULL || str == NULL) { + return -EINVAL; + } + + while (*str != '\0') { + + val_len = parse_next_key(&str, key, val, key_size, val_size); + + if (val_len == 0) { + SPDK_ERRLOG("Failed to parse host ID\n"); + return val_len; + } + + /* Ignore the rest of the options from the transport ID. */ + if (strcasecmp(key, "trtype") == 0) { + continue; + } else if (strcasecmp(key, "adrfam") == 0) { + continue; + } else if (strcasecmp(key, "traddr") == 0) { + continue; + } else if (strcasecmp(key, "trsvcid") == 0) { + continue; + } else if (strcasecmp(key, "subnqn") == 0) { + continue; + } else if (strcasecmp(key, "ns") == 0) { + continue; + } else if (strcasecmp(key, "hostaddr") == 0) { + if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) { + SPDK_ERRLOG("hostaddr length %zu greater than maximum allowed %u\n", + val_len, SPDK_NVMF_TRADDR_MAX_LEN); + return -EINVAL; + } + memcpy(hostid->hostaddr, val, val_len + 1); + + } else if (strcasecmp(key, "hostsvcid") == 0) { + if (val_len > SPDK_NVMF_TRSVCID_MAX_LEN) { + SPDK_ERRLOG("trsvcid length %zu greater than maximum allowed %u\n", + val_len, SPDK_NVMF_TRSVCID_MAX_LEN); + return -EINVAL; + } + memcpy(hostid->hostsvcid, val, val_len + 1); + } else { + SPDK_ERRLOG("Unknown transport ID key '%s'\n", key); + } + } + + return 0; +} + static int cmp_int(int a, int b) { diff --git a/test/nvmf/shutdown/shutdown.sh b/test/nvmf/shutdown/shutdown.sh index 2ea196f44..da4df979a 100755 --- a/test/nvmf/shutdown/shutdown.sh +++ b/test/nvmf/shutdown/shutdown.sh @@ -56,7 +56,7 @@ do done $rpc_py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode$i -t rdma -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT - echo " TransportID \"trtype:RDMA adrfam:IPv4 subnqn:nqn.2016-06.io.spdk:cnode$i traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT\" Nvme$i" >> $testdir/bdevperf.conf + echo " TransportID \"trtype:RDMA adrfam:IPv4 subnqn:nqn.2016-06.io.spdk:cnode$i traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT hostaddr:$NVMF_FIRST_TARGET_IP\" Nvme$i" >> $testdir/bdevperf.conf done # Test 1: Kill the initiator unexpectedly with no I/O outstanding