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