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: Ziye Yang <optimistyzy@gmail.com>
Reviewed-on: https://review.gerrithub.io/c/440831
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Ziye Yang 2019-01-17 18:18:16 +08:00 committed by Jim Harris
parent dadb948585
commit 2d0ce5b48b

View File

@ -260,7 +260,12 @@ struct spdk_nvmf_tcp_qpair {
uint16_t initiator_port;
uint16_t target_port;
TAILQ_ENTRY(spdk_nvmf_tcp_qpair) link;
/* 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;
};
struct spdk_nvmf_tcp_poll_group {
@ -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);
}
}