4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/stdinc.h"
36 #include "common/lib/test_env.c"
37 #include "spdk_cunit.h"
38 #include "spdk_internal/mock.h"
40 #include "nvmf/subsystem.c"
42 SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF
)
44 DEFINE_STUB(spdk_bdev_module_claim_bdev
,
46 (struct spdk_bdev
*bdev
, struct spdk_bdev_desc
*desc
,
47 struct spdk_bdev_module
*module
), 0);
49 DEFINE_STUB_V(spdk_bdev_module_release_bdev
,
50 (struct spdk_bdev
*bdev
));
53 _subsystem_send_msg(spdk_thread_fn fn
, void *ctx
, void *thread_ctx
)
59 subsystem_ns_remove_cb(struct spdk_nvmf_subsystem
*subsystem
, void *cb_arg
, int status
)
64 spdk_env_get_current_core(void)
70 spdk_event_allocate(uint32_t core
, spdk_event_fn fn
, void *arg1
, void *arg2
)
76 spdk_event_call(struct spdk_event
*event
)
82 spdk_nvmf_transport_listen(struct spdk_nvmf_transport
*transport
,
83 const struct spdk_nvme_transport_id
*trid
)
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
)
97 spdk_nvmf_transport_qpair_is_idle(struct spdk_nvmf_qpair
*qpair
)
102 static struct spdk_nvmf_transport g_transport
= {};
104 struct spdk_nvmf_transport
*
105 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type
,
106 struct spdk_nvmf_transport_opts
*tprt_opts
)
108 if (type
== SPDK_NVME_TRANSPORT_RDMA
) {
115 struct spdk_nvmf_subsystem
*
116 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt
*tgt
, const char *subnqn
)
121 struct spdk_nvmf_transport
*
122 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt
*tgt
, enum spdk_nvme_transport_type trtype
)
124 if (trtype
== SPDK_NVME_TRANSPORT_RDMA
) {
132 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group
*group
,
133 struct spdk_nvmf_subsystem
*subsystem
)
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
)
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
)
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
)
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
)
168 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type
*trtype
, const char *str
)
170 if (trtype
== NULL
|| str
== NULL
) {
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
;
185 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id
*trid1
,
186 const struct spdk_nvme_transport_id
*trid2
)
192 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr
*ctrlr
)
198 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair
*qpair
, uint32_t max_completions
)
204 spdk_nvme_detach(struct spdk_nvme_ctrlr
*ctrlr
)
210 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr
*ctrlr
)
215 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr
*ctrlr
, uint32_t nsid
)
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
)
227 spdk_bdev_close(struct spdk_bdev_desc
*desc
)
232 spdk_bdev_get_name(const struct spdk_bdev
*bdev
)
237 const struct spdk_uuid
*
238 spdk_bdev_get_uuid(const struct spdk_bdev
*bdev
)
244 test_spdk_nvmf_subsystem_add_ns(void)
246 struct spdk_nvmf_tgt tgt
= {};
247 struct spdk_nvmf_subsystem subsystem
= {
252 struct spdk_bdev bdev1
= {}, bdev2
= {};
253 struct spdk_nvmf_ns_opts ns_opts
;
256 tgt
.opts
.max_subsystems
= 1024;
257 tgt
.subsystems
= calloc(tgt
.opts
.max_subsystems
, sizeof(struct spdk_nvmf_subsystem
*));
258 SPDK_CU_ASSERT_FATAL(tgt
.subsystems
!= NULL
);
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
);
270 /* Request a specific NSID */
271 spdk_nvmf_ns_opts_get_defaults(&ns_opts
, sizeof(ns_opts
));
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
);
279 /* Request an NSID that is already in use */
280 spdk_nvmf_ns_opts_get_defaults(&ns_opts
, sizeof(ns_opts
));
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);
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);
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
);
297 free(tgt
.subsystems
);
301 nvmf_test_create_subsystem(void)
303 struct spdk_nvmf_tgt tgt
= {};
305 struct spdk_nvmf_subsystem
*subsystem
;
307 tgt
.opts
.max_subsystems
= 1024;
308 tgt
.subsystems
= calloc(tgt
.opts
.max_subsystems
, sizeof(struct spdk_nvmf_subsystem
*));
309 SPDK_CU_ASSERT_FATAL(tgt
.subsystems
!= NULL
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
370 /* Longest valid name */
371 snprintf(nqn
, sizeof(nqn
), "nqn.2016-06.io.spdk:");
372 memset(nqn
+ strlen(nqn
), 'a', 223 - strlen(nqn
));
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
);
380 /* Invalid name, too long */
381 snprintf(nqn
, sizeof(nqn
), "nqn.2016-06.io.spdk:");
382 memset(nqn
+ strlen(nqn
), 'a', 224 - strlen(nqn
));
384 CU_ASSERT(strlen(nqn
) == 224);
385 subsystem
= spdk_nvmf_subsystem_create(&tgt
, nqn
, SPDK_NVMF_SUBTYPE_NVME
, 0);
386 CU_ASSERT(subsystem
== NULL
);
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
);
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
);
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
);
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
);
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
);
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
);
423 free(tgt
.subsystems
);
427 test_spdk_nvmf_subsystem_set_sn(void)
429 struct spdk_nvmf_subsystem subsystem
= {};
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);
435 /* Exactly 20 characters (valid) */
436 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem
, "12345678901234567890") == 0);
437 CU_ASSERT(strcmp(subsystem
.sn
, "12345678901234567890") == 0);
439 /* 21 characters (too long, invalid) */
440 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem
, "123456789012345678901") < 0);
442 /* Non-ASCII characters (invalid) */
443 CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem
, "abcd\txyz") < 0);
446 int main(int argc
, char **argv
)
448 CU_pSuite suite
= NULL
;
449 unsigned int num_failures
;
451 if (CU_initialize_registry() != CUE_SUCCESS
) {
452 return CU_get_error();
455 suite
= CU_add_suite("nvmf", NULL
, NULL
);
457 CU_cleanup_registry();
458 return CU_get_error();
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();
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();