[LTP] [PATCH] network/tcp_fastopen: use UDP optionally

Alexey Kodanev alexey.kodanev@oracle.com
Tue Dec 15 13:48:15 CET 2015


With minor changes the test can be run over UDP.
'-U' parameter should be provided to tcp_fastopen.

Changes in server:
* recv() changed to recvfrom() to get client address and port,
* server creates only one thread that manages requests from clients,
  and sends replies with sendto().
* increase default timeout, 10s -> 60s (waiting for requests).

Also rename some variables and test messages to more general form.

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 testcases/network/tcp_fastopen/tcp_fastopen.c |  162 +++++++++++++++----------
 1 files changed, 100 insertions(+), 62 deletions(-)

diff --git a/testcases/network/tcp_fastopen/tcp_fastopen.c b/testcases/network/tcp_fastopen/tcp_fastopen.c
index c63e7f0..c75e1d1 100644
--- a/testcases/network/tcp_fastopen/tcp_fastopen.c
+++ b/testcases/network/tcp_fastopen/tcp_fastopen.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
+ * Copyright (c) 2014-2015 Oracle and/or its affiliates. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -12,8 +12,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
  *
@@ -54,10 +53,10 @@ static const int max_msg_len = 1500;
 #endif
 
 enum {
-	TCP_SERVER = 0,
-	TCP_CLIENT,
+	SERVER_HOST = 0,
+	CLIENT_HOST,
 };
