Commit be8a9d69 authored by Daniel Verkamp's avatar Daniel Verkamp
Browse files

nvme: add transport ID string parsing function



Change-Id: I33c15c8a56c25667567b373d21a117cca1f756c7
Signed-off-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent 57fbfa0a
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -169,6 +169,29 @@ struct spdk_nvme_transport_id {
	char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
};

/**
 * Parse the string representation of a transport ID.
 *
 * \param trid Output transport ID structure (must be allocated and initialized by caller).
 * \param str Input string representation of a transport ID to parse.
 * \return 0 if parsing was successful and trid is filled out, or negated errno values on failure.
 *
 * str must be a zero-terminated C string containing one or more key:value pairs separated by
 * whitespace.
 *
 * Key          | Value
 * ------------ | -----
 * trtype       | Transport type (e.g. PCIe, RDMA)
 * adrfam       | Address family (e.g. IPv4, IPv6)
 * traddr       | Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)
 * trsvcid      | Transport service identifier (e.g. 4420)
 * subnqn       | Subsystem NQN
 *
 * Unspecified fields of trid are left unmodified, so the caller must initialize trid (for example,
 * memset() to 0) before calling this function.
 */
int spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str);

/**
 * Determine whether the NVMe library can handle a specific NVMe over Fabrics transport type.
 *
+119 −0
Original line number Diff line number Diff line
@@ -443,4 +443,123 @@ spdk_nvme_probe(const struct spdk_nvme_transport_id *trid, void *cb_ctx,
	return rc;
}

static int
parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
{
	if (strcasecmp(str, "PCIe") == 0) {
		*trtype = SPDK_NVME_TRANSPORT_PCIE;
	} else if (strcasecmp(str, "RDMA") == 0) {
		*trtype = SPDK_NVME_TRANSPORT_RDMA;
	} else {
		return -ENOENT;
	}
	return 0;
}

static int
parse_adrfam(enum spdk_nvmf_adrfam *adrfam, const char *str)
{
	if (strcasecmp(str, "IPv4") == 0) {
		*adrfam = SPDK_NVMF_ADRFAM_IPV4;
	} else if (strcasecmp(str, "IPv6") == 0) {
		*adrfam = SPDK_NVMF_ADRFAM_IPV6;
	} else if (strcasecmp(str, "IB") == 0) {
		*adrfam = SPDK_NVMF_ADRFAM_IB;
	} else if (strcasecmp(str, "FC") == 0) {
		*adrfam = SPDK_NVMF_ADRFAM_FC;
	} else {
		return -ENOENT;
	}
	return 0;
}

int
spdk_nvme_transport_id_parse(struct spdk_nvme_transport_id *trid, const char *str)
{
	const char *sep;
	const char *whitespace = " \t\n";
	size_t key_len, val_len;
	char key[32];
	char val[1024];

	if (trid == NULL || str == NULL) {
		return -EINVAL;
	}

	while (*str != '\0') {
		str += strspn(str, whitespace);

		sep = strchr(str, ':');
		if (!sep) {
			SPDK_ERRLOG("Key without : separator\n");
			return -EINVAL;
		}

		key_len = sep - str;
		if (key_len >= sizeof(key)) {
			SPDK_ERRLOG("Transport key length %zu greater than maximum allowed %zu\n",
				    key_len, sizeof(key) - 1);
			return -EINVAL;
		}

		memcpy(key, str, key_len);
		key[key_len] = '\0';

		str += key_len + 1; /* Skip key: */
		val_len = strcspn(str, whitespace);
		if (val_len == 0) {
			SPDK_ERRLOG("Key without value\n");
			return -EINVAL;
		}

		if (val_len >= sizeof(val)) {
			SPDK_ERRLOG("Transport value length %zu greater than maximum allowed %zu\n",
				    val_len, sizeof(val) - 1);
			return -EINVAL;
		}

		memcpy(val, str, val_len);
		val[val_len] = '\0';

		str += val_len;

		if (strcasecmp(key, "trtype") == 0) {
			if (parse_trtype(&trid->trtype, val) != 0) {
				SPDK_ERRLOG("Unknown trtype '%s'\n", val);
				return -EINVAL;
			}
		} else if (strcasecmp(key, "adrfam") == 0) {
			if (parse_adrfam(&trid->adrfam, val) != 0) {
				SPDK_ERRLOG("Unknown adrfam '%s'\n", val);
				return -EINVAL;
			}
		} else if (strcasecmp(key, "traddr") == 0) {
			if (val_len > SPDK_NVMF_TRADDR_MAX_LEN) {
				SPDK_ERRLOG("traddr length %zu greater than maximum allowed %u\n",
					    val_len, SPDK_NVMF_TRADDR_MAX_LEN);
				return -EINVAL;
			}
			memcpy(trid->traddr, val, val_len + 1);
		} else if (strcasecmp(key, "trsvcid") == 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(trid->trsvcid, val, val_len + 1);
		} else if (strcasecmp(key, "subnqn") == 0) {
			if (val_len > SPDK_NVMF_NQN_MAX_LEN) {
				SPDK_ERRLOG("subnqn length %zu greater than maximum allowed %u\n",
					    val_len, SPDK_NVMF_NQN_MAX_LEN);
				return -EINVAL;
			}
			memcpy(trid->subnqn, val, val_len + 1);
		} else {
			SPDK_ERRLOG("Unknown transport ID key '%s'\n", key);
		}
	}

	return 0;
}

SPDK_LOG_REGISTER_TRACE_FLAG("nvme", SPDK_TRACE_NVME)
+26 −1
Original line number Diff line number Diff line
@@ -162,6 +162,30 @@ test_opc_data_transfer(void)
	CU_ASSERT(xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST);
}

static void
test_trid_parse(void)
{
	struct spdk_nvme_transport_id trid;

	memset(&trid, 0, sizeof(trid));
	CU_ASSERT(spdk_nvme_transport_id_parse(&trid,
					       "trtype:rdma\n"
					       "adrfam:ipv4\n"
					       "traddr:192.168.100.8\n"
					       "trsvcid:4420\n"
					       "subnqn:nqn.2014-08.org.nvmexpress.discovery") == 0);
	CU_ASSERT(trid.trtype == SPDK_NVME_TRANSPORT_RDMA);
	CU_ASSERT(trid.adrfam == SPDK_NVMF_ADRFAM_IPV4);
	CU_ASSERT(strcmp(trid.traddr, "192.168.100.8") == 0);
	CU_ASSERT(strcmp(trid.trsvcid, "4420") == 0);
	CU_ASSERT(strcmp(trid.subnqn, "nqn.2014-08.org.nvmexpress.discovery") == 0);

	memset(&trid, 0, sizeof(trid));
	CU_ASSERT(spdk_nvme_transport_id_parse(&trid, "trtype:PCIe traddr:0000:04:00.0") == 0);
	CU_ASSERT(trid.trtype == SPDK_NVME_TRANSPORT_PCIE);
	CU_ASSERT(strcmp(trid.traddr, "0000:04:00.0") == 0);
}

int main(int argc, char **argv)
{
	CU_pSuite	suite = NULL;
@@ -178,7 +202,8 @@ int main(int argc, char **argv)
	}

	if (
		CU_add_test(suite, "test_opc_data_transfer", test_opc_data_transfer) == NULL
		CU_add_test(suite, "test_opc_data_transfer", test_opc_data_transfer) == NULL ||
		CU_add_test(suite, "test_trid_parse", test_trid_parse) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();