[CRIU] [PATCH 1/2] zdtm: check a case when one port is shared between two sockets

Andrei Vagin avagin at virtuozzo.com
Sat Nov 4 04:21:59 MSK 2017


Applied

On Tue, Oct 31, 2017 at 08:53:42AM +0300, Andrei Vagin wrote:
> From: Andrei Vagin <avagin at virtuozzo.com>
> 
> SO_REUSEPORT allows multiple sockets on the same host to bind to the
> same port.
> 
> Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
> ---
>  test/zdtm/lib/tcp.c                        |  21 +++-
>  test/zdtm/lib/zdtmtst.h                    |   9 ++
>  test/zdtm/static/Makefile                  |   1 +
>  test/zdtm/static/socket-tcp-reuseport.c    | 171 +++++++++++++++++++++++++++++
>  test/zdtm/static/socket-tcp-reuseport.desc |   1 +
>  5 files changed, 201 insertions(+), 2 deletions(-)
>  create mode 100644 test/zdtm/static/socket-tcp-reuseport.c
>  create mode 100644 test/zdtm/static/socket-tcp-reuseport.desc
> 
> diff --git a/test/zdtm/lib/tcp.c b/test/zdtm/lib/tcp.c
> index 4fb190266..e753e3c8a 100644
> --- a/test/zdtm/lib/tcp.c
> +++ b/test/zdtm/lib/tcp.c
> @@ -11,6 +11,16 @@ union sockaddr_inet {
>  
>  int tcp_init_server(int family, int *port)
>  {
> +	struct zdtm_tcp_opts opts = {
> +		.reuseaddr = true,
> +		.reuseport = false,
> +	};
> +
> +	return tcp_init_server_with_opts(family, port, &opts);
> +}
> +
> +int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts)
> +{
>  	union sockaddr_inet addr;
>  	int sock;
>  	int yes = 1, ret;
> @@ -25,13 +35,20 @@ int tcp_init_server(int family, int *port)
>  	} else
>  		return -1;
>  
> -	sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
> +	sock = socket(family, SOCK_STREAM | opts->flags, IPPROTO_TCP);
>  	if (sock == -1) {
>  		pr_perror("socket() failed");
>  		return -1;
>  	}
>  
> -	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) {
> +	if (opts->reuseport &&
> +	    setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(int)) == -1) {
> +		pr_perror("");
> +		return -1;
> +	}
> +
> +	if (opts->reuseaddr &&
> +	    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) {
>  		pr_perror("setsockopt() error");
>  		return -1;
>  	}
> diff --git a/test/zdtm/lib/zdtmtst.h b/test/zdtm/lib/zdtmtst.h
> index de01cc2be..cd513b9c9 100644
> --- a/test/zdtm/lib/zdtmtst.h
> +++ b/test/zdtm/lib/zdtmtst.h
> @@ -3,6 +3,7 @@
>  
>  #include <sys/types.h>
>  #include <unistd.h>
> +#include <stdbool.h>
>  
>  #define INPROGRESS ".inprogress"
>  
> @@ -141,4 +142,12 @@ extern int tcp_init_server(int family, int *port);
>  extern int tcp_accept_server(int sock);
>  extern int tcp_init_client(int family, char *servIP, unsigned short servPort);
>  
> +struct zdtm_tcp_opts {
> +	bool reuseaddr;
> +	bool reuseport;
> +	int flags;
> +};
> +
> +extern int tcp_init_server_with_opts(int family, int *port, struct zdtm_tcp_opts *opts);
> +
>  #endif /* _VIMITESU_H_ */
> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
> index 9d0cb24aa..9789d624d 100644
> --- a/test/zdtm/static/Makefile
> +++ b/test/zdtm/static/Makefile
> @@ -66,6 +66,7 @@ TST_NOFILE	:=				\
>  		socket-tcp-reseted		\
>  		socket-tcp6			\
>  		socket-tcp-local		\
> +		socket-tcp-reuseport		\
>  		socket-tcp-nfconntrack		\
>  		socket-tcp6-local		\
>  		socket-tcpbuf			\
> diff --git a/test/zdtm/static/socket-tcp-reuseport.c b/test/zdtm/static/socket-tcp-reuseport.c
> new file mode 100644
> index 000000000..4cd1802f9
> --- /dev/null
> +++ b/test/zdtm/static/socket-tcp-reuseport.c
> @@ -0,0 +1,171 @@
> +#include "zdtmtst.h"
> +
> +#ifdef ZDTM_IPV6
> +#define ZDTM_FAMILY AF_INET6
> +#else
> +#define ZDTM_FAMILY AF_INET
> +#endif
> +
> +const char *test_doc = "Check a case when one port is shared between two listening sockets\n";
> +const char *test_author = "Andrey Vagin <avagin at parallels.com";
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <sched.h>
> +#include <netinet/tcp.h>
> +#include <sys/socket.h>
> +#include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
> +
> +#define BUF_SIZE 4096
> +
> +int read_data(int fd, unsigned char *buf, int size)
> +{
> +	int cur = 0;
> +	int ret;
> +	while (cur != size) {
> +		ret = read(fd, buf + cur, size - cur);
> +		if (ret <= 0)
> +			return -1;
> +		cur += ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int write_data(int fd, const unsigned char *buf, int size)
> +{
> +	int cur = 0;
> +	int ret;
> +
> +	while (cur != size) {
> +		ret = write(fd, buf + cur, size - cur);
> +		if (ret <= 0)
> +			return -1;
> +		cur += ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	struct zdtm_tcp_opts opts = { .reuseaddr = false,
> +					.reuseport = true,
> +					.flags = SOCK_NONBLOCK};
> +	unsigned char buf[BUF_SIZE];
> +	int port = 8880, port2;
> +	int fd, fd_s, fd_s2, clt, i;
> +	socklen_t optlen;
> +	int no = 0, val;
> +	uint32_t crc;
> +
> +	test_init(argc, argv);
> +
> +	if ((fd_s = tcp_init_server_with_opts(ZDTM_FAMILY, &port, &opts)) < 0) {
> +		pr_err("initializing server failed\n");
> +		return 1;
> +	}
> +
> +	port2 = port;
> +	if ((fd_s2 = tcp_init_server_with_opts(ZDTM_FAMILY, &port2, &opts)) < 0) {
> +		pr_err("initializing server failed\n");
> +		return 1;
> +	}
> +	if (port != port2)
> +		return 1;
> +
> +	if (setsockopt(fd_s, SOL_SOCKET, SO_REUSEPORT, &no, sizeof(int)) == -1 ) {
> +		pr_perror("Unable to set SO_REUSEPORT");
> +		return -1;
> +	}
> +
> +
> +	clt = tcp_init_client(ZDTM_FAMILY, "localhost", port);
> +	if (clt < 0)
> +		return 1;
> +
> +	/*
> +	 * parent is server of TCP connection
> +	 */
> +	fd = tcp_accept_server(fd_s);
> +	if (fd < 0)
> +		fd = tcp_accept_server(fd_s2);
> +	if (fd < 0) {
> +		pr_err("can't accept client connection\n");
> +		return 1;
> +	}
> +
> +	test_daemon();
> +	test_waitsig();
> +
> +
> +	optlen = sizeof(val);
> +	if (getsockopt(fd_s, SOL_SOCKET, SO_REUSEPORT, &val, &optlen)) {
> +		pr_perror("getsockopt");
> +		return 1;
> +	}
> +	if (val == 1) {
> +		fail("SO_REUSEPORT is set for %d\n", fd);
> +		return 1;
> +	}
> +	optlen = sizeof(val);
> +	if (getsockopt(fd_s2, SOL_SOCKET, SO_REUSEPORT, &val, &optlen)) {
> +		pr_perror("getsockopt");
> +		return 1;
> +	}
> +	if (val != 1) {
> +		fail("SO_REUSEPORT is not set for %d\n", fd);
> +		return 1;
> +	}
> +
> +	for (i = 0; ; i++) {
> +		crc = 0;
> +		datagen(buf, BUF_SIZE, &crc);
> +		if (write_data(fd, buf, BUF_SIZE)) {
> +			pr_perror("can't write");
> +			return 1;
> +		}
> +
> +		memset(buf, 0, BUF_SIZE);
> +		if (read_data(clt, buf, BUF_SIZE)) {
> +			pr_perror("read less then have to");
> +			return 1;
> +		}
> +		crc = 0;
> +		if (datachk(buf, BUF_SIZE, &crc))
> +			return 2;
> +
> +		close(clt);
> +		close(fd);
> +
> +		if (i == 2)
> +			break;
> +
> +		clt = tcp_init_client(ZDTM_FAMILY, "localhost", port);
> +		if (clt < 0)
> +			return 1;
> +
> +		/*
> +		 * parent is server of TCP connection
> +		 */
> +		fd = tcp_accept_server(fd_s2);
> +		if (fd < 0) {
> +			fd = tcp_accept_server(fd_s);
> +			close(fd_s);
> +		} else {
> +			close(fd_s2);
> +		}
> +		if (fd < 0) {
> +			pr_err("can't accept client connection %d\n", i);
> +			return 1;
> +		}
> +	}
> +
> +	pass();
> +	return 0;
> +}
> diff --git a/test/zdtm/static/socket-tcp-reuseport.desc b/test/zdtm/static/socket-tcp-reuseport.desc
> new file mode 100644
> index 000000000..6a406f6ec
> --- /dev/null
> +++ b/test/zdtm/static/socket-tcp-reuseport.desc
> @@ -0,0 +1 @@
> +{'flavor': 'h ns uns', 'opts': '--tcp-established', 'flags': 'nouser samens'}
> -- 
> 2.13.6
> 


More information about the CRIU mailing list