1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "common/lib/ut_multithread.c" 37 #include "spdk_cunit.h" 38 #include "spdk_internal/mock.h" 39 #include "spdk_internal/thread.h" 40 41 #include "nvmf/subsystem.c" 42 43 SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF) 44 45 DEFINE_STUB(spdk_bdev_module_claim_bdev, 46 int, 47 (struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, 48 struct spdk_bdev_module *module), 0); 49 50 DEFINE_STUB_V(spdk_bdev_module_release_bdev, 51 (struct spdk_bdev *bdev)); 52 53 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, 54 (const struct spdk_bdev *bdev), 512); 55 56 static void 57 subsystem_ns_remove_cb(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status) 58 { 59 } 60 61 uint32_t 62 spdk_env_get_current_core(void) 63 { 64 return 0; 65 } 66 67 struct spdk_event * 68 spdk_event_allocate(uint32_t core, spdk_event_fn fn, void *arg1, void *arg2) 69 { 70 return NULL; 71 } 72 73 void 74 spdk_event_call(struct spdk_event *event) 75 { 76 77 } 78 79 int 80 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport, 81 const struct spdk_nvme_transport_id *trid) 82 { 83 return 0; 84 } 85 86 void 87 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport, 88 struct spdk_nvme_transport_id *trid, 89 struct spdk_nvmf_discovery_log_page_entry *entry) 90 { 91 entry->trtype = 42; 92 } 93 94 bool 95 spdk_nvmf_transport_qpair_is_idle(struct spdk_nvmf_qpair *qpair) 96 { 97 return false; 98 } 99 100 static struct spdk_nvmf_transport g_transport = {}; 101 102 struct spdk_nvmf_transport * 103 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type, 104 struct spdk_nvmf_transport_opts *tprt_opts) 105 { 106 if (type == SPDK_NVME_TRANSPORT_RDMA) { 107 return &g_transport; 108 } 109 110 return NULL; 111 } 112 113 struct spdk_nvmf_subsystem * 114 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn) 115 { 116 return NULL; 117 } 118 119 struct spdk_nvmf_transport * 120 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype) 121 { 122 if (trtype == SPDK_NVME_TRANSPORT_RDMA) { 123 return &g_transport; 124 } 125 126 return NULL; 127 } 128 129 int 130 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group, 131 struct spdk_nvmf_subsystem *subsystem) 132 { 133 return 0; 134 } 135 136 int 137 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, 138 struct spdk_nvmf_subsystem *subsystem, 139 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 140 { 141 return 0; 142 } 143 144 void 145 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, 146 struct spdk_nvmf_subsystem *subsystem, 147 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 148 { 149 } 150 151 void 152 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group, 153 struct spdk_nvmf_subsystem *subsystem, 154 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 155 { 156 } 157 158 void 159 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group, 160 struct spdk_nvmf_subsystem *subsystem, 161 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 162 { 163 } 164 165 int 166 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str) 167 { 168 if (trtype == NULL || str == NULL) { 169 return -EINVAL; 170 } 171 172 if (strcasecmp(str, "PCIe") == 0) { 173 *trtype = SPDK_NVME_TRANSPORT_PCIE; 174 } else if (strcasecmp(str, "RDMA") == 0) { 175 *trtype = SPDK_NVME_TRANSPORT_RDMA; 176 } else { 177 return -ENOENT; 178 } 179 return 0; 180 } 181 182 int 183 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, 184 const struct spdk_nvme_transport_id *trid2) 185 { 186 return 0; 187 } 188 189 int32_t 190 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr) 191 { 192 return -1; 193 } 194 195 int32_t 196 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) 197 { 198 return -1; 199 } 200 201 int 202 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr) 203 { 204 return -1; 205 } 206 207 void 208 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr) 209 { 210 } 211 212 void 213 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid) 214 { 215 } 216 217 int 218 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb, 219 void *remove_ctx, struct spdk_bdev_desc **desc) 220 { 221 return 0; 222 } 223 224 void 225 spdk_bdev_close(struct spdk_bdev_desc *desc) 226 { 227 } 228 229 const char * 230 spdk_bdev_get_name(const struct spdk_bdev *bdev) 231 { 232 return "test"; 233 } 234 235 const struct spdk_uuid * 236 spdk_bdev_get_uuid(const struct spdk_bdev *bdev) 237 { 238 return &bdev->uuid; 239 } 240 241 static void 242 test_spdk_nvmf_subsystem_add_ns(void) 243 { 244 struct spdk_nvmf_tgt tgt = {}; 245 struct spdk_nvmf_subsystem subsystem = { 246 .max_nsid = 0, 247 .ns = NULL, 248 .tgt = &tgt 249 }; 250 struct spdk_bdev bdev1 = {}, bdev2 = {}; 251 struct spdk_nvmf_ns_opts ns_opts; 252 uint32_t nsid; 253 254 tgt.max_subsystems = 1024; 255 tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); 256 SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); 257 258 /* Allow NSID to be assigned automatically */ 259 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 260 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts)); 261 /* NSID 1 is the first unused ID */ 262 CU_ASSERT(nsid == 1); 263 CU_ASSERT(subsystem.max_nsid == 1); 264 SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL); 265 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 266 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1); 267 268 /* Request a specific NSID */ 269 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 270 ns_opts.nsid = 5; 271 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 272 CU_ASSERT(nsid == 5); 273 CU_ASSERT(subsystem.max_nsid == 5); 274 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 275 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2); 276 277 /* Request an NSID that is already in use */ 278 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 279 ns_opts.nsid = 5; 280 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 281 CU_ASSERT(nsid == 0); 282 CU_ASSERT(subsystem.max_nsid == 5); 283 284 /* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */ 285 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 286 ns_opts.nsid = 0xFFFFFFFF; 287 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 288 CU_ASSERT(nsid == 0); 289 CU_ASSERT(subsystem.max_nsid == 5); 290 291 spdk_nvmf_subsystem_remove_ns(&subsystem, 1, subsystem_ns_remove_cb, NULL); 292 poll_threads(); 293 spdk_nvmf_subsystem_remove_ns(&subsystem, 5, subsystem_ns_remove_cb, NULL); 294 poll_threads(); 295 296 free(subsystem.ns); 297 free(tgt.subsystems); 298 } 299 300 static void 301 nvmf_test_create_subsystem(void) 302 { 303 struct spdk_nvmf_tgt tgt = {}; 304 char nqn[256]; 305 struct spdk_nvmf_subsystem *subsystem; 306 307 tgt.max_subsystems = 1024; 308 tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); 309 SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); 310 311 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 312 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 313 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 314 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 315 spdk_nvmf_subsystem_destroy(subsystem); 316 317 /* valid name with complex reverse domain */ 318 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1"); 319 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 320 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 321 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 322 spdk_nvmf_subsystem_destroy(subsystem); 323 324 /* Valid name discovery controller */ 325 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 326 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 327 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 328 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 329 spdk_nvmf_subsystem_destroy(subsystem); 330 331 332 /* Invalid name, no user supplied string */ 333 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 334 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 335 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 336 337 /* Valid name, only contains top-level domain name */ 338 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1"); 339 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 340 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 341 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 342 spdk_nvmf_subsystem_destroy(subsystem); 343 344 /* Invalid name, domain label > 63 characters */ 345 snprintf(nqn, sizeof(nqn), 346 "nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub"); 347 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 348 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 349 350 /* Invalid name, domain label starts with digit */ 351 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.3spdk:sub"); 352 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 353 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 354 355 /* Invalid name, domain label starts with - */ 356 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.-spdk:subsystem1"); 357 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 358 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 359 360 /* Invalid name, domain label ends with - */ 361 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-:subsystem1"); 362 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 363 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 364 365 /* Invalid name, domain label with multiple consecutive periods */ 366 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io..spdk:subsystem1"); 367 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 368 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 369 370 /* Longest valid name */ 371 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 372 memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn)); 373 nqn[223] = '\0'; 374 CU_ASSERT(strlen(nqn) == 223); 375 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 376 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 377 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 378 spdk_nvmf_subsystem_destroy(subsystem); 379 380 /* Invalid name, too long */ 381 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:"); 382 memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn)); 383 nqn[224] = '\0'; 384 CU_ASSERT(strlen(nqn) == 224); 385 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 386 CU_ASSERT(subsystem == NULL); 387 388 /* Valid name using uuid format */ 389 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc"); 390 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 391 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 392 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 393 spdk_nvmf_subsystem_destroy(subsystem); 394 395 /* Invalid name user string contains an invalid utf-8 character */ 396 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xFFsubsystem1"); 397 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 398 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 399 400 /* Valid name with non-ascii but valid utf-8 characters */ 401 snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xe1\x8a\x88subsystem1\xca\x80"); 402 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 403 SPDK_CU_ASSERT_FATAL(subsystem != NULL); 404 CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn); 405 spdk_nvmf_subsystem_destroy(subsystem); 406 407 /* Invalid uuid (too long) */ 408 snprintf(nqn, sizeof(nqn), 409 "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef"); 410 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 411 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 412 413 /* Invalid uuid (dashes placed incorrectly) */ 414 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc"); 415 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 416 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 417 418 /* Invalid uuid (invalid characters in uuid) */ 419 snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc"); 420 subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0); 421 SPDK_CU_ASSERT_FATAL(subsystem == NULL); 422 423 free(tgt.subsystems); 424 } 425 426 static void 427 test_spdk_nvmf_subsystem_set_sn(void) 428 { 429 struct spdk_nvmf_subsystem subsystem = {}; 430 431 /* Basic valid serial number */ 432 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd xyz") == 0); 433 CU_ASSERT(strcmp(subsystem.sn, "abcd xyz") == 0); 434 435 /* Exactly 20 characters (valid) */ 436 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "12345678901234567890") == 0); 437 CU_ASSERT(strcmp(subsystem.sn, "12345678901234567890") == 0); 438 439 /* 21 characters (too long, invalid) */ 440 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "123456789012345678901") < 0); 441 442 /* Non-ASCII characters (invalid) */ 443 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd\txyz") < 0); 444 } 445 446 int main(int argc, char **argv) 447 { 448 CU_pSuite suite = NULL; 449 unsigned int num_failures; 450 451 if (CU_initialize_registry() != CUE_SUCCESS) { 452 return CU_get_error(); 453 } 454 455 suite = CU_add_suite("nvmf", NULL, NULL); 456 if (suite == NULL) { 457 CU_cleanup_registry(); 458 return CU_get_error(); 459 } 460 461 if ( 462 CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL || 463 CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL || 464 CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL) { 465 CU_cleanup_registry(); 466 return CU_get_error(); 467 } 468 469 allocate_threads(1); 470 set_thread(0); 471 472 CU_basic_set_mode(CU_BRM_VERBOSE); 473 CU_basic_run_tests(); 474 num_failures = CU_get_number_of_failures(); 475 CU_cleanup_registry(); 476 477 free_threads(); 478 479 return num_failures; 480 } 481