Commit 2d0ce5b4 authored by Ziye Yang's avatar Ziye Yang Committed by Jim Harris
Browse files

nvmf/tcp: Implement correct behavior of timeout for C2Htermreq case



From TP8000 spec 7.4.7,

"In response to a C2HTermReq PDU, the host shall terminate the connection.
If the host does not terminate the connection in an implementation specific
period that does not exceed 30 seconds, the controller may terminate the
connection on its own".

It means that the timeout is designed for: when the target is
sending out C2hTermReq, if the host does not terminate the connection,
the target should terminate the connection.

PS: For detecting the malicous connection without sending response
(such as no response of R2T PDU) which should be another patch.

Change-Id: I586dbb235d99aeab5d748a19b9128cd8b0cef183
Signed-off-by: default avatarZiye Yang <optimistyzy@gmail.com>
Reviewed-on: https://review.gerrithub.io/c/440831


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent dadb9485
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -260,6 +260,11 @@ struct spdk_nvmf_tcp_qpair {
	uint16_t				initiator_port;
	uint16_t				target_port;

	/* Timer used to destroy qpair after detecting transport error issue if initiator does
	 *  not close the connection.
	 */
	struct spdk_poller			*timeout_poller;

	TAILQ_ENTRY(spdk_nvmf_tcp_qpair)	link;
};

@@ -1245,9 +1250,32 @@ spdk_nvmf_tcp_qpair_set_recv_state(struct spdk_nvmf_tcp_qpair *tqpair,
	}
}

static int
spdk_nvmf_tcp_qpair_handle_timeout(void *ctx)
{
	struct spdk_nvmf_tcp_qpair *tqpair = ctx;

	assert(tqpair->recv_state == NVME_TCP_PDU_RECV_STATE_ERROR);

	SPDK_ERRLOG("No pdu coming for tqpair=%p within %d seconds\n", tqpair,
		    SPDK_NVME_TCP_QPAIR_EXIT_TIMEOUT);
	tqpair->state = NVME_TCP_QPAIR_STATE_EXITED;
	SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "will disconect the tqpair=%p\n", tqpair);
	spdk_poller_unregister(&tqpair->timeout_poller);
	spdk_nvmf_qpair_disconnect(&tqpair->qpair, NULL, NULL);

	return 0;
}

static void
spdk_nvmf_tcp_send_c2h_term_req_complete(void *cb_arg)
{
	struct spdk_nvmf_tcp_qpair *tqpair = (struct spdk_nvmf_tcp_qpair *)cb_arg;

	if (!tqpair->timeout_poller) {
		tqpair->timeout_poller = spdk_poller_register(spdk_nvmf_tcp_qpair_handle_timeout, tqpair,
					 SPDK_NVME_TCP_QPAIR_EXIT_TIMEOUT * 1000000);
	}
}

static void
@@ -2591,6 +2619,7 @@ spdk_nvmf_tcp_sock_cb(void *arg, struct spdk_sock_group *group, struct spdk_sock
		tqpair->state = NVME_TCP_QPAIR_STATE_EXITED;
		spdk_nvmf_tcp_qpair_flush_pdus(tqpair);
		SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "will disconect the tqpair=%p\n", tqpair);
		spdk_poller_unregister(&tqpair->timeout_poller);
		spdk_nvmf_qpair_disconnect(&tqpair->qpair, NULL, NULL);
	}
}