Loading include/spdk/nvme.h +23 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading lib/nvme/nvme.c +119 −0 Original line number Diff line number Diff line Loading @@ -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) test/lib/nvme/unit/nvme_c/nvme_ut.c +26 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); Loading Loading
include/spdk/nvme.h +23 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading
lib/nvme/nvme.c +119 −0 Original line number Diff line number Diff line Loading @@ -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)
test/lib/nvme/unit/nvme_c/nvme_ut.c +26 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); Loading