Commit 16b85196 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Darek Stojaczyk
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/455626


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarZiye Yang <ziye.yang@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 3184884f
Loading
Loading
Loading
Loading
+171 −1
Original line number Diff line number Diff line
@@ -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();