This patch introduces helper tools for creating and working
with namespaces (ltp/testcases/kernel/containers/share):

* ns_create:
    Creates a child process in the new specified namespace(s),
    child is then daemonized and is running in the background.
    PID of the daemonized child process is printed on the stdout.
    As the new namespace(s) is(are) maintained by the daemonized
    child process it(they) can be removed by killing this process.
* ns_exec:
    Enters the namespace(s) of a process specified by a PID and
    then executes the indicated program inside that namespace(s).
* ns_ifmove:
    Moves a network interface to the namespace of a process
    specified by a PID.

Example usage:
==============
$ myns=$(ns_create net,ipc)

$ ip link add veth0 type veth peer name veth1
$ ns_exec $myns ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

$ ns_ifmove veth1 $myns
$ ns_exec $myns ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth1: <BROADCAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 6a:0a:45:ed:6e:d0 brd ff:ff:ff:ff:ff:ff

$ ip link del veth0
$ kill -9 $myns
==============

The only requirement from kernel side is the support of "setns"
syscall. There is no need to have util-linux (unshare, nsenter)
installed. This way test cases utilizing namespaces can be
executed even on older kernels which do not provide required
tools for working with namespaces.

Signed-off-by: Matus Marhefka <mmarh...@redhat.com>
---
 testcases/kernel/containers/share/.gitignore  |   3 +
 testcases/kernel/containers/share/Makefile    |  22 ++++
 testcases/kernel/containers/share/ns_create.c | 100 ++++++++++++++++
 testcases/kernel/containers/share/ns_exec.c   | 157 ++++++++++++++++++++++++++
 testcases/kernel/containers/share/ns_ifmove.c | 123 ++++++++++++++++++++
 testcases/kernel/containers/share/ns_utils.h  |  42 +++++++
 6 files changed, 447 insertions(+)
 create mode 100644 testcases/kernel/containers/share/.gitignore
 create mode 100644 testcases/kernel/containers/share/Makefile
 create mode 100644 testcases/kernel/containers/share/ns_create.c
 create mode 100644 testcases/kernel/containers/share/ns_exec.c
 create mode 100644 testcases/kernel/containers/share/ns_ifmove.c
 create mode 100644 testcases/kernel/containers/share/ns_utils.h