-static int tcp_mode;
+static int net_mode;
 
 enum {
 	TFO_ENABLED = 0,
@@ -94,11 +93,12 @@ static int clients_num		= 2;
 static char *tcp_port		= "61000";
 static char *server_addr	= "localhost";
 static int busy_poll		= -1;
+static int use_udp;
 /* server socket */
 static int sfd;
 
 /* how long a client must wait for the server's reply, microsec */
-static long wait_timeout = 10000000;
+static long wait_timeout = 60000000;
 
 /* in the end test will save time result in this file */
 static char *rpath		= "./tfo_result";
@@ -125,8 +125,9 @@ static const option_t options[] = {
 	/* common */
 	{"g:", NULL, &tcp_port},
 	{"b:", NULL, &barg},
+	{"U", &use_udp, NULL},
 	{"F", &force_run, NULL},
-	{"l", &tcp_mode, NULL},
+	{"l", &net_mode, NULL},
 	{"o", &fastopen_api, NULL},
 	{"O", &tfo_support, NULL},
 	{"v", &verbose, NULL},
@@ -142,6 +143,7 @@ static void help(void)
 	printf("  -l      Become TCP Client, default is TCP server\n");
 	printf("  -g x    x - server port, default is %s\n", tcp_port);
 	printf("  -b x    x - low latency busy poll timeout\n");
+	printf("  -U      use UDP\n");
 
 	printf("\n          Client:\n");
 	printf("  -H x    x - server name or ip address, default is '%s'\n",
@@ -161,13 +163,13 @@ static void help(void)
 	printf("  -q x    x - server's limit on the queue of TFO requests\n");
 }
 
-/* common structure for TCP server and TCP client */
-struct tcp_func {
+/* common structure for TCP/UDP server and TCP/UDP client */
+struct net_func {
 	void (*init)(void);
 	void (*run)(void);
 	void (*cleanup)(void);
 };
-static struct tcp_func tcp;
+static struct net_func net;
 
 #define MAX_THREADS	10000
 static pthread_attr_t attr;
@@ -175,6 +177,9 @@ static pthread_t *thread_ids;
 
 static struct addrinfo *remote_addrinfo;
 static struct addrinfo *local_addrinfo;
+static struct sockaddr_storage remote_addr;
+static socklen_t remote_addr_len;
+
 static const struct linger clo = { 1, 3 };
 
 static void do_cleanup(void)
@@ -182,7 +187,8 @@ static void do_cleanup(void)
 	free(client_msg);
 	free(server_msg);
 
-	tcp.cleanup();
+	if (net.cleanup)
+		net.cleanup();
 
 	if (tfo_cfg_changed) {
 		SAFE_FILE_SCANF(NULL, tfo_cfg, "%d", &tfo_cfg_value);
@@ -206,6 +212,7 @@ static int sock_recv_poll(int fd, char *buf, int buf_size, int offset)
 	pfd.fd = fd;
 	pfd.events = POLLIN;
 	int len = -1;
+
 	while (1) {
 		errno = 0;
 		int ret = poll(&pfd, 1, wait_timeout / 1000);
@@ -224,8 +231,9 @@ static int sock_recv_poll(int fd, char *buf, int buf_size, int offset)
 			break;
 
 		errno = 0;
-		len = recv(fd, buf + offset,
-			buf_size - offset, MSG_DONTWAIT);
+		len = recvfrom(fd, buf + offset, buf_size - offset,
+			       MSG_DONTWAIT, (struct sockaddr *)&remote_addr,
+			       &remote_addr_len);
 
 		if (len == -1 && errno == EINTR)
 			continue;
@@ -274,7 +282,8 @@ static int client_recv(int *fd, char *buf)
 
 static int client_connect_send(const char *msg, int size)
 {
-	int cfd = socket(remote_addrinfo->ai_family, SOCK_STREAM, 0);
+	int cfd = socket(remote_addrinfo->ai_family,
+			 remote_addrinfo->ai_socktype, 0);
 	const int flag = 1;
 
 	if (cfd == -1)
@@ -330,6 +339,8 @@ void *client_fn(LTP_ATTRIBUTE_UNUSED void *arg)
 	}
 
 	for (i = 1; i < client_max_requests; ++i) {
+		if (use_udp)
+			goto send;
 
 		/* check connection, it can be closed */
 		int ret = 0;
@@ -359,6 +370,7 @@ void *client_fn(LTP_ATTRIBUTE_UNUSED void *arg)
 			break;
 		}
 
+send:
 		if (verbose) {
 			tst_resm_hexd(TINFO, client_msg, client_msg_size,
 				"try to send msg[%d]", i);
@@ -432,14 +444,18 @@ static void client_init(void)
 
 	struct addrinfo hints;
 	memset(&hints, 0, sizeof(struct addrinfo));
-	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = (use_udp) ? SOCK_DGRAM : SOCK_STREAM;
+	hints.ai_flags = 0;
+	hints.ai_protocol = 0;
+
 	int err = getaddrinfo(server_addr, tcp_port, &hints, &remote_addrinfo);
 	if (err) {
 		tst_brkm(TBROK, cleanup, "getaddrinfo of '%s' failed, %s",
 			server_addr, gai_strerror(err));
 	}
 
-	tst_resm(TINFO, "TCP Fast Open over IPv%s",
+	tst_resm(TINFO, "Running the test over IPv%s",
 		(remote_addrinfo->ai_family == AF_INET6) ? "6" : "4");
 
 	clock_gettime(CLOCK_MONOTONIC_RAW, &tv_client_start);
@@ -560,22 +576,23 @@ void *server_fn(void *cfd)
 			send_msg = make_server_reply(send_msg_size);
 		}
 
+		offset = 0;
+
 		/*
 		 * It will tell client that server is going
 		 * to close this connection.
 		 */
-		if (++num_requests >= server_max_requests)
+		if (!use_udp && ++num_requests >= server_max_requests)
 			send_msg[0] = start_fin_byte;
 
-		if (send(client_fd, send_msg, send_msg_size,
-		    MSG_NOSIGNAL) == -1) {
-			tst_resm(TFAIL | TERRNO, "send failed");
+		if (sendto(client_fd, send_msg, send_msg_size,
+		    MSG_NOSIGNAL, (struct sockaddr *)&remote_addr,
+		    remote_addr_len) < 0) {
+			tst_resm(TFAIL | TERRNO, "sendto failed");
 			goto out;
 		}
 
-		offset = 0;
-
-		if (num_requests >= server_max_requests) {
+		if (!use_udp && num_requests >= server_max_requests) {
 			/* max reqs, close socket */
 			shutdown(client_fd, SHUT_WR);
 			break;
@@ -593,13 +610,14 @@ out:
 	tst_exit();
 }
 
-static void server_thread_add(intptr_t client_fd)
+static pthread_t server_thread_add(intptr_t client_fd)
 {
 	pthread_t id;
 	if (pthread_create(&id, &attr, server_fn, (void *) client_fd)) {
 		tst_brkm(TBROK | TERRNO, cleanup,
 			"pthread_create failed at %s:%d", __FILE__, __LINE__);
 	}
+	return id;
 }
 
 static void server_init(void)
@@ -607,23 +625,27 @@ static void server_init(void)
 	struct addrinfo hints;
 	memset(&hints, 0, sizeof(struct addrinfo));
 	hints.ai_family = AF_INET6;
-	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_socktype = (use_udp) ? SOCK_DGRAM : SOCK_STREAM;
 	hints.ai_flags = AI_PASSIVE;
+
 	if (getaddrinfo(NULL, tcp_port, &hints, &local_addrinfo) != 0)
 		tst_brkm(TBROK | TERRNO, cleanup, "getaddrinfo failed");
 
-	/* IPv6 socket is also able to access IPv4 protocol stack */
-	sfd = SAFE_SOCKET(cleanup, AF_INET6, SOCK_STREAM, 0);
-
-	tst_resm(TINFO, "assigning a name to the server socket...");
 	if (!local_addrinfo)
 		tst_brkm(TBROK, cleanup, "failed to get the address");
 
+	/* IPv6 socket is also able to access IPv4 protocol stack */
+	sfd = SAFE_SOCKET(cleanup, AF_INET6, local_addrinfo->ai_socktype, 0);
+
+	tst_resm(TINFO, "assigning a name to the server socket...");
 	SAFE_BIND(cleanup, sfd, local_addrinfo->ai_addr,
 		local_addrinfo->ai_addrlen);
 
 	freeaddrinfo(local_addrinfo);
 
+	if (use_udp)
+		return;
+
 	const int flag = 1;
 	setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
 
@@ -642,6 +664,14 @@ static void server_cleanup(void)
 	SAFE_CLOSE(NULL, sfd);
 }
 
+static void server_run_udp(void)
+{
+	pthread_t p_id = server_thread_add(sfd);
+
+	if (!pthread_join(p_id, NULL))
+		tst_brkm(TBROK | TERRNO, cleanup, "pthread_join() failed");
+}
+
 static void server_run(void)
 {
 	/* IPv4 source address will be mapped to IPv6 address */
@@ -739,20 +769,16 @@ static void setup(int argc, char *argv[])
 
 	tst_sig(FORK, DEF_HANDLER, cleanup);
 
-	tst_resm(TINFO, "TCP %s is using %s TCP API.",
-		(tcp_mode == TCP_SERVER) ? "server" : "client",
-		(fastopen_api == TFO_ENABLED) ? "Fastopen" : "old");
-
-	switch (tcp_mode) {
-	case TCP_SERVER:
+	switch (net_mode) {
+	case SERVER_HOST:
 		tst_resm(TINFO, "max requests '%d'",
 			server_max_requests);
-		tcp.init	= server_init;
-		tcp.run		= server_run;
-		tcp.cleanup	= server_cleanup;
+		net.init	= server_init;
+		net.run		= (use_udp) ? server_run_udp : server_run;
+		net.cleanup	= (use_udp) ? NULL : server_cleanup;
 		tfo_bit_num = 2;
 	break;
-	case TCP_CLIENT:
+	case CLIENT_HOST:
 		tst_resm(TINFO, "connection: addr '%s', port '%s'",
 			server_addr, tcp_port);
 		tst_resm(TINFO, "client max req: %d", client_max_requests);
@@ -760,41 +786,53 @@ static void setup(int argc, char *argv[])
 		tst_resm(TINFO, "client msg size: %d", client_msg_size);
 		tst_resm(TINFO, "server msg size: %d", server_msg_size);
 
-		tcp.init	= client_init;
-		tcp.run		= client_run;
-		tcp.cleanup	= client_cleanup;
+		net.init	= client_init;
+		net.run		= client_run;
+		net.cleanup	= client_cleanup;
 		tfo_bit_num = 1;
 	break;
 	}
 
-	tfo_support = TFO_ENABLED == tfo_support;
-	if (((tfo_cfg_value & tfo_bit_num) == tfo_bit_num) != tfo_support) {
-		int value = (tfo_cfg_value & ~tfo_bit_num)
-			| (tfo_support << (tfo_bit_num - 1));
-		tst_resm(TINFO, "set '%s' to '%d'", tfo_cfg, value);
-		SAFE_FILE_PRINTF(cleanup, tfo_cfg, "%d", value);
-		tfo_cfg_changed = 1;
-	}
+	remote_addr_len = sizeof(struct sockaddr_storage);
 
-	int reuse_value = 0;
-	SAFE_FILE_SCANF(cleanup, tcp_tw_reuse, "%d", &reuse_value);
-	if (!reuse_value) {
-		SAFE_FILE_PRINTF(cleanup, tcp_tw_reuse, "1");
-		tw_reuse_changed = 1;
-		tst_resm(TINFO, "set '%s' to '1'", tcp_tw_reuse);
-	}
+	if (use_udp) {
+		tst_resm(TINFO, "using UDP");
+		fastopen_api = TFO_DISABLED;
+	} else {
+		tst_resm(TINFO, "TCP %s is using %s TCP API.",
+			(net_mode == SERVER_HOST) ? "server" : "client",
+			(fastopen_api == TFO_ENABLED) ? "Fastopen" : "old");
+
+		tfo_support = TFO_ENABLED == tfo_support;
+		if (((tfo_cfg_value & tfo_bit_num) == tfo_bit_num)
+		      != tfo_support) {
+			int value = (tfo_cfg_value & ~tfo_bit_num)
+				| (tfo_support << (tfo_bit_num - 1));
+			tst_resm(TINFO, "set '%s' to '%d'", tfo_cfg, value);
+			SAFE_FILE_PRINTF(cleanup, tfo_cfg, "%d", value);
+			tfo_cfg_changed = 1;
+		}
 
-	tst_resm(TINFO, "TFO support %s",
-		(tfo_support) ? "enabled" : "disabled");
+		int reuse_value = 0;
+		SAFE_FILE_SCANF(cleanup, tcp_tw_reuse, "%d", &reuse_value);
+		if (!reuse_value) {
+			SAFE_FILE_PRINTF(cleanup, tcp_tw_reuse, "1");
+			tw_reuse_changed = 1;
+			tst_resm(TINFO, "set '%s' to '1'", tcp_tw_reuse);
+		}
+
+		tst_resm(TINFO, "TFO support %s",
+			(tfo_support) ? "enabled" : "disabled");
+	}
 
-	tcp.init();
+	net.init();
 }
 
 int main(int argc, char *argv[])
 {
 	setup(argc, argv);
 
-	tcp.run();
+	net.run();
 
 	cleanup();
 
-- 
1.7.1



More information about the Ltp mailing list