1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 #include "spdk_internal/cunit.h" 7 #include "spdk_internal/mock.h" 8 #include "common/lib/test_env.c" 9 #include "rdma_utils/rdma_utils.c" 10 11 DEFINE_STUB(spdk_mem_map_alloc, struct spdk_mem_map *, (uint64_t default_translation, 12 const struct spdk_mem_map_ops *ops, void *cb_ctx), NULL); 13 DEFINE_STUB_V(spdk_mem_map_free, (struct spdk_mem_map **pmap)); 14 DEFINE_STUB(spdk_mem_map_set_translation, int, (struct spdk_mem_map *map, uint64_t vaddr, 15 uint64_t size, uint64_t translation), 0); 16 DEFINE_STUB(spdk_mem_map_clear_translation, int, (struct spdk_mem_map *map, uint64_t vaddr, 17 uint64_t size), 0); 18 DEFINE_STUB(spdk_mem_map_translate, uint64_t, (const struct spdk_mem_map *map, uint64_t vaddr, 19 uint64_t *size), 0); 20 DEFINE_STUB(spdk_memory_domain_create, int, (struct spdk_memory_domain **_domain, 21 enum spdk_dma_device_type type, 22 struct spdk_memory_domain_ctx *ctx, const char *id), 0); 23 DEFINE_STUB_V(spdk_memory_domain_destroy, (struct spdk_memory_domain *domain)); 24 25 struct ut_rdma_device { 26 struct ibv_context *context; 27 bool removed; 28 TAILQ_ENTRY(ut_rdma_device) tailq; 29 }; 30 31 static TAILQ_HEAD(, ut_rdma_device) g_ut_dev_list = TAILQ_HEAD_INITIALIZER(g_ut_dev_list); 32 33 struct ibv_context ** 34 rdma_get_devices(int *num_devices) 35 { 36 struct ibv_context **ctx_list; 37 struct ut_rdma_device *ut_dev; 38 int num_ut_devs = 0; 39 int i = 0; 40 41 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 42 if (!ut_dev->removed) { 43 num_ut_devs++; 44 } 45 } 46 47 ctx_list = malloc(sizeof(*ctx_list) * (num_ut_devs + 1)); 48 SPDK_CU_ASSERT_FATAL(ctx_list); 49 50 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 51 if (!ut_dev->removed) { 52 ctx_list[i++] = ut_dev->context; 53 } 54 } 55 ctx_list[i] = NULL; 56 57 if (num_devices) { 58 *num_devices = num_ut_devs; 59 } 60 61 return ctx_list; 62 } 63 64 void 65 rdma_free_devices(struct ibv_context **list) 66 { 67 free(list); 68 } 69 70 struct ibv_pd * 71 ibv_alloc_pd(struct ibv_context *context) 72 { 73 struct ibv_pd *pd; 74 struct ut_rdma_device *ut_dev; 75 76 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 77 if (ut_dev->context == context && !ut_dev->removed) { 78 break; 79 } 80 } 81 82 if (!ut_dev) { 83 return NULL; 84 } 85 86 pd = calloc(1, sizeof(*pd)); 87 SPDK_CU_ASSERT_FATAL(pd); 88 89 pd->context = context; 90 91 return pd; 92 } 93 94 int 95 ibv_dealloc_pd(struct ibv_pd *pd) 96 { 97 free(pd); 98 99 return 0; 100 } 101 102 static struct ut_rdma_device * 103 ut_rdma_add_dev(struct ibv_context *context) 104 { 105 struct ut_rdma_device *ut_dev; 106 107 ut_dev = calloc(1, sizeof(*ut_dev)); 108 if (!ut_dev) { 109 return NULL; 110 } 111 112 ut_dev->context = context; 113 TAILQ_INSERT_TAIL(&g_ut_dev_list, ut_dev, tailq); 114 115 return ut_dev; 116 } 117 118 static void 119 ut_rdma_remove_dev(struct ut_rdma_device *ut_dev) 120 { 121 TAILQ_REMOVE(&g_ut_dev_list, ut_dev, tailq); 122 free(ut_dev); 123 } 124 125 static struct rdma_utils_device * 126 _rdma_get_dev(struct ibv_context *context) 127 { 128 struct rdma_utils_device *dev; 129 130 TAILQ_FOREACH(dev, &g_dev_list, tailq) { 131 if (dev->context == context) { 132 break; 133 } 134 } 135 136 return dev; 137 } 138 139 static void 140 test_spdk_rdma_pd(void) 141 { 142 struct ut_rdma_device *ut_dev0, *ut_dev1, *ut_dev2; 143 struct ibv_pd *pd1, *pd1_1, *pd2; 144 145 ut_dev0 = ut_rdma_add_dev((struct ibv_context *)0xface); 146 SPDK_CU_ASSERT_FATAL(ut_dev0 != NULL); 147 148 ut_dev1 = ut_rdma_add_dev((struct ibv_context *)0xc0ffee); 149 SPDK_CU_ASSERT_FATAL(ut_dev1 != NULL); 150 151 ut_dev2 = ut_rdma_add_dev((struct ibv_context *)0xf00d); 152 SPDK_CU_ASSERT_FATAL(ut_dev2 != NULL); 153 154 /* There are ut_dev0 and ut_dev1. */ 155 ut_dev2->removed = true; 156 157 /* Call spdk_rdma_get_pd() to non-existent ut_dev2. */ 158 pd2 = spdk_rdma_utils_get_pd(ut_dev2->context); 159 160 /* Then, spdk_rdma_utils_get_pd() should return NULL and g_dev_list should have dev0 and dev1. */ 161 CU_ASSERT(pd2 == NULL); 162 CU_ASSERT(_rdma_get_dev(ut_dev0->context) != NULL); 163 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 164 CU_ASSERT(_rdma_get_dev(ut_dev2->context) == NULL); 165 166 /* Remove ut_dev0 and add ut_dev2. */ 167 ut_dev0->removed = true; 168 ut_dev2->removed = false; 169 170 /* Call spdk_rdma_utils_get_pd() to ut_dev1. */ 171 pd1 = spdk_rdma_utils_get_pd(ut_dev1->context); 172 173 /* Then, spdk_rdma_utils_get_pd() should return pd1 and g_dev_list should have dev1 and dev2. */ 174 CU_ASSERT(pd1 != NULL); 175 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 176 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 177 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 178 179 /* Remove ut_dev1. */ 180 ut_dev1->removed = true; 181 182 /* Call spdk_rdma_utils_get_pd() again to ut_dev1 which does not exist anymore. */ 183 pd1_1 = spdk_rdma_utils_get_pd(ut_dev1->context); 184 185 /* Then, spdk_rdma_utils_get_pd() should return NULL and g_dev_list should still have dev1. */ 186 CU_ASSERT(pd1_1 == NULL); 187 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 188 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 189 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 190 191 /* Call spdk_rdma_utils_put_pd() to pd1. */ 192 spdk_rdma_utils_put_pd(pd1); 193 194 /* Then, dev1 should be removed from g_dev_list. */ 195 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 196 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL); 197 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 198 199 /* Call spdk_rdma_utils_get_pd() to ut_dev2. */ 200 pd2 = spdk_rdma_utils_get_pd(ut_dev2->context); 201 202 /* spdk_rdma_utils_get_pd() should succeed and g_dev_list should still have dev2 203 * even after spdk_rdma_utils_put_pd() is called to pd2. 204 */ 205 CU_ASSERT(pd2 != NULL); 206 207 spdk_rdma_utils_put_pd(pd2); 208 209 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 210 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL); 211 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 212 213 _rdma_utils_fini(); 214 215 ut_rdma_remove_dev(ut_dev0); 216 ut_rdma_remove_dev(ut_dev1); 217 ut_rdma_remove_dev(ut_dev2); 218 } 219 220 int 221 main(int argc, char **argv) 222 { 223 CU_pSuite suite = NULL; 224 unsigned int num_failures; 225 226 CU_initialize_registry(); 227 228 suite = CU_add_suite("rdma_common", NULL, NULL); 229 CU_ADD_TEST(suite, test_spdk_rdma_pd); 230 231 num_failures = spdk_ut_run_tests(argc, argv, NULL); 232 CU_cleanup_registry(); 233 return num_failures; 234 } 235