[LTP] [PATCH 6/9] netstress: support SO_ZEROCOPY

Alexey Kodanev alexey.kodanev@oracle.com
Mon Jan 29 12:41:13 CET 2018


SO_ZEROCOPY is available since Linux 4.14:
commit 76851d1212c1 ("sock: add SOCK_ZEROCOPY sockopt").

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 include/lapi/socket.h                   |    8 +++++
 testcases/network/netstress/netstress.c |   46 +++++++++++++++++++++++-------
 2 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/include/lapi/socket.h b/include/lapi/socket.h
index a0217e1..426906f 100644
--- a/include/lapi/socket.h
+++ b/include/lapi/socket.h
@@ -21,6 +21,10 @@
 
 #include <sys/socket.h>
 
+#ifndef MSG_ZEROCOPY
+# define MSG_ZEROCOPY	0x4000000 /* Use user data in kernel path */
+#endif
+
 #ifndef MSG_FASTOPEN
 # define MSG_FASTOPEN	0x20000000 /* Send data in TCP SYN */
 #endif
@@ -29,6 +33,10 @@
 # define SO_BUSY_POLL	46
 #endif
 
+#ifndef SO_ZEROCOPY
+# define SO_ZEROCOPY	60
+#endif
+
 #ifndef SOCK_DCCP
 # define SOCK_DCCP		6
 #endif
diff --git a/testcases/network/netstress/netstress.c b/testcases/network/netstress/netstress.c
index 97de35c..d06cdae 100644
--- a/testcases/network/netstress/netstress.c
+++ b/testcases/network/netstress/netstress.c
@@ -139,6 +139,9 @@ struct sock_info {
 	int timeout;
 };
 
+static char *zcopy;
+static int send_flags = MSG_NOSIGNAL;
+
 static void init_socket_opts(int sd)
 {
 	if (busy_poll >= 0)
@@ -150,6 +153,8 @@ static void init_socket_opts(int sd)
 			SAFE_SETSOCKOPT_INT(sd, IPPROTO_TCP,
 					    TCP_FASTOPEN_CONNECT, 1);
 		}
+		if (client_mode && zcopy)
+			SAFE_SETSOCKOPT_INT(sd, SOL_SOCKET, SO_ZEROCOPY, 1);
 	break;
 	case TYPE_DCCP:
 		SAFE_SETSOCKOPT_INT(sd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
@@ -199,13 +204,25 @@ static int sock_recv_poll(char *buf, int size, struct sock_info *i)
 			break;
 		}
 
-		if (ret == 0) {
-			errno = ETIME;
+		if (ret != 1) {
+			if (!errno)
+				errno = ETIME;
 			break;
 		}
 
-		if (ret != 1 || !(pfd.revents & POLLIN))
+		if (!(pfd.revents & POLLIN)) {
+			if (pfd.revents & POLLERR) {
+				int err = 0;
+				socklen_t err_len = sizeof(err);
+
+				getsockopt(i->fd, SOL_SOCKET, SO_ERROR,
+					   &err, &err_len);
+				if (!err)
+					continue;
+				errno = err;
+			}
 			break;
+		}
 
 		errno = 0;
 		len = recvfrom(i->fd, buf, size, MSG_DONTWAIT,
@@ -270,7 +287,7 @@ static int client_connect_send(const char *msg, int size)
 
 	if (fastopen_api) {
 		/* Replaces connect() + send()/write() */
-		SAFE_SENDTO(1, cfd, msg, size, MSG_FASTOPEN | MSG_NOSIGNAL,
+		SAFE_SENDTO(1, cfd, msg, size, send_flags | MSG_FASTOPEN,
 			remote_addrinfo->ai_addr, remote_addrinfo->ai_addrlen);
 	} else {
 		if (local_addrinfo)
@@ -279,9 +296,8 @@ static int client_connect_send(const char *msg, int size)
 		/* old TCP API */
 		SAFE_CONNECT(cfd, remote_addrinfo->ai_addr,
 			     remote_addrinfo->ai_addrlen);
-		SAFE_SEND(1, cfd, msg, size, MSG_NOSIGNAL);
+		SAFE_SEND(1, cfd, msg, size, send_flags);
 	}
-
 	return cfd;
 }
 
@@ -358,7 +374,7 @@ send:
 		if (max_rand_msg_len)
 			make_client_request(client_msg, &cln_len, &srv_len);
 
-		SAFE_SEND(1, inf.fd, client_msg, cln_len, MSG_NOSIGNAL);
+		SAFE_SEND(1, inf.fd, client_msg, cln_len, send_flags);
 
 		if (client_recv(buf, srv_len, &inf)) {
 			err = errno;
@@ -559,20 +575,20 @@ void *server_fn(void *cfd)
 		switch (send_type) {
 		case 0:
 			SAFE_SEND(1, inf.fd, send_msg, send_msg_len,
-				  MSG_NOSIGNAL);
+				  send_flags);
 			if (proto_type != TYPE_SCTP)
 				++send_type;
 			break;
 		case 1:
 			SAFE_SENDTO(1, inf.fd, send_msg, send_msg_len,
-				    MSG_NOSIGNAL, (struct sockaddr *)&inf.raddr,
+				    send_flags, (struct sockaddr *)&inf.raddr,
 				    inf.raddr_len);
 			++send_type;
 			break;
 		default:
 			iov[0].iov_len = send_msg_len - 1;
 			msg.msg_namelen = inf.raddr_len;
-			SAFE_SENDMSG(send_msg_len, inf.fd, &msg, MSG_NOSIGNAL);
+			SAFE_SENDMSG(send_msg_len, inf.fd, &msg, send_flags);
 			send_type = start_send_type;
 			break;
 		}
@@ -636,8 +652,13 @@ static void server_init(void)
 			tfo_queue_size);
 	}
 
+	if (zcopy)
+		SAFE_SETSOCKOPT_INT(sfd, SOL_SOCKET, SO_ZEROCOPY, 1);
+
 	SAFE_LISTEN(sfd, max_queue_len);
+
 	tst_res(TINFO, "Listen on the socket '%d', port '%s'", sfd, tcp_port);
+
 }
 
 static void server_cleanup(void)
@@ -843,6 +864,8 @@ static void setup(void)
 		tst_res(TINFO, "TCP %s is using %s TCP API.",
 			(client_mode) ? "client" : "server",
 			(fastopen_api) ? "Fastopen" : "old");
+		if (zcopy)
+			send_flags |= MSG_ZEROCOPY;
 		check_tfo_value();
 	break;
 	case TYPE_UDP:
@@ -887,7 +910,8 @@ static struct tst_option options[] = {
 	{"S:", &source_addr, "-S x     Source address to bind"},
 	{"g:", &tcp_port, "-g x     x - server port"},
 	{"b:", &barg, "-b x     x - low latency busy poll timeout"},
-	{"T:", &type, "-T x     tcp (default), udp, dccp, sctp\n"},
+	{"T:", &type, "-T x     tcp (default), udp, dccp, sctp"},
+	{"z", &zcopy, "-z       enable SO_ZEROCOPY\n"},
 
 	{"H:", &server_addr, "Client:\n-H x     Server name or IP address"},
 	{"l", &client_mode, "-l       Become client, default is server"},
-- 
1.7.1



More information about the ltp mailing list