xref: /spdk/test/unit/lib/nvmf/subsystem.c/subsystem_ut.c (revision fa2d95b3fe66e7f5c543eaef89fa00d4eaa0e6e7)
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 DEFINE_STUB(spdk_nvmf_transport_stop_listen,
57 	    int,
58 	    (struct spdk_nvmf_transport *transport,
59 	     const struct spdk_nvme_transport_id *trid), 0);
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 static struct spdk_nvmf_transport g_transport = {};
100 
101 struct spdk_nvmf_transport *
102 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
103 			   struct spdk_nvmf_transport_opts *tprt_opts)
104 {
105 	if (type == SPDK_NVME_TRANSPORT_RDMA) {
106 		return &g_transport;
107 	}
108 
109 	return NULL;
110 }
111 
112 struct spdk_nvmf_subsystem *
113 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
114 {
115 	return NULL;
116 }
117 
118 struct spdk_nvmf_transport *
119 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type trtype)
120 {
121 	if (trtype == SPDK_NVME_TRANSPORT_RDMA) {
122 		return &g_transport;
123 	}
124 
125 	return NULL;
126 }
127 
128 int
129 spdk_nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group,
130 				      struct spdk_nvmf_subsystem *subsystem)
131 {
132 	return 0;
133 }
134 
135 int
136 spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
137 				   struct spdk_nvmf_subsystem *subsystem,
138 				   spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
139 {
140 	return 0;
141 }
142 
143 void
144 spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
145 				      struct spdk_nvmf_subsystem *subsystem,
146 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
147 {
148 }
149 
150 void
151 spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
152 				     struct spdk_nvmf_subsystem *subsystem,
153 				     spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
154 {
155 }
156 
157 void
158 spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
159 				      struct spdk_nvmf_subsystem *subsystem,
160 				      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
161 {
162 }
163 
164 int
165 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
166 {
167 	if (trtype == NULL || str == NULL) {
168 		return -EINVAL;
169 	}
170 
171 	if (strcasecmp(str, "PCIe") == 0) {
172 		*trtype = SPDK_NVME_TRANSPORT_PCIE;
173 	} else if (strcasecmp(str, "RDMA") == 0) {
174 		*trtype = SPDK_NVME_TRANSPORT_RDMA;
175 	} else {
176 		return -ENOENT;
177 	}
178 	return 0;
179 }
180 
181 int
182 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
183 			       const struct spdk_nvme_transport_id *trid2)
184 {
185 	return 0;
186 }
187 
188 int32_t
189 spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr)
190 {
191 	return -1;
192 }
193 
194 int32_t
195 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
196 {
197 	return -1;
198 }
199 
200 int
201 spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
202 {
203 	return -1;
204 }
205 
206 void
207 spdk_nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr)
208 {
209 }
210 
211 void
212 spdk_nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
213 {
214 }
215 
216 int
217 spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb,
218 	       void *remove_ctx, struct spdk_bdev_desc **desc)
219 {
220 	return 0;
221 }
222 
223 void
224 spdk_bdev_close(struct spdk_bdev_desc *desc)
225 {
226 }
227 
228 const char *
229 spdk_bdev_get_name(const struct spdk_bdev *bdev)
230 {
231 	return "test";
232 }
233 
234 const struct spdk_uuid *
235 spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
236 {
237 	return &bdev->uuid;
238 }
239 
240 static void
241 test_spdk_nvmf_subsystem_add_ns(void)
242 {
243 	struct spdk_nvmf_tgt tgt = {};
244 	struct spdk_nvmf_subsystem subsystem = {
245 		.max_nsid = 0,
246 		.ns = NULL,
247 		.tgt = &tgt
248 	};
249 	struct spdk_bdev bdev1 = {}, bdev2 = {};
250 	struct spdk_nvmf_ns_opts ns_opts;
251 	uint32_t nsid;
252 
253 	tgt.max_subsystems = 1024;
254 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
255 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
256 
257 	/* Allow NSID to be assigned automatically */
258 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
259 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev1, &ns_opts, sizeof(ns_opts));
260 	/* NSID 1 is the first unused ID */
261 	CU_ASSERT(nsid == 1);
262 	CU_ASSERT(subsystem.max_nsid == 1);
263 	SPDK_CU_ASSERT_FATAL(subsystem.ns != NULL);
264 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
265 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev1);
266 
267 	/* Request a specific NSID */
268 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
269 	ns_opts.nsid = 5;
270 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
271 	CU_ASSERT(nsid == 5);
272 	CU_ASSERT(subsystem.max_nsid == 5);
273 	SPDK_CU_ASSERT_FATAL(subsystem.ns[nsid - 1] != NULL);
274 	CU_ASSERT(subsystem.ns[nsid - 1]->bdev == &bdev2);
275 
276 	/* Request an NSID that is already in use */
277 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
278 	ns_opts.nsid = 5;
279 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
280 	CU_ASSERT(nsid == 0);
281 	CU_ASSERT(subsystem.max_nsid == 5);
282 
283 	/* Request 0xFFFFFFFF (invalid NSID, reserved for broadcast) */
284 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
285 	ns_opts.nsid = 0xFFFFFFFF;
286 	nsid = spdk_nvmf_subsystem_add_ns(&subsystem, &bdev2, &ns_opts, sizeof(ns_opts));
287 	CU_ASSERT(nsid == 0);
288 	CU_ASSERT(subsystem.max_nsid == 5);
289 
290 	spdk_nvmf_subsystem_remove_ns(&subsystem, 1, subsystem_ns_remove_cb, NULL);
291 	poll_threads();
292 	spdk_nvmf_subsystem_remove_ns(&subsystem, 5, subsystem_ns_remove_cb, NULL);
293 	poll_threads();
294 
295 	free(subsystem.ns);
296 	free(tgt.subsystems);
297 }
298 
299 static void
300 nvmf_test_create_subsystem(void)
301 {
302 	struct spdk_nvmf_tgt tgt = {};
303 	char nqn[256];
304 	struct spdk_nvmf_subsystem *subsystem;
305 
306 	tgt.max_subsystems = 1024;
307 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
308 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
309 
310 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
311 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
312 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
313 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
314 	spdk_nvmf_subsystem_destroy(subsystem);
315 
316 	/* valid name with complex reverse domain */
317 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-full--rev-domain.name:subsystem1");
318 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
319 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
320 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
321 	spdk_nvmf_subsystem_destroy(subsystem);
322 
323 	/* Valid name discovery controller */
324 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
325 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
326 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
327 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
328 	spdk_nvmf_subsystem_destroy(subsystem);
329 
330 
331 	/* Invalid name, no user supplied string */
332 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
333 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
334 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
335 
336 	/* Valid name, only contains top-level domain name */
337 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:subsystem1");
338 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
339 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
340 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
341 	spdk_nvmf_subsystem_destroy(subsystem);
342 
343 	/* Invalid name, domain label > 63 characters */
344 	snprintf(nqn, sizeof(nqn),
345 		 "nqn.2016-06.io.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz:sub");
346 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
347 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
348 
349 	/* Invalid name, domain label starts with digit */
350 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.3spdk:sub");
351 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
352 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
353 
354 	/* Invalid name, domain label starts with - */
355 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.-spdk:subsystem1");
356 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
357 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
358 
359 	/* Invalid name, domain label ends with - */
360 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk-:subsystem1");
361 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
362 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
363 
364 	/* Invalid name, domain label with multiple consecutive periods */
365 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io..spdk:subsystem1");
366 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
367 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
368 
369 	/* Longest valid name */
370 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
371 	memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn));
372 	nqn[223] = '\0';
373 	CU_ASSERT(strlen(nqn) == 223);
374 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
375 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
376 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
377 	spdk_nvmf_subsystem_destroy(subsystem);
378 
379 	/* Invalid name, too long */
380 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:");
381 	memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn));
382 	nqn[224] = '\0';
383 	CU_ASSERT(strlen(nqn) == 224);
384 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
385 	CU_ASSERT(subsystem == NULL);
386 
387 	/* Valid name using uuid format */
388 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abc");
389 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
390 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
391 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
392 	spdk_nvmf_subsystem_destroy(subsystem);
393 
394 	/* Invalid name user string contains an invalid utf-8 character */
395 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xFFsubsystem1");
396 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
397 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
398 
399 	/* Valid name with non-ascii but valid utf-8 characters */
400 	snprintf(nqn, sizeof(nqn), "nqn.2016-06.io.spdk:\xe1\x8a\x88subsystem1\xca\x80");
401 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
402 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
403 	CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
404 	spdk_nvmf_subsystem_destroy(subsystem);
405 
406 	/* Invalid uuid (too long) */
407 	snprintf(nqn, sizeof(nqn),
408 		 "nqn.2014-08.org.nvmexpress:uuid:11111111-aaaa-bbdd-FFEE-123456789abcdef");
409 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
410 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
411 
412 	/* Invalid uuid (dashes placed incorrectly) */
413 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111111-11aaaa-bbdd-FFEE-123456789abc");
414 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
415 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
416 
417 	/* Invalid uuid (invalid characters in uuid) */
418 	snprintf(nqn, sizeof(nqn), "nqn.2014-08.org.nvmexpress:uuid:111hg111-aaaa-bbdd-FFEE-123456789abc");
419 	subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
420 	SPDK_CU_ASSERT_FATAL(subsystem == NULL);
421 
422 	free(tgt.subsystems);
423 }
424 
425 static void
426 test_spdk_nvmf_subsystem_set_sn(void)
427 {
428 	struct spdk_nvmf_subsystem subsystem = {};
429 
430 	/* Basic valid serial number */
431 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd xyz") == 0);
432 	CU_ASSERT(strcmp(subsystem.sn, "abcd xyz") == 0);
433 
434 	/* Exactly 20 characters (valid) */
435 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "12345678901234567890") == 0);
436 	CU_ASSERT(strcmp(subsystem.sn, "12345678901234567890") == 0);
437 
438 	/* 21 characters (too long, invalid) */
439 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "123456789012345678901") < 0);
440 
441 	/* Non-ASCII characters (invalid) */
442 	CU_ASSERT(spdk_nvmf_subsystem_set_sn(&subsystem, "abcd\txyz") < 0);
443 }
444 
445 /*
446  * Reservation Unit Test Configuration
447  *       --------             --------    --------
448  *      | Host A |           | Host B |  | Host C |
449  *       --------             --------    --------
450  *      /        \               |           |
451  *  --------   --------       -------     -------
452  * |Ctrlr1_A| |Ctrlr2_A|     |Ctrlr_B|   |Ctrlr_C|
453  *  --------   --------       -------     -------
454  *    \           \              /           /
455  *     \           \            /           /
456  *      \           \          /           /
457  *      --------------------------------------
458  *     |            NAMESPACE 1               |
459  *      --------------------------------------
460  */
461 
462 static struct spdk_nvmf_ctrlr g_ctrlr1_A, g_ctrlr2_A, g_ctrlr_B, g_ctrlr_C;
463 static struct spdk_nvmf_ns g_ns;
464 struct spdk_nvmf_subsystem_pg_ns_info g_ns_info;
465 
466 static void
467 ut_reservation_init(void)
468 {
469 	memset(&g_ns, 0, sizeof(g_ns));
470 	TAILQ_INIT(&g_ns.registrants);
471 
472 	/* Host A has two controllers */
473 	spdk_uuid_generate(&g_ctrlr1_A.hostid);
474 	spdk_uuid_copy(&g_ctrlr2_A.hostid, &g_ctrlr1_A.hostid);
475 
476 	/* Host B has 1 controller */
477 	spdk_uuid_generate(&g_ctrlr_B.hostid);
478 
479 	/* Host C has 1 controller */
480 	spdk_uuid_generate(&g_ctrlr_C.hostid);
481 }
482 
483 static void
484 ut_reservation_deinit(void)
485 {
486 	struct spdk_nvmf_registrant *reg, *tmp;
487 
488 	TAILQ_FOREACH_SAFE(reg, &g_ns.registrants, link, tmp) {
489 		TAILQ_REMOVE(&g_ns.registrants, reg, link);
490 		free(reg);
491 	}
492 }
493 
494 static struct spdk_nvmf_request *
495 ut_reservation_build_req(uint32_t length)
496 {
497 	struct spdk_nvmf_request *req;
498 
499 	req = calloc(1, sizeof(*req));
500 	assert(req != NULL);
501 
502 	req->data = calloc(1, length);
503 	assert(req->data != NULL);
504 	req->length = length;
505 
506 	req->cmd = (union nvmf_h2c_msg *)calloc(1, sizeof(union nvmf_h2c_msg));
507 	assert(req->cmd != NULL);
508 
509 	req->rsp = (union nvmf_c2h_msg *)calloc(1, sizeof(union nvmf_c2h_msg));
510 	assert(req->rsp != NULL);
511 
512 	return req;
513 }
514 
515 static void
516 ut_reservation_free_req(struct spdk_nvmf_request *req)
517 {
518 	free(req->cmd);
519 	free(req->rsp);
520 	free(req->data);
521 	free(req);
522 }
523 
524 static void
525 ut_reservation_build_register_request(struct spdk_nvmf_request *req,
526 				      uint8_t rrega, uint8_t iekey,
527 				      uint8_t cptpl, uint64_t crkey,
528 				      uint64_t nrkey)
529 {
530 	uint32_t cdw10;
531 	struct spdk_nvme_reservation_register_data key;
532 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
533 
534 	cdw10 = ((cptpl << 30) | (iekey << 3) | rrega);
535 	key.crkey = crkey;
536 	key.nrkey = nrkey;
537 	cmd->cdw10 = cdw10;
538 	memcpy(req->data, &key, sizeof(key));
539 }
540 
541 static void
542 ut_reservation_build_acquire_request(struct spdk_nvmf_request *req,
543 				     uint8_t racqa, uint8_t iekey,
544 				     uint8_t rtype, uint64_t crkey,
545 				     uint64_t prkey)
546 {
547 	uint32_t cdw10;
548 	struct spdk_nvme_reservation_acquire_data key;
549 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
550 
551 	cdw10 = ((rtype << 8) | (iekey << 3) | racqa);
552 	key.crkey = crkey;
553 	key.prkey = prkey;
554 	cmd->cdw10 = cdw10;
555 	memcpy(req->data, &key, sizeof(key));
556 }
557 
558 static void
559 ut_reservation_build_release_request(struct spdk_nvmf_request *req,
560 				     uint8_t rrela, uint8_t iekey,
561 				     uint8_t rtype, uint64_t crkey)
562 {
563 	uint32_t cdw10;
564 	struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
565 
566 	cdw10 = ((rtype << 8) | (iekey << 3) | rrela);
567 	cmd->cdw10 = cdw10;
568 	memcpy(req->data, &crkey, sizeof(crkey));
569 }
570 
571 /*
572  * Construct four registrants for other test cases.
573  *
574  * g_ctrlr1_A register with key 0xa1.
575  * g_ctrlr2_A register with key 0xa1.
576  * g_ctrlr_B register with key 0xb1.
577  * g_ctrlr_C register with key 0xc1.
578  * */
579 static void
580 ut_reservation_build_registrants(void)
581 {
582 	struct spdk_nvmf_request *req;
583 	struct spdk_nvme_cpl *rsp;
584 	struct spdk_nvmf_registrant *reg;
585 	uint32_t gen;
586 
587 	req = ut_reservation_build_req(16);
588 	rsp = &req->rsp->nvme_cpl;
589 	SPDK_CU_ASSERT_FATAL(req != NULL);
590 	gen = g_ns.gen;
591 
592 	/* TEST CASE: g_ctrlr1_A register with a new key */
593 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
594 					      0, 0, 0, 0xa1);
595 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
596 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
597 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
598 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1);
599 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 1);
600 
601 	/* TEST CASE: g_ctrlr2_A register with a new key, because it has same
602 	 * Host Identifier with g_ctrlr1_A, so the register key should same.
603 	 */
604 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
605 					      0, 0, 0, 0xa2);
606 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr2_A, req);
607 	/* Reservation conflict for other key than 0xa1 */
608 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_RESERVATION_CONFLICT);
609 
610 	/* g_ctrlr_B register with a new key */
611 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
612 					      0, 0, 0, 0xb1);
613 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
614 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
615 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
616 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb1);
617 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 2);
618 
619 	/* g_ctrlr_C register with a new key */
620 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REGISTER_KEY,
621 					      0, 0, 0, 0xc1);
622 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
623 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
624 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
625 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc1);
626 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen + 3);
627 
628 	ut_reservation_free_req(req);
629 }
630 
631 static void
632 test_reservation_register(void)
633 {
634 	struct spdk_nvmf_request *req;
635 	struct spdk_nvme_cpl *rsp;
636 	struct spdk_nvmf_registrant *reg;
637 	uint32_t gen;
638 
639 	ut_reservation_init();
640 
641 	req = ut_reservation_build_req(16);
642 	rsp = &req->rsp->nvme_cpl;
643 	SPDK_CU_ASSERT_FATAL(req != NULL);
644 
645 	ut_reservation_build_registrants();
646 
647 	/* TEST CASE: Replace g_ctrlr1_A with a new key */
648 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_REPLACE_KEY,
649 					      0, 0, 0xa1, 0xa11);
650 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
651 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
652 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
653 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa11);
654 
655 	/* TEST CASE: Host A with g_ctrlr1_A get reservation with
656 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
657 	 */
658 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
659 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE, 0xa11, 0x0);
660 	gen = g_ns.gen;
661 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
662 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
663 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
664 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE);
665 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa11);
666 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
667 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
668 
669 	/* TEST CASE: g_ctrlr_C unregister with IEKEY enabled */
670 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
671 					      1, 0, 0, 0);
672 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_C, req);
673 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
674 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
675 	SPDK_CU_ASSERT_FATAL(reg == NULL);
676 
677 	/* TEST CASE: g_ctrlr_B unregister with correct key */
678 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
679 					      0, 0, 0xb1, 0);
680 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr_B, req);
681 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
682 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
683 	SPDK_CU_ASSERT_FATAL(reg == NULL);
684 
685 	/* TEST CASE: g_ctrlr1_A unregister with correct key,
686 	 * reservation should be removed as well.
687 	 */
688 	ut_reservation_build_register_request(req, SPDK_NVME_RESERVE_UNREGISTER_KEY,
689 					      0, 0, 0xa11, 0);
690 	nvmf_ns_reservation_register(&g_ns, &g_ctrlr1_A, req);
691 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
692 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
693 	SPDK_CU_ASSERT_FATAL(reg == NULL);
694 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
695 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
696 	SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
697 
698 	ut_reservation_free_req(req);
699 	ut_reservation_deinit();
700 }
701 
702 static void
703 test_reservation_acquire_preempt_1(void)
704 {
705 	struct spdk_nvmf_request *req;
706 	struct spdk_nvme_cpl *rsp;
707 	struct spdk_nvmf_registrant *reg;
708 	uint32_t gen;
709 
710 	ut_reservation_init();
711 
712 	req = ut_reservation_build_req(16);
713 	rsp = &req->rsp->nvme_cpl;
714 	SPDK_CU_ASSERT_FATAL(req != NULL);
715 
716 	ut_reservation_build_registrants();
717 
718 	gen = g_ns.gen;
719 	/* ACQUIRE: Host A with g_ctrlr1_A acquire reservation with
720 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE.
721 	 */
722 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
723 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY, 0xa1, 0x0);
724 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
725 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
726 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
727 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY);
728 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0xa1);
729 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
730 	SPDK_CU_ASSERT_FATAL(g_ns.gen == gen);
731 
732 	/* TEST CASE: g_ctrlr1_A holds the reservation, g_ctrlr_B preempt g_ctrl1_A,
733 	 * g_ctrl1_A registrant is unregistred.
734 	 */
735 	gen = g_ns.gen;
736 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
737 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1, 0xa1);
738 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_B, req);
739 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
740 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
741 	SPDK_CU_ASSERT_FATAL(reg == NULL);
742 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
743 	SPDK_CU_ASSERT_FATAL(reg != NULL);
744 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
745 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
746 	SPDK_CU_ASSERT_FATAL(reg != NULL);
747 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
748 	SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
749 
750 	/* TEST CASE: g_ctrlr_B holds the reservation, g_ctrlr_C preempt g_ctrlr_B
751 	 * with valid key and PRKEY set to 0, all registrants other the host that issued
752 	 * the command are unregistered.
753 	 */
754 	gen = g_ns.gen;
755 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_PREEMPT, 0,
756 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xc1, 0x0);
757 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr_C, req);
758 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
759 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
760 	SPDK_CU_ASSERT_FATAL(reg == NULL);
761 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
762 	SPDK_CU_ASSERT_FATAL(reg == NULL);
763 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
764 	SPDK_CU_ASSERT_FATAL(reg != NULL);
765 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
766 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
767 	SPDK_CU_ASSERT_FATAL(g_ns.gen > gen);
768 
769 	ut_reservation_free_req(req);
770 	ut_reservation_deinit();
771 }
772 
773 static void
774 test_reservation_release(void)
775 {
776 	struct spdk_nvmf_request *req;
777 	struct spdk_nvme_cpl *rsp;
778 	struct spdk_nvmf_registrant *reg;
779 
780 	ut_reservation_init();
781 
782 	req = ut_reservation_build_req(16);
783 	rsp = &req->rsp->nvme_cpl;
784 	SPDK_CU_ASSERT_FATAL(req != NULL);
785 
786 	ut_reservation_build_registrants();
787 
788 	/* ACQUIRE: Host A with g_ctrlr1_A get reservation with
789 	 * type SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS
790 	 */
791 	ut_reservation_build_acquire_request(req, SPDK_NVME_RESERVE_ACQUIRE, 0,
792 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xa1, 0x0);
793 	nvmf_ns_reservation_acquire(&g_ns, &g_ctrlr1_A, req);
794 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
795 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
796 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS);
797 	SPDK_CU_ASSERT_FATAL(g_ns.holder == reg);
798 
799 	/* Test Case: Host B release the reservation */
800 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_RELEASE, 0,
801 					     SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS, 0xb1);
802 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_B, req);
803 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
804 	SPDK_CU_ASSERT_FATAL(g_ns.rtype == 0);
805 	SPDK_CU_ASSERT_FATAL(g_ns.crkey == 0);
806 	SPDK_CU_ASSERT_FATAL(g_ns.holder == NULL);
807 
808 	/* Test Case: Host C clear the registrants */
809 	ut_reservation_build_release_request(req, SPDK_NVME_RESERVE_CLEAR, 0,
810 					     0, 0xc1);
811 	nvmf_ns_reservation_release(&g_ns, &g_ctrlr_C, req);
812 	SPDK_CU_ASSERT_FATAL(rsp->status.sc == SPDK_NVME_SC_SUCCESS);
813 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr1_A.hostid);
814 	SPDK_CU_ASSERT_FATAL(reg == NULL);
815 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr2_A.hostid);
816 	SPDK_CU_ASSERT_FATAL(reg == NULL);
817 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_B.hostid);
818 	SPDK_CU_ASSERT_FATAL(reg == NULL);
819 	reg = nvmf_ns_reservation_get_registrant(&g_ns, &g_ctrlr_C.hostid);
820 	SPDK_CU_ASSERT_FATAL(reg == NULL);
821 
822 	ut_reservation_free_req(req);
823 	ut_reservation_deinit();
824 }
825 
826 int main(int argc, char **argv)
827 {
828 	CU_pSuite	suite = NULL;
829 	unsigned int	num_failures;
830 
831 	if (CU_initialize_registry() != CUE_SUCCESS) {
832 		return CU_get_error();
833 	}
834 
835 	suite = CU_add_suite("nvmf", NULL, NULL);
836 	if (suite == NULL) {
837 		CU_cleanup_registry();
838 		return CU_get_error();
839 	}
840 
841 	if (
842 		CU_add_test(suite, "create_subsystem", nvmf_test_create_subsystem) == NULL ||
843 		CU_add_test(suite, "nvmf_subsystem_add_ns", test_spdk_nvmf_subsystem_add_ns) == NULL ||
844 		CU_add_test(suite, "nvmf_subsystem_set_sn", test_spdk_nvmf_subsystem_set_sn) == NULL ||
845 		CU_add_test(suite, "reservation_register", test_reservation_register) == NULL ||
846 		CU_add_test(suite, "reservation_acquire_preempt_1", test_reservation_acquire_preempt_1) == NULL ||
847 		CU_add_test(suite, "reservation_release", test_reservation_release) == NULL
848 	) {
849 		CU_cleanup_registry();
850 		return CU_get_error();
851 	}
852 
853 	allocate_threads(1);
854 	set_thread(0);
855 
856 	CU_basic_set_mode(CU_BRM_VERBOSE);
857 	CU_basic_run_tests();
858 	num_failures = CU_get_number_of_failures();
859 	CU_cleanup_registry();
860 
861 	free_threads();
862 
863 	return num_failures;
864 }
865