1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include "spdk/stdinc.h" 8 #include "spdk_cunit.h" 9 #include "nvme/nvme_fabric.c" 10 #include "common/lib/test_env.c" 11 12 SPDK_LOG_REGISTER_COMPONENT(nvme) 13 14 pid_t g_spdk_nvme_pid; 15 struct spdk_nvmf_fabric_prop_set_cmd g_ut_cmd = {}; 16 struct spdk_nvmf_fabric_prop_get_rsp g_ut_response = {}; 17 18 DEFINE_STUB_V(spdk_nvme_ctrlr_get_default_ctrlr_opts, 19 (struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)); 20 21 DEFINE_STUB(nvme_transport_ctrlr_set_reg_4, int, 22 (struct spdk_nvme_ctrlr *ctrlr, 23 uint32_t offset, uint32_t value), 0); 24 25 DEFINE_STUB_V(nvme_ctrlr_destruct, (struct spdk_nvme_ctrlr *ctrlr)); 26 27 DEFINE_STUB(nvme_ctrlr_cmd_identify, int, 28 (struct spdk_nvme_ctrlr *ctrlr, uint8_t cns, uint16_t cntid, 29 uint32_t nsid, uint8_t csi, void *payload, size_t payload_size, 30 spdk_nvme_cmd_cb cb_fn, void *cb_arg), 0); 31 32 DEFINE_STUB_V(nvme_ctrlr_connected, (struct spdk_nvme_probe_ctx *probe_ctx, 33 struct spdk_nvme_ctrlr *ctrlr)); 34 DEFINE_STUB(nvme_ctrlr_add_process, int, 35 (struct spdk_nvme_ctrlr *ctrlr, void *devhandle), 0); 36 37 DEFINE_STUB(spdk_nvme_ctrlr_cmd_get_log_page, int, 38 (struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page, 39 uint32_t nsid, void *payload, uint32_t payload_size, 40 uint64_t offset, spdk_nvme_cmd_cb cb_fn, void *cb_arg), 0); 41 42 DEFINE_STUB(spdk_nvme_transport_available_by_name, bool, 43 (const char *transport_name), true); 44 45 DEFINE_STUB(nvme_transport_ctrlr_construct, struct spdk_nvme_ctrlr *, 46 (const struct spdk_nvme_transport_id *trid, 47 const struct spdk_nvme_ctrlr_opts *opts, 48 void *devhandle), NULL); 49 50 DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, 51 (enum spdk_nvmf_adrfam adrfam), NULL); 52 53 DEFINE_STUB(nvme_ctrlr_process_init, int, (struct spdk_nvme_ctrlr *ctrlr), 0); 54 55 static struct spdk_nvmf_fabric_connect_data g_nvmf_data; 56 static struct nvme_request *g_request; 57 58 int 59 nvme_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req) 60 { 61 CU_ASSERT(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG); 62 63 g_request = req; 64 memcpy(&g_nvmf_data, req->payload.contig_or_cb_arg, sizeof(g_nvmf_data)); 65 66 return 0; 67 } 68 69 void 70 nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl) 71 { 72 struct nvme_completion_poll_status *status = arg; 73 74 if (status->timed_out) { 75 spdk_free(status->dma_data); 76 free(status); 77 } 78 79 g_request = NULL; 80 } 81 82 static bool g_nvme_wait_for_completion_timeout; 83 84 int 85 nvme_wait_for_completion_robust_lock_timeout_poll(struct spdk_nvme_qpair *qpair, 86 struct nvme_completion_poll_status *status, 87 pthread_mutex_t *robust_mutex) 88 { 89 struct spdk_nvmf_fabric_connect_rsp *rsp = (void *)&status->cpl; 90 91 if (nvme_qpair_is_admin_queue(qpair)) { 92 rsp->status_code_specific.success.cntlid = 1; 93 } 94 95 status->timed_out = g_nvme_wait_for_completion_timeout; 96 97 return 0; 98 } 99 100 int 101 spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring) 102 { 103 int len, i, rc; 104 105 if (trstring == NULL) { 106 return -EINVAL; 107 } 108 109 len = strnlen(trstring, SPDK_NVMF_TRSTRING_MAX_LEN); 110 if (len == SPDK_NVMF_TRSTRING_MAX_LEN) { 111 return -EINVAL; 112 } 113 114 rc = snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", trstring); 115 if (rc < 0) { 116 return rc; 117 } 118 119 /* cast official trstring to uppercase version of input. */ 120 for (i = 0; i < len; i++) { 121 trid->trstring[i] = toupper(trid->trstring[i]); 122 } 123 return 0; 124 } 125 126 static struct spdk_nvme_transport_id g_ut_trid; 127 static bool g_ut_ctrlr_is_probed; 128 129 int 130 nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid, 131 struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle) 132 { 133 g_ut_trid = *trid; 134 g_ut_ctrlr_is_probed = true; 135 136 return 0; 137 } 138 139 const char * 140 spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype) 141 { 142 switch (trtype) { 143 case SPDK_NVME_TRANSPORT_PCIE: 144 return "PCIe"; 145 case SPDK_NVME_TRANSPORT_RDMA: 146 return "RDMA"; 147 case SPDK_NVME_TRANSPORT_FC: 148 return "FC"; 149 case SPDK_NVME_TRANSPORT_TCP: 150 return "TCP"; 151 case SPDK_NVME_TRANSPORT_VFIOUSER: 152 return "VFIOUSER"; 153 case SPDK_NVME_TRANSPORT_CUSTOM: 154 return "CUSTOM"; 155 default: 156 return NULL; 157 } 158 } 159 160 DEFINE_RETURN_MOCK(nvme_wait_for_completion, int); 161 int 162 nvme_wait_for_completion(struct spdk_nvme_qpair *qpair, 163 struct nvme_completion_poll_status *status) 164 { 165 status->timed_out = false; 166 HANDLE_RETURN_MOCK(nvme_wait_for_completion); 167 return 0; 168 } 169 170 DEFINE_RETURN_MOCK(nvme_wait_for_completion_robust_lock, int); 171 int 172 nvme_wait_for_completion_robust_lock(struct spdk_nvme_qpair *qpair, 173 struct nvme_completion_poll_status *status, 174 pthread_mutex_t *robust_mutex) 175 { 176 status->timed_out = false; 177 HANDLE_RETURN_MOCK(nvme_wait_for_completion_robust_lock); 178 return 0; 179 } 180 181 DEFINE_RETURN_MOCK(spdk_nvme_ctrlr_cmd_admin_raw, int); 182 int 183 spdk_nvme_ctrlr_cmd_admin_raw(struct spdk_nvme_ctrlr *ctrlr, 184 struct spdk_nvme_cmd *cmd, 185 void *buf, uint32_t len, 186 spdk_nvme_cmd_cb cb_fn, void *cb_arg) 187 { 188 struct spdk_nvmf_fabric_prop_set_cmd *cmd_tmp = (void *)cmd; 189 struct nvme_completion_poll_status *status = cb_arg; 190 struct spdk_nvmf_fabric_prop_get_rsp *response = (void *)&status->cpl; 191 192 g_ut_cmd.opcode = cmd_tmp->opcode; 193 g_ut_cmd.fctype = cmd_tmp->fctype; 194 g_ut_cmd.ofst = cmd_tmp->ofst; 195 g_ut_cmd.attrib.size = cmd_tmp->attrib.size; 196 197 if (cmd_tmp->fctype == SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET) { 198 g_ut_cmd.value.u64 = cmd_tmp->value.u64; 199 } else if (cmd_tmp->fctype == SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET) { 200 memcpy(&g_ut_response, response, sizeof(g_ut_response)); 201 } 202 203 HANDLE_RETURN_MOCK(spdk_nvme_ctrlr_cmd_admin_raw); 204 return 0; 205 } 206 207 static void 208 abort_request(struct nvme_request *request) 209 { 210 struct spdk_nvme_cpl cpl = { 211 .status = { 212 .sct = SPDK_NVME_SCT_GENERIC, 213 .sc = SPDK_NVME_SC_ABORTED_SQ_DELETION, 214 } 215 }; 216 217 request->cb_fn(request->cb_arg, &cpl); 218 } 219 220 static void 221 test_nvme_fabric_prop_set_cmd(void) 222 { 223 int rc; 224 struct spdk_nvme_ctrlr ctrlr = {}; 225 226 memset(&g_ut_cmd, 0, sizeof(g_ut_cmd)); 227 228 rc = nvme_fabric_prop_set_cmd_sync(&ctrlr, 1024, SPDK_NVMF_PROP_SIZE_8, 4096); 229 CU_ASSERT(rc == 0); 230 CU_ASSERT(g_ut_cmd.opcode == SPDK_NVME_OPC_FABRIC); 231 CU_ASSERT(g_ut_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET); 232 CU_ASSERT(g_ut_cmd.ofst == 1024); 233 CU_ASSERT(g_ut_cmd.attrib.size == SPDK_NVMF_PROP_SIZE_8); 234 CU_ASSERT(g_ut_cmd.value.u64 == 4096); 235 } 236 237 static void 238 test_nvme_fabric_prop_get_cmd(void) 239 { 240 int rc; 241 uint64_t value; 242 struct spdk_nvme_ctrlr ctrlr = {}; 243 244 memset(&g_ut_cmd, 0, sizeof(g_ut_cmd)); 245 memset(&g_ut_response, 0, sizeof(g_ut_response)); 246 value = 0xFFDEADBEEF; 247 248 /* Case 1: size is SPDK_NVMF_PROP_SIZE_4 */ 249 rc = nvme_fabric_prop_get_cmd_sync(&ctrlr, 1024, SPDK_NVMF_PROP_SIZE_4, &value); 250 CU_ASSERT(rc == 0); 251 CU_ASSERT(g_ut_cmd.opcode == SPDK_NVME_OPC_FABRIC); 252 CU_ASSERT(g_ut_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET); 253 CU_ASSERT(g_ut_cmd.ofst == 1024); 254 CU_ASSERT(g_ut_cmd.attrib.size == SPDK_NVMF_PROP_SIZE_4); 255 CU_ASSERT(g_ut_response.value.u32.low == (value & 0xFFFFFFFF)); 256 257 /* Case 2: size is SPDK_NVMF_PROP_SIZE_8 */ 258 memset(&g_ut_cmd, 0, sizeof(g_ut_cmd)); 259 memset(&g_ut_response, 0, sizeof(g_ut_response)); 260 261 rc = nvme_fabric_prop_get_cmd_sync(&ctrlr, 1024, SPDK_NVMF_PROP_SIZE_8, &value); 262 CU_ASSERT(rc == 0); 263 CU_ASSERT(g_ut_cmd.opcode == SPDK_NVME_OPC_FABRIC); 264 CU_ASSERT(g_ut_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET); 265 CU_ASSERT(g_ut_cmd.ofst == 1024); 266 CU_ASSERT(g_ut_cmd.attrib.size == SPDK_NVMF_PROP_SIZE_8); 267 CU_ASSERT(g_ut_response.value.u64 == value); 268 } 269 270 static void 271 test_nvme_fabric_get_discovery_log_page(void) 272 { 273 struct spdk_nvme_ctrlr ctrlr = {}; 274 char buffer[4096] = {}; 275 uint64_t offset = 0; 276 int rc; 277 278 rc = nvme_fabric_get_discovery_log_page(&ctrlr, buffer, sizeof(buffer), offset); 279 CU_ASSERT(rc == 0); 280 281 /* Get log page fail */ 282 MOCK_SET(spdk_nvme_ctrlr_cmd_get_log_page, -EINVAL); 283 284 rc = nvme_fabric_get_discovery_log_page(&ctrlr, buffer, sizeof(buffer), offset); 285 CU_ASSERT(rc == -1); 286 MOCK_CLEAR(spdk_nvme_ctrlr_cmd_get_log_page); 287 288 /* Completion time out */ 289 MOCK_SET(nvme_wait_for_completion, -1); 290 291 rc = nvme_fabric_get_discovery_log_page(&ctrlr, buffer, sizeof(buffer), offset); 292 CU_ASSERT(rc == -1); 293 MOCK_CLEAR(nvme_wait_for_completion); 294 } 295 296 static void 297 test_nvme_fabric_discover_probe(void) 298 { 299 struct spdk_nvmf_discovery_log_page_entry entry = {}; 300 struct spdk_nvme_probe_ctx probe_ctx = {}; 301 char hostnqn[256] = "nqn.2016-06.io.spdk:cnode1"; 302 char traddr[SPDK_NVMF_TRADDR_MAX_LEN] = "192.168.100.8"; 303 char trsvcid[SPDK_NVMF_TRSVCID_MAX_LEN] = "4420"; 304 char trstring[SPDK_NVMF_TRSTRING_MAX_LEN + 1] = "RDMA"; 305 306 entry.trtype = SPDK_NVME_TRANSPORT_RDMA; 307 entry.subtype = SPDK_NVMF_SUBTYPE_NVME; 308 entry.adrfam = SPDK_NVMF_ADRFAM_IPV4; 309 310 memcpy(entry.subnqn, hostnqn, 256); 311 memcpy(entry.traddr, traddr, SPDK_NVMF_TRADDR_MAX_LEN); 312 memcpy(entry.trsvcid, trsvcid, SPDK_NVMF_TRSVCID_MAX_LEN); 313 memcpy(probe_ctx.trid.trstring, trstring, sizeof(probe_ctx.trid.trstring)); 314 315 nvme_fabric_discover_probe(&entry, &probe_ctx, 1); 316 CU_ASSERT(g_ut_ctrlr_is_probed == true); 317 CU_ASSERT(g_ut_trid.trtype == SPDK_NVME_TRANSPORT_RDMA); 318 CU_ASSERT(g_ut_trid.adrfam == SPDK_NVMF_ADRFAM_IPV4); 319 CU_ASSERT(!strncmp(g_ut_trid.trstring, trstring, sizeof(trstring))); 320 CU_ASSERT(!strncmp(g_ut_trid.subnqn, hostnqn, sizeof(hostnqn))); 321 CU_ASSERT(!strncmp(g_ut_trid.traddr, traddr, sizeof(traddr))); 322 CU_ASSERT(!strncmp(g_ut_trid.trsvcid, trsvcid, sizeof(trsvcid))); 323 324 g_ut_ctrlr_is_probed = false; 325 memset(&g_ut_trid, 0, sizeof(g_ut_trid)); 326 327 /* Entry type unsupported */ 328 entry.subtype = SPDK_NVMF_SUBTYPE_DISCOVERY; 329 330 nvme_fabric_discover_probe(&entry, &probe_ctx, 1); 331 CU_ASSERT(g_ut_ctrlr_is_probed == false); 332 333 /* Entry type invalid */ 334 entry.subtype = 3; 335 336 nvme_fabric_discover_probe(&entry, &probe_ctx, 1); 337 CU_ASSERT(g_ut_ctrlr_is_probed == false); 338 } 339 340 static void 341 test_nvme_fabric_qpair_connect(void) 342 { 343 struct spdk_nvme_qpair qpair = {}; 344 struct nvme_request reserved_req = {}; 345 struct nvme_request req = {}; 346 struct spdk_nvme_ctrlr ctrlr = {}; 347 struct spdk_nvmf_fabric_connect_cmd *cmd = NULL; 348 int rc; 349 char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1] = "nqn.2016-06.io.spdk:host1"; 350 char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1] = "nqn.2016-06.io.spdk:subsystem1"; 351 const uint8_t hostid[16] = { 352 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 353 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F 354 }; 355 356 cmd = (void *)&reserved_req.cmd; 357 qpair.ctrlr = &ctrlr; 358 req.qpair = &qpair; 359 reserved_req.qpair = &qpair; 360 STAILQ_INIT(&qpair.free_req); 361 STAILQ_INSERT_HEAD(&qpair.free_req, &req, stailq); 362 qpair.reserved_req = &reserved_req; 363 memset(&g_nvmf_data, 0, sizeof(g_nvmf_data)); 364 365 qpair.id = 1; 366 ctrlr.opts.keep_alive_timeout_ms = 100; 367 ctrlr.cntlid = 2; 368 memcpy(ctrlr.opts.extended_host_id, hostid, sizeof(hostid)); 369 memcpy(ctrlr.opts.hostnqn, hostnqn, sizeof(hostnqn)); 370 memcpy(ctrlr.trid.subnqn, subnqn, sizeof(subnqn)); 371 372 rc = nvme_fabric_qpair_connect(&qpair, 1); 373 CU_ASSERT(rc == 0); 374 CU_ASSERT(cmd->opcode == SPDK_NVME_OPC_FABRIC); 375 CU_ASSERT(cmd->fctype == SPDK_NVMF_FABRIC_COMMAND_CONNECT); 376 CU_ASSERT(cmd->qid == 1); 377 CU_ASSERT(cmd->sqsize == 0); 378 CU_ASSERT(cmd->kato == 100); 379 CU_ASSERT(g_nvmf_data.cntlid == 2); 380 CU_ASSERT(!strncmp(g_nvmf_data.hostid, ctrlr.opts.extended_host_id, sizeof(g_nvmf_data.hostid))); 381 CU_ASSERT(!strncmp(g_nvmf_data.hostnqn, ctrlr.opts.hostnqn, sizeof(ctrlr.opts.hostnqn))); 382 CU_ASSERT(!strncmp(g_nvmf_data.subnqn, ctrlr.trid.subnqn, sizeof(ctrlr.trid.subnqn))); 383 /* Make sure we used the qpair's reserved_req, and not one from the STAILQ */ 384 CU_ASSERT(g_request == qpair.reserved_req); 385 CU_ASSERT(!STAILQ_EMPTY(&qpair.free_req)); 386 387 /* qid is adminq */ 388 memset(&g_nvmf_data, 0, sizeof(g_nvmf_data)); 389 memset(&reserved_req, 0, sizeof(reserved_req)); 390 qpair.id = 0; 391 ctrlr.cntlid = 0; 392 393 rc = nvme_fabric_qpair_connect(&qpair, 1); 394 CU_ASSERT(rc == 0); 395 CU_ASSERT(cmd->opcode == SPDK_NVME_OPC_FABRIC); 396 CU_ASSERT(cmd->fctype == SPDK_NVMF_FABRIC_COMMAND_CONNECT); 397 CU_ASSERT(cmd->qid == 0); 398 CU_ASSERT(cmd->sqsize == 0); 399 CU_ASSERT(cmd->kato == 100); 400 CU_ASSERT(ctrlr.cntlid == 1); 401 CU_ASSERT(g_nvmf_data.cntlid == 0xffff); 402 CU_ASSERT(!strncmp(g_nvmf_data.hostid, ctrlr.opts.extended_host_id, sizeof(g_nvmf_data.hostid))); 403 CU_ASSERT(!strncmp(g_nvmf_data.hostnqn, ctrlr.opts.hostnqn, sizeof(ctrlr.opts.hostnqn))); 404 CU_ASSERT(!strncmp(g_nvmf_data.subnqn, ctrlr.trid.subnqn, sizeof(ctrlr.trid.subnqn))); 405 /* Make sure we used the qpair's reserved_req, and not one from the STAILQ */ 406 CU_ASSERT(g_request == qpair.reserved_req); 407 CU_ASSERT(!STAILQ_EMPTY(&qpair.free_req)); 408 409 /* Wait_for completion timeout */ 410 g_nvme_wait_for_completion_timeout = true; 411 412 rc = nvme_fabric_qpair_connect(&qpair, 1); 413 CU_ASSERT(rc == -ECANCELED); 414 g_nvme_wait_for_completion_timeout = false; 415 abort_request(g_request); 416 417 /* Input parameters invalid */ 418 rc = nvme_fabric_qpair_connect(&qpair, 0); 419 CU_ASSERT(rc == -EINVAL); 420 } 421 422 int 423 main(int argc, char **argv) 424 { 425 CU_pSuite suite = NULL; 426 unsigned int num_failures; 427 428 CU_set_error_action(CUEA_ABORT); 429 CU_initialize_registry(); 430 431 suite = CU_add_suite("nvme_fabric", NULL, NULL); 432 CU_ADD_TEST(suite, test_nvme_fabric_prop_set_cmd); 433 CU_ADD_TEST(suite, test_nvme_fabric_prop_get_cmd); 434 CU_ADD_TEST(suite, test_nvme_fabric_get_discovery_log_page); 435 CU_ADD_TEST(suite, test_nvme_fabric_discover_probe); 436 CU_ADD_TEST(suite, test_nvme_fabric_qpair_connect); 437 438 CU_basic_set_mode(CU_BRM_VERBOSE); 439 CU_basic_run_tests(); 440 num_failures = CU_get_number_of_failures(); 441 CU_cleanup_registry(); 442 return num_failures; 443 } 444