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/test_env.c" 37 #include "spdk_cunit.h" 38 #include "spdk_internal/mock.h" 39 40 #include "nvmf/subsystem.c" 41 42 SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF) 43 44 DEFINE_STUB(spdk_bdev_module_claim_bdev, 45 int, 46 (struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, 47 struct spdk_bdev_module *module), 0); 48 49 DEFINE_STUB_V(spdk_bdev_module_release_bdev, 50 (struct spdk_bdev *bdev)); 51 52 static void 53 _subsystem_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx) 54 { 55 fn(ctx); 56 } 57 58 static void 59 subsystem_ns_remove_cb(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status) 60 { 61 } 62 63 uint32_t 64 spdk_env_get_current_core(void) 65 { 66 return 0; 67 } 68 69 struct spdk_event * 70 spdk_event_allocate(uint32_t core, spdk_event_fn fn, void *arg1, void *arg2) 71 { 72 return NULL; 73 } 74 75 void 76 spdk_event_call(struct spdk_event *event) 77 { 78 79 } 80 81 int 82 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport, 83 const struct spdk_nvme_transport_id *trid) 84 { 85 return 0; 86 } 87 88 void 89 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport, 90 struct spdk_nvme_transport_id *trid, 91 struct spdk_nvmf_discovery_log_page_entry *entry) 92 { 93 entry->trtype = 42; 94 } 95 96 bool 97 spdk_nvmf_transport_qpair_is_idle(struct spdk_nvmf_qpair *qpair) 98 { 99 return false; 100 } 101 102 static struct spdk_nvmf_transport g_transport = {}; 103 104 struct spdk_nvmf_transport * 105 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type, 106 struct spdk_nvmf_transport_opts *tprt_opts) 107 { 108 if (type == SPDK_NVME_TRANSPORT_RDMA) { 109 return &g_transport; 110 } 111 112 return NULL; 113 } 114 115 struct spdk_nvmf_subsystem * 116 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn) 117 { 118 return NULL; 119 } 120 121 struct spdk_nvmf_transport * 122 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype) 123 { 124 if (trtype == SPDK_NVME_TRANSPORT_RDMA) { 125 return &g_transport; 126 } 127 128 return NULL; 129 } 130 131 int 132 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group, 133 struct spdk_nvmf_subsystem *subsystem) 134 { 135 return 0; 136 } 137 138 int 139 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group, 140 struct spdk_nvmf_subsystem *subsystem, 141 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 142 { 143 return 0; 144 } 145 146 void 147 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group, 148 struct spdk_nvmf_subsystem *subsystem, 149 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 150 { 151 } 152 153 void 154 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group, 155 struct spdk_nvmf_subsystem *subsystem, 156 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 157 { 158 } 159 160 void 161 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group, 162 struct spdk_nvmf_subsystem *subsystem, 163 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg) 164 { 165 } 166 167 int 168 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str) 169 { 170 if (trtype == NULL || str == NULL) { 171 return -EINVAL; 172 } 173 174 if (strcasecmp(str, "PCIe") == 0) { 175 *trtype = SPDK_NVME_TRANSPORT_PCIE; 176 } else if (strcasecmp(str, "RDMA") == 0) { 177 *trtype = SPDK_NVME_TRANSPORT_RDMA; 178 } else { 179 return -ENOENT; 180 } 181 return 0; 182 } 183 184 int 185 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, 186 const struct spdk_nvme_transport_id *trid2) 187 { 188 return 0; 189 } 190 191 int32_t 192 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr) 193 { 194 return -1; 195 } 196 197 int32_t 198 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) 199 { 200 return -1; 201 } 202 203 int 204 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr) 205 { 206 return -1; 207 } 208 209 void 210 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr) 211 { 212 } 213 214 void 215 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid) 216 { 217 } 218 219 int 220 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb, 221 void *remove_ctx, struct spdk_bdev_desc **desc) 222 { 223 return 0; 224 } 225 226 void 227 spdk_bdev_close(struct spdk_bdev_desc *desc) 228 { 229 } 230 231 const char * 232 spdk_bdev_get_name(const struct spdk_bdev *bdev) 233 { 234 return "test"; 235 } 236 237 const struct spdk_uuid * 238 spdk_bdev_get_uuid(const struct spdk_bdev *bdev) 239 { 240 return &bdev->uuid; 241 } 242 243 static void 244 test_spdk_nvmf_subsystem_add_ns(void) 245 { 246 struct spdk_nvmf_tgt tgt = {}; 247 struct spdk_nvmf_subsystem subsystem = { 248 .max_nsid = 0, 249 .ns = NULL, 250 .tgt = &tgt 251 }; 252 struct spdk_bdev bdev1 = {}, bdev2 = {}; 253 struct spdk_nvmf_ns_opts ns_opts; 254 uint32_t nsid; 255 256 tgt.max_subsystems = 1024; 257 tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *)); 258 SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL); 259 260 /* Allow NSID to be assigned automatically */ 261 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 262 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts)); 263 /* NSID 1 is the first unused ID */ 264 CU_ASSERT(nsid == 1); 265 CU_ASSERT(subsystem.max_nsid == 1); 266 SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL); 267 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 268 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1); 269 270 /* Request a specific NSID */ 271 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 272 ns_opts.nsid = 5; 273 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 274 CU_ASSERT(nsid == 5); 275 CU_ASSERT(subsystem.max_nsid == 5); 276 SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL); 277 CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2); 278 279 /* Request an NSID that is already in use */ 280 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 281 ns_opts.nsid = 5; 282 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 283 CU_ASSERT(nsid == 0); 284 CU_ASSERT(subsystem.max_nsid == 5); 285 286 /* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */ 287 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 288 ns_opts.nsid = 0xFFFFFFFF; 289 nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts)); 290 CU_ASSERT(nsid == 0); 291 CU_ASSERT(subsystem.max_nsid == 5); 292 293 spdk_nvmf_subsystem_remove_ns(&subsystem, 1, subsystem_ns_remove_cb, NULL); 294 spdk_nvmf_subsystem_remove_ns(&subsystem, 5, subsystem_ns_remove_cb, NULL); 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 spdk_allocate_thread(_subsystem_send_msg, NULL, NULL, NULL, "thread0"); 470 CU_basic_set_mode(CU_BRM_VERBOSE); 471 CU_basic_run_tests(); 472 num_failures = CU_get_number_of_failures(); 473 CU_cleanup_registry(); 474 spdk_free_thread(); 475 476 return num_failures; 477 } 478