From 16b8519660a5db9cf0585c888833351106bac8e0 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Fri, 24 May 2019 14:14:59 +0900 Subject: [PATCH] nvmf/tcp: Add unit test to test SGL handling in C2H and H2C This patch adds UT code to test nvmf_tcp_send_c2h_data, nvmf_tcp_calc_c2h_data_pdu_num, and nvmf_tcp_h2c_data_hdr_handle, and verifies if the last changes works expectedly. Change-Id: Idba21a4739635b7828049f1d71c3bc1595deaab0 Signed-off-by: Shuhei Matsumoto Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/455626 Tested-by: SPDK CI Jenkins Reviewed-by: Ziye Yang Reviewed-by: Darek Stojaczyk Reviewed-by: Changpeng Liu --- test/unit/lib/nvmf/tcp.c/tcp_ut.c | 172 +++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/test/unit/lib/nvmf/tcp.c/tcp_ut.c b/test/unit/lib/nvmf/tcp.c/tcp_ut.c index 41d16dc51..28bae7b78 100644 --- a/test/unit/lib/nvmf/tcp.c/tcp_ut.c +++ b/test/unit/lib/nvmf/tcp.c/tcp_ut.c @@ -374,6 +374,174 @@ test_nvmf_tcp_poll_group_create(void) spdk_thread_destroy(thread); } +static void +test_nvmf_tcp_send_c2h_data(void) +{ + struct spdk_thread *thread; + struct spdk_nvmf_tcp_transport ttransport = {}; + struct spdk_nvmf_tcp_qpair tqpair = {}; + struct spdk_nvmf_tcp_req tcp_req = {}; + struct nvme_tcp_pdu pdu = {}; + struct spdk_nvme_tcp_c2h_data_hdr *c2h_data; + + thread = spdk_thread_create(NULL, NULL); + SPDK_CU_ASSERT_FATAL(thread != NULL); + spdk_set_thread(thread); + + tqpair.qpair.transport = &ttransport.transport; + TAILQ_INIT(&tqpair.free_queue); + TAILQ_INIT(&tqpair.send_queue); + TAILQ_INIT(&tqpair.queued_c2h_data_tcp_req); + + /* Set qpair state to make unrelated operations NOP */ + tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING; + tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR; + + TAILQ_INSERT_TAIL(&tqpair.free_queue, &pdu, tailq); + tqpair.free_pdu_num++; + + tcp_req.req.cmd = (union nvmf_h2c_msg *)&tcp_req.cmd; + + tcp_req.req.iov[0].iov_base = (void *)0xDEADBEEF; + tcp_req.req.iov[0].iov_len = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE; + tcp_req.req.iov[1].iov_base = (void *)0xFEEDBEEF; + tcp_req.req.iov[1].iov_len = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE; + tcp_req.req.iov[2].iov_base = (void *)0xC0FFEE; + tcp_req.req.iov[2].iov_len = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE; + tcp_req.req.iovcnt = 3; + tcp_req.req.length = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE * 3; + + CU_ASSERT(spdk_nvmf_tcp_calc_c2h_data_pdu_num(&tcp_req) == 3); + + TAILQ_INSERT_TAIL(&tqpair.queued_c2h_data_tcp_req, &tcp_req, link); + + tcp_req.c2h_data_offset = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2; + + /* 1st C2H */ + spdk_nvmf_tcp_send_c2h_data(&tqpair, &tcp_req); + + CU_ASSERT(TAILQ_FIRST(&tqpair.send_queue) == &pdu); + TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq); + TAILQ_INSERT_TAIL(&tqpair.free_queue, &pdu, tailq); + tqpair.free_pdu_num++; + + c2h_data = &pdu.hdr.c2h_data; + CU_ASSERT(c2h_data->datao == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(c2h_data->datal = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE); + CU_ASSERT(c2h_data->common.plen == sizeof(*c2h_data) + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE); + CU_ASSERT(!(c2h_data->common.flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU)); + + CU_ASSERT(pdu.data_iovcnt == 2); + CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xDEADBEEF + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(pdu.data_iov[0].iov_len == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT((uint64_t)pdu.data_iov[1].iov_base == 0xFEEDBEEF); + CU_ASSERT(pdu.data_iov[1].iov_len == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + + CU_ASSERT(tcp_req.c2h_data_offset == (NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2) * 3); + CU_ASSERT(TAILQ_FIRST(&tqpair.queued_c2h_data_tcp_req) == &tcp_req); + + /* 2nd C2H */ + spdk_nvmf_tcp_send_c2h_data(&tqpair, &tcp_req); + + CU_ASSERT(TAILQ_FIRST(&tqpair.send_queue) == &pdu); + TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq); + TAILQ_INSERT_TAIL(&tqpair.free_queue, &pdu, tailq); + tqpair.free_pdu_num++; + + c2h_data = &pdu.hdr.c2h_data; + CU_ASSERT(c2h_data->datao == (NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2) * 3); + CU_ASSERT(c2h_data->datal = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE); + CU_ASSERT(c2h_data->common.plen == sizeof(*c2h_data) + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE); + CU_ASSERT(!(c2h_data->common.flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU)); + + CU_ASSERT(pdu.data_iovcnt == 2); + CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xFEEDBEEF + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(pdu.data_iov[0].iov_len == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT((uint64_t)pdu.data_iov[1].iov_base == 0xC0FFEE); + CU_ASSERT(pdu.data_iov[1].iov_len == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + + CU_ASSERT(tcp_req.c2h_data_offset == (NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2) * 5); + CU_ASSERT(TAILQ_FIRST(&tqpair.queued_c2h_data_tcp_req) == &tcp_req); + + /* 3rd C2H */ + spdk_nvmf_tcp_send_c2h_data(&tqpair, &tcp_req); + + CU_ASSERT(TAILQ_FIRST(&tqpair.send_queue) == &pdu); + TAILQ_REMOVE(&tqpair.send_queue, &pdu, tailq); + CU_ASSERT(TAILQ_EMPTY(&tqpair.send_queue)); + + c2h_data = &pdu.hdr.c2h_data; + CU_ASSERT(c2h_data->datao == (NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2) * 5); + CU_ASSERT(c2h_data->datal = NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(c2h_data->common.plen == sizeof(*c2h_data) + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(c2h_data->common.flags & SPDK_NVME_TCP_C2H_DATA_FLAGS_LAST_PDU); + + CU_ASSERT(pdu.data_iovcnt == 1); + CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xC0FFEE + NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + CU_ASSERT(pdu.data_iov[0].iov_len == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE / 2); + + CU_ASSERT(tcp_req.c2h_data_offset == NVMF_TCP_PDU_MAX_C2H_DATA_SIZE * 3); + CU_ASSERT(tqpair.c2h_data_pdu_cnt == 3); + CU_ASSERT(TAILQ_EMPTY(&tqpair.queued_c2h_data_tcp_req)); + + spdk_poller_unregister(&tqpair.flush_poller); + + spdk_thread_exit(thread); + spdk_thread_destroy(thread); +} + +static void +test_nvmf_tcp_h2c_data_hdr_handle(void) +{ + struct spdk_nvmf_tcp_transport ttransport = {}; + struct spdk_nvmf_tcp_qpair tqpair = {}; + struct nvme_tcp_pdu pdu = {}; + struct spdk_nvmf_tcp_req tcp_req = {}; + struct spdk_nvme_tcp_h2c_data_hdr *h2c_data; + + TAILQ_INIT(&tqpair.state_queue[TCP_REQUEST_STATE_TRANSFERRING_HOST_TO_CONTROLLER]); + tqpair.maxh2cdata = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE; + + /* Set qpair state to make unrelated operations NOP */ + tqpair.state = NVME_TCP_QPAIR_STATE_RUNNING; + tqpair.recv_state = NVME_TCP_PDU_RECV_STATE_ERROR; + + tcp_req.req.iov[0].iov_base = (void *)0xDEADBEEF; + tcp_req.req.iov[0].iov_len = (NVMF_TCP_PDU_MAX_H2C_DATA_SIZE / 2) * 5; + tcp_req.req.iov[1].iov_base = (void *)0xFEEDBEEF; + tcp_req.req.iov[1].iov_len = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE / 2; + tcp_req.req.iovcnt = 2; + tcp_req.req.length = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE * 3; + + tcp_req.req.cmd = (union nvmf_h2c_msg *)&tcp_req.cmd; + tcp_req.req.cmd->nvme_cmd.cid = 1; + tcp_req.req.length = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE * 3; + tcp_req.ttag = 2; + tcp_req.next_expected_r2t_offset = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE * 2; + + TAILQ_INSERT_TAIL(&tqpair.state_queue[TCP_REQUEST_STATE_TRANSFERRING_HOST_TO_CONTROLLER], + &tcp_req, state_link); + + h2c_data = &pdu.hdr.h2c_data; + h2c_data->cccid = 1; + h2c_data->ttag = 2; + h2c_data->datao = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE * 2; + h2c_data->datal = NVMF_TCP_PDU_MAX_H2C_DATA_SIZE; + + spdk_nvmf_tcp_h2c_data_hdr_handle(&ttransport, &tqpair, &pdu); + + CU_ASSERT(pdu.data_iovcnt == 2); + CU_ASSERT((uint64_t)pdu.data_iov[0].iov_base == 0xDEADBEEF + NVMF_TCP_PDU_MAX_H2C_DATA_SIZE * 2); + CU_ASSERT(pdu.data_iov[0].iov_len == NVMF_TCP_PDU_MAX_H2C_DATA_SIZE / 2); + CU_ASSERT((uint64_t)pdu.data_iov[1].iov_base == 0xFEEDBEEF); + CU_ASSERT(pdu.data_iov[1].iov_len == NVMF_TCP_PDU_MAX_H2C_DATA_SIZE / 2); + + CU_ASSERT(TAILQ_FIRST(&tqpair.state_queue[TCP_REQUEST_STATE_TRANSFERRING_HOST_TO_CONTROLLER]) == + &tcp_req); + TAILQ_REMOVE(&tqpair.state_queue[TCP_REQUEST_STATE_TRANSFERRING_HOST_TO_CONTROLLER], + &tcp_req, state_link); +} + int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -392,7 +560,9 @@ int main(int argc, char **argv) if ( CU_add_test(suite, "nvmf_tcp_create", test_nvmf_tcp_create) == NULL || CU_add_test(suite, "nvmf_tcp_destroy", test_nvmf_tcp_destroy) == NULL || - CU_add_test(suite, "nvmf_tcp_poll_group_create", test_nvmf_tcp_poll_group_create) == NULL + CU_add_test(suite, "nvmf_tcp_poll_group_create", test_nvmf_tcp_poll_group_create) == NULL || + CU_add_test(suite, "nvmf_tcp_send_c2h_data", test_nvmf_tcp_send_c2h_data) == NULL || + CU_add_test(suite, "nvmf_tcp_h2c_data_hdr_handle", test_nvmf_tcp_h2c_data_hdr_handle) == NULL ) { CU_cleanup_registry(); return CU_get_error();