[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