On FreeBSD some of the test-vconn.c tests failed intermittently due to timing variations in a TCP localhost connection.
- If we receive EAGAIN for certain functions, retry. - Allow EPIPE in addition to ECONNRESET in some cases. A write() to a socket where the other side has closed returns EPIPE on FreeBSD and ECONNRESET on Linux. Signed-off-by: Ed Maste <ema...@freebsd.org> --- tests/test-vconn.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/tests/test-vconn.c b/tests/test-vconn.c index f37bc38..fa244ef 100644 --- a/tests/test-vconn.c +++ b/tests/test-vconn.c @@ -67,6 +67,50 @@ check_errno(int a, int b, const char *as, const char *file, int line) #define CHECK_ERRNO(A, B) check_errno(A, B, #A, __FILE__, __LINE__) +/* Fail if the value in a is not one of the permissible ones in the INT_MAX + * terminated list b. + */ +static void +check_errno_list(int a, int *b, const char *as, const char *file, int line) +{ + int cnt = 0; + + /* Fall back to check_errno for the single element case so that we produce + * the same error message. + */ + if (b[0] != INT_MAX && b[1] == INT_MAX) { + check_errno(a, b[0], as, file, line); + return; + } + while (b[cnt] != INT_MAX) { + if (a == b[cnt]) { + return; + } + cnt++; + } + ovs_fatal(0, "%s:%d: %s is %d (%s) which is not one of %d permissible", + file, line, as, a, strerror(abs(a)), cnt); +} + +#define CHECK_ERRNO_RETRY_FN(A, B, CHECK_FN) do { \ + int count = 0; \ + int retval; \ + do { \ + retval = A; \ + } while (retval == EAGAIN && count++ < 10000); \ + CHECK_FN(retval, B, #A, __FILE__, __LINE__); \ +} while (0) + +/* Retry function A on EAGAIN. Final return value must be that given by B. + */ +#define CHECK_ERRNO_RETRY(A, B) CHECK_ERRNO_RETRY_FN(A, B, check_errno) + +/* Retry function A on EAGAIN. Final return value must be in the list given + * by B. + */ +#define CHECK_ERRNO_RETRY_LIST(A, B) \ + CHECK_ERRNO_RETRY_FN(A, B, check_errno_list) + static void fpv_create(const char *type, struct fake_pvconn *fpv) { @@ -137,26 +181,33 @@ fpv_destroy(struct fake_pvconn *fpv) free(fpv->vconn_name); } +/* Permissible return values for a write to a socket with the other side + * closed */ +static int expected_error_tcp_closed[] = {ECONNRESET, EPIPE, INT_MAX}; + /* Connects to a fake_pvconn with vconn_open(), then closes the listener and * verifies that vconn_connect() reports 'expected_error'. */ static void test_refuse_connection(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; - int expected_error; + int *expected_error; struct fake_pvconn fpv; struct vconn *vconn; + int expected_error_unix[] = {EPIPE, INT_MAX}; + int expected_error_other[] = {EPROTO, INT_MAX}; - expected_error = (!strcmp(type, "unix") ? EPIPE - : !strcmp(type, "tcp") ? ECONNRESET - : EPROTO); + expected_error = (!strcmp(type, "unix") ? expected_error_unix + : !strcmp(type, "tcp") ? expected_error_tcp_closed + : expected_error_other); fpv_create(type, &fpv); CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, DSCP_DEFAULT), 0); fpv_close(&fpv); vconn_run(vconn); - CHECK_ERRNO(vconn_connect(vconn), expected_error); + CHECK_ERRNO_RETRY_LIST(vconn_connect(vconn), expected_error); vconn_close(vconn); fpv_destroy(&fpv); } @@ -229,7 +280,7 @@ test_read_hello(int argc OVS_UNUSED, char *argv[]) poll_block(); } stream_close(stream); - CHECK_ERRNO(vconn_connect(vconn), ECONNRESET); + CHECK_ERRNO_RETRY_LIST(vconn_connect(vconn), expected_error_tcp_closed); vconn_close(vconn); } @@ -322,7 +373,7 @@ test_send_hello(const char *type, const void *out, size_t out_size, poll_block(); } stream_close(stream); - CHECK_ERRNO(vconn_recv(vconn, &msg), EOF); + CHECK_ERRNO_RETRY(vconn_recv(vconn, &msg), EOF); vconn_close(vconn); } -- 1.7.10.3 To: Cc: Bcc: Subject: Reply-To: _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev