xref: /spdk/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c (revision 7d38f16674f1bc7071d08f4d4dad68fc3ffad965)
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 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t,
53 	    (const struct spdk_bdev *bdev), 512);
54 
55 static void
56 _subsystem_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx)
57 {
58 	fn(ctx);
59 }
60 
61 static void
62 subsystem_ns_remove_cb(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status)
63 {
64 }
65 
66 uint32_t
67 spdk_env_get_current_core(void)
68 {
69 	return 0;
70 }
71 
72 struct spdk_event *
73 spdk_event_allocate(uint32_t core, spdk_event_fn fn, void *arg1, void *arg2)
74 {
75 	return NULL;
76 }
77 
78 void
79 spdk_event_call(struct spdk_event *event)
80 {
81 
82 }
83 
84 int
85 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
86 			   const struct spdk_nvme_transport_id *trid)
87 {
88 	return 0;
89 }
90 
91 void
92 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport,
93 				      struct spdk_nvme_transport_id *trid,
94 				      struct spdk_nvmf_discovery_log_page_entry *entry)
95 {
96 	entry->trtype = 42;
97 }
98 
99 bool
100 spdk_nvmf_transport_qpair_is_idle(struct spdk_nvmf_qpair *qpair)
101 {
102 	return false;
103 }
104 
105 static struct spdk_nvmf_transport g_transport = {};
106 
107 struct spdk_nvmf_transport *
108 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
109 			   struct spdk_nvmf_transport_opts *tprt_opts)
110 {
111 	if (type == SPDK_NVME_TRANSPORT_RDMA) {
112 		return &g_transport;
113 	}
114 
115 	return NULL;
116 }
117 
118 struct spdk_nvmf_subsystem *
119 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
120 {
121 	return NULL;
122 }
123 
124 struct spdk_nvmf_transport *
125 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype)
126 {
127 	if (trtype == SPDK_NVME_TRANSPORT_RDMA) {
128 		return &g_transport;
129 	}
130 
131 	return NULL;
132 }
133 
134 int
135 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group,
136 				      struct spdk_nvmf_subsystem *subsystem)
137 {
138 	return 0;
139 }
140 
141 int
142 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
143 				   struct spdk_nvmf_subsystem *subsystem,
144 				   spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
145 {
146 	return 0;
147 }
148 
149 void
150 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
151 				      struct spdk_nvmf_subsystem *subsystem,
152 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
153 {
154 }
155 
156 void
157 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
158 				     struct spdk_nvmf_subsystem *subsystem,
159 				     spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
160 {
161 }
162 
163 void
164 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
165 				      struct spdk_nvmf_subsystem *subsystem,
166 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
167 {
168 }
169 
170 int
171 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
172 {
173 	if (trtype == NULL || str == NULL) {
174 		return -EINVAL;
175 	}
176 
177 	if (strcasecmp(str, "PCIe") == 0) {
178 		*trtype = SPDK_NVME_TRANSPORT_PCIE;
179 	} else if (strcasecmp(str, "RDMA") == 0) {
180 		*trtype = SPDK_NVME_TRANSPORT_RDMA;
181 	} else {
182 		return -ENOENT;
183 	}
184 	return 0;
185 }
186 
187 int
188 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
189 			       const struct spdk_nvme_transport_id *trid2)
190 {
191 	return 0;
192 }
193 
194 int32_t
195 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr)
196 {
197 	return -1;
198 }
199 
200 int32_t
201 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
202 {
203 	return -1;
204 }
205 
206 int
207 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
208 {
209 	return -1;
210 }
211 
212 void
213 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr)
214 {
215 }
216 
217 void
218 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
219 {
220 }
221 
222 int
223 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb,
224 	       void *remove_ctx, struct spdk_bdev_desc **desc)
225 {
226 	return 0;
227 }
228 
229 void
230 spdk_bdev_close(struct spdk_bdev_desc *desc)
231 {
232 }
233 
234 const char *
235 spdk_bdev_get_name(const struct spdk_bdev *bdev)
236 {
237 	return "test";
238 }
239 
240 const struct spdk_uuid *
241 spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
242 {
243 	return &bdev->uuid;
244 }
245 
246 static void
247 test_spdk_nvmf_subsystem_add_ns(void)
248 {
249 	struct spdk_nvmf_tgt tgt = {};
250 	struct spdk_nvmf_subsystem subsystem = {
251 		.max_nsid = 0,
252 		.ns = NULL,
253 		.tgt = &tgt
254 	};
255 	struct spdk_bdev bdev1 = {}, bdev2 = {};
256 	struct spdk_nvmf_ns_opts ns_opts;
257 	uint32_t nsid;
258 
259 	tgt.max_subsystems = 1024;
260 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
261 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
262 
263 	/* Allow NSID to be assigned automatically */
264 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
265 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts));
266 	/* NSID 1 is the first unused ID */
267 	CU_ASSERT(nsid == 1);
268 	CU_ASSERT(subsystem.max_nsid == 1);
269 	SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL);
270 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
271 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1);
272 
273 	/* Request a specific NSID */
274 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
275 	ns_opts.nsid = 5;
276 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
277 	CU_ASSERT(nsid == 5);
278 	CU_ASSERT(subsystem.max_nsid == 5);
279 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
280 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2);
281 
282 	/* Request an NSID that is already in use */
283 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
284 	ns_opts.nsid = 5;
285 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
286 	CU_ASSERT(nsid == 0);
287 	CU_ASSERT(subsystem.max_nsid == 5);
288 
289 	/* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */
290 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
291 	ns_opts.nsid = 0xFFFFFFFF;
292 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
293 	CU_ASSERT(nsid == 0);
294 	CU_ASSERT(subsystem.max_nsid == 5);
295 
296 	spdk_nvmf_subsystem_remove_ns(&subsystem, 1, subsystem_ns_remove_cb, NULL);
297 	spdk_nvmf_subsystem_remove_ns(&subsystem, 5, subsystem_ns_remove_cb, NULL);
298 
299 	free(subsystem.ns);
300 	free(tgt.subsystems);
301 }
302 
303 static void
304 nvmf_test_create_subsystem(void)
305 {
306 	struct spdk_nvmf_tgt tgt = {};
307 	char nqn[256];
308 	struct spdk_nvmf_subsystem *subsystem;
309 
310 	tgt.max_subsystems = 1024;
311 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
312 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
313 
314 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
315 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
316 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
317 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
318 	spdk_nvmf_subsystem_destroy(subsystem);
319 
320 	/* valid name with complex reverse domain */
321 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1");
322 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
323 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
324 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
325 	spdk_nvmf_subsystem_destroy(subsystem);
326 
327 	/* Valid name discovery controller */
328 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
329 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
330 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
331 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
332 	spdk_nvmf_subsystem_destroy(subsystem);
333 
334 
335 	/* Invalid name, no user supplied string */
336 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
337 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
338 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
339 
340 	/* Valid name, only contains top-level domain name */
341 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
342 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
343 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
344 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
345 	spdk_nvmf_subsystem_destroy(subsystem);
346 
347 	/* Invalid name, domain label > 63 characters */
348 	snprintf(nqn, sizeof(nqn),
349 		 "nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub");
350 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
351 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
352 
353 	/* Invalid name, domain label starts with digit */
354 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.3spdk:sub");
355 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
356 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
357 
358 	/* Invalid name, domain label starts with - */
359 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.-spdk:subsystem1");
360 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
361 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
362 
363 	/* Invalid name, domain label ends with - */
364 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-:subsystem1");
365 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
366 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
367 
368 	/* Invalid name, domain label with multiple consecutive periods */
369 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io..spdk:subsystem1");
370 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
371 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
372 
373 	/* Longest valid name */
374 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
375 	memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn));
376 	nqn[223] = '\0';
377 	CU_ASSERT(strlen(nqn) == 223);
378 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
379 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
380 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
381 	spdk_nvmf_subsystem_destroy(subsystem);
382 
383 	/* Invalid name, too long */
384 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
385 	memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn));
386 	nqn[224] = '\0';
387 	CU_ASSERT(strlen(nqn) == 224);
388 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
389 	CU_ASSERT(subsystem == NULL);
390 
391 	/* Valid name using uuid format */
392 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc");
393 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
394 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
395 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
396 	spdk_nvmf_subsystem_destroy(subsystem);
397 
398 	/* Invalid name user string contains an invalid utf-8 character */
399 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xFFsubsystem1");
400 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
401 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
402 
403 	/* Valid name with non-ascii but valid utf-8 characters */
404 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xe1\x8a\x88subsystem1\xca\x80");
405 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
406 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
407 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
408 	spdk_nvmf_subsystem_destroy(subsystem);
409 
410 	/* Invalid uuid (too long) */
411 	snprintf(nqn, sizeof(nqn),
412 		 "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef");
413 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
414 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
415 
416 	/* Invalid uuid (dashes placed incorrectly) */
417 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc");
418 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
419 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
420 
421 	/* Invalid uuid (invalid characters in uuid) */
422 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc");
423 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
424 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
425 
426 	free(tgt.subsystems);
427 }
428 
429 static void
430 test_spdk_nvmf_subsystem_set_sn(void)
431 {
432 	struct spdk_nvmf_subsystem subsystem = {};
433 
434 	/* Basic valid serial number */
435 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd xyz") == 0);
436 	CU_ASSERT(strcmp(subsystem.sn, "abcd xyz") == 0);
437 
438 	/* Exactly 20 characters (valid) */
439 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "12345678901234567890") == 0);
440 	CU_ASSERT(strcmp(subsystem.sn, "12345678901234567890") == 0);
441 
442 	/* 21 characters (too long, invalid) */
443 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "123456789012345678901") < 0);
444 
445 	/* Non-ASCII characters (invalid) */
446 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd\txyz") < 0);
447 }
448 
449 int main(int argc, char **argv)
450 {
451 	CU_pSuite	suite = NULL;
452 	unsigned int	num_failures;
453 
454 	if (CU_initialize_registry() != CUE_SUCCESS) {
455 		return CU_get_error();
456 	}
457 
458 	suite = CU_add_suite("nvmf", NULL, NULL);
459 	if (suite == NULL) {
460 		CU_cleanup_registry();
461 		return CU_get_error();
462 	}
463 
464 	if (
465 		CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL ||
466 		CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL ||
467 		CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL) {
468 		CU_cleanup_registry();
469 		return CU_get_error();
470 	}
471 
472 	spdk_allocate_thread(_subsystem_send_msg, NULL, NULL, NULL, "thread0");
473 	CU_basic_set_mode(CU_BRM_VERBOSE);
474 	CU_basic_run_tests();
475 	num_failures = CU_get_number_of_failures();
476 	CU_cleanup_registry();
477 	spdk_free_thread();
478 
479 	return num_failures;
480 }
481