diff mbox series

[mptcp-net,3/3] selftests: mptcp: avoid spurious errors on disconnect

Message ID be1fa3944536edc745e897234a38ace68e912e55.1736527092.git.pabeni@redhat.com (mailing list archive)
State Accepted
Commit f1255ad62bbda4e6b3107ed04af0e303619d09ae
Delegated to: Matthieu Baerts
Headers show
Series mptcp: a bunch of fixes for ST flakes | expand

Checks

Context Check Description
matttbe/build success Build and static analysis OK
matttbe/checkpatch fail total: 2 errors, 3 warnings, 0 checks, 71 lines checked
matttbe/shellcheck success MPTCP selftests files have not been modified
matttbe/KVM_Validation__normal success Success! ✅
matttbe/KVM_Validation__debug success Success! ✅
matttbe/KVM_Validation__btf-normal__only_bpftest_all_ success Success! ✅
matttbe/KVM_Validation__btf-debug__only_bpftest_all_ success Success! ✅

Commit Message

Paolo Abeni Jan. 10, 2025, 4:43 p.m. UTC
The disconnect test-case generates spurious errors:

NFO: disconnect
INFO: extra options: -I 3 -i /tmp/tmp.r43niviyoI
01 ns1 MPTCP -> ns1 (10.0.1.1:10000      ) MPTCP     Unexpected revents: POLLERR/POLLNVAL(19)
(duration   140ms) [FAIL] file received by server does not match (in, out):
-rw-r--r-- 1 root root 10028676 Jan 10 10:47 /tmp/tmp.r43niviyoI.disconnect
Trailing bytes are:
��\����R���!8��u2��5N%w------- 1 root root 9992290 Jan 10 10:47 /tmp/tmp.Os4UbnWbI1
Trailing bytes are:
��\����R���!8��u2��5N%2 ns1 MPTCP -> ns1 (dead:beef:1::1:10001) MPTCP     (duration   206ms) [ OK ]
03 ns1 MPTCP -> ns1 (dead:beef:1::1:10002) TCP       (duration    31ms) [ OK ]
04 ns1 TCP   -> ns1 (dead:beef:1::1:10003) MPTCP     (duration    26ms) [ OK ]
[FAIL] Tests of the full disconnection have failed
Time: 2 seconds

The root cause is actually in the user-space bits: the test program
currently disconnects as soon as all the pending data has been spooled,
generating an FASTCLOSE. If such option reaches the peer before that
the latter has reached the closed status, the msk socket will report an
error to the user-space, as per protocol specification, causing the above
failure.

Address the issue explicitly waiting for all the relevant sockets to reach
a closed status before performing the disconnect.

Fixes: 05be5e273c84 ("selftests: mptcp: add disconnect tests")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
 .../selftests/net/mptcp/mptcp_connect.c       | 44 ++++++++++++++-----
 1 file changed, 33 insertions(+), 11 deletions(-)

Comments

Matthieu Baerts Jan. 11, 2025, 11:41 a.m. UTC | #1
Hi Paolo,

On 10/01/2025 17:43, Paolo Abeni wrote:
> The disconnect test-case generates spurious errors:
> 
> NFO: disconnect
> INFO: extra options: -I 3 -i /tmp/tmp.r43niviyoI
> 01 ns1 MPTCP -> ns1 (10.0.1.1:10000      ) MPTCP     Unexpected revents: POLLERR/POLLNVAL(19)
> (duration   140ms) [FAIL] file received by server does not match (in, out):
> -rw-r--r-- 1 root root 10028676 Jan 10 10:47 /tmp/tmp.r43niviyoI.disconnect
> Trailing bytes are:
> ��\����R���!8��u2��5N%w------- 1 root root 9992290 Jan 10 10:47 /tmp/tmp.Os4UbnWbI1
> Trailing bytes are:
> ��\����R���!8��u2��5N%2 ns1 MPTCP -> ns1 (dead:beef:1::1:10001) MPTCP     (duration   206ms) [ OK ]
> 03 ns1 MPTCP -> ns1 (dead:beef:1::1:10002) TCP       (duration    31ms) [ OK ]
> 04 ns1 TCP   -> ns1 (dead:beef:1::1:10003) MPTCP     (duration    26ms) [ OK ]
> [FAIL] Tests of the full disconnection have failed
> Time: 2 seconds
> 
> The root cause is actually in the user-space bits: the test program
> currently disconnects as soon as all the pending data has been spooled,
> generating an FASTCLOSE. If such option reaches the peer before that
> the latter has reached the closed status, the msk socket will report an
> error to the user-space, as per protocol specification, causing the above
> failure.

Good catch!

