selftests: fixes for UDP GRO

The current implementation for UDP GRO tests is racy: the receiver
may flush the RX queue while the sending is still transmitting and
incorrectly report RX errors, with a wrong number of packet received.

Add explicit timeouts to the receiver for both connection activation
(first packet received for UDP) and reception completion, so that
in the above critical scenario the receiver will wait for the
transfer completion.

Fixes: 3327a9c46352 ("selftests: add functionals test for UDP GRO")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/tools/testing/selftests/net/udpgro.sh b/tools/testing/selftests/net/udpgro.sh
index aeac53a..ac2a30b 100755
--- a/tools/testing/selftests/net/udpgro.sh
+++ b/tools/testing/selftests/net/udpgro.sh
@@ -37,7 +37,7 @@
 
 	cfg_veth
 
-	ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} && \
+	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} && \
 		echo "ok" || \
 		echo "failed" &
 
@@ -81,7 +81,7 @@
 	# will land on the 'plain' one
 	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -G ${family} -b ${addr1} -n 0 &
 	pid=$!
-	ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${family} -b ${addr2%/*} ${rx_args} && \
+	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${family} -b ${addr2%/*} ${rx_args} && \
 		echo "ok" || \
 		echo "failed"&
 
@@ -99,8 +99,8 @@
 
 	cfg_veth
 
-	ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -p 12345 &
-	ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} && \
+	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} -p 12345 &
+	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 2000 -R 10 ${rx_args} && \
 		echo "ok" || \
 		echo "failed" &
 
diff --git a/tools/testing/selftests/net/udpgso_bench_rx.c b/tools/testing/selftests/net/udpgso_bench_rx.c
index 0c960f6..db3d4a8 100644
--- a/tools/testing/selftests/net/udpgso_bench_rx.c
+++ b/tools/testing/selftests/net/udpgso_bench_rx.c
@@ -45,6 +45,8 @@
 static int  cfg_expected_pkt_nr;
 static int  cfg_expected_pkt_len;
 static int  cfg_expected_gso_size;
+static int  cfg_connect_timeout_ms;
+static int  cfg_rcv_timeout_ms;
 static struct sockaddr_storage cfg_bind_addr;
 
 static bool interrupted;
@@ -87,7 +89,7 @@
 	return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
 }
 
-static void do_poll(int fd)
+static void do_poll(int fd, int timeout_ms)
 {
 	struct pollfd pfd;
 	int ret;
@@ -102,8 +104,16 @@
 			break;
 		if (ret == -1)
 			error(1, errno, "poll");
-		if (ret == 0)
-			continue;
+		if (ret == 0) {
+			if (!timeout_ms)
+				continue;
+
+			timeout_ms -= 10;
+			if (timeout_ms <= 0) {
+				interrupted = true;
+				break;
+			}
+		}
 		if (pfd.revents != POLLIN)
 			error(1, errno, "poll: 0x%x expected 0x%x\n",
 					pfd.revents, POLLIN);
@@ -134,7 +144,7 @@
 		if (listen(accept_fd, 1))
 			error(1, errno, "listen");
 
-		do_poll(accept_fd);
+		do_poll(accept_fd, cfg_connect_timeout_ms);
 		if (interrupted)
 			exit(0);
 
@@ -273,7 +283,9 @@
 
 static void usage(const char *filepath)
 {
-	error(1, 0, "Usage: %s [-Grtv] [-b addr] [-p port] [-l pktlen] [-n packetnr] [-S gsosize]", filepath);
+	error(1, 0, "Usage: %s [-C connect_timeout] [-Grtv] [-b addr] [-p port]"
+	      " [-l pktlen] [-n packetnr] [-R rcv_timeout] [-S gsosize]",
+	      filepath);
 }
 
 static void parse_opts(int argc, char **argv)
@@ -282,7 +294,7 @@
 
 	/* bind to any by default */
 	setup_sockaddr(PF_INET6, "::", &cfg_bind_addr);
-	while ((c = getopt(argc, argv, "4b:Gl:n:p:rS:tv")) != -1) {
+	while ((c = getopt(argc, argv, "4b:C:Gl:n:p:rR:S:tv")) != -1) {
 		switch (c) {
 		case '4':
 			cfg_family = PF_INET;
@@ -292,6 +304,9 @@
 		case 'b':
 			setup_sockaddr(cfg_family, optarg, &cfg_bind_addr);
 			break;
+		case 'C':
+			cfg_connect_timeout_ms = strtoul(optarg, NULL, 0);
+			break;
 		case 'G':
 			cfg_gro_segment = true;
 			break;
@@ -307,6 +322,9 @@
 		case 'r':
 			cfg_read_all = true;
 			break;
+		case 'R':
+			cfg_rcv_timeout_ms = strtoul(optarg, NULL, 0);
+			break;
 		case 'S':
 			cfg_expected_gso_size = strtol(optarg, NULL, 0);
 			break;
@@ -329,8 +347,9 @@
 
 static void do_recv(void)
 {
+	int timeout_ms = cfg_tcp ? cfg_rcv_timeout_ms : cfg_connect_timeout_ms;
 	unsigned long tnow, treport;
-	int fd, loop = 0;
+	int fd;
 
 	fd = do_socket(cfg_tcp);
 
@@ -342,12 +361,7 @@
 
 	treport = gettimeofday_ms() + 1000;
 	do {
-		/* force termination after the second poll(); this cope both
-		 * with sender slower than receiver and missing packet errors
-		 */
-		if (cfg_expected_pkt_nr && loop++)
-			interrupted = true;
-		do_poll(fd);
+		do_poll(fd, timeout_ms);
 
 		if (cfg_tcp)
 			do_flush_tcp(fd);
@@ -365,6 +379,8 @@
 			treport = tnow + 1000;
 		}
 
+		timeout_ms = cfg_rcv_timeout_ms;
+
 	} while (!interrupted);
 
 	if (cfg_expected_pkt_nr && (packets != cfg_expected_pkt_nr))