From 78a31ad4a1286ac192b4f3650242e35ddeb9de23 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Sat, 20 Oct 2012 18:43:48 +0200 Subject: [PATCH] Add iscsi_set_tcp_syncnt function This patch adds support for setting TCP_SYNCNT to overwrite the system default values. This allows indirect support for a configurable connect timeout. Linux uses a exponential backoff for SYN retries starting with 1 second. This means for a value n for TCP_SYNCNT, the connect will effectively timeout after 2^(n+1)-1 seconds. --- include/iscsi-private.h | 1 + lib/connect.c | 1 + lib/init.c | 10 +++++++--- lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + lib/socket.c | 42 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index d0a73f6..f523b6e 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -89,6 +89,7 @@ struct iscsi_context { int tcp_keepcnt; int tcp_keepintvl; int tcp_keepidle; + int tcp_syncnt; int current_phase; int next_phase; diff --git a/lib/connect.c b/lib/connect.c index c20e4ed..650b0a2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -238,6 +238,7 @@ try_again: iscsi->tcp_keepidle = old_iscsi->tcp_keepidle; iscsi->tcp_keepcnt = old_iscsi->tcp_keepcnt; iscsi->tcp_keepintvl = old_iscsi->tcp_keepintvl; + iscsi->tcp_syncnt = old_iscsi->tcp_syncnt; if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { iscsi_destroy_context(iscsi); diff --git a/lib/init.c b/lib/init.c index 0cb5cf9..41e20f0 100644 --- a/lib/init.c +++ b/lib/init.c @@ -74,6 +74,10 @@ iscsi_create_context(const char *initiator_name) iscsi->tcp_keepcnt=3; iscsi->tcp_keepintvl=30; iscsi->tcp_keepidle=30; + + if (getenv("LIBISCSI_DEBUG") != NULL) { + iscsi_set_debug(iscsi,atoi(getenv("LIBISCSI_DEBUG"))); + } if (getenv("LIBISCSI_TCP_USER_TIMEOUT") != NULL) { iscsi_set_tcp_user_timeout(iscsi,atoi(getenv("LIBISCSI_TCP_USER_TIMEOUT"))); @@ -90,9 +94,9 @@ iscsi_create_context(const char *initiator_name) if (getenv("LIBISCSI_TCP_KEEPIDLE") != NULL) { iscsi_set_tcp_keepidle(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPIDLE"))); } - - if (getenv("LIBISCSI_DEBUG") != NULL) { - iscsi_set_debug(iscsi,atoi(getenv("LIBISCSI_DEBUG"))); + + if (getenv("LIBISCSI_TCP_SYNCNT") != NULL) { + iscsi_set_tcp_syncnt(iscsi,atoi(getenv("LIBISCSI_TCP_SYNCNT"))); } return iscsi; diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 00cef83..6c197f8 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -76,6 +76,7 @@ iscsi_set_tcp_user_timeout iscsi_set_tcp_keepidle iscsi_set_tcp_keepcnt iscsi_set_tcp_keepintvl +iscsi_set_tcp_syncnt iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 47fb0dc..5a86af8 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -74,6 +74,7 @@ iscsi_set_tcp_user_timeout iscsi_set_tcp_keepidle iscsi_set_tcp_keepcnt iscsi_set_tcp_keepintvl +iscsi_set_tcp_syncnt iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/socket.c b/lib/socket.c index 1327ee0..f481f60 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -86,6 +86,34 @@ int set_tcp_user_timeout(struct iscsi_context *iscsi) return 0; } +#ifndef TCP_SYNCNT +#define TCP_SYNCNT 7 +#endif + +int set_tcp_syncnt(struct iscsi_context *iscsi) +{ + int level, value; + + #if defined(__FreeBSD__) || defined(__sun) + struct protoent *buf; + + if ((buf = getprotobyname("tcp")) != NULL) + level = buf->p_proto; + else + return -1; + #else + level = SOL_TCP; + #endif + + value = iscsi->tcp_syncnt; + if (setsockopt(iscsi->fd, level, TCP_SYNCNT, &value, sizeof(value)) != 0) { + iscsi_set_error(iscsi, "TCP: Failed to set tcp syn retries. Error %s(%d)", strerror(errno), errno); + return -1; + } + DPRINTF(iscsi,3,"TCP_SYNCNT set to %d",value); + return 0; +} + int iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_command_cb cb, void *private_data) @@ -194,6 +222,10 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, set_tcp_user_timeout(iscsi); } + if (iscsi->tcp_syncnt > 0) { + set_tcp_syncnt(iscsi); + } + if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { iscsi_set_error(iscsi, "Connect failed with errno : " @@ -461,7 +493,7 @@ iscsi_service(struct iscsi_context *iscsi, int revents) if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) { int err = 0; socklen_t err_size = sizeof(err); - + DPRINTF(iscsi,3,"inside iscsi service is_connected=0"); if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR, &err, &err_size) != 0 || err != 0) { if (err == 0) { @@ -480,6 +512,8 @@ iscsi_service(struct iscsi_context *iscsi, int revents) return -1; } + DPRINTF(iscsi,2,"connection to %s established",iscsi->connected_portal); + iscsi->is_connected = 1; iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL, iscsi->connect_data); @@ -557,6 +591,12 @@ iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue) } } +void iscsi_set_tcp_syncnt(struct iscsi_context *iscsi, int value) +{ + iscsi->tcp_syncnt=value; + DPRINTF(iscsi,2,"TCP_SYNCNT will be set to %d on next socket creation",value); +} + void iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms) { iscsi->tcp_user_timeout=timeout_ms;