1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 #include "spdk_cunit.h" 7 #include "common/lib/test_env.c" 8 #include "nvmf/transport.c" 9 #include "nvmf/rdma.c" 10 #include "common/lib/test_rdma.c" 11 12 SPDK_LOG_REGISTER_COMPONENT(nvmf) 13 14 #define RDMA_UT_UNITS_IN_MAX_IO 16 15 #define SPDK_NVMF_DEFAULT_BUFFER_CACHE_SIZE 32 16 17 struct spdk_nvmf_transport_opts g_rdma_ut_transport_opts = { 18 .max_queue_depth = SPDK_NVMF_RDMA_DEFAULT_MAX_QUEUE_DEPTH, 19 .max_qpairs_per_ctrlr = SPDK_NVMF_RDMA_DEFAULT_MAX_QPAIRS_PER_CTRLR, 20 .in_capsule_data_size = SPDK_NVMF_RDMA_DEFAULT_IN_CAPSULE_DATA_SIZE, 21 .max_io_size = (SPDK_NVMF_RDMA_MIN_IO_BUFFER_SIZE * RDMA_UT_UNITS_IN_MAX_IO), 22 .io_unit_size = SPDK_NVMF_RDMA_MIN_IO_BUFFER_SIZE, 23 .max_aq_depth = SPDK_NVMF_RDMA_DEFAULT_AQ_DEPTH, 24 .num_shared_buffers = SPDK_NVMF_RDMA_DEFAULT_NUM_SHARED_BUFFERS, 25 .opts_size = sizeof(g_rdma_ut_transport_opts) 26 }; 27 28 DEFINE_STUB(spdk_nvme_transport_id_compare, int, (const struct spdk_nvme_transport_id *trid1, 29 const struct spdk_nvme_transport_id *trid2), 0); 30 DEFINE_STUB_V(spdk_nvmf_tgt_new_qpair, (struct spdk_nvmf_tgt *tgt, struct spdk_nvmf_qpair *qpair)); 31 DEFINE_STUB(spdk_nvmf_request_get_dif_ctx, bool, (struct spdk_nvmf_request *req, 32 struct spdk_dif_ctx *dif_ctx), false); 33 DEFINE_STUB(spdk_nvmf_qpair_disconnect, int, (struct spdk_nvmf_qpair *qpair, 34 nvmf_qpair_disconnect_cb cb_fn, void *ctx), 0); 35 DEFINE_STUB_V(spdk_nvmf_request_exec, (struct spdk_nvmf_request *req)); 36 DEFINE_STUB_V(spdk_nvme_trid_populate_transport, (struct spdk_nvme_transport_id *trid, 37 enum spdk_nvme_transport_type trtype)); 38 DEFINE_STUB(nvmf_ctrlr_abort_request, int, (struct spdk_nvmf_request *req), 0); 39 DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), 0); 40 DEFINE_STUB(ut_transport_create, struct spdk_nvmf_transport *, 41 (struct spdk_nvmf_transport_opts *opts), NULL); 42 DEFINE_STUB(ut_transport_destroy, int, (struct spdk_nvmf_transport *transport, 43 spdk_nvmf_transport_destroy_done_cb cb_fn, void *cb_arg), 0); 44 DEFINE_STUB(ibv_get_device_name, const char *, (struct ibv_device *device), NULL); 45 DEFINE_STUB(ibv_query_qp, int, (struct ibv_qp *qp, struct ibv_qp_attr *attr, 46 int attr_mask, 47 struct ibv_qp_init_attr *init_attr), 0); 48 DEFINE_STUB(rdma_create_id, int, (struct rdma_event_channel *channel, 49 struct rdma_cm_id **id, void *context, 50 enum rdma_port_space ps), 0); 51 DEFINE_STUB(rdma_bind_addr, int, (struct rdma_cm_id *id, struct sockaddr *addr), 0); 52 DEFINE_STUB(rdma_listen, int, (struct rdma_cm_id *id, int backlog), 0); 53 DEFINE_STUB(rdma_destroy_id, int, (struct rdma_cm_id *id), 0); 54 DEFINE_STUB(ibv_dereg_mr, int, (struct ibv_mr *mr), 0); 55 DEFINE_STUB(rdma_reject, int, (struct rdma_cm_id *id, 56 const void *private_data, uint8_t private_data_len), 0); 57 DEFINE_STUB(ibv_resize_cq, int, (struct ibv_cq *cq, int cqe), 0); 58 DEFINE_STUB_V(rdma_destroy_qp, (struct rdma_cm_id *id)); 59 DEFINE_STUB_V(rdma_destroy_event_channel, (struct rdma_event_channel *channel)); 60 DEFINE_STUB(ibv_dealloc_pd, int, (struct ibv_pd *pd), 0); 61 DEFINE_STUB(rdma_create_event_channel, struct rdma_event_channel *, (void), NULL); 62 DEFINE_STUB(rdma_get_devices, struct ibv_context **, (int *num_devices), NULL); 63 DEFINE_STUB(ibv_query_device, int, (struct ibv_context *context, 64 struct ibv_device_attr *device_attr), 0); 65 DEFINE_STUB(ibv_alloc_pd, struct ibv_pd *, (struct ibv_context *context), NULL); 66 DEFINE_STUB_V(rdma_free_devices, (struct ibv_context **list)); 67 DEFINE_STUB(ibv_get_async_event, int, (struct ibv_context *context, struct ibv_async_event *event), 68 0); 69 DEFINE_STUB(ibv_event_type_str, const char *, (enum ibv_event_type event_type), NULL); 70 DEFINE_STUB_V(ibv_ack_async_event, (struct ibv_async_event *event)); 71 DEFINE_STUB(rdma_get_cm_event, int, (struct rdma_event_channel *channel, 72 struct rdma_cm_event **event), 0); 73 DEFINE_STUB(rdma_ack_cm_event, int, (struct rdma_cm_event *event), 0); 74 DEFINE_STUB(ibv_destroy_cq, int, (struct ibv_cq *cq), 0); 75 DEFINE_STUB(ibv_create_cq, struct ibv_cq *, (struct ibv_context *context, int cqe, 76 void *cq_context, 77 struct ibv_comp_channel *channel, 78 int comp_vector), NULL); 79 DEFINE_STUB(ibv_wc_status_str, const char *, (enum ibv_wc_status status), NULL); 80 DEFINE_STUB(rdma_get_dst_port, __be16, (struct rdma_cm_id *id), 0); 81 DEFINE_STUB(rdma_get_src_port, __be16, (struct rdma_cm_id *id), 0); 82 DEFINE_STUB(spdk_nvmf_qpair_get_listen_trid, int, (struct spdk_nvmf_qpair *qpair, 83 struct spdk_nvme_transport_id *trid), 0); 84 DEFINE_STUB(ibv_reg_mr_iova2, struct ibv_mr *, (struct ibv_pd *pd, void *addr, size_t length, 85 uint64_t iova, unsigned int access), NULL); 86 DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, (enum spdk_nvmf_adrfam adrfam), NULL); 87 DEFINE_STUB_V(ut_opts_init, (struct spdk_nvmf_transport_opts *opts)); 88 DEFINE_STUB(ut_transport_listen, int, (struct spdk_nvmf_transport *transport, 89 const struct spdk_nvme_transport_id *trid, struct spdk_nvmf_listen_opts *opts), 0); 90 DEFINE_STUB_V(ut_transport_stop_listen, (struct spdk_nvmf_transport *transport, 91 const struct spdk_nvme_transport_id *trid)); 92 93 /* ibv_reg_mr can be a macro, need to undefine it */ 94 #ifdef ibv_reg_mr 95 #undef ibv_reg_mr 96 #endif 97 98 DEFINE_RETURN_MOCK(ibv_reg_mr, struct ibv_mr *); 99 struct ibv_mr * 100 ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access) 101 { 102 HANDLE_RETURN_MOCK(ibv_reg_mr); 103 if (length > 0) { 104 return &g_rdma_mr; 105 } else { 106 return NULL; 107 } 108 } 109 110 static void 111 test_spdk_nvmf_transport_create(void) 112 { 113 int rc; 114 struct spdk_nvmf_transport ut_transport = {}; 115 struct spdk_nvmf_transport *transport = NULL; 116 struct nvmf_transport_ops_list_element *ops_element; 117 struct spdk_nvmf_transport_ops ops = { 118 .name = "new_ops", 119 .type = (enum spdk_nvme_transport_type)SPDK_NVMF_TRTYPE_RDMA, 120 .create = ut_transport_create, 121 .destroy = ut_transport_destroy 122 }; 123 124 /* No available ops element */ 125 transport = spdk_nvmf_transport_create("new_ops", &g_rdma_ut_transport_opts); 126 CU_ASSERT(transport == NULL); 127 128 /* Create transport successfully */ 129 MOCK_SET(ut_transport_create, &ut_transport); 130 spdk_nvmf_transport_register(&ops); 131 132 transport = spdk_nvmf_transport_create("new_ops", &g_rdma_ut_transport_opts); 133 CU_ASSERT(transport == &ut_transport); 134 CU_ASSERT(!memcmp(&transport->opts, &g_rdma_ut_transport_opts, sizeof(g_rdma_ut_transport_opts))); 135 CU_ASSERT(!memcmp(transport->ops, &ops, sizeof(ops))); 136 CU_ASSERT(transport->data_buf_pool != NULL); 137 138 rc = spdk_nvmf_transport_destroy(transport, NULL, NULL); 139 CU_ASSERT(rc == 0); 140 141 /* transport_opts parameter invalid */ 142 g_rdma_ut_transport_opts.max_io_size = 4096; 143 144 transport = spdk_nvmf_transport_create("new_ops", &g_rdma_ut_transport_opts); 145 CU_ASSERT(transport == NULL); 146 g_rdma_ut_transport_opts.max_io_size = (SPDK_NVMF_RDMA_MIN_IO_BUFFER_SIZE * 147 RDMA_UT_UNITS_IN_MAX_IO); 148 149 ops_element = TAILQ_LAST(&g_spdk_nvmf_transport_ops, nvmf_transport_ops_list); 150 TAILQ_REMOVE(&g_spdk_nvmf_transport_ops, ops_element, link); 151 free(ops_element); 152 MOCK_CLEAR(ut_transport_create); 153 } 154 155 static struct spdk_nvmf_transport_poll_group * 156 ut_poll_group_create(struct spdk_nvmf_transport *transport, 157 struct spdk_nvmf_poll_group *group) 158 { 159 struct spdk_nvmf_transport_poll_group *tgroup; 160 161 tgroup = calloc(1, sizeof(*tgroup)); 162 SPDK_CU_ASSERT_FATAL(tgroup != NULL); 163 return tgroup; 164 } 165 166 static void 167 ut_poll_group_destroy(struct spdk_nvmf_transport_poll_group *group) 168 { 169 free(group); 170 } 171 172 static void 173 test_nvmf_transport_poll_group_create(void) 174 { 175 struct spdk_nvmf_transport_poll_group *poll_group = NULL; 176 struct spdk_nvmf_transport transport = {}; 177 struct spdk_nvmf_transport_ops ops = {}; 178 179 ops.poll_group_create = ut_poll_group_create; 180 ops.poll_group_destroy = ut_poll_group_destroy; 181 transport.ops = &ops; 182 transport.opts.buf_cache_size = SPDK_NVMF_DEFAULT_BUFFER_CACHE_SIZE; 183 transport.data_buf_pool = spdk_mempool_create("buf_pool", 32, 4096, 0, 0); 184 185 poll_group = nvmf_transport_poll_group_create(&transport, NULL); 186 SPDK_CU_ASSERT_FATAL(poll_group != NULL); 187 CU_ASSERT(poll_group->transport == &transport); 188 CU_ASSERT(poll_group->buf_cache_size == SPDK_NVMF_DEFAULT_BUFFER_CACHE_SIZE); 189 CU_ASSERT(poll_group->buf_cache_count == SPDK_NVMF_DEFAULT_BUFFER_CACHE_SIZE); 190 191 nvmf_transport_poll_group_destroy(poll_group); 192 spdk_mempool_free(transport.data_buf_pool); 193 194 /* Mempool members insufficient */ 195 transport.data_buf_pool = spdk_mempool_create("buf_pool", 31, 4096, 0, 0); 196 197 poll_group = nvmf_transport_poll_group_create(&transport, NULL); 198 SPDK_CU_ASSERT_FATAL(poll_group != NULL); 199 CU_ASSERT(poll_group->transport == &transport); 200 CU_ASSERT(poll_group->buf_cache_size == 31); 201 CU_ASSERT(poll_group->buf_cache_count == 31); 202 203 nvmf_transport_poll_group_destroy(poll_group); 204 spdk_mempool_free(transport.data_buf_pool); 205 } 206 207 static void 208 test_spdk_nvmf_transport_opts_init(void) 209 { 210 int rc; 211 bool rcbool; 212 size_t opts_size; 213 struct spdk_nvmf_transport rtransport = {}; 214 struct spdk_nvmf_transport *transport = NULL; 215 struct spdk_nvmf_transport_opts opts = {}; 216 const struct spdk_nvmf_transport_ops *tops; 217 struct spdk_nvmf_transport_ops ops = { 218 .name = "ut_ops", 219 .type = (enum spdk_nvme_transport_type)SPDK_NVMF_TRTYPE_RDMA, 220 .create = ut_transport_create, 221 .destroy = ut_transport_destroy, 222 .opts_init = ut_opts_init 223 }; 224 225 MOCK_SET(ut_transport_create, &rtransport); 226 spdk_nvmf_transport_register(&ops); 227 transport = spdk_nvmf_transport_create("ut_ops", &g_rdma_ut_transport_opts); 228 CU_ASSERT(transport == &rtransport); 229 230 tops = nvmf_get_transport_ops(ops.name); 231 CU_ASSERT(memcmp(tops, &ops, sizeof(struct spdk_nvmf_transport_ops)) == 0); 232 233 /* Test1: Invalid parameter: unavailable transport type */ 234 opts_size = sizeof(struct spdk_nvmf_transport_opts); 235 236 rcbool = spdk_nvmf_transport_opts_init("invalid_ops", &opts, opts_size); 237 CU_ASSERT(rcbool == false); 238 239 /* Test2: Invalid parameter: NULL pointer */ 240 rcbool = true; 241 242 rcbool = spdk_nvmf_transport_opts_init(ops.name, NULL, opts_size); 243 CU_ASSERT(rcbool == false); 244 245 /* Test3: Invalid parameter: opts_size inside opts be zero value */ 246 rcbool = true; 247 opts_size = 0; 248 249 rcbool = spdk_nvmf_transport_opts_init(ops.name, &opts, opts_size); 250 CU_ASSERT(rcbool == false); 251 252 /* Test4: success */ 253 opts.opts_size = 0; 254 opts_size = sizeof(struct spdk_nvmf_transport_opts); 255 256 rcbool = spdk_nvmf_transport_opts_init(ops.name, &opts, opts_size); 257 CU_ASSERT(rcbool == true); 258 CU_ASSERT(opts.opts_size == opts_size); 259 260 rc = spdk_nvmf_transport_destroy(transport, NULL, NULL); 261 CU_ASSERT(rc == 0); 262 } 263 264 static void 265 test_spdk_nvmf_transport_listen_ext(void) 266 { 267 int rc; 268 struct spdk_nvmf_transport rtransport = {}; 269 struct spdk_nvmf_transport *transport = NULL; 270 struct spdk_nvme_transport_id trid1 = {}; 271 struct spdk_nvme_transport_id trid2 = {}; 272 struct spdk_nvmf_listen_opts lopts = {}; 273 struct spdk_nvmf_listener *tlistener; 274 struct spdk_nvmf_transport_ops ops = { 275 .name = "ut_ops1", 276 .type = (enum spdk_nvme_transport_type)SPDK_NVMF_TRTYPE_RDMA, 277 .create = ut_transport_create, 278 .destroy = ut_transport_destroy, 279 .opts_init = ut_opts_init, 280 .listen = ut_transport_listen, 281 .stop_listen = ut_transport_stop_listen 282 }; 283 284 trid1.trtype = (enum spdk_nvme_transport_type)SPDK_NVMF_TRTYPE_RDMA; 285 trid1.adrfam = (enum spdk_nvmf_adrfam)SPDK_NVMF_ADRFAM_IPV4; 286 trid1.priority = 4; 287 memcpy(trid1.traddr, "192.168.100.72", sizeof("192.168.100.72")); 288 memcpy(trid1.trsvcid, "4420", sizeof("4420")); 289 290 MOCK_SET(ut_transport_create, &rtransport); 291 spdk_nvmf_transport_register(&ops); 292 transport = spdk_nvmf_transport_create("ut_ops1", &g_rdma_ut_transport_opts); 293 294 /* Test1: Execute listen failed */ 295 MOCK_SET(ut_transport_listen, -1); 296 297 rc = spdk_nvmf_transport_listen(transport, &trid1, &lopts); 298 tlistener = nvmf_transport_find_listener(transport, &trid1); 299 CU_ASSERT(rc == -1); 300 CU_ASSERT(tlistener == NULL); 301 302 /* Test2: Execute listen success */ 303 MOCK_SET(ut_transport_listen, 0); 304 305 rc = spdk_nvmf_transport_listen(transport, &trid1, &lopts); 306 tlistener = nvmf_transport_find_listener(transport, &trid1); 307 CU_ASSERT(rc == 0); 308 CU_ASSERT(tlistener != NULL); 309 CU_ASSERT(tlistener->ref == 1); 310 CU_ASSERT(memcmp(&tlistener->trid, &trid1, sizeof(trid1)) == 0); 311 312 /* Test3: Listen for an identifier repeatedly */ 313 tlistener = NULL; 314 315 rc = spdk_nvmf_transport_listen(transport, &trid1, &lopts); 316 tlistener = nvmf_transport_find_listener(transport, &trid1); 317 CU_ASSERT(rc == 0); 318 CU_ASSERT(tlistener != NULL); 319 CU_ASSERT(tlistener->ref == 2); 320 CU_ASSERT(memcmp(&tlistener->trid, &trid1, sizeof(trid1)) == 0); 321 322 /* Test4: Stop listen when ref >1, Listen will not be released */ 323 tlistener = NULL; 324 325 rc = spdk_nvmf_transport_stop_listen(transport, &trid1); 326 tlistener = nvmf_transport_find_listener(transport, &trid1); 327 CU_ASSERT(rc == 0); 328 CU_ASSERT(tlistener != NULL); 329 CU_ASSERT(tlistener->ref == 1); 330 CU_ASSERT(memcmp(&tlistener->trid, &trid1, sizeof(trid1)) == 0); 331 332 /* Test5: Stop listen when ref == 1, Listen will be released */ 333 334 rc = spdk_nvmf_transport_stop_listen(transport, &trid1); 335 tlistener = nvmf_transport_find_listener(transport, &trid1); 336 CU_ASSERT(rc == 0); 337 CU_ASSERT(tlistener == NULL); 338 339 /* Test6: Release unrecognized listener */ 340 rc = spdk_nvmf_transport_stop_listen(transport, &trid2); 341 342 CU_ASSERT(rc == -ENOENT); 343 344 rc = spdk_nvmf_transport_destroy(transport, NULL, NULL); 345 CU_ASSERT(rc == 0); 346 } 347 348 int 349 main(int argc, char **argv) 350 { 351 CU_pSuite suite = NULL; 352 unsigned int num_failures; 353 354 CU_set_error_action(CUEA_ABORT); 355 CU_initialize_registry(); 356 357 suite = CU_add_suite("nvmf", NULL, NULL); 358 359 CU_ADD_TEST(suite, test_spdk_nvmf_transport_create); 360 CU_ADD_TEST(suite, test_nvmf_transport_poll_group_create); 361 CU_ADD_TEST(suite, test_spdk_nvmf_transport_opts_init); 362 CU_ADD_TEST(suite, test_spdk_nvmf_transport_listen_ext); 363 364 CU_basic_set_mode(CU_BRM_VERBOSE); 365 CU_basic_run_tests(); 366 num_failures = CU_get_number_of_failures(); 367 CU_cleanup_registry(); 368 return num_failures; 369 } 370