nvme: add transport ID string parsing function

Change-Id: I33c15c8a56c25667567b373d21a117cca1f756c7
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Daniel Verkamp 2017-01-13 14:36:26 -07:00
parent 57fbfa0abe
commit be8a9d6966
3 changed files with 168 additions and 1 deletions

View File

@ -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.
*

View File

@ -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)

View File

@ -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();