> Address the issue explicitly waiting for all the relevant sockets to reach
> a closed status before performing the disconnect.
> 
> Fixes: 05be5e273c84 ("selftests: mptcp: add disconnect tests")
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
>  .../selftests/net/mptcp/mptcp_connect.c       | 44 ++++++++++++++-----
>  1 file changed, 33 insertions(+), 11 deletions(-)
> 
> diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
> index 4209b9569039..5cfea1760431 100644
> --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
> +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
> @@ -25,6 +25,8 @@
>  #include <sys/types.h>
>  #include <sys/mman.h>
>  
> +#include <arpa/inet.h>
> +
>  #include <netdb.h>
>  #include <netinet/in.h>
>  
> @@ -1211,23 +1213,43 @@ static void parse_setsock_options(const char *name)
>  	exit(1);
>  }
>  
> -void xdisconnect(int fd, int addrlen)
> +void xdisconnect(int fd)
>  {
> -	struct sockaddr_storage empty;
> +	socklen_t addrlen = sizeof(struct sockaddr_storage);
> +	struct sockaddr_storage addr, empty;
>  	int msec_sleep = 10;
> -	int queued = 1;
> -	int i;
> +	void *raw_addr;
> +	int i, cmdlen;
> +	char cmd[128];
> +
> +	/* get the local address and convert it to string */
> +	if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0)
> +		xerror("getsockname");
> +
> +	if (addr.ss_family == AF_INET)
> +		raw_addr= &(((struct sockaddr_in *)&addr)->sin_addr);
> +	else if (addr.ss_family == AF_INET6)
> +		raw_addr = &(((struct sockaddr_in6 *)&addr)->sin6_addr);
> +	else
> +		xerror("bad family");
> +
> +	strcpy(cmd, "ss -M | grep ");
> +	cmdlen = strlen(cmd);
> +	if (!inet_ntop(addr.ss_family , raw_addr, &cmd[cmdlen],
> +		       sizeof(cmd) - cmdlen))
> +		xerror("inet_ntop");
> +	strcat(cmd, " >/dev/null");

Detail: we can use 'grep -q', so no need to add ">/dev/null".

Cheers,
Matt
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index 4209b9569039..5cfea1760431 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -25,6 +25,8 @@ 
 #include <sys/types.h>
 #include <sys/mman.h>
 
+#include <arpa/inet.h>
+
 #include <netdb.h>
 #include <netinet/in.h>
 
@@ -1211,23 +1213,43 @@  static void parse_setsock_options(const char *name)
 	exit(1);
 }
 
-void xdisconnect(int fd, int addrlen)
+void xdisconnect(int fd)
 {
-	struct sockaddr_storage empty;
+	socklen_t addrlen = sizeof(struct sockaddr_storage);
+	struct sockaddr_storage addr, empty;
 	int msec_sleep = 10;
-	int queued = 1;
-	int i;
+	void *raw_addr;
+	int i, cmdlen;
+	char cmd[128];
+
+	/* get the local address and convert it to string */
+	if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0)
+		xerror("getsockname");
+
+	if (addr.ss_family == AF_INET)
+		raw_addr= &(((struct sockaddr_in *)&addr)->sin_addr);
+	else if (addr.ss_family == AF_INET6)
+		raw_addr = &(((struct sockaddr_in6 *)&addr)->sin6_addr);
+	else
+		xerror("bad family");
+
+	strcpy(cmd, "ss -M | grep ");
+	cmdlen = strlen(cmd);
+	if (!inet_ntop(addr.ss_family , raw_addr, &cmd[cmdlen],
+		       sizeof(cmd) - cmdlen))
+		xerror("inet_ntop");
+	strcat(cmd, " >/dev/null");
 
 	shutdown(fd, SHUT_WR);
 
-	/* while until the pending data is completely flushed, the later
+	/*
+	 * wait until the pending data is completely flushed and all
+	 * the MPTCP sockets reached the closed status.
 	 * disconnect will bypass/ignore/drop any pending data.
 	 */
 	for (i = 0; ; i += msec_sleep) {
-		if (ioctl(fd, SIOCOUTQ, &queued) < 0)
-			xerror("can't query out socket queue: %d", errno);
-
-		if (!queued)
+		/* closed socket are not listed by 'ss' */
+		if (system(cmd))
 			break;
 
 		if (i > poll_timeout)
@@ -1281,9 +1303,9 @@  int main_loop(void)
 		return ret;
 
 	if (cfg_truncate > 0) {
-		xdisconnect(fd, peer->ai_addrlen);
+		xdisconnect(fd);
 	} else if (--cfg_repeat > 0) {
-		xdisconnect(fd, peer->ai_addrlen);
+		xdisconnect(fd);
 
 		/* the socket could be unblocking at this point, we need the
 		 * connect to be blocking