On some systems in case where remote is not responding, socket could remain in SYN_SENT state for a really long time without errors waiting for connection. This leads to situations where vconn connection hangs for a few minutes waiting for connection to the DOWN remote.
For example, this situation emulated by "refuse-connection" vconn testcase. This leads to test failures because Alarm signal arrives much faster than ETIMEDOUT from the socket: ./vconn.at:21: ovstest test-vconn refuse-connection tcp Alarm clock stderr: |socket_util|INFO|0:127.0.0.1: listening on port 63812 |poll_loop|DBG|wakeup due to 0-ms timeout |poll_loop|DBG|wakeup due to 10155-ms timeout |fatal_signal|WARN|terminating with signal 14 (Alarm clock) ./vconn.at:21: exit code was 142, expected 0 vconn.at:21: 535. tcp vconn - refuse connection (vconn.at:21): FAILED This patch allowes to specify timeout value for vconn blocking connections. If the connection takes more time, socket will be closed with ETIMEDOUT error code. Negative value could be used to wait infinitely. Signed-off-by: Ilya Maximets <[email protected]> --- include/openvswitch/vconn.h | 4 ++-- lib/vconn.c | 22 ++++++++++++++++++---- ovn/utilities/ovn-sbctl.c | 2 +- ovn/utilities/ovn-trace.c | 2 +- tests/test-vconn.c | 14 ++++++++------ utilities/ovs-ofctl.c | 2 +- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/include/openvswitch/vconn.h b/include/openvswitch/vconn.h index b30d46af0..3e41868b7 100644 --- a/include/openvswitch/vconn.h +++ b/include/openvswitch/vconn.h @@ -73,8 +73,8 @@ void vconn_run_wait(struct vconn *); int vconn_get_status(const struct vconn *); int vconn_open_block(const char *name, uint32_t allowed_versions, uint8_t dscp, - struct vconn **); -int vconn_connect_block(struct vconn *); + struct vconn **, long long int timeout); +int vconn_connect_block(struct vconn *, long long int timeout); int vconn_send_block(struct vconn *, struct ofpbuf *); int vconn_recv_block(struct vconn *, struct ofpbuf **); diff --git a/lib/vconn.c b/lib/vconn.c index 4d5f308d8..675110b14 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -306,7 +306,7 @@ vconn_get_status(const struct vconn *vconn) int vconn_open_block(const char *name, uint32_t allowed_versions, uint8_t dscp, - struct vconn **vconnp) + struct vconn **vconnp, long long int timeout) { struct vconn *vconn; int error; @@ -315,7 +315,7 @@ vconn_open_block(const char *name, uint32_t allowed_versions, uint8_t dscp, error = vconn_open(name, allowed_versions, dscp, &vconn); if (!error) { - error = vconn_connect_block(vconn); + error = vconn_connect_block(vconn, timeout); } if (error) { @@ -697,16 +697,30 @@ do_send(struct vconn *vconn, struct ofpbuf *msg) } /* Same as vconn_connect(), except that it waits until the connection on - * 'vconn' completes or fails. Thus, it will never return EAGAIN. */ + * 'vconn' completes or fails, but no more than 'timeout' milliseconds. + * Thus, it will never return EAGAIN. Negative value of 'timeout' means + * infinite waiting.*/ int -vconn_connect_block(struct vconn *vconn) +vconn_connect_block(struct vconn *vconn, long long int timeout) { int error; + long long int deadline = -1; + + if (timeout >= 0) { + deadline = time_msec() + timeout; + } while ((error = vconn_connect(vconn)) == EAGAIN) { + if (deadline >= 0 && time_msec() > deadline) { + error = ETIMEDOUT; + break; + } vconn_run(vconn); vconn_run_wait(vconn); vconn_connect_wait(vconn); + if (deadline >= 0) { + poll_timer_wait_until(deadline); + } poll_block(); } ovs_assert(error != EINPROGRESS); diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c index d0af83fa0..ca0e9c8db 100644 --- a/ovn/utilities/ovn-sbctl.c +++ b/ovn/utilities/ovn-sbctl.c @@ -777,7 +777,7 @@ sbctl_open_vconn(struct shash *options) char *remote = ovs->data ? xstrdup(ovs->data) : default_ovs(); struct vconn *vconn; - int retval = vconn_open_block(remote, 1 << OFP13_VERSION, 0, &vconn); + int retval = vconn_open_block(remote, 1 << OFP13_VERSION, 0, &vconn, -1); if (retval) { VLOG_WARN("%s: connection failed (%s)", remote, ovs_strerror(retval)); } diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c index cbf3e54d2..2bb08739a 100644 --- a/ovn/utilities/ovn-trace.c +++ b/ovn/utilities/ovn-trace.c @@ -2244,7 +2244,7 @@ trace(const char *dp_s, const char *flow_s) ds_put_char(&output, '\n'); if (ovs) { - int retval = vconn_open_block(ovs, 1 << OFP13_VERSION, 0, &vconn); + int retval = vconn_open_block(ovs, 1 << OFP13_VERSION, 0, &vconn, -1); if (retval) { VLOG_WARN("%s: connection failed (%s)", ovs, ovs_strerror(retval)); } diff --git a/tests/test-vconn.c b/tests/test-vconn.c index 8b8d12e36..73ef9a958 100644 --- a/tests/test-vconn.c +++ b/tests/test-vconn.c @@ -37,6 +37,8 @@ #include "timeval.h" #include "util.h" +#define TIMEOUT 10 + struct fake_pvconn { const char *type; char *pvconn_name; @@ -152,9 +154,9 @@ test_refuse_connection(struct ovs_cmdl_context *ctx) fpv_close(&fpv); vconn_run(vconn); - error = vconn_connect_block(vconn); + error = vconn_connect_block(vconn, (TIMEOUT - 2) * 1000); if (!strcmp(type, "tcp")) { - if (error != ECONNRESET && error != EPIPE + if (error != ECONNRESET && error != EPIPE && error != ETIMEDOUT #ifdef _WIN32 && error != WSAECONNRESET #endif @@ -165,7 +167,7 @@ test_refuse_connection(struct ovs_cmdl_context *ctx) } else if (!strcmp(type, "unix")) { CHECK_ERRNO(error, EPIPE); } else if (!strcmp(type, "ssl")) { - if (error != EPROTO && error != ECONNRESET) { + if (error != EPROTO && error != ECONNRESET && error != ETIMEDOUT) { ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", error, ovs_strerror(error)); } @@ -194,7 +196,7 @@ test_accept_then_close(struct ovs_cmdl_context *ctx) stream_close(fpv_accept(&fpv)); fpv_close(&fpv); - error = vconn_connect_block(vconn); + error = vconn_connect_block(vconn, -1); if (!strcmp(type, "tcp") || !strcmp(type, "unix")) { if (error != ECONNRESET && error != EPIPE #ifdef _WIN32 @@ -254,7 +256,7 @@ test_read_hello(struct ovs_cmdl_context *ctx) poll_block(); } stream_close(stream); - error = vconn_connect_block(vconn); + error = vconn_connect_block(vconn, -1); if (error != ECONNRESET && error != EPIPE) { ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", error, ovs_strerror(error)); @@ -451,7 +453,7 @@ test_vconn_main(int argc, char *argv[]) vlog_set_levels(NULL, VLF_CONSOLE, VLL_DBG); fatal_ignore_sigpipe(); - time_alarm(10); + time_alarm(TIMEOUT); ovs_cmdl_run_command(&ctx, commands); } diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 8a713e370..0ff4ed259 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -601,7 +601,7 @@ open_vconn__(const char *name, enum open_target target, free(socket_name); VLOG_DBG("connecting to %s", vconn_get_name(*vconnp)); - error = vconn_connect_block(*vconnp); + error = vconn_connect_block(*vconnp, -1); if (error) { ovs_fatal(0, "%s: failed to connect to socket (%s)", name, ovs_strerror(error)); -- 2.17.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
