xref: /spdk/test/unit/lib/nvmf/ctrlr_discovery.c/ctrlr_discovery_ut.c (revision 8dd1cd2104ea4001e4a0da2a4851ccd62c82f8e8)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  *   Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 
9 #include "spdk_cunit.h"
10 #include "spdk_internal/mock.h"
11 
12 #include "common/lib/test_env.c"
13 #include "spdk/bdev_module.h"
14 #include "nvmf/ctrlr_discovery.c"
15 #include "nvmf/subsystem.c"
16 
17 SPDK_LOG_REGISTER_COMPONENT(nvmf)
18 
19 DEFINE_STUB_V(spdk_bdev_module_release_bdev,
20 	      (struct spdk_bdev *bdev));
21 
22 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t,
23 	    (const struct spdk_bdev *bdev), 512);
24 
25 DEFINE_STUB(spdk_nvmf_transport_stop_listen,
26 	    int,
27 	    (struct spdk_nvmf_transport *transport,
28 	     const struct spdk_nvme_transport_id *trid), 0);
29 
30 DEFINE_STUB(spdk_nvmf_transport_get_first,
31 	    struct spdk_nvmf_transport *,
32 	    (struct spdk_nvmf_tgt *tgt), NULL);
33 
34 DEFINE_STUB(spdk_nvmf_transport_get_next,
35 	    struct spdk_nvmf_transport *,
36 	    (struct spdk_nvmf_transport *transport), NULL);
37 
38 DEFINE_STUB_V(spdk_bdev_close, (struct spdk_bdev_desc *desc));
39 
40 DEFINE_STUB_V(nvmf_ctrlr_async_event_discovery_log_change_notice, (void *ctx));
41 
42 DEFINE_STUB(spdk_nvmf_qpair_disconnect, int,
43 	    (struct spdk_nvmf_qpair *qpair,
44 	     nvmf_qpair_disconnect_cb cb_fn, void *ctx), 0);
45 
46 DEFINE_STUB(spdk_bdev_open_ext, int,
47 	    (const char *bdev_name, bool write,	spdk_bdev_event_cb_t event_cb,
48 	     void *event_ctx, struct spdk_bdev_desc **desc), 0);
49 
50 DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *,
51 	    (struct spdk_bdev_desc *desc), NULL);
52 
53 DEFINE_STUB(spdk_bdev_get_md_size, uint32_t,
54 	    (const struct spdk_bdev *bdev), 0);
55 
56 DEFINE_STUB(spdk_bdev_is_md_interleaved, bool,
57 	    (const struct spdk_bdev *bdev), false);
58 
59 DEFINE_STUB(spdk_bdev_module_claim_bdev, int,
60 	    (struct spdk_bdev *bdev, struct spdk_bdev_desc *desc,
61 	     struct spdk_bdev_module *module), 0);
62 
63 DEFINE_STUB(spdk_bdev_io_type_supported, bool,
64 	    (struct spdk_bdev *bdev, enum spdk_bdev_io_type io_type), false);
65 
66 DEFINE_STUB_V(nvmf_ctrlr_reservation_notice_log,
67 	      (struct spdk_nvmf_ctrlr *ctrlr, struct spdk_nvmf_ns *ns,
68 	       enum spdk_nvme_reservation_notification_log_page_type type));
69 
70 DEFINE_STUB(spdk_nvmf_request_complete, int,
71 	    (struct spdk_nvmf_request *req), -1);
72 
73 DEFINE_STUB(nvmf_ctrlr_async_event_ana_change_notice, int,
74 	    (struct spdk_nvmf_ctrlr *ctrlr), 0);
75 
76 DEFINE_STUB(spdk_nvme_transport_id_trtype_str, const char *,
77 	    (enum spdk_nvme_transport_type trtype), NULL);
78 
79 const char *
80 spdk_bdev_get_name(const struct spdk_bdev *bdev)
81 {
82 	return "test";
83 }
84 
85 const struct spdk_uuid *
86 spdk_bdev_get_uuid(const struct spdk_bdev *bdev)
87 {
88 	return &bdev->uuid;
89 }
90 
91 int
92 spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1,
93 			       const struct spdk_nvme_transport_id *trid2)
94 {
95 	return !(trid1->trtype == trid2->trtype && strcasecmp(trid1->traddr, trid2->traddr) == 0 &&
96 		 strcasecmp(trid1->trsvcid, trid2->trsvcid) == 0);
97 }
98 
99 int
100 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
101 			   const struct spdk_nvme_transport_id *trid, struct spdk_nvmf_listen_opts *opts)
102 {
103 	return 0;
104 }
105 
106 static struct spdk_nvmf_listener g_listener = {};
107 
108 struct spdk_nvmf_listener *
109 nvmf_transport_find_listener(struct spdk_nvmf_transport *transport,
110 			     const struct spdk_nvme_transport_id *trid)
111 {
112 	struct spdk_nvmf_listener *listener;
113 
114 	if (TAILQ_EMPTY(&transport->listeners)) {
115 		return &g_listener;
116 	}
117 
118 	TAILQ_FOREACH(listener, &transport->listeners, link) {
119 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
120 			return listener;
121 		}
122 	}
123 
124 	return NULL;
125 }
126 
127 void
128 nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport,
129 				 struct spdk_nvme_transport_id *trid,
130 				 struct spdk_nvmf_discovery_log_page_entry *entry)
131 {
132 	transport->ops->listener_discover(transport, trid, entry);
133 }
134 
135 static void
136 test_dummy_listener_discover(struct spdk_nvmf_transport *transport,
137 			     struct spdk_nvme_transport_id *trid, struct spdk_nvmf_discovery_log_page_entry *entry)
138 {
139 	entry->trtype = 42;
140 }
141 
142 struct spdk_nvmf_transport_ops g_transport_ops = { .listener_discover = test_dummy_listener_discover };
143 
144 static struct spdk_nvmf_transport g_transport = {
145 	.ops = &g_transport_ops
146 };
147 
148 struct spdk_nvmf_transport *
149 spdk_nvmf_transport_create(const char *transport_name,
150 			   struct spdk_nvmf_transport_opts *tprt_opts)
151 {
152 	if (strcasecmp(transport_name, spdk_nvme_transport_id_trtype_str(SPDK_NVME_TRANSPORT_RDMA))) {
153 		return &g_transport;
154 	}
155 
156 	return NULL;
157 }
158 
159 struct spdk_nvmf_subsystem *
160 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
161 {
162 	return NULL;
163 }
164 
165 DEFINE_RETURN_MOCK(spdk_nvmf_tgt_get_transport, struct spdk_nvmf_transport *);
166 struct spdk_nvmf_transport *
167 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, const char *transport_name)
168 {
169 	HANDLE_RETURN_MOCK(spdk_nvmf_tgt_get_transport);
170 	return &g_transport;
171 }
172 
173 int
174 spdk_nvme_transport_id_parse_trtype(enum spdk_nvme_transport_type *trtype, const char *str)
175 {
176 	if (trtype == NULL || str == NULL) {
177 		return -EINVAL;
178 	}
179 
180 	if (strcasecmp(str, "PCIe") == 0) {
181 		*trtype = SPDK_NVME_TRANSPORT_PCIE;
182 	} else if (strcasecmp(str, "RDMA") == 0) {
183 		*trtype = SPDK_NVME_TRANSPORT_RDMA;
184 	} else {
185 		return -ENOENT;
186 	}
187 	return 0;
188 }
189 
190 void
191 nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
192 {
193 }
194 
195 void
196 nvmf_ctrlr_destruct(struct spdk_nvmf_ctrlr *ctrlr)
197 {
198 }
199 
200 int
201 nvmf_poll_group_update_subsystem(struct spdk_nvmf_poll_group *group,
202 				 struct spdk_nvmf_subsystem *subsystem)
203 {
204 	return 0;
205 }
206 
207 int
208 nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
209 			      struct spdk_nvmf_subsystem *subsystem,
210 			      spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
211 {
212 	return 0;
213 }
214 
215 void
216 nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
217 				 struct spdk_nvmf_subsystem *subsystem,
218 				 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
219 {
220 }
221 
222 void
223 nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
224 				struct spdk_nvmf_subsystem *subsystem,
225 				uint32_t nsid,
226 				spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
227 {
228 }
229 
230 void
231 nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
232 				 struct spdk_nvmf_subsystem *subsystem,
233 				 spdk_nvmf_poll_group_mod_done cb_fn, void *cb_arg)
234 {
235 }
236 
237 static void
238 _subsystem_add_listen_done(void *cb_arg, int status)
239 {
240 	SPDK_CU_ASSERT_FATAL(status == 0);
241 }
242 
243 static void
244 test_gen_trid(struct spdk_nvme_transport_id *trid, enum spdk_nvme_transport_type trtype,
245 	      enum spdk_nvmf_adrfam adrfam, const char *tradd, const char *trsvcid)
246 {
247 	snprintf(trid->traddr, sizeof(trid->traddr), "%s", tradd);
248 	snprintf(trid->trsvcid, sizeof(trid->trsvcid), "%s", trsvcid);
249 	trid->adrfam = adrfam;
250 	trid->trtype = trtype;
251 	switch (trtype) {
252 	case SPDK_NVME_TRANSPORT_RDMA:
253 		snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", SPDK_NVME_TRANSPORT_NAME_RDMA);
254 		break;
255 	case SPDK_NVME_TRANSPORT_TCP:
256 		snprintf(trid->trstring, SPDK_NVMF_TRSTRING_MAX_LEN, "%s", SPDK_NVME_TRANSPORT_NAME_TCP);
257 		break;
258 	default:
259 		SPDK_CU_ASSERT_FATAL(0 && "not supported by test");
260 	}
261 }
262 
263 static void
264 test_discovery_log(void)
265 {
266 	struct spdk_nvmf_tgt tgt = {};
267 	struct spdk_nvmf_subsystem *subsystem;
268 	uint8_t buffer[8192];
269 	struct iovec iov;
270 	struct spdk_nvmf_discovery_log_page *disc_log;
271 	struct spdk_nvmf_discovery_log_page_entry *entry;
272 	struct spdk_nvme_transport_id trid = {};
273 	const char *hostnqn = "nqn.2016-06.io.spdk:host1";
274 	int rc;
275 
276 	iov.iov_base = buffer;
277 	iov.iov_len = 8192;
278 
279 	tgt.max_subsystems = 1024;
280 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
281 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
282 
283 	/* Add one subsystem and verify that the discovery log contains it */
284 	subsystem = spdk_nvmf_subsystem_create(&tgt, "nqn.2016-06.io.spdk:subsystem1",
285 					       SPDK_NVMF_SUBTYPE_NVME, 0);
286 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
287 
288 	rc = spdk_nvmf_subsystem_add_host(subsystem, hostnqn);
289 	CU_ASSERT(rc == 0);
290 
291 	/* Get only genctr (first field in the header) */
292 	memset(buffer, 0xCC, sizeof(buffer));
293 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
294 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(disc_log->genctr),
295 				    &trid);
296 	/* No listeners yet on new subsystem, so genctr should still be 0. */
297 	CU_ASSERT(disc_log->genctr == 0);
298 
299 	test_gen_trid(&trid, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "1234", "5678");
300 	spdk_nvmf_subsystem_add_listener(subsystem, &trid, _subsystem_add_listen_done, NULL);
301 	subsystem->state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
302 
303 	/* Get only genctr (first field in the header) */
304 	memset(buffer, 0xCC, sizeof(buffer));
305 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
306 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(disc_log->genctr),
307 				    &trid);
308 	CU_ASSERT(disc_log->genctr == 1); /* one added subsystem and listener */
309 
310 	/* Get only the header, no entries */
311 	memset(buffer, 0xCC, sizeof(buffer));
312 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
313 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(*disc_log),
314 				    &trid);
315 	CU_ASSERT(disc_log->genctr == 1);
316 	CU_ASSERT(disc_log->numrec == 1);
317 
318 	/* Offset 0, exact size match */
319 	memset(buffer, 0xCC, sizeof(buffer));
320 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
321 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0,
322 				    sizeof(*disc_log) + sizeof(disc_log->entries[0]), &trid);
323 	CU_ASSERT(disc_log->genctr != 0);
324 	CU_ASSERT(disc_log->numrec == 1);
325 	CU_ASSERT(disc_log->entries[0].trtype == 42);
326 
327 	/* Offset 0, oversize buffer */
328 	memset(buffer, 0xCC, sizeof(buffer));
329 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
330 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(buffer), &trid);
331 	CU_ASSERT(disc_log->genctr != 0);
332 	CU_ASSERT(disc_log->numrec == 1);
333 	CU_ASSERT(disc_log->entries[0].trtype == 42);
334 	CU_ASSERT(spdk_mem_all_zero(buffer + sizeof(*disc_log) + sizeof(disc_log->entries[0]),
335 				    sizeof(buffer) - (sizeof(*disc_log) + sizeof(disc_log->entries[0]))));
336 
337 	/* Get just the first entry, no header */
338 	memset(buffer, 0xCC, sizeof(buffer));
339 	entry = (struct spdk_nvmf_discovery_log_page_entry *)buffer;
340 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1,
341 				    offsetof(struct spdk_nvmf_discovery_log_page, entries[0]), sizeof(*entry), &trid);
342 	CU_ASSERT(entry->trtype == 42);
343 
344 	/* remove the host and verify that the discovery log contains nothing */
345 	rc = spdk_nvmf_subsystem_remove_host(subsystem, hostnqn);
346 	CU_ASSERT(rc == 0);
347 
348 	/* Get only the header, no entries */
349 	memset(buffer, 0xCC, sizeof(buffer));
350 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
351 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(*disc_log),
352 				    &trid);
353 	CU_ASSERT(disc_log->genctr != 0);
354 	CU_ASSERT(disc_log->numrec == 0);
355 
356 	/* destroy the subsystem and verify that the discovery log contains nothing */
357 	subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
358 	rc = spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
359 	CU_ASSERT(rc == 0);
360 
361 	/* Get only the header, no entries */
362 	memset(buffer, 0xCC, sizeof(buffer));
363 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
364 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, sizeof(*disc_log),
365 				    &trid);
366 	CU_ASSERT(disc_log->genctr != 0);
367 	CU_ASSERT(disc_log->numrec == 0);
368 
369 	free(tgt.subsystems);
370 }
371 
372 static void
373 test_rdma_discover(struct spdk_nvmf_transport *transport, struct spdk_nvme_transport_id *trid,
374 		   struct spdk_nvmf_discovery_log_page_entry *entry)
375 {
376 	entry->trtype = SPDK_NVMF_TRTYPE_RDMA;
377 	entry->adrfam = trid->adrfam;
378 	memcpy(entry->traddr, trid->traddr, sizeof(entry->traddr));
379 	memcpy(entry->trsvcid, trid->trsvcid, sizeof(entry->trsvcid));
380 }
381 
382 static void
383 test_tcp_discover(struct spdk_nvmf_transport *transport, struct spdk_nvme_transport_id *trid,
384 		  struct spdk_nvmf_discovery_log_page_entry *entry)
385 {
386 	entry->trtype = SPDK_NVMF_TRTYPE_TCP;
387 	entry->adrfam = trid->adrfam;
388 	memcpy(entry->traddr, trid->traddr, sizeof(entry->traddr));
389 	memcpy(entry->trsvcid, trid->trsvcid, sizeof(entry->trsvcid));
390 }
391 
392 static void
393 test_discovery_log_with_filters(void)
394 {
395 	struct spdk_nvmf_tgt tgt = {};
396 	struct spdk_nvmf_transport_ops rdma_tr_ops = { .listener_discover = test_rdma_discover }, tcp_tr_ops
397 		= { .listener_discover = test_tcp_discover };
398 	struct spdk_nvmf_transport rdma_tr = {.ops = &rdma_tr_ops }, tcp_tr = { .ops = &tcp_tr_ops };
399 	struct spdk_nvmf_subsystem *subsystem;
400 	const char *hostnqn = "nqn.2016-06.io.spdk:host1";
401 	uint8_t buffer[8192];
402 	struct iovec iov;
403 	struct spdk_nvmf_discovery_log_page *disc_log;
404 	struct spdk_nvmf_listener rdma_listener_1 = {}, rdma_listener_2 = {}, rdma_listener_3 = {},
405 	tcp_listener_1 = {}, tcp_listener_2 = {}, tcp_listener_3 = {};
406 	struct spdk_nvme_transport_id rdma_trid_1 = {}, rdma_trid_2 = {}, rdma_trid_3 = {}, tcp_trid_1 = {},
407 	tcp_trid_2 = {}, tcp_trid_3 = {};
408 
409 	iov.iov_base = buffer;
410 	iov.iov_len = 8192;
411 
412 	tgt.max_subsystems = 4;
413 	tgt.subsystems = calloc(tgt.max_subsystems, sizeof(struct spdk_nvmf_subsystem *));
414 	SPDK_CU_ASSERT_FATAL(tgt.subsystems != NULL);
415 
416 	subsystem = spdk_nvmf_subsystem_create(&tgt, "nqn.2016-06.io.spdk:subsystem1",
417 					       SPDK_NVMF_SUBTYPE_NVME, 0);
418 	subsystem->flags.allow_any_host = true;
419 	SPDK_CU_ASSERT_FATAL(subsystem != NULL);
420 
421 	test_gen_trid(&rdma_trid_1, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4420");
422 	test_gen_trid(&rdma_trid_2, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4420");
423 	test_gen_trid(&rdma_trid_3, SPDK_NVME_TRANSPORT_RDMA, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4421");
424 	test_gen_trid(&tcp_trid_1, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4421");
425 	test_gen_trid(&tcp_trid_2, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "10.10.10.10", "4422");
426 	test_gen_trid(&tcp_trid_3, SPDK_NVME_TRANSPORT_TCP, SPDK_NVMF_ADRFAM_IPV4, "11.11.11.11", "4422");
427 
428 	rdma_listener_1.trid = rdma_trid_1;
429 	rdma_listener_2.trid = rdma_trid_2;
430 	rdma_listener_3.trid = rdma_trid_3;
431 	TAILQ_INIT(&rdma_tr.listeners);
432 	TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_1, link);
433 	TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_2, link);
434 	TAILQ_INSERT_TAIL(&rdma_tr.listeners, &rdma_listener_3, link);
435 
436 	tcp_listener_1.trid = tcp_trid_1;
437 	tcp_listener_2.trid = tcp_trid_2;
438 	tcp_listener_3.trid = tcp_trid_3;
439 	TAILQ_INIT(&tcp_tr.listeners);
440 	TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_1, link);
441 	TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_2, link);
442 	TAILQ_INSERT_TAIL(&tcp_tr.listeners, &tcp_listener_3, link);
443 
444 	MOCK_SET(spdk_nvmf_tgt_get_transport, &rdma_tr);
445 	spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_1, _subsystem_add_listen_done, NULL);
446 	spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_2, _subsystem_add_listen_done, NULL);
447 	spdk_nvmf_subsystem_add_listener(subsystem, &rdma_trid_3, _subsystem_add_listen_done, NULL);
448 	MOCK_SET(spdk_nvmf_tgt_get_transport, &tcp_tr);
449 	spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_1, _subsystem_add_listen_done, NULL);
450 	spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_2, _subsystem_add_listen_done, NULL);
451 	spdk_nvmf_subsystem_add_listener(subsystem, &tcp_trid_3, _subsystem_add_listen_done, NULL);
452 	MOCK_CLEAR(spdk_nvmf_tgt_get_transport);
453 
454 	subsystem->state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
455 
456 	disc_log = (struct spdk_nvmf_discovery_log_page *)buffer;
457 	memset(buffer, 0, sizeof(buffer));
458 
459 	/* Test case 1 - check that all trids are reported */
460 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY;
461 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
462 	CU_ASSERT(disc_log->numrec == 6);
463 
464 	/* Test case 2 - check that only entries of the same transport type are returned */
465 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE;
466 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
467 	CU_ASSERT(disc_log->numrec == 3);
468 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype);
469 	CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_1.trtype);
470 	CU_ASSERT(disc_log->entries[2].trtype == rdma_trid_1.trtype);
471 
472 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
473 	CU_ASSERT(disc_log->numrec == 3);
474 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype);
475 	CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_1.trtype);
476 	CU_ASSERT(disc_log->entries[2].trtype == tcp_trid_1.trtype);
477 
478 	/* Test case 3 - check that only entries of the same transport address are returned */
479 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS;
480 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
481 	CU_ASSERT(disc_log->numrec == 3);
482 	/* one tcp and 2 rdma  */
483 	CU_ASSERT((disc_log->entries[0].trtype ^ disc_log->entries[1].trtype ^ disc_log->entries[2].trtype)
484 		  != 0);
485 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0);
486 	CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, rdma_trid_1.traddr) == 0);
487 	CU_ASSERT(strcasecmp(disc_log->entries[2].traddr, rdma_trid_1.traddr) == 0);
488 
489 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
490 	CU_ASSERT(disc_log->numrec == 3);
491 	/* one rdma and two tcp */
492 	CU_ASSERT((disc_log->entries[0].trtype ^ disc_log->entries[1].trtype ^ disc_log->entries[2].trtype)
493 		  != 0);
494 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0);
495 	CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, tcp_trid_1.traddr) == 0);
496 	CU_ASSERT(strcasecmp(disc_log->entries[2].traddr, tcp_trid_1.traddr) == 0);
497 
498 	/* Test case 4 - check that only entries of the same transport address and type returned */
499 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE |
500 			       SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS;
501 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
502 	CU_ASSERT(disc_log->numrec == 2);
503 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0);
504 	CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, rdma_trid_1.traddr) == 0);
505 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype);
506 	CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_1.trtype);
507 
508 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_2);
509 	CU_ASSERT(disc_log->numrec == 1);
510 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0);
511 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype);
512 
513 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
514 	CU_ASSERT(disc_log->numrec == 2);
515 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0);
516 	CU_ASSERT(strcasecmp(disc_log->entries[1].traddr, tcp_trid_1.traddr) == 0);
517 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype);
518 	CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_1.trtype);
519 
520 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_2);
521 	CU_ASSERT(disc_log->numrec == 1);
522 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0);
523 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype);
524 
525 	/* Test case 5 - check that only entries of the same transport address and type returned */
526 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE |
527 			       SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID;
528 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
529 	CU_ASSERT(disc_log->numrec == 2);
530 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0);
531 	CU_ASSERT(strcasecmp(disc_log->entries[1].trsvcid, rdma_trid_2.trsvcid) == 0);
532 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype);
533 	CU_ASSERT(disc_log->entries[1].trtype == rdma_trid_2.trtype);
534 
535 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_3);
536 	CU_ASSERT(disc_log->numrec == 1);
537 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0);
538 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype);
539 
540 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
541 	CU_ASSERT(disc_log->numrec == 1);
542 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0);
543 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype);
544 
545 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_2);
546 	CU_ASSERT(disc_log->numrec == 2);
547 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0);
548 	CU_ASSERT(strcasecmp(disc_log->entries[1].trsvcid, tcp_trid_2.trsvcid) == 0);
549 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype);
550 	CU_ASSERT(disc_log->entries[1].trtype == tcp_trid_2.trtype);
551 
552 	/* Test case 6 - check that only entries of the same transport address and type returned.
553 	 * That also implies trtype since RDMA and TCP listeners can't occupy the same socket */
554 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS |
555 			       SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID;
556 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
557 	CU_ASSERT(disc_log->numrec == 1);
558 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0);
559 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0);
560 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype);
561 
562 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_2);
563 	CU_ASSERT(disc_log->numrec == 1);
564 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0);
565 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_2.trsvcid) == 0);
566 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype);
567 
568 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_3);
569 	CU_ASSERT(disc_log->numrec == 1);
570 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_3.traddr) == 0);
571 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0);
572 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype);
573 
574 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
575 	CU_ASSERT(disc_log->numrec == 1);
576 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0);
577 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0);
578 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype);
579 
580 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_2);
581 	CU_ASSERT(disc_log->numrec == 1);
582 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_2.traddr) == 0);
583 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0);
584 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype);
585 
586 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_3);
587 	CU_ASSERT(disc_log->numrec == 1);
588 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_3.traddr) == 0);
589 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_3.trsvcid) == 0);
590 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_3.trtype);
591 
592 	/* Test case 7 - check that only entries of the same transport address, svcid and type returned */
593 	tgt.discovery_filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE |
594 			       SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS |
595 			       SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID;
596 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_1);
597 	CU_ASSERT(disc_log->numrec == 1);
598 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_1.traddr) == 0);
599 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_1.trsvcid) == 0);
600 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_1.trtype);
601 
602 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_2);
603 	CU_ASSERT(disc_log->numrec == 1);
604 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_2.traddr) == 0);
605 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_2.trsvcid) == 0);
606 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_2.trtype);
607 
608 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &rdma_trid_3);
609 	CU_ASSERT(disc_log->numrec == 1);
610 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, rdma_trid_3.traddr) == 0);
611 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, rdma_trid_3.trsvcid) == 0);
612 	CU_ASSERT(disc_log->entries[0].trtype == rdma_trid_3.trtype);
613 
614 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_1);
615 	CU_ASSERT(disc_log->numrec == 1);
616 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_1.traddr) == 0);
617 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_1.trsvcid) == 0);
618 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_1.trtype);
619 
620 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_2);
621 	CU_ASSERT(disc_log->numrec == 1);
622 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_2.traddr) == 0);
623 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_2.trsvcid) == 0);
624 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_2.trtype);
625 
626 	nvmf_get_discovery_log_page(&tgt, hostnqn, &iov, 1, 0, 8192, &tcp_trid_3);
627 	CU_ASSERT(disc_log->numrec == 1);
628 	CU_ASSERT(strcasecmp(disc_log->entries[0].traddr, tcp_trid_3.traddr) == 0);
629 	CU_ASSERT(strcasecmp(disc_log->entries[0].trsvcid, tcp_trid_3.trsvcid) == 0);
630 	CU_ASSERT(disc_log->entries[0].trtype == tcp_trid_3.trtype);
631 
632 	subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
633 	spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
634 	free(tgt.subsystems);
635 }
636 
637 int
638 main(int argc, char **argv)
639 {
640 	CU_pSuite	suite = NULL;
641 	unsigned int	num_failures;
642 
643 	CU_set_error_action(CUEA_ABORT);
644 	CU_initialize_registry();
645 
646 	suite = CU_add_suite("nvmf", NULL, NULL);
647 
648 	CU_ADD_TEST(suite, test_discovery_log);
649 	CU_ADD_TEST(suite, test_discovery_log_with_filters);
650 
651 	CU_basic_set_mode(CU_BRM_VERBOSE);
652 	CU_basic_run_tests();
653 	num_failures = CU_get_number_of_failures();
654 	CU_cleanup_registry();
655 	return num_failures;
656 }
657