[11/11] zdtm: add a test for nested network namespaces

Submitted by Andrei Vagin on Feb. 2, 2017, 12:04 a.m.

Details

Message ID 1485993871-3990-12-git-send-email-avagin@openvz.org
State New
Series "Dump and restore nested network namespaces"
Headers show

Commit Message

Andrei Vagin Feb. 2, 2017, 12:04 a.m.
From: Andrew Vagin <avagin@virtuozzo.com>

This tests create a few processes which live in three network namespaces
and have a few sockets which are created in different network namespaces.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 test/zdtm/static/Makefile       |   1 +
 test/zdtm/static/netns_sub.c    | 203 ++++++++++++++++++++++++++++++++++++++++
 test/zdtm/static/netns_sub.desc |   1 +
 3 files changed, 205 insertions(+)
 create mode 100644 test/zdtm/static/netns_sub.c
 create mode 100644 test/zdtm/static/netns_sub.desc

Patch hide | download patch | download mbox

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index c24ee8f..bb7a86d 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -172,6 +172,7 @@  TST_NOFILE	:=				\
 		macvlan			\
 		cr_veth				\
 		sock_peercred			\
+		netns_sub			\
 #		jobctl00			\
 
 ifneq ($(SRCARCH),arm)
diff --git a/test/zdtm/static/netns_sub.c b/test/zdtm/static/netns_sub.c
new file mode 100644
index 0000000..d36fdee
--- /dev/null
+++ b/test/zdtm/static/netns_sub.c
@@ -0,0 +1,203 @@ 
+#define _GNU_SOURCE
+#include <sched.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc	= "Check dump and restore a few network namespaces";
+
+static int fill_name(int nsid, struct sockaddr_un *name)
+{
+	int len;
+
+	name->sun_family = AF_LOCAL;
+	snprintf(name->sun_path, 108, "X/zdtm/static/netns_sub-%d", nsid);
+	len = SUN_LEN(name);
+	name->sun_path[0] = 0;
+
+	return len;
+}
+
+static int create_socket(int nsid)
+{
+	struct sockaddr_un name;
+	int len, sk;
+
+	len = fill_name(nsid, &name);
+
+	sk = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		pr_perror("socket");
+		return -1;
+	}
+
+	if (bind(sk, (struct sockaddr *) &name, len) < 0) {
+		pr_perror("bind");
+		close(sk);
+		return -1;
+	}
+
+	return sk;
+}
+
+static int check_socket(int nsid, bool success)
+{
+	struct sockaddr_un name;
+	int len, sk;
+
+	len = fill_name(nsid, &name);
+
+	sk = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		pr_perror("socket");
+		return -1;
+	}
+
+	if (connect(sk, (struct sockaddr *) &name, len) < 0) {
+		if (!success && errno == ECONNREFUSED)
+			return 0;
+		pr_perror("connect to %d", nsid);
+		close(sk);
+		return -1;
+	}
+	close(sk);
+
+	if (!success) {
+		pr_err("A sokcet is able to connect to %d\n", nsid);
+		return -1;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	task_waiter_t lock;
+	pid_t pid1, pid2, pid3, pid0 = getpid();
+	int status = -1, sk;
+
+	test_init(argc, argv);
+	task_waiter_init(&lock);
+
+	sk = create_socket(0);
+	if (sk < 0)
+		return 1;
+
+	pid1 = fork();
+	if (pid1 < 0) {
+		pr_perror("fork");
+		return -1;
+	}
+	if (pid1 == 0) {
+		close(sk);
+		unshare(CLONE_NEWNET);
+		sk = create_socket(1);
+		if (sk < 0)
+			return 1;
+
+		pid3 = fork();
+		if (pid3 < 0) {
+			pr_perror("fork");
+			return 1;
+		}
+		if (pid3 == 0) {
+			char ns[] = "/proc/0123456789/ns/net";
+			int fd;
+
+			snprintf(ns, sizeof(ns), "/proc/%d/ns/net", pid0);
+			fd = open(ns, O_RDONLY);
+			if (fd < 0)
+				return 1;
+
+			if (setns(fd, 0))
+				return 1;
+			close(fd);
+
+			task_waiter_complete(&lock, 3);
+			test_waitsig();
+
+			if (check_socket(0, true))
+				return 1;
+			if (check_socket(2, false))
+				return 1;
+			if (check_socket(1, false))
+				return 1;
+
+			return 0;
+		}
+		/* This socket will be alive in the 3 process */
+		close(sk);
+
+		task_waiter_complete(&lock, 1);
+		test_waitsig();
+
+		if (check_socket(1, true))
+			return 1;
+
+		kill(pid3, SIGTERM);
+		waitpid(pid3, &status, 0);
+		if (status) {
+			fail();
+			return 1;
+		}
+
+		return 0;
+	}
+	pid2 = fork();
+	if (pid2 < 0) {
+		pr_perror("fork");
+		return -1;
+	}
+	if (pid2 == 0) {
+		unshare(CLONE_NEWNET);
+		sk = create_socket(2);
+		if (sk < 0)
+			return 1;
+		task_waiter_complete(&lock, 2);
+
+		test_waitsig();
+
+		if (check_socket(0, false))
+			return 1;
+		if (check_socket(1, false))
+			return 1;
+		if (check_socket(2, true))
+			return 1;
+
+		return 0;
+	}
+	close(sk);
+	task_waiter_wait4(&lock, 1);
+	task_waiter_wait4(&lock, 2);
+	task_waiter_wait4(&lock, 3);
+
+	test_daemon();
+	test_waitsig();
+
+	kill(pid1, SIGTERM);
+	waitpid(pid1, &status, 0);
+	if (status) {
+		fail();
+		return 1;
+	}
+	kill(pid2, SIGTERM);
+	status = -1;
+	waitpid(pid2, &status, 0);
+	if (status) {
+		fail();
+		return 1;
+	}
+	pass();
+	return 0;
+}
diff --git a/test/zdtm/static/netns_sub.desc b/test/zdtm/static/netns_sub.desc
new file mode 100644
index 0000000..7657ba4
--- /dev/null
+++ b/test/zdtm/static/netns_sub.desc
@@ -0,0 +1 @@ 
+{'flavor': 'ns uns', 'flags': 'suid'}