Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021,2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk/nvme.h"
9 : :
10 : : #include "spdk_internal/cunit.h"
11 : :
12 : : #include "common/lib/test_sock.c"
13 : : #include "nvme/nvme_internal.h"
14 : : #include "common/lib/nvme/common_stubs.h"
15 : :
16 : : /* nvme_transport_ctrlr_disconnect_qpair_done() stub is defined in common_stubs.h, but we need to
17 : : * override it here */
18 : : static void nvme_transport_ctrlr_disconnect_qpair_done_mocked(struct spdk_nvme_qpair *qpair);
19 : : #define nvme_transport_ctrlr_disconnect_qpair_done nvme_transport_ctrlr_disconnect_qpair_done_mocked
20 : :
21 : : #include "nvme/nvme_tcp.c"
22 : :
23 : 3 : SPDK_LOG_REGISTER_COMPONENT(nvme)
24 : :
25 [ # # # # ]: 0 : DEFINE_STUB(nvme_qpair_submit_request,
26 : : int, (struct spdk_nvme_qpair *qpair, struct nvme_request *req), 0);
27 : :
28 [ # # # # ]: 0 : DEFINE_STUB(spdk_nvme_poll_group_remove, int, (struct spdk_nvme_poll_group *group,
29 : : struct spdk_nvme_qpair *qpair), 0);
30 [ # # # # ]: 0 : DEFINE_STUB(spdk_sock_get_optimal_sock_group,
31 : : int,
32 : : (struct spdk_sock *sock, struct spdk_sock_group **group, struct spdk_sock_group *hint),
33 : : 0);
34 : :
35 [ # # # # ]: 0 : DEFINE_STUB(spdk_sock_group_get_ctx,
36 : : void *,
37 : : (struct spdk_sock_group *group),
38 : : NULL);
39 [ - + - + ]: 6 : DEFINE_STUB(spdk_sock_get_numa_id, int32_t, (struct spdk_sock *sock), SPDK_ENV_NUMA_ID_ANY);
40 : :
41 [ # # # # ]: 0 : DEFINE_STUB(spdk_nvme_poll_group_process_completions, int64_t, (struct spdk_nvme_poll_group *group,
42 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb), 0);
43 : :
44 [ # # # # ]: 0 : DEFINE_STUB(nvme_poll_group_connect_qpair, int, (struct spdk_nvme_qpair *qpair), 0);
45 : 3 : DEFINE_STUB_V(nvme_qpair_resubmit_requests, (struct spdk_nvme_qpair *qpair, uint32_t num_requests));
46 : :
47 : 9 : DEFINE_STUB_V(spdk_nvme_qpair_print_command, (struct spdk_nvme_qpair *qpair,
48 : : struct spdk_nvme_cmd *cmd));
49 : :
50 : 9 : DEFINE_STUB_V(spdk_nvme_qpair_print_completion, (struct spdk_nvme_qpair *qpair,
51 : : struct spdk_nvme_cpl *cpl));
52 [ # # # # ]: 0 : DEFINE_STUB(spdk_key_get_key, int, (struct spdk_key *key, void *buf, int len), 0);
53 [ # # # # ]: 0 : DEFINE_STUB(spdk_key_get_name, const char *, (struct spdk_key *key), NULL);
54 : :
55 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_get_system_domain, struct spdk_memory_domain *, (void), NULL);
56 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_translate_data, int,
57 : : (struct spdk_memory_domain *src_domain, void *src_domain_ctx,
58 : : struct spdk_memory_domain *dst_domain, struct spdk_memory_domain_translation_ctx *dst_domain_ctx,
59 : : void *addr, size_t len, struct spdk_memory_domain_translation_result *result), 0);
60 : 0 : DEFINE_STUB_V(spdk_memory_domain_invalidate_data, (struct spdk_memory_domain *domain,
61 : : void *domain_ctx, struct iovec *iov, uint32_t iovcnt));
62 : :
63 : : static void
64 : 12 : nvme_transport_ctrlr_disconnect_qpair_done_mocked(struct spdk_nvme_qpair *qpair)
65 : : {
66 : 12 : qpair->state = NVME_QPAIR_DISCONNECTED;
67 : 12 : }
68 : :
69 : : static void
70 : 3 : test_nvme_tcp_pdu_set_data_buf(void)
71 : : {
72 : 3 : struct nvme_tcp_pdu pdu = {};
73 : 3 : struct iovec iov[NVME_TCP_MAX_SGL_DESCRIPTORS] = {};
74 : : uint32_t data_len;
75 : : uint64_t i;
76 : :
77 : : /* 1st case: input is a single SGL entry. */
78 : 3 : iov[0].iov_base = (void *)0xDEADBEEF;
79 : 3 : iov[0].iov_len = 4096;
80 : :
81 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iov, 1, 1024, 512);
82 : :
83 : 3 : CU_ASSERT(pdu.data_iovcnt == 1);
84 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xDEADBEEF + 1024);
85 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 512);
86 : :
87 : : /* 2nd case: simulate split on multiple SGL entries. */
88 : 3 : iov[0].iov_base = (void *)0xDEADBEEF;
89 : 3 : iov[0].iov_len = 4096;
90 : 3 : iov[1].iov_base = (void *)0xFEEDBEEF;
91 : 3 : iov[1].iov_len = 512 * 7;
92 : 3 : iov[2].iov_base = (void *)0xF00DF00D;
93 : 3 : iov[2].iov_len = 4096 * 2;
94 : :
95 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iov, 3, 0, 2048);
96 : :
97 : 3 : CU_ASSERT(pdu.data_iovcnt == 1);
98 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xDEADBEEF);
99 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 2048);
100 : :
101 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iov, 3, 2048, 2048 + 512 * 3);
102 : :
103 : 3 : CU_ASSERT(pdu.data_iovcnt == 2);
104 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xDEADBEEF + 2048);
105 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 2048);
106 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[1].iov_base == 0xFEEDBEEF);
107 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == 512 * 3);
108 : :
109 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iov, 3, 4096 + 512 * 3, 512 * 4 + 4096 * 2);
110 : :
111 : 3 : CU_ASSERT(pdu.data_iovcnt == 2);
112 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xFEEDBEEF + 512 * 3);
113 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 512 * 4);
114 : 3 : CU_ASSERT((uint64_t)pdu.data_iov[1].iov_base == 0xF00DF00D);
115 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == 4096 * 2);
116 : :
117 : : /* 3rd case: Number of input SGL entries is equal to the number of PDU SGL
118 : : * entries.
119 : : */
120 : 3 : data_len = 0;
121 [ + + ]: 51 : for (i = 0; i < NVME_TCP_MAX_SGL_DESCRIPTORS; i++) {
122 : 48 : iov[i].iov_base = (void *)(0xDEADBEEF + i);
123 : 48 : iov[i].iov_len = 512 * (i + 1);
124 : 48 : data_len += 512 * (i + 1);
125 : 16 : }
126 : :
127 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iov, NVME_TCP_MAX_SGL_DESCRIPTORS, 0, data_len);
128 : :
129 : 3 : CU_ASSERT(pdu.data_iovcnt == NVME_TCP_MAX_SGL_DESCRIPTORS);
130 [ + + ]: 51 : for (i = 0; i < NVME_TCP_MAX_SGL_DESCRIPTORS; i++) {
131 : 48 : CU_ASSERT((uint64_t)pdu.data_iov[i].iov_base == 0xDEADBEEF + i);
132 : 48 : CU_ASSERT(pdu.data_iov[i].iov_len == 512 * (i + 1));
133 : 16 : }
134 : 3 : }
135 : :
136 : : static void
137 : 3 : test_nvme_tcp_build_iovs(void)
138 : : {
139 : 3 : const uintptr_t pdu_iov_len = 4096;
140 : 3 : struct nvme_tcp_pdu pdu = {};
141 : 3 : struct iovec iovs[5] = {};
142 : 3 : uint32_t mapped_length = 0;
143 : : int rc;
144 : :
145 : 3 : pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD;
146 : 3 : pdu.hdr.common.hlen = sizeof(struct spdk_nvme_tcp_cmd);
147 : 3 : pdu.hdr.common.plen = pdu.hdr.common.hlen + SPDK_NVME_TCP_DIGEST_LEN + pdu_iov_len * 2 +
148 : : SPDK_NVME_TCP_DIGEST_LEN;
149 : 3 : pdu.data_len = pdu_iov_len * 2;
150 : 3 : pdu.padding_len = 0;
151 : :
152 : 3 : pdu.data_iov[0].iov_base = (void *)0xDEADBEEF;
153 : 3 : pdu.data_iov[0].iov_len = pdu_iov_len;
154 : 3 : pdu.data_iov[1].iov_base = (void *)(0xDEADBEEF + pdu_iov_len);
155 : 3 : pdu.data_iov[1].iov_len = pdu_iov_len;
156 : 3 : pdu.data_iovcnt = 2;
157 : :
158 : 3 : rc = nvme_tcp_build_iovs(iovs, 5, &pdu, true, true, &mapped_length);
159 : 3 : CU_ASSERT(rc == 4);
160 : 3 : CU_ASSERT(iovs[0].iov_base == (void *)&pdu.hdr.raw);
161 : 3 : CU_ASSERT(iovs[0].iov_len == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN);
162 : 3 : CU_ASSERT(iovs[1].iov_base == (void *)0xDEADBEEF);
163 : 3 : CU_ASSERT(iovs[1].iov_len == pdu_iov_len);
164 : 3 : CU_ASSERT(iovs[2].iov_base == (void *)(0xDEADBEEF + pdu_iov_len));
165 : 3 : CU_ASSERT(iovs[2].iov_len == pdu_iov_len);
166 : 3 : CU_ASSERT(iovs[3].iov_base == (void *)pdu.data_digest);
167 : 3 : CU_ASSERT(iovs[3].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
168 : 3 : CU_ASSERT(mapped_length == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN +
169 : : pdu_iov_len * 2 + SPDK_NVME_TCP_DIGEST_LEN);
170 : :
171 : : /* Add a new data_iov entry, update pdu iov count and data length */
172 : 3 : pdu.data_iov[2].iov_base = (void *)(0xBAADF00D);
173 : 3 : pdu.data_iov[2].iov_len = 123;
174 : 3 : pdu.data_iovcnt = 3;
175 : 3 : pdu.data_len += 123;
176 : 3 : pdu.hdr.common.plen += 123;
177 : :
178 : 3 : rc = nvme_tcp_build_iovs(iovs, 5, &pdu, true, true, &mapped_length);
179 : 3 : CU_ASSERT(rc == 5);
180 : 3 : CU_ASSERT(iovs[0].iov_base == (void *)&pdu.hdr.raw);
181 : 3 : CU_ASSERT(iovs[0].iov_len == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN);
182 : 3 : CU_ASSERT(iovs[1].iov_base == (void *)0xDEADBEEF);
183 : 3 : CU_ASSERT(iovs[1].iov_len == pdu_iov_len);
184 : 3 : CU_ASSERT(iovs[2].iov_base == (void *)(0xDEADBEEF + pdu_iov_len));
185 : 3 : CU_ASSERT(iovs[2].iov_len == pdu_iov_len);
186 : 3 : CU_ASSERT(iovs[3].iov_base == (void *)(0xBAADF00D));
187 : 3 : CU_ASSERT(iovs[3].iov_len == 123);
188 : 3 : CU_ASSERT(iovs[4].iov_base == (void *)pdu.data_digest);
189 : 3 : CU_ASSERT(iovs[4].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
190 : 3 : CU_ASSERT(mapped_length == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN +
191 : : pdu_iov_len * 2 + SPDK_NVME_TCP_DIGEST_LEN + 123);
192 : 3 : }
193 : :
194 : : struct nvme_tcp_ut_bdev_io {
195 : : struct iovec iovs[NVME_TCP_MAX_SGL_DESCRIPTORS];
196 : : int iovpos;
197 : : };
198 : :
199 : : /* essentially a simplification of bdev_nvme_next_sge and bdev_nvme_reset_sgl */
200 : : static void
201 : 18 : nvme_tcp_ut_reset_sgl(void *cb_arg, uint32_t offset)
202 : : {
203 : 18 : struct nvme_tcp_ut_bdev_io *bio = cb_arg;
204 : : struct iovec *iov;
205 : :
206 [ + + ]: 18 : for (bio->iovpos = 0; bio->iovpos < NVME_TCP_MAX_SGL_DESCRIPTORS; bio->iovpos++) {
207 : 18 : iov = &bio->iovs[bio->iovpos];
208 : : /* Offset must be aligned with the start of any SGL entry */
209 [ + + ]: 18 : if (offset == 0) {
210 : 18 : break;
211 : : }
212 : :
213 [ # # ]: 0 : SPDK_CU_ASSERT_FATAL(offset >= iov->iov_len);
214 : 0 : offset -= iov->iov_len;
215 : 0 : }
216 : :
217 [ + + ]: 18 : SPDK_CU_ASSERT_FATAL(offset == 0);
218 [ - + ]: 18 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_TCP_MAX_SGL_DESCRIPTORS);
219 : 18 : }
220 : :
221 : : static int
222 : 75 : nvme_tcp_ut_next_sge(void *cb_arg, void **address, uint32_t *length)
223 : : {
224 : 75 : struct nvme_tcp_ut_bdev_io *bio = cb_arg;
225 : : struct iovec *iov;
226 : :
227 [ + + ]: 75 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_TCP_MAX_SGL_DESCRIPTORS);
228 : :
229 : 75 : iov = &bio->iovs[bio->iovpos];
230 : :
231 : 75 : *address = iov->iov_base;
232 : 75 : *length = iov->iov_len;
233 : 75 : bio->iovpos++;
234 : :
235 : 75 : return 0;
236 : : }
237 : :
238 : : static void
239 : 3 : test_nvme_tcp_build_sgl_request(void)
240 : : {
241 : 2 : struct nvme_tcp_qpair tqpair;
242 : 3 : struct spdk_nvme_ctrlr ctrlr = {{0}};
243 : 3 : struct nvme_tcp_req tcp_req = {0};
244 : 3 : struct nvme_request req = {{0}};
245 : 2 : struct nvme_tcp_ut_bdev_io bio;
246 : : uint64_t i;
247 : : int rc;
248 : :
249 : 3 : ctrlr.max_sges = NVME_TCP_MAX_SGL_DESCRIPTORS;
250 : 3 : tqpair.qpair.ctrlr = &ctrlr;
251 : 3 : tcp_req.req = &req;
252 : :
253 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_tcp_ut_reset_sgl, nvme_tcp_ut_next_sge, &bio, NULL);
254 : 3 : req.qpair = &tqpair.qpair;
255 : :
256 [ + + ]: 51 : for (i = 0; i < NVME_TCP_MAX_SGL_DESCRIPTORS; i++) {
257 : 48 : bio.iovs[i].iov_base = (void *)(0xFEEDB000 + i * 0x1000);
258 : 48 : bio.iovs[i].iov_len = 0;
259 : 16 : }
260 : :
261 : : /* Test case 1: Single SGL. Expected: PASS */
262 : 3 : bio.iovpos = 0;
263 : 3 : req.payload_offset = 0;
264 : 3 : req.payload_size = 0x1000;
265 : 3 : bio.iovs[0].iov_len = 0x1000;
266 : 3 : rc = nvme_tcp_build_sgl_request(&tqpair, &tcp_req);
267 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
268 : 3 : CU_ASSERT(bio.iovpos == 1);
269 : 3 : CU_ASSERT((uint64_t)tcp_req.iov[0].iov_base == (uint64_t)bio.iovs[0].iov_base);
270 : 3 : CU_ASSERT(tcp_req.iov[0].iov_len == bio.iovs[0].iov_len);
271 : 3 : CU_ASSERT(tcp_req.iovcnt == 1);
272 : :
273 : : /* Test case 2: Multiple SGL. Expected: PASS */
274 : 3 : bio.iovpos = 0;
275 : 3 : req.payload_offset = 0;
276 : 3 : req.payload_size = 0x4000;
277 [ + + ]: 15 : for (i = 0; i < 4; i++) {
278 : 12 : bio.iovs[i].iov_len = 0x1000;
279 : 4 : }
280 : 3 : rc = nvme_tcp_build_sgl_request(&tqpair, &tcp_req);
281 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
282 : 3 : CU_ASSERT(bio.iovpos == 4);
283 : 3 : CU_ASSERT(tcp_req.iovcnt == 4);
284 [ + + ]: 15 : for (i = 0; i < 4; i++) {
285 : 12 : CU_ASSERT(tcp_req.iov[i].iov_len == bio.iovs[i].iov_len);
286 : 12 : CU_ASSERT((uint64_t)tcp_req.iov[i].iov_base == (uint64_t)bio.iovs[i].iov_base);
287 : 4 : }
288 : :
289 : : /* Test case 3: Payload is bigger than SGL. Expected: FAIL */
290 : 3 : bio.iovpos = 0;
291 : 3 : req.payload_offset = 0;
292 : 3 : req.payload_size = 0x17000;
293 [ + + ]: 51 : for (i = 0; i < NVME_TCP_MAX_SGL_DESCRIPTORS; i++) {
294 : 48 : bio.iovs[i].iov_len = 0x1000;
295 : 16 : }
296 : 3 : rc = nvme_tcp_build_sgl_request(&tqpair, &tcp_req);
297 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
298 : 3 : CU_ASSERT(bio.iovpos == NVME_TCP_MAX_SGL_DESCRIPTORS);
299 [ + + ]: 51 : for (i = 0; i < NVME_TCP_MAX_SGL_DESCRIPTORS; i++) {
300 : 48 : CU_ASSERT(tcp_req.iov[i].iov_len == bio.iovs[i].iov_len);
301 : 48 : CU_ASSERT((uint64_t)tcp_req.iov[i].iov_base == (uint64_t)bio.iovs[i].iov_base);
302 : 16 : }
303 : 3 : }
304 : :
305 : : static void
306 : 3 : test_nvme_tcp_pdu_set_data_buf_with_md(void)
307 : : {
308 : 3 : struct nvme_tcp_pdu pdu = {};
309 : 3 : struct iovec iovs[7] = {};
310 : 3 : struct spdk_dif_ctx dif_ctx = {};
311 : : int rc;
312 : 2 : struct spdk_dif_ctx_init_ext_opts dif_opts;
313 : :
314 : 3 : pdu.dif_ctx = &dif_ctx;
315 : :
316 : 3 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
317 : 3 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
318 : 3 : rc = spdk_dif_ctx_init(&dif_ctx, 520, 8, true, false, SPDK_DIF_DISABLE, 0,
319 : : 0, 0, 0, 0, 0, &dif_opts);
320 : 3 : CU_ASSERT(rc == 0);
321 : :
322 : : /* Single iovec case */
323 : 3 : iovs[0].iov_base = (void *)0xDEADBEEF;
324 : 3 : iovs[0].iov_len = 2080;
325 : :
326 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 1, 0, 500);
327 : :
328 : 3 : CU_ASSERT(dif_ctx.data_offset == 0);
329 : 3 : CU_ASSERT(pdu.data_len == 500);
330 : 3 : CU_ASSERT(pdu.data_iovcnt == 1);
331 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)0xDEADBEEF);
332 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 500);
333 : :
334 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 1, 500, 1000);
335 : :
336 : 3 : CU_ASSERT(dif_ctx.data_offset == 500);
337 : 3 : CU_ASSERT(pdu.data_len == 1000);
338 : 3 : CU_ASSERT(pdu.data_iovcnt == 1);
339 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)(0xDEADBEEF + 500));
340 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 1016);
341 : :
342 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 1, 1500, 548);
343 : :
344 : 3 : CU_ASSERT(dif_ctx.data_offset == 1500);
345 : 3 : CU_ASSERT(pdu.data_len == 548);
346 : 3 : CU_ASSERT(pdu.data_iovcnt == 1);
347 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)(0xDEADBEEF + 1516));
348 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 564);
349 : :
350 : : /* Multiple iovecs case */
351 : 3 : iovs[0].iov_base = (void *)0xDEADBEEF;
352 : 3 : iovs[0].iov_len = 256;
353 : 3 : iovs[1].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x1000));
354 : 3 : iovs[1].iov_len = 256 + 1;
355 : 3 : iovs[2].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x2000));
356 : 3 : iovs[2].iov_len = 4;
357 : 3 : iovs[3].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x3000));
358 : 3 : iovs[3].iov_len = 3 + 123;
359 : 3 : iovs[4].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x4000));
360 : 3 : iovs[4].iov_len = 389 + 6;
361 : 3 : iovs[5].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x5000));
362 : 3 : iovs[5].iov_len = 2 + 512 + 8 + 432;
363 : 3 : iovs[6].iov_base = (void *)((uint8_t *)(0xDEADBEEF + 0x6000));
364 : 3 : iovs[6].iov_len = 80 + 8;
365 : :
366 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 7, 0, 500);
367 : :
368 : 3 : CU_ASSERT(dif_ctx.data_offset == 0);
369 : 3 : CU_ASSERT(pdu.data_len == 500);
370 : 3 : CU_ASSERT(pdu.data_iovcnt == 2);
371 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)0xDEADBEEF);
372 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 256);
373 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == (void *)(0xDEADBEEF + 0x1000));
374 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == 244);
375 : :
376 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 7, 500, 1000);
377 : :
378 : 3 : CU_ASSERT(dif_ctx.data_offset == 500);
379 : 3 : CU_ASSERT(pdu.data_len == 1000);
380 : 3 : CU_ASSERT(pdu.data_iovcnt == 5);
381 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)(0xDEADBEEF + 0x1000 + 244));
382 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 13);
383 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == (void *)(0xDEADBEEF + 0x2000));
384 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == 4);
385 : 3 : CU_ASSERT(pdu.data_iov[2].iov_base == (void *)(0xDEADBEEF + 0x3000));
386 : 3 : CU_ASSERT(pdu.data_iov[2].iov_len == 3 + 123);
387 : 3 : CU_ASSERT(pdu.data_iov[3].iov_base == (void *)(0xDEADBEEF + 0x4000));
388 : 3 : CU_ASSERT(pdu.data_iov[3].iov_len == 395);
389 : 3 : CU_ASSERT(pdu.data_iov[4].iov_base == (void *)(0xDEADBEEF + 0x5000));
390 : 3 : CU_ASSERT(pdu.data_iov[4].iov_len == 478);
391 : :
392 : 3 : nvme_tcp_pdu_set_data_buf(&pdu, iovs, 7, 1500, 548);
393 : :
394 : 3 : CU_ASSERT(dif_ctx.data_offset == 1500);
395 : 3 : CU_ASSERT(pdu.data_len == 548);
396 : 3 : CU_ASSERT(pdu.data_iovcnt == 2);
397 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == (void *)(0xDEADBEEF + 0x5000 + 478));
398 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == 476);
399 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == (void *)(0xDEADBEEF + 0x6000));
400 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == 88);
401 : 3 : }
402 : :
403 : : static void
404 : 3 : test_nvme_tcp_build_iovs_with_md(void)
405 : : {
406 : 3 : struct nvme_tcp_pdu pdu = {};
407 : 3 : struct iovec iovs[11] = {};
408 : 3 : struct spdk_dif_ctx dif_ctx = {};
409 : 3 : uint32_t mapped_length = 0;
410 : : int rc;
411 : 2 : struct spdk_dif_ctx_init_ext_opts dif_opts;
412 : :
413 : 3 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
414 : 3 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
415 : 3 : rc = spdk_dif_ctx_init(&dif_ctx, 520, 8, true, false, SPDK_DIF_DISABLE, 0,
416 : : 0, 0, 0, 0, 0, &dif_opts);
417 : 3 : CU_ASSERT(rc == 0);
418 : :
419 : 3 : pdu.dif_ctx = &dif_ctx;
420 : :
421 : 3 : pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD;
422 : 3 : pdu.hdr.common.hlen = sizeof(struct spdk_nvme_tcp_cmd);
423 : 3 : pdu.hdr.common.plen = pdu.hdr.common.hlen + SPDK_NVME_TCP_DIGEST_LEN + 512 * 8 +
424 : : SPDK_NVME_TCP_DIGEST_LEN;
425 : 3 : pdu.data_len = 512 * 8;
426 : 3 : pdu.padding_len = 0;
427 : :
428 : 3 : pdu.data_iov[0].iov_base = (void *)0xDEADBEEF;
429 : 3 : pdu.data_iov[0].iov_len = (512 + 8) * 8;
430 : 3 : pdu.data_iovcnt = 1;
431 : :
432 : 3 : rc = nvme_tcp_build_iovs(iovs, 11, &pdu, true, true, &mapped_length);
433 : 3 : CU_ASSERT(rc == 10);
434 : 3 : CU_ASSERT(iovs[0].iov_base == (void *)&pdu.hdr.raw);
435 : 3 : CU_ASSERT(iovs[0].iov_len == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN);
436 : 3 : CU_ASSERT(iovs[1].iov_base == (void *)0xDEADBEEF);
437 : 3 : CU_ASSERT(iovs[1].iov_len == 512);
438 : 3 : CU_ASSERT(iovs[2].iov_base == (void *)(0xDEADBEEF + 520));
439 : 3 : CU_ASSERT(iovs[2].iov_len == 512);
440 : 3 : CU_ASSERT(iovs[3].iov_base == (void *)(0xDEADBEEF + 520 * 2));
441 : 3 : CU_ASSERT(iovs[3].iov_len == 512);
442 : 3 : CU_ASSERT(iovs[4].iov_base == (void *)(0xDEADBEEF + 520 * 3));
443 : 3 : CU_ASSERT(iovs[4].iov_len == 512);
444 : 3 : CU_ASSERT(iovs[5].iov_base == (void *)(0xDEADBEEF + 520 * 4));
445 : 3 : CU_ASSERT(iovs[5].iov_len == 512);
446 : 3 : CU_ASSERT(iovs[6].iov_base == (void *)(0xDEADBEEF + 520 * 5));
447 : 3 : CU_ASSERT(iovs[6].iov_len == 512);
448 : 3 : CU_ASSERT(iovs[7].iov_base == (void *)(0xDEADBEEF + 520 * 6));
449 : 3 : CU_ASSERT(iovs[7].iov_len == 512);
450 : 3 : CU_ASSERT(iovs[8].iov_base == (void *)(0xDEADBEEF + 520 * 7));
451 : 3 : CU_ASSERT(iovs[8].iov_len == 512);
452 : 3 : CU_ASSERT(iovs[9].iov_base == (void *)pdu.data_digest);
453 : 3 : CU_ASSERT(iovs[9].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
454 : 3 : CU_ASSERT(mapped_length == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN +
455 : : 512 * 8 + SPDK_NVME_TCP_DIGEST_LEN);
456 : 3 : }
457 : :
458 : : /* Just define, nothing to do */
459 : : static void
460 : 21 : ut_nvme_complete_request(void *arg, const struct spdk_nvme_cpl *cpl)
461 : : {
462 : 21 : return;
463 : : }
464 : :
465 : : static void
466 : 3 : test_nvme_tcp_req_complete_safe(void)
467 : : {
468 : : bool rc;
469 : 3 : struct nvme_tcp_req tcp_req = {0};
470 : 3 : struct nvme_request req = {{0}};
471 : 3 : struct nvme_tcp_qpair tqpair = {{0}};
472 : :
473 : 3 : tcp_req.req = &req;
474 : 3 : tcp_req.req->qpair = &tqpair.qpair;
475 : 3 : tcp_req.req->cb_fn = ut_nvme_complete_request;
476 : 3 : tcp_req.tqpair = &tqpair;
477 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
478 : 3 : TAILQ_INIT(&tcp_req.tqpair->outstanding_reqs);
479 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
480 : :
481 : : /* Test case 1: send operation and transfer completed. Expect: PASS */
482 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
483 : 3 : tcp_req.ordering.bits.send_ack = 1;
484 : 3 : tcp_req.ordering.bits.data_recv = 1;
485 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
486 : :
487 : 3 : rc = nvme_tcp_req_complete_safe(&tcp_req);
488 : 3 : CU_ASSERT(rc == true);
489 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
490 : :
491 : : /* Test case 2: send operation not completed. Expect: FAIL */
492 : 3 : tcp_req.ordering.raw = 0;
493 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
494 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
495 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
496 : :
497 : 3 : rc = nvme_tcp_req_complete_safe(&tcp_req);
498 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != true);
499 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 1);
500 [ - + ]: 3 : TAILQ_REMOVE(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
501 : :
502 : : /* Test case 3: in completion context. Expect: PASS */
503 : 3 : tqpair.qpair.in_completion_context = 1;
504 : 3 : tqpair.async_complete = 0;
505 : 3 : tcp_req.ordering.bits.send_ack = 1;
506 : 3 : tcp_req.ordering.bits.data_recv = 1;
507 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
508 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
509 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
510 : :
511 : 3 : rc = nvme_tcp_req_complete_safe(&tcp_req);
512 : 3 : CU_ASSERT(rc == true);
513 : 3 : CU_ASSERT(tcp_req.tqpair->async_complete == 0);
514 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
515 : :
516 : : /* Test case 4: in async complete. Expect: PASS */
517 : 3 : tqpair.qpair.in_completion_context = 0;
518 : 3 : tcp_req.ordering.bits.send_ack = 1;
519 : 3 : tcp_req.ordering.bits.data_recv = 1;
520 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
521 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
522 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
523 : :
524 : 3 : rc = nvme_tcp_req_complete_safe(&tcp_req);
525 : 3 : CU_ASSERT(rc == true);
526 : 3 : CU_ASSERT(tcp_req.tqpair->async_complete);
527 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
528 : 3 : }
529 : :
530 : : static void
531 : 3 : test_nvme_tcp_req_init(void)
532 : : {
533 : 3 : struct nvme_tcp_qpair tqpair = {};
534 : 3 : struct nvme_request req = {};
535 : 3 : struct nvme_tcp_req tcp_req = {0};
536 : 3 : struct spdk_nvme_ctrlr ctrlr = {{0}};
537 : 3 : struct nvme_tcp_ut_bdev_io bio = {};
538 : : int rc;
539 : :
540 : 3 : tqpair.qpair.ctrlr = &ctrlr;
541 : 3 : req.qpair = &tqpair.qpair;
542 : :
543 : 3 : tcp_req.cid = 1;
544 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_tcp_ut_reset_sgl, nvme_tcp_ut_next_sge, &bio, NULL);
545 : 3 : req.payload_offset = 0;
546 : 3 : req.payload_size = 4096;
547 : 3 : ctrlr.max_sges = NVME_TCP_MAX_SGL_DESCRIPTORS;
548 : 3 : ctrlr.ioccsz_bytes = 1024;
549 : 3 : bio.iovpos = 0;
550 : 3 : bio.iovs[0].iov_len = 8192;
551 : 3 : bio.iovs[0].iov_base = (void *)0xDEADBEEF;
552 : :
553 : : /* Test case1: payload type SGL. Expect: PASS */
554 : 3 : req.cmd.opc = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
555 : 3 : req.payload.reset_sgl_fn = nvme_tcp_ut_reset_sgl;
556 : :
557 : 3 : rc = nvme_tcp_req_init(&tqpair, &req, &tcp_req);
558 : 3 : CU_ASSERT(rc == 0);
559 : 3 : CU_ASSERT(tcp_req.req == &req);
560 [ - + ]: 3 : CU_ASSERT(tcp_req.in_capsule_data == true);
561 : 3 : CU_ASSERT(tcp_req.iovcnt == 1);
562 : 3 : CU_ASSERT(tcp_req.iov[0].iov_len == req.payload_size);
563 : 3 : CU_ASSERT(tcp_req.iov[0].iov_base == bio.iovs[0].iov_base);
564 : 3 : CU_ASSERT(req.cmd.cid == tcp_req.cid);
565 : 3 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
566 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
567 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
568 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
569 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
570 : :
571 : : /* Test case2: payload type CONTIG. Expect: PASS */
572 [ - + ]: 3 : memset(&req.cmd, 0, sizeof(req.cmd));
573 [ - + ]: 3 : memset(&tcp_req, 0, sizeof(tcp_req));
574 : 3 : tcp_req.cid = 1;
575 : 3 : req.payload = NVME_PAYLOAD_CONTIG(&bio, NULL);
576 : 3 : req.cmd.opc = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
577 : :
578 : 3 : rc = nvme_tcp_req_init(&tqpair, &req, &tcp_req);
579 : 3 : CU_ASSERT(rc == 0);
580 : 3 : CU_ASSERT(tcp_req.req == &req);
581 [ - + ]: 3 : CU_ASSERT(tcp_req.in_capsule_data == true);
582 : 3 : CU_ASSERT(tcp_req.iov[0].iov_len == req.payload_size);
583 : 3 : CU_ASSERT(tcp_req.iov[0].iov_base == &bio);
584 : 3 : CU_ASSERT(tcp_req.iovcnt == 1);
585 : 3 : CU_ASSERT(req.cmd.cid == tcp_req.cid);
586 : 3 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
587 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
588 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
589 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
590 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
591 : :
592 : 3 : }
593 : :
594 : : static void
595 : 3 : test_nvme_tcp_req_get(void)
596 : : {
597 : 3 : struct nvme_tcp_req tcp_req = {0};
598 : 3 : struct nvme_tcp_qpair tqpair = {};
599 : 3 : struct nvme_tcp_pdu send_pdu = {};
600 : :
601 : 3 : tcp_req.pdu = &send_pdu;
602 : 3 : tcp_req.state = NVME_TCP_REQ_FREE;
603 : :
604 : 3 : TAILQ_INIT(&tqpair.free_reqs);
605 : 3 : TAILQ_INIT(&tqpair.outstanding_reqs);
606 [ - + ]: 3 : TAILQ_INSERT_HEAD(&tqpair.free_reqs, &tcp_req, link);
607 : :
608 : 3 : CU_ASSERT(nvme_tcp_req_get(&tqpair) == &tcp_req);
609 : 3 : CU_ASSERT(tcp_req.state == NVME_TCP_REQ_ACTIVE);
610 : 3 : CU_ASSERT(tcp_req.datao == 0);
611 : 3 : CU_ASSERT(tcp_req.req == NULL);
612 [ - + ]: 3 : CU_ASSERT(tcp_req.in_capsule_data == false);
613 : 3 : CU_ASSERT(tcp_req.r2tl_remain == 0);
614 : 3 : CU_ASSERT(tcp_req.iovcnt == 0);
615 : 3 : CU_ASSERT(tcp_req.ordering.raw == 0);
616 : : /* outstanding_reqs should still be empty - caller is responsible
617 : : * for putting it on the TAILQ after any other initialization is
618 : : * completed.
619 : : */
620 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair.outstanding_reqs));
621 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair.free_reqs));
622 : :
623 : : /* No tcp request available, expect fail */
624 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(nvme_tcp_req_get(&tqpair) == NULL);
625 : 3 : }
626 : :
627 : : static void
628 : 3 : test_nvme_tcp_qpair_capsule_cmd_send(void)
629 : : {
630 : 3 : struct nvme_tcp_qpair tqpair = {};
631 : 3 : struct spdk_nvme_tcp_stat stats = {};
632 : 3 : struct nvme_tcp_req tcp_req = {};
633 : 3 : struct nvme_tcp_pdu pdu = {};
634 : 3 : struct nvme_request req = {};
635 : 2 : char iov_base0[4096];
636 : 2 : char iov_base1[4096];
637 : : uint32_t plen;
638 : : uint8_t pdo;
639 : :
640 [ - + ]: 3 : memset(iov_base0, 0xFF, 4096);
641 [ - + ]: 3 : memset(iov_base1, 0xFF, 4096);
642 : 3 : tcp_req.req = &req;
643 : 3 : tcp_req.pdu = &pdu;
644 : 3 : TAILQ_INIT(&tqpair.send_queue);
645 : 3 : tqpair.stats = &stats;
646 : :
647 : 3 : tcp_req.iov[0].iov_base = (void *)iov_base0;
648 : 3 : tcp_req.iov[0].iov_len = 4096;
649 : 3 : tcp_req.iov[1].iov_base = (void *)iov_base1;
650 : 3 : tcp_req.iov[1].iov_len = 4096;
651 : 3 : tcp_req.iovcnt = 2;
652 : 3 : tcp_req.req->payload_size = 8192;
653 : 3 : tcp_req.in_capsule_data = true;
654 : 3 : tqpair.cpda = NVME_TCP_HPDA_DEFAULT;
655 : :
656 : : /* Test case 1: host hdgst and ddgst enable. Expect: PASS */
657 : 3 : tqpair.flags.host_hdgst_enable = 1;
658 : 3 : tqpair.flags.host_ddgst_enable = 1;
659 : 3 : pdo = plen = sizeof(struct spdk_nvme_tcp_cmd) +
660 : : SPDK_NVME_TCP_DIGEST_LEN;
661 : 3 : plen += tcp_req.req->payload_size;
662 : 3 : plen += SPDK_NVME_TCP_DIGEST_LEN;
663 : :
664 : 3 : nvme_tcp_qpair_capsule_cmd_send(&tqpair, &tcp_req);
665 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq);
666 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.flags
667 : : & SPDK_NVME_TCP_CH_FLAGS_HDGSTF);
668 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.flags
669 : : & SPDK_NVME_TCP_CH_FLAGS_DDGSTF);
670 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdu_type ==
671 : : SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD);
672 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdo == pdo);
673 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.plen == plen);
674 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == tcp_req.iov[0].iov_base);
675 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == tcp_req.iov[0].iov_len);
676 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == tcp_req.iov[1].iov_base);
677 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == tcp_req.iov[0].iov_len);
678 : :
679 : : /* Test case 2: host hdgst and ddgst disable. Expect: PASS */
680 [ - + ]: 3 : memset(&pdu, 0, sizeof(pdu));
681 : 3 : tqpair.flags.host_hdgst_enable = 0;
682 : 3 : tqpair.flags.host_ddgst_enable = 0;
683 : :
684 : 3 : pdo = plen = sizeof(struct spdk_nvme_tcp_cmd);
685 : 3 : plen += tcp_req.req->payload_size;
686 : :
687 : 3 : nvme_tcp_qpair_capsule_cmd_send(&tqpair, &tcp_req);
688 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq);
689 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.flags == 0)
690 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdu_type ==
691 : : SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD);
692 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdo == pdo);
693 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.plen == plen);
694 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == tcp_req.iov[0].iov_base);
695 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == tcp_req.iov[0].iov_len);
696 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == tcp_req.iov[1].iov_base);
697 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == tcp_req.iov[0].iov_len);
698 : :
699 : : /* Test case 3: padding available. Expect: PASS */
700 [ - + ]: 3 : memset(&pdu, 0, sizeof(pdu));
701 : 3 : tqpair.flags.host_hdgst_enable = 1;
702 : 3 : tqpair.flags.host_ddgst_enable = 1;
703 : 3 : tqpair.cpda = SPDK_NVME_TCP_CPDA_MAX;
704 : :
705 : 3 : pdo = plen = (SPDK_NVME_TCP_CPDA_MAX + 1) << 2;
706 : 3 : plen += tcp_req.req->payload_size;
707 : 3 : plen += SPDK_NVME_TCP_DIGEST_LEN;
708 : :
709 : 3 : nvme_tcp_qpair_capsule_cmd_send(&tqpair, &tcp_req);
710 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq);
711 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.flags
712 : : & SPDK_NVME_TCP_CH_FLAGS_HDGSTF);
713 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.flags
714 : : & SPDK_NVME_TCP_CH_FLAGS_DDGSTF);
715 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdu_type ==
716 : : SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD);
717 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.pdo == pdo);
718 : 3 : CU_ASSERT(pdu.hdr.capsule_cmd.common.plen == plen);
719 : 3 : CU_ASSERT(pdu.data_iov[0].iov_base == tcp_req.iov[0].iov_base);
720 : 3 : CU_ASSERT(pdu.data_iov[0].iov_len == tcp_req.iov[0].iov_len);
721 : 3 : CU_ASSERT(pdu.data_iov[1].iov_base == tcp_req.iov[1].iov_base);
722 : 3 : CU_ASSERT(pdu.data_iov[1].iov_len == tcp_req.iov[0].iov_len);
723 : 3 : }
724 : :
725 : : /* Just define, nothing to do */
726 : : static void
727 : 0 : ut_nvme_tcp_qpair_xfer_complete_cb(void *cb_arg)
728 : : {
729 : 0 : return;
730 : : }
731 : :
732 : : static void
733 : 3 : test_nvme_tcp_qpair_write_pdu(void)
734 : : {
735 : 3 : struct nvme_tcp_qpair tqpair = {};
736 : 3 : struct spdk_nvme_tcp_stat stats = {};
737 : 3 : struct nvme_request req = {};
738 : 3 : struct nvme_tcp_req treq = { .req = &req };
739 : 3 : struct nvme_tcp_pdu pdu = { .req = &treq };
740 : 3 : void *cb_arg = (void *)0xDEADBEEF;
741 : 2 : char iov_base0[4096];
742 : 2 : char iov_base1[4096];
743 : :
744 [ - + ]: 3 : memset(iov_base0, 0xFF, 4096);
745 [ - + ]: 3 : memset(iov_base1, 0xFF, 4096);
746 : 3 : pdu.data_len = 4096 * 2;
747 : 3 : pdu.padding_len = 0;
748 : 3 : pdu.data_iov[0].iov_base = (void *)iov_base0;
749 : 3 : pdu.data_iov[0].iov_len = 4096;
750 : 3 : pdu.data_iov[1].iov_base = (void *)iov_base1;
751 : 3 : pdu.data_iov[1].iov_len = 4096;
752 : 3 : pdu.data_iovcnt = 2;
753 : 3 : TAILQ_INIT(&tqpair.send_queue);
754 : :
755 : : /* Test case1: host hdgst and ddgst enable Expect: PASS */
756 [ - + ]: 3 : memset(pdu.hdr.raw, 0, SPDK_NVME_TCP_TERM_REQ_PDU_MAX_SIZE);
757 [ - + ]: 3 : memset(pdu.data_digest, 0, SPDK_NVME_TCP_DIGEST_LEN);
758 : :
759 : 3 : pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD;
760 : 3 : pdu.hdr.common.hlen = sizeof(struct spdk_nvme_tcp_cmd);
761 : 3 : pdu.hdr.common.plen = pdu.hdr.common.hlen +
762 : : SPDK_NVME_TCP_DIGEST_LEN * 2 ;
763 : 3 : pdu.hdr.common.plen += pdu.data_len;
764 : 3 : tqpair.flags.host_hdgst_enable = 1;
765 : 3 : tqpair.flags.host_ddgst_enable = 1;
766 : 3 : tqpair.stats = &stats;
767 : :
768 : 3 : nvme_tcp_qpair_write_pdu(&tqpair,
769 : : &pdu,
770 : : ut_nvme_tcp_qpair_xfer_complete_cb,
771 : 1 : cb_arg);
772 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq);
773 : : /* Check the crc data of header digest filled into raw */
774 : 3 : CU_ASSERT(pdu.hdr.raw[pdu.hdr.common.hlen]);
775 : 3 : CU_ASSERT(pdu.data_digest[0]);
776 : 3 : CU_ASSERT(pdu.sock_req.iovcnt == 4);
777 : 3 : CU_ASSERT(pdu.iov[0].iov_base == &pdu.hdr.raw);
778 : 3 : CU_ASSERT(pdu.iov[0].iov_len == (sizeof(struct spdk_nvme_tcp_cmd) +
779 : : SPDK_NVME_TCP_DIGEST_LEN));
780 : 3 : CU_ASSERT(pdu.iov[1].iov_base == pdu.data_iov[0].iov_base);
781 : 3 : CU_ASSERT(pdu.iov[1].iov_len == pdu.data_iov[0].iov_len);
782 : 3 : CU_ASSERT(pdu.iov[2].iov_base == pdu.data_iov[1].iov_base);
783 : 3 : CU_ASSERT(pdu.iov[2].iov_len == pdu.data_iov[1].iov_len);
784 : 3 : CU_ASSERT(pdu.iov[3].iov_base == &pdu.data_digest);
785 : 3 : CU_ASSERT(pdu.iov[3].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
786 : 3 : CU_ASSERT(pdu.cb_fn == ut_nvme_tcp_qpair_xfer_complete_cb);
787 : 3 : CU_ASSERT(pdu.cb_arg == cb_arg);
788 : 3 : CU_ASSERT(pdu.qpair == &tqpair);
789 : 3 : CU_ASSERT(pdu.sock_req.cb_arg == (void *)&pdu);
790 : :
791 : : /* Test case2: host hdgst and ddgst disable Expect: PASS */
792 [ - + ]: 3 : memset(pdu.hdr.raw, 0, SPDK_NVME_TCP_TERM_REQ_PDU_MAX_SIZE);
793 [ - + ]: 3 : memset(pdu.data_digest, 0, SPDK_NVME_TCP_DIGEST_LEN);
794 : :
795 : 3 : pdu.hdr.common.hlen = sizeof(struct spdk_nvme_tcp_cmd);
796 : 3 : pdu.hdr.common.plen = pdu.hdr.common.hlen + pdu.data_len;
797 : 3 : tqpair.flags.host_hdgst_enable = 0;
798 : 3 : tqpair.flags.host_ddgst_enable = 0;
799 : :
800 : 3 : nvme_tcp_qpair_write_pdu(&tqpair,
801 : : &pdu,
802 : : ut_nvme_tcp_qpair_xfer_complete_cb,
803 : 1 : cb_arg);
804 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq);
805 : 3 : CU_ASSERT(pdu.hdr.raw[pdu.hdr.common.hlen] == 0);
806 : 3 : CU_ASSERT(pdu.data_digest[0] == 0);
807 : 3 : CU_ASSERT(pdu.sock_req.iovcnt == 3);
808 : 3 : CU_ASSERT(pdu.iov[0].iov_base == &pdu.hdr.raw);
809 : 3 : CU_ASSERT(pdu.iov[0].iov_len == sizeof(struct spdk_nvme_tcp_cmd));
810 : 3 : CU_ASSERT(pdu.iov[1].iov_base == pdu.data_iov[0].iov_base);
811 : 3 : CU_ASSERT(pdu.iov[1].iov_len == pdu.data_iov[0].iov_len);
812 : 3 : CU_ASSERT(pdu.iov[2].iov_base == pdu.data_iov[1].iov_base);
813 : 3 : CU_ASSERT(pdu.iov[2].iov_len == pdu.data_iov[1].iov_len);
814 : 3 : CU_ASSERT(pdu.cb_fn == ut_nvme_tcp_qpair_xfer_complete_cb);
815 : 3 : CU_ASSERT(pdu.cb_arg == cb_arg);
816 : 3 : CU_ASSERT(pdu.qpair == &tqpair);
817 : 3 : CU_ASSERT(pdu.sock_req.cb_arg == (void *)&pdu);
818 : 3 : }
819 : :
820 : : static void
821 : 3 : test_nvme_tcp_qpair_set_recv_state(void)
822 : : {
823 : 3 : struct nvme_tcp_qpair tqpair = {};
824 : :
825 : : /* case1: The recv state of tqpair is same with the state to be set */
826 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR;
827 : 3 : nvme_tcp_qpair_set_recv_state(&tqpair, NVME_TCP_PDU_RECV_STATE_ERROR);
828 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_ERROR);
829 : :
830 : : /* Different state will be set accordingly */
831 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY;
832 : 3 : nvme_tcp_qpair_set_recv_state(&tqpair, 0xff);
833 : 3 : CU_ASSERT(tqpair.recv_state == 0xff);
834 : 3 : }
835 : :
836 : : static void
837 : 3 : test_nvme_tcp_alloc_reqs(void)
838 : : {
839 : 3 : struct nvme_tcp_qpair tqpair = {};
840 : 3 : int rc = 0;
841 : :
842 : : /* case1: single entry. Expect: PASS */
843 : 3 : tqpair.num_entries = 1;
844 : 3 : rc = nvme_tcp_alloc_reqs(&tqpair);
845 : 3 : CU_ASSERT(rc == 0);
846 : 3 : CU_ASSERT(tqpair.tcp_reqs[0].cid == 0);
847 : 3 : CU_ASSERT(tqpair.tcp_reqs[0].tqpair == &tqpair);
848 : 3 : CU_ASSERT(tqpair.tcp_reqs[0].pdu == &tqpair.send_pdus[0]);
849 : 3 : CU_ASSERT(tqpair.send_pdu == &tqpair.send_pdus[tqpair.num_entries]);
850 : 3 : free(tqpair.tcp_reqs);
851 : 3 : spdk_free(tqpair.send_pdus);
852 : :
853 : : /* case2: multiple entries. Expect: PASS */
854 : 3 : tqpair.num_entries = 5;
855 : 3 : rc = nvme_tcp_alloc_reqs(&tqpair);
856 : 3 : CU_ASSERT(rc == 0);
857 [ + + ]: 18 : for (int i = 0; i < tqpair.num_entries; i++) {
858 : 15 : CU_ASSERT(tqpair.tcp_reqs[i].cid == i);
859 : 15 : CU_ASSERT(tqpair.tcp_reqs[i].tqpair == &tqpair);
860 : 15 : CU_ASSERT(tqpair.tcp_reqs[i].pdu == &tqpair.send_pdus[i]);
861 : 5 : }
862 : 3 : CU_ASSERT(tqpair.send_pdu == &tqpair.send_pdus[tqpair.num_entries]);
863 : :
864 : : /* case3: Test nvme_tcp_free_reqs test. Expect: PASS */
865 : 3 : nvme_tcp_free_reqs(&tqpair);
866 : 3 : CU_ASSERT(tqpair.tcp_reqs == NULL);
867 : 3 : CU_ASSERT(tqpair.send_pdus == NULL);
868 : 3 : }
869 : :
870 : : static void
871 : 3 : test_nvme_tcp_qpair_send_h2c_term_req(void)
872 : : {
873 : 3 : struct nvme_tcp_qpair tqpair = {};
874 : 3 : struct spdk_nvme_tcp_stat stats = {};
875 : 3 : struct nvme_tcp_pdu pdu = {}, recv_pdu = {}, send_pdu = {};
876 : 3 : enum spdk_nvme_tcp_term_req_fes fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
877 : 3 : uint32_t error_offset = 1;
878 : :
879 : 3 : tqpair.send_pdu = &send_pdu;
880 : 3 : tqpair.recv_pdu = &recv_pdu;
881 : 3 : tqpair.stats = &stats;
882 : 3 : TAILQ_INIT(&tqpair.send_queue);
883 : : /* case1: hlen < SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE, Expect: copy_len == hlen */
884 : 3 : pdu.hdr.common.hlen = 64;
885 : 3 : nvme_tcp_qpair_send_h2c_term_req(&tqpair, &pdu, fes, error_offset);
886 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
887 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
888 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
889 : : pdu.hdr.common.hlen);
890 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
891 : :
892 : : /* case2: hlen > SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE, Expect: copy_len == SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE */
893 : 3 : pdu.hdr.common.hlen = 255;
894 : 3 : nvme_tcp_qpair_send_h2c_term_req(&tqpair, &pdu, fes, error_offset);
895 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
896 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
897 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == (unsigned)
898 : : tqpair.send_pdu->hdr.term_req.common.hlen + SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE);
899 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
900 : 3 : }
901 : :
902 : : static void
903 : 3 : test_nvme_tcp_pdu_ch_handle(void)
904 : : {
905 : 3 : struct nvme_tcp_qpair tqpair = {};
906 : 3 : struct spdk_nvme_tcp_stat stats = {};
907 : 3 : struct nvme_tcp_pdu send_pdu = {}, recv_pdu = {};
908 : :
909 : 3 : tqpair.send_pdu = &send_pdu;
910 : 3 : tqpair.recv_pdu = &recv_pdu;
911 : 3 : tqpair.stats = &stats;
912 : 3 : TAILQ_INIT(&tqpair.send_queue);
913 : : /* case 1: Already received IC_RESP PDU. Expect: fail */
914 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_RESP;
915 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_INITIALIZING;
916 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
917 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
918 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
919 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
920 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen);
921 : :
922 : : /* case 2: Expected PDU header length and received are different. Expect: fail */
923 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_RESP;
924 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_INVALID;
925 : 3 : tqpair.recv_pdu->hdr.common.plen = sizeof(struct spdk_nvme_tcp_ic_resp);
926 : 3 : tqpair.recv_pdu->hdr.common.hlen = 0;
927 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
928 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
929 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
930 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
931 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen);
932 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 2);
933 : :
934 : : /* case 3: The TCP/IP tqpair connection is not negotiated. Expect: fail */
935 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP;
936 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_INVALID;
937 : 3 : tqpair.recv_pdu->hdr.common.plen = sizeof(struct spdk_nvme_tcp_ic_resp);
938 : 3 : tqpair.recv_pdu->hdr.common.hlen = 0;
939 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
940 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
941 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
942 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
943 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen);
944 : :
945 : : /* case 4: Unexpected PDU type. Expect: fail */
946 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_REQ;
947 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
948 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
949 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_ic_resp);
950 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
951 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
952 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
953 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
954 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
955 : : (unsigned)SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE);
956 : :
957 : : /* case 5: plen error. Expect: fail */
958 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_RESP;
959 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_INVALID;
960 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
961 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_ic_resp);
962 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
963 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
964 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
965 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
966 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
967 : : (unsigned)SPDK_NVME_TCP_TERM_REQ_ERROR_DATA_MAX_SIZE);
968 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 4);
969 : :
970 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_RESP;
971 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
972 : 3 : tqpair.recv_pdu->hdr.common.flags = SPDK_NVME_TCP_CH_FLAGS_HDGSTF;
973 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
974 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_rsp);
975 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
976 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
977 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
978 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
979 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
980 : : (unsigned)sizeof(struct spdk_nvme_tcp_term_req_hdr));
981 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 4);
982 : :
983 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_C2H_DATA;
984 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
985 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
986 : 3 : tqpair.recv_pdu->hdr.common.pdo = 64;
987 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_c2h_data_hdr);
988 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
989 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
990 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
991 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
992 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
993 : : (unsigned)sizeof(struct spdk_nvme_tcp_term_req_hdr));
994 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 4);
995 : :
996 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ;
997 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
998 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
999 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_term_req_hdr);
1000 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
1001 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1002 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
1003 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
1004 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
1005 : : (unsigned)sizeof(struct spdk_nvme_tcp_term_req_hdr));
1006 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 4);
1007 : :
1008 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_R2T;
1009 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
1010 : 3 : tqpair.recv_pdu->hdr.common.flags = SPDK_NVME_TCP_CH_FLAGS_HDGSTF;
1011 : 3 : tqpair.recv_pdu->hdr.common.plen = 0;
1012 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_r2t_hdr);
1013 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
1014 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1015 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_H2C_TERM_REQ);
1016 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.hlen == sizeof(struct spdk_nvme_tcp_term_req_hdr));
1017 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.common.plen == tqpair.send_pdu->hdr.term_req.common.hlen +
1018 : : (unsigned)sizeof(struct spdk_nvme_tcp_r2t_hdr));
1019 : 3 : CU_ASSERT(tqpair.send_pdu->hdr.term_req.fei[0] == 4);
1020 : :
1021 : : /* case 6: Expect: PASS */
1022 : 3 : tqpair.recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_RESP;
1023 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_INVALID;
1024 : 3 : tqpair.recv_pdu->hdr.common.plen = sizeof(struct spdk_nvme_tcp_ic_resp);
1025 : 3 : tqpair.recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_ic_resp);
1026 : 3 : nvme_tcp_pdu_ch_handle(&tqpair);
1027 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH);
1028 : 3 : CU_ASSERT(tqpair.recv_pdu->psh_len == tqpair.recv_pdu->hdr.common.hlen - sizeof(
1029 : : struct spdk_nvme_tcp_common_pdu_hdr));
1030 : 3 : }
1031 : :
1032 [ # # ]: 0 : DEFINE_RETURN_MOCK(spdk_sock_connect_ext, struct spdk_sock *);
1033 : : struct spdk_sock *
1034 : 18 : spdk_sock_connect_ext(const char *ip, int port,
1035 : : const char *_impl_name, struct spdk_sock_opts *opts)
1036 : : {
1037 [ - + + + : 18 : HANDLE_RETURN_MOCK(spdk_sock_connect_ext);
+ + ]
1038 : 9 : CU_ASSERT(port == 23);
1039 : 9 : CU_ASSERT(opts->opts_size == sizeof(*opts));
1040 : 9 : CU_ASSERT(opts->priority == 1);
1041 [ - + ]: 9 : CU_ASSERT(opts->zcopy == true);
1042 [ - + ]: 9 : CU_ASSERT(!strcmp(ip, "192.168.1.78"));
1043 : 9 : return (struct spdk_sock *)0xDDADBEEF;
1044 : 6 : }
1045 : :
1046 : : static void
1047 : 3 : test_nvme_tcp_qpair_connect_sock(void)
1048 : : {
1049 : 3 : struct nvme_tcp_ctrlr tctrlr = {};
1050 : 3 : struct spdk_nvme_ctrlr *ctrlr = &tctrlr.ctrlr;
1051 : 3 : struct nvme_tcp_qpair tqpair = {};
1052 : : int rc;
1053 : :
1054 : 3 : tqpair.qpair.trtype = SPDK_NVME_TRANSPORT_TCP;
1055 : 3 : tqpair.qpair.id = 1;
1056 : 3 : tqpair.qpair.poll_group = (void *)0xDEADBEEF;
1057 : 3 : ctrlr->trid.priority = 1;
1058 : 3 : ctrlr->trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
1059 [ - + - + ]: 3 : memcpy(ctrlr->trid.traddr, "192.168.1.78", sizeof("192.168.1.78"));
1060 [ - + - + ]: 3 : memcpy(ctrlr->trid.trsvcid, "23", sizeof("23"));
1061 [ - + - + ]: 3 : memcpy(ctrlr->opts.src_addr, "192.168.1.77", sizeof("192.168.1.77"));
1062 [ - + - + ]: 3 : memcpy(ctrlr->opts.src_svcid, "23", sizeof("23"));
1063 : :
1064 : 3 : rc = nvme_tcp_qpair_connect_sock(ctrlr, &tqpair.qpair);
1065 : 3 : CU_ASSERT(rc == 0);
1066 : :
1067 : : /* Unsupported family of the transport address */
1068 : 3 : ctrlr->trid.adrfam = SPDK_NVMF_ADRFAM_IB;
1069 : :
1070 : 3 : rc = nvme_tcp_qpair_connect_sock(ctrlr, &tqpair.qpair);
1071 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == -1);
1072 : :
1073 : : /* Invalid dst_port, INT_MAX is 2147483647 */
1074 : 3 : ctrlr->trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
1075 [ - + - + ]: 3 : memcpy(ctrlr->trid.trsvcid, "2147483647", sizeof("2147483647"));
1076 : :
1077 : 3 : rc = nvme_tcp_qpair_connect_sock(ctrlr, &tqpair.qpair);
1078 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == -EINVAL);
1079 : :
1080 : : /* Parse invalid address */
1081 [ - + - + ]: 3 : memcpy(ctrlr->trid.trsvcid, "23", sizeof("23"));
1082 [ - + - + ]: 3 : memcpy(ctrlr->trid.traddr, "192.168.1.256", sizeof("192.168.1.256"));
1083 : :
1084 : 3 : rc = nvme_tcp_qpair_connect_sock(ctrlr, &tqpair.qpair);
1085 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc != 0);
1086 : 3 : }
1087 : :
1088 : : static void
1089 : 3 : test_nvme_tcp_qpair_icreq_send(void)
1090 : : {
1091 : 3 : struct nvme_tcp_qpair tqpair = {};
1092 : 3 : struct spdk_nvme_tcp_stat stats = {};
1093 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
1094 : 3 : struct nvme_tcp_pdu pdu = {};
1095 : 3 : struct nvme_tcp_poll_group poll_group = {};
1096 : 3 : struct spdk_nvme_tcp_ic_req *ic_req = NULL;
1097 : : int rc;
1098 : :
1099 : 3 : tqpair.send_pdu = &pdu;
1100 : 3 : tqpair.qpair.ctrlr = &ctrlr;
1101 : 3 : tqpair.qpair.poll_group = &poll_group.group;
1102 : 3 : tqpair.stats = &stats;
1103 : 3 : ic_req = &pdu.hdr.ic_req;
1104 : :
1105 : 3 : tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING;
1106 : 3 : tqpair.qpair.ctrlr->opts.header_digest = true;
1107 : 3 : tqpair.qpair.ctrlr->opts.data_digest = true;
1108 : 3 : TAILQ_INIT(&tqpair.send_queue);
1109 : :
1110 : 3 : rc = nvme_tcp_qpair_icreq_send(&tqpair);
1111 : 3 : CU_ASSERT(rc == 0);
1112 : 3 : CU_ASSERT(ic_req->common.hlen == sizeof(*ic_req));
1113 : 3 : CU_ASSERT(ic_req->common.plen == sizeof(*ic_req));
1114 : 3 : CU_ASSERT(ic_req->common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_REQ);
1115 : 3 : CU_ASSERT(ic_req->pfv == 0);
1116 : 3 : CU_ASSERT(ic_req->maxr2t == NVME_TCP_MAX_R2T_DEFAULT - 1);
1117 : 3 : CU_ASSERT(ic_req->hpda == NVME_TCP_HPDA_DEFAULT);
1118 : 3 : CU_ASSERT(ic_req->dgst.bits.hdgst_enable == true);
1119 : 3 : CU_ASSERT(ic_req->dgst.bits.ddgst_enable == true);
1120 : 3 : }
1121 : :
1122 : : static void
1123 : 3 : test_nvme_tcp_c2h_payload_handle(void)
1124 : : {
1125 : 3 : struct nvme_tcp_qpair tqpair = {};
1126 : 3 : struct spdk_nvme_tcp_stat stats = {};
1127 : 3 : struct nvme_tcp_pdu pdu = {};
1128 : 3 : struct nvme_tcp_req tcp_req = {};
1129 : 3 : struct nvme_request req = {};
1130 : 3 : struct nvme_tcp_pdu recv_pdu = {};
1131 : 3 : uint32_t reaped = 1;
1132 : :
1133 : 3 : tcp_req.req = &req;
1134 : 3 : tcp_req.req->qpair = &tqpair.qpair;
1135 : 3 : tcp_req.req->cb_fn = ut_nvme_complete_request;
1136 : 3 : tcp_req.tqpair = &tqpair;
1137 : 3 : tcp_req.cid = 1;
1138 : 3 : tqpair.stats = &stats;
1139 : :
1140 : 3 : TAILQ_INIT(&tcp_req.tqpair->outstanding_reqs);
1141 : :
1142 : 3 : pdu.req = &tcp_req;
1143 : 3 : pdu.hdr.c2h_data.common.flags = SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS |
1144 : : SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU;
1145 : 3 : pdu.data_len = 1024;
1146 : :
1147 : 3 : tqpair.qpair.id = 1;
1148 : 3 : tqpair.recv_pdu = &recv_pdu;
1149 : :
1150 : : /* case 1: nvme_tcp_c2h_data_payload_handle: tcp_req->datao != tcp_req->req->payload_size */
1151 : 3 : tcp_req.datao = 1024;
1152 : 3 : tcp_req.req->payload_size = 2048;
1153 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
1154 : 3 : tcp_req.ordering.bits.send_ack = 1;
1155 [ - + ]: 3 : memset(&tcp_req.rsp, 0, sizeof(tcp_req.rsp));
1156 : 3 : tcp_req.ordering.bits.data_recv = 0;
1157 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR;
1158 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
1159 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
1160 : :
1161 : 3 : nvme_tcp_c2h_data_payload_handle(&tqpair, &pdu, &reaped);
1162 : :
1163 : 3 : CU_ASSERT(tcp_req.rsp.status.p == 0);
1164 : 3 : CU_ASSERT(tcp_req.rsp.cid == tcp_req.cid);
1165 : 3 : CU_ASSERT(tcp_req.rsp.sqid == tqpair.qpair.id);
1166 : 3 : CU_ASSERT(tcp_req.ordering.bits.data_recv == 1);
1167 : 3 : CU_ASSERT(reaped == 2);
1168 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
1169 : :
1170 : : /* case 2: nvme_tcp_c2h_data_payload_handle: tcp_req->datao == tcp_req->req->payload_size */
1171 : 3 : tcp_req.datao = 1024;
1172 : 3 : tcp_req.req->payload_size = 1024;
1173 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
1174 : 3 : tcp_req.ordering.bits.send_ack = 1;
1175 [ - + ]: 3 : memset(&tcp_req.rsp, 0, sizeof(tcp_req.rsp));
1176 : 3 : tcp_req.ordering.bits.data_recv = 0;
1177 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR;
1178 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
1179 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
1180 : :
1181 : 3 : nvme_tcp_c2h_data_payload_handle(&tqpair, &pdu, &reaped);
1182 : :
1183 : 3 : CU_ASSERT(tcp_req.rsp.status.p == 1);
1184 : 3 : CU_ASSERT(tcp_req.rsp.cid == tcp_req.cid);
1185 : 3 : CU_ASSERT(tcp_req.rsp.sqid == tqpair.qpair.id);
1186 : 3 : CU_ASSERT(tcp_req.ordering.bits.data_recv == 1);
1187 : 3 : CU_ASSERT(reaped == 3);
1188 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
1189 : :
1190 : : /* case 3: nvme_tcp_c2h_data_payload_handle: flag does not have SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS */
1191 : 3 : pdu.hdr.c2h_data.common.flags = SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU;
1192 : 3 : tcp_req.datao = 1024;
1193 : 3 : tcp_req.req->payload_size = 1024;
1194 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
1195 : 3 : tcp_req.ordering.bits.send_ack = 1;
1196 [ - + ]: 3 : memset(&tcp_req.rsp, 0, sizeof(tcp_req.rsp));
1197 : 3 : tcp_req.ordering.bits.data_recv = 0;
1198 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR;
1199 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
1200 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
1201 : :
1202 : 3 : nvme_tcp_c2h_data_payload_handle(&tqpair, &pdu, &reaped);
1203 : :
1204 : 3 : CU_ASSERT(reaped == 3);
1205 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 1);
1206 : :
1207 : : /* case 4: nvme_tcp_c2h_term_req_payload_handle: recv_state is NVME_TCP_PDU_RECV_STATE_ERROR */
1208 : 3 : pdu.hdr.term_req.fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1209 : 3 : nvme_tcp_c2h_term_req_payload_handle(&tqpair, &pdu);
1210 : :
1211 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1212 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 1);
1213 : 3 : }
1214 : :
1215 : : static void
1216 : 3 : test_nvme_tcp_icresp_handle(void)
1217 : : {
1218 : 3 : struct nvme_tcp_qpair tqpair = {};
1219 : 3 : struct spdk_nvme_tcp_stat stats = {};
1220 : 3 : struct nvme_tcp_pdu pdu = {};
1221 : 3 : struct nvme_tcp_pdu send_pdu = {};
1222 : 3 : struct nvme_tcp_pdu recv_pdu = {};
1223 : :
1224 : 3 : tqpair.send_pdu = &send_pdu;
1225 : 3 : tqpair.recv_pdu = &recv_pdu;
1226 : 3 : tqpair.stats = &stats;
1227 : 3 : TAILQ_INIT(&tqpair.send_queue);
1228 : :
1229 : : /* case 1: Expected ICResp PFV and got are different. */
1230 : 3 : pdu.hdr.ic_resp.pfv = 1;
1231 : :
1232 : 3 : nvme_tcp_icresp_handle(&tqpair, &pdu);
1233 : :
1234 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1235 : :
1236 : : /* case 2: Expected ICResp maxh2cdata and got are different. */
1237 : 3 : pdu.hdr.ic_resp.pfv = 0;
1238 : 3 : pdu.hdr.ic_resp.maxh2cdata = 2048;
1239 : :
1240 : 3 : nvme_tcp_icresp_handle(&tqpair, &pdu);
1241 : :
1242 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1243 : :
1244 : : /* case 3: Expected ICResp cpda and got are different. */
1245 : 3 : pdu.hdr.ic_resp.maxh2cdata = NVME_TCP_PDU_H2C_MIN_DATA_SIZE;
1246 : 3 : pdu.hdr.ic_resp.cpda = 64;
1247 : :
1248 : 3 : nvme_tcp_icresp_handle(&tqpair, &pdu);
1249 : :
1250 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1251 : :
1252 : : /* case 4: waiting icreq ack. */
1253 : 3 : pdu.hdr.ic_resp.maxh2cdata = NVME_TCP_PDU_H2C_MIN_DATA_SIZE;
1254 : 3 : pdu.hdr.ic_resp.cpda = 30;
1255 : 3 : pdu.hdr.ic_resp.dgst.bits.hdgst_enable = true;
1256 : 3 : pdu.hdr.ic_resp.dgst.bits.ddgst_enable = true;
1257 : 3 : tqpair.flags.icreq_send_ack = 0;
1258 : :
1259 : 3 : nvme_tcp_icresp_handle(&tqpair, &pdu);
1260 : :
1261 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1262 : 3 : CU_ASSERT(tqpair.state == NVME_TCP_QPAIR_STATE_INITIALIZING);
1263 : 3 : CU_ASSERT(tqpair.maxh2cdata == pdu.hdr.ic_resp.maxh2cdata);
1264 : 3 : CU_ASSERT(tqpair.cpda == pdu.hdr.ic_resp.cpda);
1265 : 3 : CU_ASSERT(tqpair.flags.host_hdgst_enable == pdu.hdr.ic_resp.dgst.bits.hdgst_enable);
1266 : 3 : CU_ASSERT(tqpair.flags.host_ddgst_enable == pdu.hdr.ic_resp.dgst.bits.ddgst_enable);
1267 : :
1268 : : /* case 5: Expect: PASS. */
1269 : 3 : tqpair.flags.icreq_send_ack = 1;
1270 : :
1271 : 3 : nvme_tcp_icresp_handle(&tqpair, &pdu);
1272 : :
1273 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1274 : 3 : CU_ASSERT(tqpair.state == NVME_TCP_QPAIR_STATE_FABRIC_CONNECT_SEND);
1275 : 3 : CU_ASSERT(tqpair.maxh2cdata == pdu.hdr.ic_resp.maxh2cdata);
1276 : 3 : CU_ASSERT(tqpair.cpda == pdu.hdr.ic_resp.cpda);
1277 : 3 : CU_ASSERT(tqpair.flags.host_hdgst_enable == pdu.hdr.ic_resp.dgst.bits.hdgst_enable);
1278 : 3 : CU_ASSERT(tqpair.flags.host_ddgst_enable == pdu.hdr.ic_resp.dgst.bits.ddgst_enable);
1279 : 3 : }
1280 : :
1281 : : static void
1282 : 3 : test_nvme_tcp_pdu_payload_handle(void)
1283 : : {
1284 : 3 : struct nvme_tcp_qpair tqpair = {};
1285 : 3 : struct spdk_nvme_tcp_stat stats = {};
1286 : 3 : struct nvme_tcp_pdu recv_pdu = {};
1287 : 3 : struct nvme_tcp_req tcp_req = {};
1288 : 3 : struct nvme_request req = {};
1289 : 3 : uint32_t reaped = 0;
1290 : :
1291 : 3 : tqpair.recv_pdu = &recv_pdu;
1292 : 3 : tcp_req.tqpair = &tqpair;
1293 : 3 : tcp_req.req = &req;
1294 : 3 : tcp_req.req->qpair = &tqpair.qpair;
1295 : 3 : tqpair.stats = &stats;
1296 : :
1297 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD;
1298 : 3 : tqpair.qpair.id = 1;
1299 : 3 : recv_pdu.ddgst_enable = false;
1300 : 3 : recv_pdu.req = &tcp_req;
1301 : 3 : recv_pdu.hdr.c2h_data.common.flags = SPDK_NVME_TCP_C2H_DATA_FLAGS_SUCCESS |
1302 : : SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU;
1303 : 3 : recv_pdu.data_len = 1024;
1304 : 3 : tcp_req.ordering.bits.data_recv = 0;
1305 : 3 : tcp_req.req->cb_fn = ut_nvme_complete_request;
1306 : 3 : tcp_req.cid = 1;
1307 : 3 : TAILQ_INIT(&tcp_req.tqpair->outstanding_reqs);
1308 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
1309 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
1310 : :
1311 : : /* C2H_DATA */
1312 : 3 : recv_pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_C2H_DATA;
1313 : 3 : tcp_req.datao = 1024;
1314 : 3 : tcp_req.req->payload_size = 2048;
1315 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
1316 : 3 : tcp_req.ordering.bits.send_ack = 1;
1317 : :
1318 : 3 : recv_pdu.req = &tcp_req;
1319 : 3 : nvme_tcp_pdu_payload_handle(&tqpair, &reaped);
1320 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1321 : 3 : CU_ASSERT(tcp_req.rsp.status.p == 0);
1322 : 3 : CU_ASSERT(tcp_req.rsp.cid == 1);
1323 : 3 : CU_ASSERT(tcp_req.rsp.sqid == 1);
1324 : 3 : CU_ASSERT(tcp_req.ordering.bits.data_recv == 1);
1325 : 3 : CU_ASSERT(reaped == 1);
1326 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
1327 : :
1328 : : /* TermResp */
1329 : 3 : recv_pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_C2H_TERM_REQ;
1330 : 3 : recv_pdu.hdr.term_req.fes = SPDK_NVME_TCP_TERM_REQ_FES_INVALID_HEADER_FIELD;
1331 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD;
1332 : :
1333 : 3 : recv_pdu.req = &tcp_req;
1334 : 3 : nvme_tcp_pdu_payload_handle(&tqpair, &reaped);
1335 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1336 : 3 : }
1337 : :
1338 : : static void
1339 : 3 : test_nvme_tcp_capsule_resp_hdr_handle(void)
1340 : : {
1341 : 3 : struct nvme_tcp_qpair tqpair = {};
1342 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
1343 : 3 : struct spdk_nvme_tcp_stat stats = {};
1344 : 3 : struct nvme_request req = {};
1345 : 3 : struct spdk_nvme_cpl rccqe_tgt = {};
1346 : 3 : struct nvme_tcp_req *tcp_req = NULL;
1347 : 3 : uint32_t reaped = 0;
1348 : : int rc;
1349 : :
1350 : : /* Initialize requests and pdus */
1351 : 3 : tqpair.num_entries = 1;
1352 : 3 : tqpair.stats = &stats;
1353 : 3 : req.qpair = &tqpair.qpair;
1354 : 3 : req.qpair->ctrlr = &ctrlr;
1355 : 3 : req.payload = NVME_PAYLOAD_CONTIG(NULL, NULL);
1356 : :
1357 : 3 : rc = nvme_tcp_alloc_reqs(&tqpair);
1358 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
1359 : 3 : tcp_req = nvme_tcp_req_get(&tqpair);
1360 [ + + ]: 3 : SPDK_CU_ASSERT_FATAL(tcp_req != NULL);
1361 : 3 : rc = nvme_tcp_req_init(&tqpair, &req, tcp_req);
1362 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(rc == 0);
1363 : 3 : tcp_req->ordering.bits.send_ack = 1;
1364 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH;
1365 : : /* tqpair.recv_pdu will be reset after handling */
1366 : 3 : memset(&rccqe_tgt, 0xff, sizeof(rccqe_tgt));
1367 : 3 : rccqe_tgt.cid = 0;
1368 : 3 : memcpy(&tqpair.recv_pdu->hdr.capsule_resp.rccqe, &rccqe_tgt, sizeof(rccqe_tgt));
1369 : 3 : tqpair.qpair.num_outstanding_reqs = 1;
1370 : :
1371 : 3 : nvme_tcp_capsule_resp_hdr_handle(&tqpair, tqpair.recv_pdu, &reaped);
1372 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
1373 [ - + ]: 3 : CU_ASSERT(!memcmp(&tcp_req->rsp, &rccqe_tgt, sizeof(rccqe_tgt)));
1374 : 3 : CU_ASSERT(tcp_req->ordering.bits.data_recv == 1);
1375 : 3 : CU_ASSERT(reaped == 1);
1376 : 3 : CU_ASSERT(TAILQ_EMPTY(&tcp_req->tqpair->outstanding_reqs));
1377 : 3 : CU_ASSERT(tqpair.qpair.num_outstanding_reqs == 0);
1378 : :
1379 : : /* Get tcp request error, expect fail */
1380 : 3 : reaped = 0;
1381 : 3 : tqpair.recv_pdu->hdr.capsule_resp.rccqe.cid = 1;
1382 : 3 : tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH;
1383 : :
1384 : 3 : nvme_tcp_capsule_resp_hdr_handle(&tqpair, tqpair.recv_pdu, &reaped);
1385 : 3 : CU_ASSERT(reaped == 0);
1386 : 3 : CU_ASSERT(tqpair.recv_state == NVME_TCP_PDU_RECV_STATE_QUIESCING);
1387 : 3 : nvme_tcp_free_reqs(&tqpair);
1388 : 3 : }
1389 : :
1390 : : static void
1391 : 3 : test_nvme_tcp_ctrlr_connect_qpair(void)
1392 : : {
1393 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
1394 : : struct spdk_nvme_qpair *qpair;
1395 : : struct nvme_tcp_qpair *tqpair;
1396 : 3 : struct nvme_tcp_pdu pdu = {};
1397 : 3 : struct nvme_tcp_pdu recv_pdu = {};
1398 : 3 : struct spdk_nvme_tcp_ic_req *ic_req = NULL;
1399 : : int rc;
1400 : :
1401 : 3 : tqpair = calloc(1, sizeof(*tqpair));
1402 : 3 : tqpair->qpair.trtype = SPDK_NVME_TRANSPORT_TCP;
1403 : 3 : tqpair->recv_pdu = &recv_pdu;
1404 : 3 : qpair = &tqpair->qpair;
1405 : 3 : tqpair->sock = (struct spdk_sock *)0xDEADBEEF;
1406 : 3 : tqpair->send_pdu = &pdu;
1407 : 3 : tqpair->qpair.ctrlr = &ctrlr;
1408 : 3 : tqpair->qpair.state = NVME_QPAIR_CONNECTING;
1409 : 3 : tqpair->num_entries = 128;
1410 : 3 : ic_req = &pdu.hdr.ic_req;
1411 : :
1412 : 3 : tqpair->recv_pdu->hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_IC_RESP;
1413 : 3 : tqpair->recv_pdu->hdr.common.plen = sizeof(struct spdk_nvme_tcp_ic_resp);
1414 : 3 : tqpair->recv_pdu->hdr.common.hlen = sizeof(struct spdk_nvme_tcp_ic_resp);
1415 : 3 : tqpair->recv_pdu->ch_valid_bytes = sizeof(struct spdk_nvme_tcp_common_pdu_hdr) - 1;
1416 : 5 : tqpair->recv_pdu->psh_valid_bytes = tqpair->recv_pdu->hdr.common.hlen -
1417 : 3 : sizeof(struct spdk_nvme_tcp_common_pdu_hdr) - 1;
1418 : 3 : tqpair->recv_pdu->hdr.ic_resp.maxh2cdata = 4096;
1419 : 3 : tqpair->recv_pdu->hdr.ic_resp.cpda = 1;
1420 : 3 : tqpair->flags.icreq_send_ack = 1;
1421 : 3 : tqpair->qpair.ctrlr->opts.header_digest = true;
1422 : 3 : tqpair->qpair.ctrlr->opts.data_digest = true;
1423 : 3 : TAILQ_INIT(&tqpair->send_queue);
1424 : :
1425 : 3 : rc = nvme_tcp_ctrlr_connect_qpair(&ctrlr, qpair);
1426 : 3 : CU_ASSERT(rc == 0);
1427 : :
1428 : : /* skip NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY state */
1429 : : /* assume already received the icresp */
1430 : 3 : tqpair->recv_state = NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_CH;
1431 : :
1432 [ + + ]: 9 : while (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
1433 : 6 : rc = nvme_tcp_qpair_process_completions(qpair, 0);
1434 : 6 : CU_ASSERT(rc >= 0);
1435 : : }
1436 : :
1437 : 3 : CU_ASSERT(tqpair->maxr2t == NVME_TCP_MAX_R2T_DEFAULT);
1438 : 3 : CU_ASSERT(tqpair->state == NVME_TCP_QPAIR_STATE_RUNNING);
1439 : 3 : CU_ASSERT(tqpair->recv_state == NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_CH);
1440 : 3 : CU_ASSERT(ic_req->common.hlen == sizeof(*ic_req));
1441 : 3 : CU_ASSERT(ic_req->common.plen == sizeof(*ic_req));
1442 : 3 : CU_ASSERT(ic_req->common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_REQ);
1443 : 3 : CU_ASSERT(ic_req->pfv == 0);
1444 : 3 : CU_ASSERT(ic_req->maxr2t == NVME_TCP_MAX_R2T_DEFAULT - 1);
1445 : 3 : CU_ASSERT(ic_req->hpda == NVME_TCP_HPDA_DEFAULT);
1446 : 3 : CU_ASSERT(ic_req->dgst.bits.hdgst_enable == true);
1447 : 3 : CU_ASSERT(ic_req->dgst.bits.ddgst_enable == true);
1448 : :
1449 : 3 : nvme_tcp_ctrlr_delete_io_qpair(&ctrlr, qpair);
1450 : 3 : }
1451 : :
1452 : : static void
1453 : 3 : ut_disconnect_qpair_req_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
1454 : : {
1455 : 3 : CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_ABORTED_SQ_DELETION);
1456 : 3 : CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
1457 : 3 : }
1458 : :
1459 : : static void
1460 : 3 : ut_disconnect_qpair_poll_group_cb(struct spdk_nvme_qpair *qpair, void *ctx)
1461 : : {
1462 : 3 : int *disconnected = ctx;
1463 : :
1464 : 3 : (*disconnected)++;
1465 : 3 : }
1466 : :
1467 : : static void
1468 : 3 : test_nvme_tcp_ctrlr_disconnect_qpair(void)
1469 : : {
1470 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
1471 : : struct spdk_nvme_qpair *qpair;
1472 : 3 : struct nvme_tcp_pdu pdu = {}, recv_pdu = {};
1473 : 4 : struct nvme_tcp_qpair tqpair = {
1474 : 1 : .qpair = {
1475 : : .trtype = SPDK_NVME_TRANSPORT_TCP,
1476 : : .ctrlr = &ctrlr,
1477 : : .async = true,
1478 : : },
1479 : : .recv_pdu = &recv_pdu,
1480 : : };
1481 : 3 : struct spdk_nvme_poll_group group = {};
1482 : 3 : struct nvme_tcp_poll_group tgroup = { .group.group = &group };
1483 : 3 : struct nvme_request req = { .qpair = &tqpair.qpair, .cb_fn = ut_disconnect_qpair_req_cb };
1484 : 3 : struct nvme_tcp_req treq = { .req = &req, .tqpair = &tqpair };
1485 : 2 : int rc, disconnected;
1486 : :
1487 : 3 : qpair = &tqpair.qpair;
1488 : 3 : qpair->poll_group = &tgroup.group;
1489 : 3 : tqpair.sock = (struct spdk_sock *)0xDEADBEEF;
1490 : 3 : tqpair.needs_poll = true;
1491 : 3 : TAILQ_INIT(&tgroup.needs_poll);
1492 : 3 : STAILQ_INIT(&tgroup.group.disconnected_qpairs);
1493 : 3 : TAILQ_INIT(&tqpair.send_queue);
1494 : 3 : TAILQ_INIT(&tqpair.free_reqs);
1495 : 3 : TAILQ_INIT(&tqpair.outstanding_reqs);
1496 : 3 : TAILQ_INSERT_TAIL(&tgroup.needs_poll, &tqpair, link);
1497 : 3 : TAILQ_INSERT_TAIL(&tqpair.send_queue, &pdu, tailq);
1498 : :
1499 : 3 : nvme_tcp_ctrlr_disconnect_qpair(&ctrlr, qpair);
1500 : :
1501 [ - + ]: 3 : CU_ASSERT(tqpair.needs_poll == false);
1502 : 3 : CU_ASSERT(tqpair.sock == NULL);
1503 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair.send_queue) == true);
1504 : :
1505 : : /* Check that outstanding requests are aborted */
1506 : 3 : treq.state = NVME_TCP_REQ_ACTIVE;
1507 : 3 : qpair->num_outstanding_reqs = 1;
1508 : 3 : qpair->state = NVME_QPAIR_DISCONNECTING;
1509 : 3 : TAILQ_INSERT_TAIL(&tqpair.outstanding_reqs, &treq, link);
1510 : :
1511 : 3 : nvme_tcp_ctrlr_disconnect_qpair(&ctrlr, qpair);
1512 : :
1513 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair.outstanding_reqs));
1514 : 3 : CU_ASSERT_EQUAL(qpair->num_outstanding_reqs, 0);
1515 : 3 : CU_ASSERT_EQUAL(&treq, TAILQ_FIRST(&tqpair.free_reqs));
1516 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTING);
1517 : :
1518 : : /* Check that a request with an accel operation in progress won't be aborted until that
1519 : : * operation is completed */
1520 : 3 : treq.state = NVME_TCP_REQ_ACTIVE;
1521 : 3 : treq.ordering.bits.in_progress_accel = 1;
1522 : 3 : tqpair.async_complete = 0;
1523 : 3 : qpair->poll_group = NULL;
1524 : 3 : qpair->num_outstanding_reqs = 1;
1525 : 3 : qpair->state = NVME_QPAIR_DISCONNECTING;
1526 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.free_reqs, &treq, link);
1527 : 3 : TAILQ_INSERT_TAIL(&tqpair.outstanding_reqs, &treq, link);
1528 : :
1529 : 3 : nvme_tcp_ctrlr_disconnect_qpair(&ctrlr, qpair);
1530 : :
1531 : 3 : CU_ASSERT_EQUAL(&treq, TAILQ_FIRST(&tqpair.outstanding_reqs));
1532 : 3 : CU_ASSERT_EQUAL(qpair->num_outstanding_reqs, 1);
1533 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTING);
1534 : :
1535 : : /* Check that a qpair will be transitioned to a DISCONNECTED state only once the accel
1536 : : * operation is completed */
1537 : 3 : rc = nvme_tcp_qpair_process_completions(qpair, 0);
1538 : 3 : CU_ASSERT_EQUAL(rc, 0);
1539 : 3 : CU_ASSERT_EQUAL(&treq, TAILQ_FIRST(&tqpair.outstanding_reqs));
1540 : 3 : CU_ASSERT_EQUAL(qpair->num_outstanding_reqs, 1);
1541 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTING);
1542 : :
1543 : 3 : treq.ordering.bits.in_progress_accel = 0;
1544 : 3 : qpair->num_outstanding_reqs = 0;
1545 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.outstanding_reqs, &treq, link);
1546 : :
1547 : 3 : rc = nvme_tcp_qpair_process_completions(qpair, 0);
1548 : 3 : CU_ASSERT_EQUAL(rc, -ENXIO);
1549 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTED);
1550 : :
1551 : : /* Check the same scenario but this time with spdk_sock_flush() returning errors */
1552 : 3 : treq.state = NVME_TCP_REQ_ACTIVE;
1553 : 3 : treq.ordering.bits.in_progress_accel = 1;
1554 : 3 : qpair->num_outstanding_reqs = 1;
1555 : 3 : qpair->state = NVME_QPAIR_DISCONNECTING;
1556 : 3 : TAILQ_INSERT_TAIL(&tqpair.outstanding_reqs, &treq, link);
1557 : :
1558 : 3 : nvme_tcp_ctrlr_disconnect_qpair(&ctrlr, qpair);
1559 : :
1560 : 3 : CU_ASSERT_EQUAL(&treq, TAILQ_FIRST(&tqpair.outstanding_reqs));
1561 : 3 : CU_ASSERT_EQUAL(qpair->num_outstanding_reqs, 1);
1562 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTING);
1563 : :
1564 : 3 : MOCK_SET(spdk_sock_flush, -ENOTCONN);
1565 : 3 : treq.ordering.bits.in_progress_accel = 0;
1566 : 3 : qpair->num_outstanding_reqs = 0;
1567 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.outstanding_reqs, &treq, link);
1568 : :
1569 : 3 : rc = nvme_tcp_qpair_process_completions(qpair, 0);
1570 : 3 : CU_ASSERT_EQUAL(rc, 0);
1571 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTED);
1572 : 3 : rc = nvme_tcp_qpair_process_completions(qpair, 0);
1573 : 3 : CU_ASSERT_EQUAL(rc, -ENXIO);
1574 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTED);
1575 [ - + - + ]: 3 : MOCK_CLEAR(spdk_sock_flush);
1576 : :
1577 : : /* Now check the same scenario, but with a qpair that's part of a poll group */
1578 : 3 : disconnected = 0;
1579 : 3 : group.ctx = &disconnected;
1580 : 3 : treq.state = NVME_TCP_REQ_ACTIVE;
1581 : 3 : treq.ordering.bits.in_progress_accel = 1;
1582 : 3 : qpair->poll_group = &tgroup.group;
1583 : 3 : qpair->num_outstanding_reqs = 1;
1584 : 3 : qpair->state = NVME_QPAIR_DISCONNECTING;
1585 : 3 : STAILQ_INSERT_TAIL(&tgroup.group.disconnected_qpairs, qpair, poll_group_stailq);
1586 : 3 : TAILQ_INSERT_TAIL(&tqpair.outstanding_reqs, &treq, link);
1587 : :
1588 : 3 : nvme_tcp_poll_group_process_completions(&tgroup.group, 0,
1589 : : ut_disconnect_qpair_poll_group_cb);
1590 : : /* Until there's an outstanding request, disconnect_cb shouldn't be executed */
1591 : 3 : CU_ASSERT_EQUAL(disconnected, 0);
1592 : 3 : CU_ASSERT_EQUAL(qpair->num_outstanding_reqs, 1);
1593 : 3 : CU_ASSERT_EQUAL(&treq, TAILQ_FIRST(&tqpair.outstanding_reqs));
1594 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTING);
1595 : :
1596 : 3 : treq.ordering.bits.in_progress_accel = 0;
1597 : 3 : qpair->num_outstanding_reqs = 0;
1598 [ + + ]: 3 : TAILQ_REMOVE(&tqpair.outstanding_reqs, &treq, link);
1599 : :
1600 : 3 : nvme_tcp_poll_group_process_completions(&tgroup.group, 0,
1601 : : ut_disconnect_qpair_poll_group_cb);
1602 : 3 : CU_ASSERT_EQUAL(disconnected, 1);
1603 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTED);
1604 : :
1605 : : /* Check that a non-async qpair is marked as disconnected immediately */
1606 : 3 : qpair->poll_group = NULL;
1607 : 3 : qpair->state = NVME_QPAIR_DISCONNECTING;
1608 : 3 : qpair->async = false;
1609 : :
1610 : 3 : nvme_tcp_ctrlr_disconnect_qpair(&ctrlr, qpair);
1611 : :
1612 : 3 : CU_ASSERT_EQUAL(qpair->state, NVME_QPAIR_DISCONNECTED);
1613 : 3 : }
1614 : :
1615 : : static void
1616 : 3 : test_nvme_tcp_ctrlr_create_io_qpair(void)
1617 : : {
1618 : 3 : struct spdk_nvme_qpair *qpair = NULL;
1619 : 3 : struct nvme_tcp_ctrlr tctrlr = {};
1620 : 3 : struct spdk_nvme_ctrlr *ctrlr = &tctrlr.ctrlr;
1621 : 3 : uint16_t qid = 1;
1622 : 3 : struct spdk_nvme_io_qpair_opts opts = {
1623 : : .io_queue_size = 2,
1624 : : .qprio = SPDK_NVME_QPRIO_URGENT,
1625 : : .io_queue_requests = 1,
1626 : : };
1627 : : struct nvme_tcp_qpair *tqpair;
1628 : :
1629 : 3 : ctrlr->trid.priority = 1;
1630 : 3 : ctrlr->trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
1631 [ - + - + ]: 3 : memcpy(ctrlr->trid.traddr, "192.168.1.78", sizeof("192.168.1.78"));
1632 [ - + - + ]: 3 : memcpy(ctrlr->trid.trsvcid, "23", sizeof("23"));
1633 [ - + - + ]: 3 : memcpy(ctrlr->opts.src_addr, "192.168.1.77", sizeof("192.168.1.77"));
1634 [ - + - + ]: 3 : memcpy(ctrlr->opts.src_svcid, "23", sizeof("23"));
1635 : :
1636 : 3 : qpair = nvme_tcp_ctrlr_create_io_qpair(ctrlr, qid, &opts);
1637 : 3 : tqpair = nvme_tcp_qpair(qpair);
1638 : :
1639 : 3 : CU_ASSERT(qpair != NULL);
1640 : 3 : CU_ASSERT(qpair->id == 1);
1641 : 3 : CU_ASSERT(qpair->ctrlr == ctrlr);
1642 : 3 : CU_ASSERT(qpair->qprio == SPDK_NVME_QPRIO_URGENT);
1643 : 3 : CU_ASSERT(qpair->trtype == SPDK_NVME_TRANSPORT_TCP);
1644 : 3 : CU_ASSERT(qpair->poll_group == (void *)0xDEADBEEF);
1645 : 3 : CU_ASSERT(tqpair->num_entries == 1);
1646 : :
1647 : 3 : free(tqpair->tcp_reqs);
1648 : 3 : spdk_free(tqpair->send_pdus);
1649 : 3 : free(tqpair);
1650 : :
1651 : : /* Max queue size shall pass */
1652 : 3 : opts.io_queue_size = 0xffff;
1653 : 3 : qpair = nvme_tcp_ctrlr_create_io_qpair(ctrlr, qid, &opts);
1654 : 3 : tqpair = nvme_tcp_qpair(qpair);
1655 : :
1656 : 3 : CU_ASSERT(qpair != NULL);
1657 : 3 : CU_ASSERT(tqpair->num_entries == 0xfffe);
1658 : :
1659 : 3 : free(tqpair->tcp_reqs);
1660 : 3 : spdk_free(tqpair->send_pdus);
1661 : 3 : free(tqpair);
1662 : :
1663 : : /* Queue size 0 shall fail */
1664 : 3 : opts.io_queue_size = 0;
1665 : 3 : qpair = nvme_tcp_ctrlr_create_io_qpair(ctrlr, qid, &opts);
1666 : 3 : CU_ASSERT(qpair == NULL);
1667 : :
1668 : : /* Queue size 1 shall fail */
1669 : 3 : opts.io_queue_size = 1;
1670 : 3 : qpair = nvme_tcp_ctrlr_create_io_qpair(ctrlr, qid, &opts);
1671 : 3 : CU_ASSERT(qpair == NULL);
1672 : 3 : }
1673 : :
1674 : : static void
1675 : 3 : test_nvme_tcp_ctrlr_delete_io_qpair(void)
1676 : : {
1677 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
1678 : : struct spdk_nvme_qpair *qpair;
1679 : : struct nvme_tcp_qpair *tqpair;
1680 : 3 : struct nvme_tcp_req tcp_req = {};
1681 : 3 : struct nvme_request req = {};
1682 : : int rc;
1683 : :
1684 : 3 : tqpair = calloc(1, sizeof(struct nvme_tcp_qpair));
1685 : 3 : tqpair->tcp_reqs = calloc(1, sizeof(struct nvme_tcp_req));
1686 : 3 : tqpair->send_pdus = calloc(1, sizeof(struct nvme_tcp_pdu));
1687 : 3 : tqpair->qpair.trtype = SPDK_NVME_TRANSPORT_TCP;
1688 : 3 : qpair = &tqpair->qpair;
1689 : 3 : qpair->ctrlr = &ctrlr;
1690 : 3 : tcp_req.req = &req;
1691 : 3 : tcp_req.req->qpair = &tqpair->qpair;
1692 : 3 : tcp_req.req->cb_fn = ut_nvme_complete_request;
1693 : 3 : tcp_req.tqpair = tqpair;
1694 : 3 : tcp_req.state = NVME_TCP_REQ_ACTIVE;
1695 : 3 : TAILQ_INIT(&tqpair->outstanding_reqs);
1696 : 3 : TAILQ_INSERT_TAIL(&tcp_req.tqpair->outstanding_reqs, &tcp_req, link);
1697 : 3 : qpair->num_outstanding_reqs = 1;
1698 : :
1699 : 3 : rc = nvme_tcp_ctrlr_delete_io_qpair(&ctrlr, qpair);
1700 : :
1701 : 3 : CU_ASSERT(rc == 0);
1702 : 3 : }
1703 : :
1704 : : static void
1705 : 3 : test_nvme_tcp_poll_group_get_stats(void)
1706 : : {
1707 : 3 : int rc = 0;
1708 : 3 : struct spdk_sock_group sgroup = {};
1709 : 3 : struct nvme_tcp_poll_group *pgroup = NULL;
1710 : 3 : struct spdk_nvme_transport_poll_group *tgroup = NULL;
1711 : 3 : struct spdk_nvme_transport_poll_group_stat *tgroup_stat = NULL;
1712 : :
1713 : 3 : MOCK_SET(spdk_sock_group_create, &sgroup);
1714 : 3 : tgroup = nvme_tcp_poll_group_create();
1715 : 3 : CU_ASSERT(tgroup != NULL);
1716 : 3 : pgroup = nvme_tcp_poll_group(tgroup);
1717 : 3 : CU_ASSERT(pgroup != NULL);
1718 : :
1719 : : /* Invalid group pointer, expect fail and return -EINVAL */
1720 : 3 : rc = nvme_tcp_poll_group_get_stats(NULL, &tgroup_stat);
1721 : 3 : CU_ASSERT(rc == -EINVAL);
1722 : 3 : CU_ASSERT(tgroup_stat == NULL);
1723 : :
1724 : : /* Invalid stats, expect fail and return -EINVAL */
1725 : 3 : rc = nvme_tcp_poll_group_get_stats(tgroup, NULL);
1726 : 3 : CU_ASSERT(rc == -EINVAL);
1727 : :
1728 : : /* Get stats success */
1729 : 3 : rc = nvme_tcp_poll_group_get_stats(tgroup, &tgroup_stat);
1730 : 3 : CU_ASSERT(rc == 0);
1731 : 3 : CU_ASSERT(tgroup_stat != NULL);
1732 : 3 : CU_ASSERT(tgroup_stat->trtype == SPDK_NVME_TRANSPORT_TCP);
1733 [ - + - + ]: 3 : CU_ASSERT(memcmp(&tgroup_stat->tcp, &pgroup->stats, sizeof(struct spdk_nvme_tcp_stat)) == 0);
1734 : :
1735 : 3 : nvme_tcp_poll_group_free_stats(tgroup, tgroup_stat);
1736 : 3 : rc = nvme_tcp_poll_group_destroy(tgroup);
1737 : 3 : CU_ASSERT(rc == 0);
1738 : :
1739 [ - + - + ]: 3 : MOCK_CLEAR(spdk_sock_group_create);
1740 : 3 : }
1741 : :
1742 : : static void
1743 : 3 : test_nvme_tcp_ctrlr_construct(void)
1744 : : {
1745 : 3 : struct nvme_tcp_qpair *tqpair = NULL;
1746 : 3 : struct nvme_tcp_ctrlr *tctrlr = NULL;
1747 : 3 : struct spdk_nvme_ctrlr *ctrlr = NULL;
1748 : 3 : struct spdk_nvme_transport_id trid = {
1749 : : .trtype = SPDK_NVME_TRANSPORT_TCP,
1750 : : .priority = 1,
1751 : : .adrfam = SPDK_NVMF_ADRFAM_IPV4,
1752 : : .traddr = "192.168.1.78",
1753 : : .trsvcid = "23",
1754 : : };
1755 : 3 : struct spdk_nvme_ctrlr_opts opts = {
1756 : : .admin_queue_size = 2,
1757 : : .src_addr = "192.168.1.77",
1758 : : .src_svcid = "23",
1759 : : };
1760 : :
1761 : : /* Transmit ACK timeout value exceeds max, expected to pass and using max */
1762 : 3 : opts.transport_ack_timeout = NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT + 1;
1763 : 3 : MOCK_SET(spdk_sock_connect_ext, (struct spdk_sock *)0xDEADBEEF);
1764 : 3 : ctrlr = nvme_tcp_ctrlr_construct(&trid, &opts, NULL);
1765 : 3 : tctrlr = nvme_tcp_ctrlr(ctrlr);
1766 : 3 : tqpair = nvme_tcp_qpair(tctrlr->ctrlr.adminq);
1767 : :
1768 : 3 : CU_ASSERT(ctrlr != NULL);
1769 : 3 : CU_ASSERT(tctrlr != NULL);
1770 : 3 : CU_ASSERT(tqpair != NULL);
1771 : 3 : CU_ASSERT(ctrlr->opts.transport_ack_timeout == NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT);
1772 [ - + ]: 3 : CU_ASSERT(memcmp(&ctrlr->trid, &trid, sizeof(struct spdk_nvme_transport_id)) == 0);
1773 : 3 : CU_ASSERT(tqpair->num_entries == 1);
1774 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair->send_queue));
1775 : 3 : CU_ASSERT(TAILQ_EMPTY(&tqpair->outstanding_reqs));
1776 : 3 : CU_ASSERT(!TAILQ_EMPTY(&tqpair->free_reqs));
1777 : 3 : CU_ASSERT(TAILQ_FIRST(&tqpair->free_reqs) == &tqpair->tcp_reqs[0]);
1778 : 3 : CU_ASSERT(TAILQ_FIRST(&tqpair->free_reqs)->cid == 0);
1779 : 3 : CU_ASSERT(TAILQ_FIRST(&tqpair->free_reqs)->tqpair == tqpair);
1780 : 3 : CU_ASSERT(TAILQ_FIRST(&tqpair->free_reqs)->pdu == &tqpair->send_pdus[0]);
1781 : 3 : CU_ASSERT(tqpair->send_pdu == &tqpair->send_pdus[1]);
1782 : 3 : CU_ASSERT(tqpair->recv_pdu == &tqpair->send_pdus[2]);
1783 : :
1784 : 3 : free(tqpair->tcp_reqs);
1785 : 3 : spdk_free(tqpair->send_pdus);
1786 : 3 : free(tqpair);
1787 : 3 : free(tctrlr);
1788 : :
1789 : : /* The Admin queue size is less than the minimum required size, expected to create Admin qpair failed */
1790 : 3 : opts.admin_queue_size = 1;
1791 : 3 : ctrlr = nvme_tcp_ctrlr_construct(&trid, &opts, NULL);
1792 : 3 : CU_ASSERT(ctrlr == NULL);
1793 : :
1794 : : /* Unhandled ADRFAM, expected to create Admin qpair failed */
1795 : 3 : opts.admin_queue_size = 2;
1796 : 3 : trid.adrfam = SPDK_NVMF_ADRFAM_INTRA_HOST;
1797 : 3 : ctrlr = nvme_tcp_ctrlr_construct(&trid, &opts, NULL);
1798 : 3 : CU_ASSERT(ctrlr == NULL);
1799 : :
1800 : : /* Error connecting socket, expected to create Admin qpair failed */
1801 : 3 : trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
1802 : 3 : MOCK_SET(spdk_sock_connect_ext, NULL);
1803 : 3 : ctrlr = nvme_tcp_ctrlr_construct(&trid, &opts, NULL);
1804 : 3 : CU_ASSERT(ctrlr == NULL);
1805 : :
1806 [ - + - + ]: 3 : MOCK_CLEAR(spdk_sock_connect_ext);
1807 : 3 : }
1808 : :
1809 : : static void
1810 : 3 : test_nvme_tcp_qpair_submit_request(void)
1811 : : {
1812 : 3 : int rc = 0;
1813 : 3 : struct nvme_tcp_ctrlr *tctrlr = NULL;
1814 : 3 : struct nvme_tcp_qpair *tqpair = NULL;
1815 : 3 : struct spdk_nvme_ctrlr *ctrlr = NULL;
1816 : 3 : struct nvme_tcp_req *tcp_req = NULL;
1817 : 3 : struct nvme_request req = {};
1818 : 3 : struct nvme_tcp_ut_bdev_io bio = {};
1819 : 3 : struct spdk_nvme_tcp_stat stat = {};
1820 : 3 : struct spdk_nvme_transport_id trid = {
1821 : : .trtype = SPDK_NVME_TRANSPORT_TCP,
1822 : : .priority = 1,
1823 : : .adrfam = SPDK_NVMF_ADRFAM_IPV4,
1824 : : .traddr = "192.168.1.78",
1825 : : .trsvcid = "23",
1826 : : };
1827 : 3 : struct spdk_nvme_ctrlr_opts opts = {
1828 : : .admin_queue_size = 2,
1829 : : .src_addr = "192.168.1.77",
1830 : : .src_svcid = "23",
1831 : : };
1832 : :
1833 : : /* Construct TCP Controller */
1834 : 3 : opts.transport_ack_timeout = NVME_TCP_CTRLR_MAX_TRANSPORT_ACK_TIMEOUT + 1;
1835 : 3 : MOCK_SET(spdk_sock_connect_ext, (struct spdk_sock *)0xDCADBEEF);
1836 : :
1837 : 3 : ctrlr = nvme_tcp_ctrlr_construct(&trid, &opts, NULL);
1838 : 3 : CU_ASSERT(ctrlr != NULL);
1839 : 3 : tctrlr = nvme_tcp_ctrlr(ctrlr);
1840 : 3 : tqpair = nvme_tcp_qpair(tctrlr->ctrlr.adminq);
1841 : 3 : tcp_req = TAILQ_FIRST(&tqpair->free_reqs);
1842 : 3 : CU_ASSERT(tctrlr != NULL);
1843 : 3 : CU_ASSERT(tqpair != NULL);
1844 : 3 : CU_ASSERT(tcp_req->pdu != NULL);
1845 : 3 : CU_ASSERT(tqpair->num_entries == 1);
1846 : :
1847 : 3 : tqpair->stats = &stat;
1848 : 3 : req.qpair = &tqpair->qpair;
1849 : 3 : req.cmd.opc = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
1850 : 3 : req.payload = NVME_PAYLOAD_SGL(nvme_tcp_ut_reset_sgl, nvme_tcp_ut_next_sge, &bio, NULL);
1851 : :
1852 : : /* Failed to construct request, because not enough max_sges */
1853 : 3 : req.qpair->ctrlr->max_sges = 1;
1854 : 3 : req.payload_size = 2048;
1855 : 3 : req.payload_offset = 0;
1856 : 3 : bio.iovpos = 0;
1857 : 3 : bio.iovs[0].iov_len = 1024;
1858 : 3 : bio.iovs[1].iov_len = 1024;
1859 : 3 : bio.iovs[0].iov_base = (void *)0xDEADBEEF;
1860 : 3 : bio.iovs[1].iov_base = (void *)0xDFADBEEF;
1861 : :
1862 : 3 : rc = nvme_tcp_qpair_submit_request(tctrlr->ctrlr.adminq, &req);
1863 : 3 : CU_ASSERT(rc == -1);
1864 : 3 : CU_ASSERT(tcp_req == TAILQ_FIRST(&tqpair->free_reqs));
1865 : 3 : CU_ASSERT(tcp_req->state == NVME_TCP_REQ_FREE);
1866 : :
1867 : : /* Multiple SGL, expected to pass */
1868 : 3 : req.qpair->ctrlr->max_sges = 2;
1869 : :
1870 : 3 : rc = nvme_tcp_qpair_submit_request(tctrlr->ctrlr.adminq, &req);
1871 : 3 : CU_ASSERT(rc == 0);
1872 : 3 : CU_ASSERT(tcp_req->state == NVME_TCP_REQ_ACTIVE);
1873 : 3 : CU_ASSERT(NULL == TAILQ_FIRST(&tqpair->free_reqs));
1874 : 3 : CU_ASSERT(tcp_req == TAILQ_FIRST(&tqpair->outstanding_reqs));
1875 : 3 : CU_ASSERT(tcp_req->expected_datao == 0);
1876 : 3 : CU_ASSERT(tcp_req->req == &req);
1877 : 3 : CU_ASSERT(tcp_req->r2tl_remain == 0);
1878 : 3 : CU_ASSERT(tcp_req->r2tl_remain_next == 0);
1879 : 3 : CU_ASSERT(tcp_req->active_r2ts == 0);
1880 : 3 : CU_ASSERT(tcp_req->iovcnt == 2);
1881 : 3 : CU_ASSERT(tcp_req->ordering.raw == 0);
1882 : 3 : CU_ASSERT(req.cmd.cid == tcp_req->cid);
1883 : 3 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
1884 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
1885 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET);
1886 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == req.payload_size);
1887 : 3 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0);
1888 [ - + ]: 3 : CU_ASSERT(tcp_req->in_capsule_data == true);
1889 : 3 : CU_ASSERT(tcp_req->iov[0].iov_len == bio.iovs[0].iov_len);
1890 : 3 : CU_ASSERT(tcp_req->iov[1].iov_len == bio.iovs[1].iov_len);
1891 : 3 : CU_ASSERT(tcp_req->iov[0].iov_base == bio.iovs[0].iov_base);
1892 : 3 : CU_ASSERT(tcp_req->iov[1].iov_base == bio.iovs[1].iov_base);
1893 : 3 : CU_ASSERT(tcp_req->pdu->hdr.capsule_cmd.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD);
1894 : 3 : CU_ASSERT((tcp_req->pdu->hdr.capsule_cmd.common.flags & SPDK_NVME_TCP_CH_FLAGS_HDGSTF) == 0);
1895 : 3 : CU_ASSERT((tcp_req->pdu->hdr.capsule_cmd.common.flags & SPDK_NVME_TCP_CH_FLAGS_DDGSTF) == 0);
1896 : 3 : CU_ASSERT(tcp_req->datao == 0);
1897 : 3 : CU_ASSERT(tcp_req->pdu->data_len == req.payload_size);
1898 : 3 : CU_ASSERT(tcp_req->pdu->hdr.capsule_cmd.common.pdo == sizeof(struct spdk_nvme_tcp_cmd));
1899 : 3 : CU_ASSERT(tcp_req->pdu->hdr.capsule_cmd.common.plen == sizeof(struct spdk_nvme_tcp_cmd) +
1900 : : req.payload_size);
1901 : 3 : CU_ASSERT(tcp_req->pdu->data_iov[0].iov_base == (void *)0xDEADBEEF);
1902 : 3 : CU_ASSERT(tcp_req->pdu->data_iov[0].iov_len == 1024);
1903 : 3 : CU_ASSERT(tcp_req->pdu->data_iov[1].iov_base == (void *)0xDFADBEEF);
1904 : 3 : CU_ASSERT(tcp_req->pdu->data_iov[1].iov_len == 1024);
1905 : 3 : CU_ASSERT(tcp_req->pdu->data_iovcnt == 2);
1906 : :
1907 : : /* Request resource limit reached, expected to return -EAGAIN */
1908 [ - + ]: 3 : memset(&req, 0x00, sizeof(struct nvme_request));
1909 : 3 : CU_ASSERT(tqpair->stats->queued_requests == 0);
1910 : :
1911 : 3 : rc = nvme_tcp_qpair_submit_request(tctrlr->ctrlr.adminq, &req);
1912 : 3 : CU_ASSERT(rc == -EAGAIN);
1913 : 3 : CU_ASSERT(tqpair->stats->queued_requests == 1);
1914 : :
1915 [ - + - + ]: 3 : MOCK_CLEAR(spdk_sock_connect_ext);
1916 : 3 : free(tqpair->tcp_reqs);
1917 : 3 : spdk_free(tqpair->send_pdus);
1918 : 3 : free(tqpair);
1919 : 3 : free(tctrlr);
1920 : 3 : }
1921 : :
1922 : : int
1923 : 3 : main(int argc, char **argv)
1924 : : {
1925 : 3 : CU_pSuite suite = NULL;
1926 : : unsigned int num_failures;
1927 : :
1928 : 3 : CU_initialize_registry();
1929 : :
1930 : 3 : suite = CU_add_suite("nvme_tcp", NULL, NULL);
1931 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_pdu_set_data_buf);
1932 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_build_iovs);
1933 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_build_sgl_request);
1934 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_pdu_set_data_buf_with_md);
1935 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_build_iovs_with_md);
1936 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_req_complete_safe);
1937 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_req_get);
1938 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_req_init);
1939 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_capsule_cmd_send);
1940 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_write_pdu);
1941 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_set_recv_state);
1942 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_alloc_reqs);
1943 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_send_h2c_term_req);
1944 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_pdu_ch_handle);
1945 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_connect_sock);
1946 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_icreq_send);
1947 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_c2h_payload_handle);
1948 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_icresp_handle);
1949 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_pdu_payload_handle);
1950 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_capsule_resp_hdr_handle);
1951 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_ctrlr_connect_qpair);
1952 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_ctrlr_disconnect_qpair);
1953 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_ctrlr_create_io_qpair);
1954 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_ctrlr_delete_io_qpair);
1955 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_poll_group_get_stats);
1956 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_ctrlr_construct);
1957 : 3 : CU_ADD_TEST(suite, test_nvme_tcp_qpair_submit_request);
1958 : :
1959 : 3 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1960 : 3 : CU_cleanup_registry();
1961 : 3 : return num_failures;
1962 : : }
|