diff --git a/testcases/kernel/containers/share/.gitignore 
b/testcases/kernel/containers/share/.gitignore
new file mode 100644
index 0000000..0d5ecf0
--- /dev/null
+++ b/testcases/kernel/containers/share/.gitignore
@@ -0,0 +1,3 @@
+/ns_ifmove
+/ns_create
+/ns_exec
diff --git a/testcases/kernel/containers/share/Makefile 
b/testcases/kernel/containers/share/Makefile
new file mode 100644
index 0000000..962d688
--- /dev/null
+++ b/testcases/kernel/containers/share/Makefile
@@ -0,0 +1,22 @@
+# Copyright (c) 2015 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of version 2 the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# 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, see <http://www.gnu.org/licenses/>.
+##############################################################################
+top_srcdir              ?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(abs_srcdir)/../Makefile.inc
+
+LDLIBS                  := -lltp
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/containers/share/ns_create.c 
b/testcases/kernel/containers/share/ns_create.c
new file mode 100644
index 0000000..8e18fab
--- /dev/null
+++ b/testcases/kernel/containers/share/ns_create.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Matus Marhefka <mmarh...@redhat.com>
+ *
+ ***********************************************************************
+ * File: ns_create.c
+ *
+ * Creates a child process in the new specified namespace(s), child is then
+ * daemonized and is running in the background. PID of the daemonized child
+ * process is printed on the stdout. As the new namespace(s) is(are) maintained
+ * by the daemonized child process it(they) can be removed by killing this
+ * process.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "test.h"
+#include "ns_utils.h"
+
+char *TCID = "ns_create";
+
+
+static int child_fn(void *arg)
+{
+       int i;
+
+       if (chdir("/") == -1) {
+               tst_resm(TINFO | TERRNO, "chdir");
+               exit(1);
+       }
+
+       /* close all inherrited file descriptors */
+       for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
+               close(i);
+
+       pause();
+       return 0;
+}
+
+/*
+ * ./ns_create <comma separated namespaces list>
+ * where full list is: ipc,mnt,net,pid,user,uts.
+ */
+int main(int argc, char *argv[])
+{
+       int pid, flags;
+
+       if (argc != 2) {
+               tst_resm(TINFO, "%s  <comma separated namespaces list> "
+                               "(full list: ipc,mnt,net,pid,user,uts "
+                               "-- do not use whitespaces in list)", argv[0]);
+               return 1;
+       }
+
+       flags = 0;
+       if (strstr(argv[1], "ipc") != NULL)
+               flags |= CLONE_NEWIPC;
+       if (strstr(argv[1], "mnt") != NULL)
+               flags |= CLONE_NEWNS;
+       if (strstr(argv[1], "net") != NULL)
+               flags |= CLONE_NEWNET;
+       if (strstr(argv[1], "pid") != NULL)
+               flags |= CLONE_NEWPID;
+       if (strstr(argv[1], "user") != NULL)
+               flags |= CLONE_NEWUSER;
+       if (strstr(argv[1], "uts") != NULL)
+               flags |= CLONE_NEWUTS;
+       if (flags == 0) {
+               tst_resm(TINFO, "unknown namespace: %s", argv[1]);
+               return 1;
+       }
+
+       pid = ltp_clone_quick(flags | SIGCHLD, (void *)child_fn, NULL);
+       if (pid == -1) {
+               tst_resm(TINFO | TERRNO, "ltp_clone_quick");
+               return 1;
+       }
+
+       printf("%d", pid);
+       return 0;
+}
diff --git a/testcases/kernel/containers/share/ns_exec.c 
b/testcases/kernel/containers/share/ns_exec.c
new file mode 100644
index 0000000..8c350d3
--- /dev/null
+++ b/testcases/kernel/containers/share/ns_exec.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Matus Marhefka <mmarh...@redhat.com>
+ *
+ ***********************************************************************
+ * File: ns_exec.c
+ *
+ * Enters the namespace(s) of a process specified by a PID and then executes
+ * the indicated program inside that namespace(s).
+ *
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "test.h"
+#include "linux_syscall_numbers.h"
+#include "ns_utils.h"
+
+#define PROC_PATH "/proc"
+#define NS_TOTAL 6
+
+char *TCID = "ns_exec";
+int ns_fd[NS_TOTAL];
+int ns_fd_index;
+
+struct argst {
+       char **argv;
+       int argc;
+};
+
+
+static int open_ns_fd(const char *pid, const char *ns)
+{
+       int fd;
+       char file_buf[30];
+
+       sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns);
+
+       fd = open(file_buf, O_RDONLY);
+       if (fd > 0) {
+               ns_fd[ns_fd_index] = fd;
+               ++ns_fd_index;
+       } else if (fd == -1 && errno != ENOENT) {
+               tst_resm(TINFO | TERRNO, "open");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void close_ns_fd(void)
+{
+       int i;
+
+       for (i = 0; i < ns_fd_index; i++)
+               close(ns_fd[i]);
+}
+
+static int child_fn(void *arg)
+{
+       struct argst *args = arg;
+       int i;
+
+       for (i = 1; i < args->argc-1; i++)
+               args->argv[i] = args->argv[i+1];
+       args->argv[i] = NULL;
+
+       execvp(args->argv[1], args->argv+1);
+       tst_resm(TINFO | TERRNO, "execvp");
+       return 1;
+}
+
+/*
+ * ./ns_exec <NS_PID> <PROGRAM> [ARGS]
+ */
+int main(int argc, char *argv[])
+{
+       int i, rv, pid;
+       struct argst args;
+
+       rv = syscall(__NR_setns, -1, 0);
+       if (rv == -1 && errno == ENOSYS) {
+               tst_resm(TINFO, "setns is not supported in the kernel");
+               return 1;
+       }
+
+       if (argc < 3) {
+               tst_resm(TINFO, "%s <NS_PID> <PROGRAM> [ARGS]\n", argv[0]);
+               return 1;
+       }
+
+       rv = 0;
+       memset(ns_fd, 0, sizeof(ns_fd));
+       rv |= open_ns_fd(argv[1], "ipc");
+       rv |= open_ns_fd(argv[1], "mnt");
+       rv |= open_ns_fd(argv[1], "net");
+       rv |= open_ns_fd(argv[1], "pid");
+       rv |= open_ns_fd(argv[1], "user");
+       rv |= open_ns_fd(argv[1], "uts");
+       if (rv != 0)
+               return 1;
+
+       if (ns_fd_index == 0) {
+               tst_resm(TINFO, "no namespace entries in /proc/%s/ns/",
+                        argv[1]);
+               close_ns_fd();
+               return 1;
+       }
+
+       for (i = 0; i < ns_fd_index; i++) {
+               if (syscall(__NR_setns, ns_fd[i], 0) == -1) {
+                       tst_resm(TINFO | TERRNO, "setns");
+                       close_ns_fd();
+                       return 1;
+               }
+       }
+
+       args.argv = argv;
+       args.argc = argc;
+       pid = ltp_clone_quick(SIGCHLD, (void *)child_fn, (void *)&args);
+       if (pid == -1) {
+               tst_resm(TINFO | TERRNO, "ltp_clone_quick");
+               close_ns_fd();
+               return 1;
+       }
+
+       if (waitpid(pid, &rv, 0) == -1) {
+               tst_resm(TINFO | TERRNO, "waitpid");
+               return 1;
+       }
+
+       close_ns_fd();
+
+       if (WIFEXITED(rv))
+               return WEXITSTATUS(rv);
+
+       return 0;
+}
diff --git a/testcases/kernel/containers/share/ns_ifmove.c 
b/testcases/kernel/containers/share/ns_ifmove.c
new file mode 100644
index 0000000..728863b
--- /dev/null
+++ b/testcases/kernel/containers/share/ns_ifmove.c
@@ -0,0 +1,123 @@
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Matus Marhefka <mmarh...@redhat.com>
+ *
+ ***********************************************************************
+ * File: ns_ifmove.c
+ *
+ * Moves a network interface to the namespace of a process specified by a PID.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <net/ethernet.h>
+#include <arpa/inet.h>
+#include "test.h"
+
+char *TCID = "ns_linkset";
+
+struct {
+       struct nlmsghdr nh;
+       struct ifinfomsg ifi;
+       char attrbuf[512];
+} req;
+
+
+int get_intf_index_from_name(const char *intf_name)
+{
+       struct ifreq ifr;
+       int sock_fd;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, intf_name, sizeof(ifr.ifr_name) - 1);
+       ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
+
+       sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (sock_fd == -1) {
+               tst_resm(TINFO | TERRNO, "socket");
+               return -1;
+       }
+
+       /* gets interface index */
+       if (ioctl(sock_fd, SIOCGIFINDEX, &ifr) == -1) {
+               close(sock_fd);
+               tst_resm(TINFO | TERRNO, "ioctl");
+               return -1;
+       }
+
+       close(sock_fd);
+       return ifr.ifr_ifindex;
+}
+
+/*
+ * ./ns_ifmove <INTERFACE_NAME> <NAMESPACE_PID>
+ */
+int main(int argc, char **argv)
+{
+       struct rtattr *rta;
+       int intf_index, pid, rtnetlink_socket;
+
+       if (argc != 3) {
+               tst_resm(TINFO, "%s <INTERFACE_NAME> <NAMESPACE_PID>\n",
+                        argv[0]);
+               return 1;
+       }
+
+       intf_index = get_intf_index_from_name(argv[1]);
+       if (intf_index == -1) {
+               tst_resm(TINFO , "unable to get interface index");
+               return 1;
+       }
+
+       pid = atoi(argv[2]);
+
+       rtnetlink_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (rtnetlink_socket == -1) {
+               tst_resm(TINFO | TERRNO, "socket");
+               return 1;
+       }
+
+       memset(&req, 0, sizeof(req));
+       req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.nh.nlmsg_flags = NLM_F_REQUEST;
+       req.nh.nlmsg_type = RTM_NEWLINK;
+       req.ifi.ifi_family = AF_UNSPEC;
+       req.ifi.ifi_index = intf_index;
+       req.ifi.ifi_change = 0xffffffff;
+       rta = (struct rtattr *)(((char *) &req) +
+               NLMSG_ALIGN(req.nh.nlmsg_len));
+       rta->rta_type = IFLA_NET_NS_PID;
+       rta->rta_len = RTA_LENGTH(sizeof(int));
+       req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) +
+               RTA_LENGTH(sizeof(pid));
+       memcpy(RTA_DATA(rta), &pid, sizeof(pid));
+
+       if (send(rtnetlink_socket, &req, req.nh.nlmsg_len, 0) == -1) {
+               tst_resm(TINFO | TERRNO, "send");
+               return 1;
+       }
+
+       close(rtnetlink_socket);
+       return 0;
+}
diff --git a/testcases/kernel/containers/share/ns_utils.h 
b/testcases/kernel/containers/share/ns_utils.h
new file mode 100644
index 0000000..fe11a6b
--- /dev/null
+++ b/testcases/kernel/containers/share/ns_utils.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ ***********************************************************************
+ * File: ns_utils.h
+ *
+ */
+
+#ifndef NS_UTILS_H
+#define NS_UTILS_H
+
+#ifndef CLONE_NEWIPC
+#  define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS  0x00020000
+#endif
+#ifndef CLONE_NEWNET
+#  define CLONE_NEWNET 0x40000000
+#endif
+#ifndef CLONE_NEWPID
+#  define CLONE_NEWPID 0x20000000
+#endif
+#ifndef CLONE_NEWUSER
+#  define CLONE_NEWUSER        0x10000000
+#endif
+#ifndef CLONE_NEWUTS
+#  define CLONE_NEWUTS 0x04000000
+#endif
+
+
+#endif
-- 
1.8.3.1


------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that
you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to