[Libct] [PATCH v2 1/6] VZ containers: Initial groundwork

Alexander Burluka aburluka at parallels.com
Wed Nov 12 04:52:15 PST 2014


Modified Makefile, make it recognize PCS server
Surrounded uncompilable parts with VZ macros
Added necessary files for further work
Added some already-implemented and easy functions to vz container_ops
---
 Makefile              |   15 +++
 src/Makefile          |    1 +
 src/ct.c              |   39 +++++++--
 src/include/ct.h      |   12 +++
 src/include/session.h |    1 +
 src/include/util.h    |    3 +
 src/include/vz.h      |   11 +++
 src/namespaces.c      |    4 +
 src/session.c         |   44 +++++++++-
 src/util.c            |   55 ++++++++++++
 src/vz.c              |  226 +++++++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 400 insertions(+), 11 deletions(-)
 create mode 100644 src/include/vz.h
 create mode 100644 src/vz.c

diff --git a/Makefile b/Makefile
index b8bbd80..61795b1 100644
--- a/Makefile
+++ b/Makefile
@@ -52,9 +52,17 @@ ifneq ($(ARCH),x86)
 $(error "The architecture $(ARCH) isn't supported"))
 endif
 
+ifneq ("$(wildcard /proc/vz)","")
+	VZ := 1
+endif
+
+
 cflags-y	+= -iquote src/include
 cflags-y	+= -fno-strict-aliasing
 cflags-y	+= -I/usr/include
+ifeq ($(VZ),1)
+	cflags-y += -I/usr/src/kernels/$(shell uname -r)/include/
+endif
 export cflags-y
 
 VERSION_MAJOR		:= 0
@@ -72,6 +80,9 @@ LIBS		:= -lrt
 
 DEFINES		+= -D_FILE_OFFSET_BITS=64
 DEFINES		+= -D_GNU_SOURCE
+ifeq ($(VZ),1)
+	DEFINES += -D_VZ
+endif
 
 WARNINGS	:= -Wall -Wno-unused-result
 
@@ -88,6 +99,10 @@ endif
 
 CFLAGS		+= $(WARNINGS) $(DEFINES)
 
+ifneq ("$(wildcard /proc/vz)","")
+	CFLAGS += -D VZ
+endif
+
 export E Q CC ECHO MAKE CFLAGS LIBS ARCH DEFINES MAKEFLAGS
 export SH RM OBJCOPY LDARCH LD CP MKDIR CD LN
 export ESED SED CAT
diff --git a/src/Makefile b/src/Makefile
index 050ef95..6ef8016 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -16,6 +16,7 @@ obj-y			+= util.o
 obj-y			+= devnodes.o
 obj-y			+= route.o
 obj-y			+= process.o
+obj-y			+= vz.o
 
 cflags-y		+= -fPIC -Wa,--noexecstack -fno-stack-protector
 cflags-so		+= -rdynamic
diff --git a/src/ct.c b/src/ct.c
index b3a13ff..284b51e 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -28,6 +28,7 @@
 #include "net.h"
 #include "ct.h"
 #include "fs.h"
+#include "vz.h"
 
 static enum ct_state local_get_state(ct_handler_t h)
 {
@@ -399,13 +400,6 @@ err_cg:
 	return ret;
 }
 
-struct execv_args {
-	char *path;
-	char **argv;
-	char **env;
-	int *fds;
-};
-
 static int ct_execv(void *a)
 {
 	struct execv_args *ea = a;
@@ -644,7 +638,7 @@ static int local_add_map(struct list_head *list, unsigned int first,
 	return 0;
 }
 
-static int local_add_uid_map(ct_handler_t h, unsigned int first,
+int local_add_uid_map(ct_handler_t h, unsigned int first,
 			unsigned int lower_first, unsigned int count)
 {
 	struct container *ct = cth2ct(h);
@@ -652,7 +646,7 @@ static int local_add_uid_map(ct_handler_t h, unsigned int first,
 	return local_add_map(&ct->uid_map, first, lower_first, count);
 }
 
-static int local_add_gid_map(ct_handler_t h, unsigned int first,
+int local_add_gid_map(ct_handler_t h, unsigned int first,
 			unsigned int lower_first, unsigned int count)
 {
 	struct container *ct = cth2ct(h);
@@ -714,3 +708,30 @@ ct_handler_t ct_create(char *name)
 
 	return NULL;
 }
+
+ct_handler_t vz_ct_create(char *name)
+{
+	struct container *ct;
+
+	ct = xzalloc(sizeof(*ct));
+	if (ct) {
+		ct_handler_init(&ct->h);
+		ct->h.ops = get_vz_ct_ops();
+		ct->state = CT_STOPPED;
+		ct->name = xstrdup(name);
+		ct->tty_fd = -1;
+		INIT_LIST_HEAD(&ct->cgroups);
+		INIT_LIST_HEAD(&ct->cg_configs);
+		INIT_LIST_HEAD(&ct->ct_nets);
+		INIT_LIST_HEAD(&ct->ct_net_routes);
+		INIT_LIST_HEAD(&ct->fs_mnts);
+		INIT_LIST_HEAD(&ct->fs_devnodes);
+		INIT_LIST_HEAD(&ct->uid_map);
+		INIT_LIST_HEAD(&ct->gid_map);
+
+		return &ct->h;
+	}
+
+	return NULL;
+
+}
diff --git a/src/include/ct.h b/src/include/ct.h
index ebce788..c3a760f 100644
--- a/src/include/ct.h
+++ b/src/include/ct.h
@@ -48,6 +48,7 @@ struct ct_handler {
 };
 
 ct_handler_t ct_create(char *name);
+ct_handler_t vz_ct_create(char *name);
 
 #define CT_AUTO_PROC		0x1
 #define CT_KILLABLE		0x2
@@ -117,6 +118,10 @@ static inline struct container *cth2ct(struct ct_handler *h)
 }
 
 extern char *local_ct_name(ct_handler_t h);
+extern int local_add_uid_map(ct_handler_t h, unsigned int first,
+			unsigned int lower_first, unsigned int count);
+extern int local_add_gid_map(ct_handler_t h, unsigned int first,
+			unsigned int lower_first, unsigned int count);
 
 static inline bool fs_private(struct container *ct)
 {
@@ -125,4 +130,11 @@ static inline bool fs_private(struct container *ct)
 
 extern void ct_handler_init(ct_handler_t h);
 
+struct execv_args {
+	char *path;
+	char **argv;
+	char **env;
+	int *fds;
+};
+
 #endif /* __LIBCT_CT_H__ */
diff --git a/src/include/session.h b/src/include/session.h
index 7a67e8d..45a7595 100644
--- a/src/include/session.h
+++ b/src/include/session.h
@@ -10,6 +10,7 @@ enum {
 	BACKEND_NONE,
 	BACKEND_LOCAL,
 	BACKEND_UNIX,
+	BACKEND_VZ,
 };
 
 struct backend_ops {
diff --git a/src/include/util.h b/src/include/util.h
index 8937a13..7227255 100644
--- a/src/include/util.h
+++ b/src/include/util.h
@@ -13,5 +13,8 @@
 
 extern int do_mount(char *src, char *dst, int flags, char *fstype, char *data);
 extern int set_string(char **dest, char *src);
+extern int parse_int(const char *str, int *val);
+extern int parse_uint(const char *str, unsigned int *val);
+extern int stat_file(const char *file);
 
 #endif /* __LIBCT_UTIL_H__ */
diff --git a/src/include/vz.h b/src/include/vz.h
new file mode 100644
index 0000000..f4c2f34
--- /dev/null
+++ b/src/include/vz.h
@@ -0,0 +1,11 @@
+#ifndef __LIBCT_VZ_H__
+#define __LIBCT_VZ_H__
+
+struct container_ops;
+
+const struct container_ops *get_vz_ct_ops(void);
+int vzctl_open(void);
+void vzctl_close(void);
+int get_vzctlfd(void);
+
+#endif
diff --git a/src/namespaces.c b/src/namespaces.c
index f3a1b74..035ad99 100644
--- a/src/namespaces.c
+++ b/src/namespaces.c
@@ -57,7 +57,9 @@ int switch_ns(int pid, struct ns_desc *nd, int *rst)
 			goto err_rst;
 	}
 
+#ifndef VZ
 	ret = setns(nsfd, nd->cflag);
+#endif
 	if (ret < 0)
 		goto err_set;
 
@@ -75,6 +77,8 @@ err_ns:
 
 void restore_ns(int rst, struct ns_desc *nd)
 {
+#ifndef VZ
 	setns(rst, nd->cflag);
+#endif
 	close(rst);
 }
diff --git a/src/session.c b/src/session.c
index 6e32a4d..26af8cc 100644
--- a/src/session.c
+++ b/src/session.c
@@ -8,6 +8,7 @@
 #include "libct.h"
 #include "async.h"
 #include "ct.h"
+#include "vz.h"
 
 static void close_local_session(libct_session_t s)
 {
@@ -22,8 +23,8 @@ static ct_handler_t create_local_ct(libct_session_t s, char *name)
 	ct = ct_create(name);
 	if (!ct)
 		return libct_err_to_handle(-1);
-	else
-		return ct;
+
+	return ct;
 }
 
 static ct_process_desc_t local_process_create_desc(libct_session_t s)
@@ -62,6 +63,41 @@ static const struct backend_ops local_session_ops = {
 	.update_ct_state = update_local_ct_state,
 };
 
+
+static void close_vz_session(libct_session_t s)
+{
+	struct local_session *l = s2ls(s);
+	xfree(l);
+	vzctl_close();
+}
+
+static ct_handler_t create_vz_ct(libct_session_t s, char *name)
+{
+	ct_handler_t ct = NULL;
+	if (vzctl_open() == -1)
+		return libct_err_to_handle(-1);
+
+	ct = vz_ct_create(name);
+	if (!ct)
+		return libct_err_to_handle(-1);
+
+	return ct;
+}
+
+static void update_vz_ct_state(libct_session_t s, pid_t pid)
+{
+	/* TODO: implement afterwards */
+}
+
+
+static const struct backend_ops vz_session_ops = {
+	.type = BACKEND_VZ,
+	.create_ct = create_vz_ct,
+	.create_process_desc = local_process_create_desc,
+	.close = close_vz_session,
+	.update_ct_state = update_vz_ct_state,
+};
+
 libct_session_t libct_session_open_local(void)
 {
 	struct local_session *s;
@@ -73,7 +109,11 @@ libct_session_t libct_session_open_local(void)
 	if (s) {
 		INIT_LIST_HEAD(&s->s.s_cts);
 		INIT_LIST_HEAD(&s->s.async_list);
+#ifndef VZ
 		s->s.ops = &local_session_ops;
+#else
+		s->s.ops = &vz_session_ops;
+#endif
 		return &s->s;
 	}
 
diff --git a/src/util.c b/src/util.c
index 62dfbaf..d303815 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,6 +6,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
+#include <sys/param.h>
 
 #include "uapi/libct.h"
 #include "xmalloc.h"
@@ -113,3 +116,55 @@ int set_string(char **dest, char *src)
 	return 0;
 }
 
+int parse_uint(const char *str, unsigned int *val)
+{
+	char *tail;
+	long int n;
+
+	if (*str == '\0')
+		return -1;
+
+	errno = 0;
+	n = strtoul(str, &tail, 10);
+	if (*tail != '\0' || n >= UINT_MAX)
+		return -1;
+	*val = (unsigned int)n;
+
+	return 0;
+}
+
+int parse_int(const char *str, int *val)
+{
+	char *tail;
+	long int n;
+
+	if (*str == '\0')
+		return -1;
+
+	errno = 0;
+	n = strtol(str, &tail, 10);
+	if (*tail != '\0' || errno == ERANGE || n > INT_MAX)
+		return -1;
+	*val = (int)n;
+
+	return 0;
+}
+
+/*
+	1 - exist
+	0 - doesn't exist
+	-1 - error
+*/
+int stat_file(const char *file)
+{
+	struct stat st;
+
+	if (stat(file, &st)) {
+		if (errno != ENOENT) {
+			pr_perror("unable to stat %s", file);
+			return -1;
+		}
+		return 0;
+	}
+	return 1;
+}
diff --git a/src/vz.c b/src/vz.c
new file mode 100644
index 0000000..8b56a73
--- /dev/null
+++ b/src/vz.c
@@ -0,0 +1,226 @@
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <linux/vzcalluser.h>
+#include <linux/vzlist.h>
+#include <linux/vziolimit.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/personality.h>
+#include <linux/vzcalluser.h>
+#include <linux/vziolimit.h>
+#include <grp.h>
+#include <limits.h>
+#include <sched.h>
+
+#include "linux-kernel.h"
+#include "vz.h"
+#include "ct.h"
+#include "xmalloc.h"
+#include "fs.h"
+#include "cgroups.h"
+#include "net.h"
+#include "util.h"
+
+#define VZCTLDEV			"/dev/vzctl"
+
+static int __vzctlfd = -1;
+
+void vzctl_close(void)
+{
+	if (__vzctlfd != -1)
+		close(__vzctlfd);
+}
+
+int vzctl_open(void)
+{
+	if (__vzctlfd != -1)
+		return 0;
+
+	__vzctlfd = open(VZCTLDEV, O_RDWR);
+	if (__vzctlfd == -1) {
+		pr_perror("Unable to open " VZCTLDEV);
+		return -1;
+	}
+
+	return 0;
+}
+
+int get_vzctlfd(void)
+{
+	if (__vzctlfd == -1)
+		vzctl_open();
+
+	return __vzctlfd;
+}
+
+static void vz_ct_destroy(ct_handler_t h)
+{
+	struct container *ct = cth2ct(h);
+
+	fs_free(ct);
+
+	xfree(ct->name);
+	xfree(ct->hostname);
+	xfree(ct->domainname);
+	xfree(ct->cgroup_sub);
+	xfree(ct);
+}
+
+static int vz_spawn_cb(ct_handler_t h, ct_process_desc_t p, int (*cb)(void *), void *arg)
+{
+	pr_err("Spawn with callback is not supported");
+	return -1;
+}
+
+static int vz_set_option(ct_handler_t h, int opt, void *args)
+{
+	int ret = -LCTERR_BADTYPE;
+	struct container *ct = cth2ct(h);
+
+	switch (opt) {
+	case LIBCT_OPT_AUTO_PROC_MOUNT:
+		ret = 0;
+		ct->flags |= CT_AUTO_PROC;
+		break;
+	case LIBCT_OPT_CGROUP_SUBMOUNT:
+		pr_warn("LIBCT_OPT_CGROUP_SUBMOUNT is currently unsupported");
+		ret = -1;
+		break;
+	case LIBCT_OPT_KILLABLE:
+		pr_warn("LIBCT_OPT_KILLABLE option is always set for VZ containers");
+		ret = -1;
+		break;
+	case LIBCT_OPT_NOSETSID:
+		pr_warn("LIBCT_OPT_NOSETSID option is always set for VZ containers");
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int vz_uname(ct_handler_t h, char *host, char *dom)
+{
+	struct container *ct = NULL;
+
+	if (!h)
+		return -LCTERR_BADARG;
+
+	ct = cth2ct(h);
+	if (!(ct->nsmask & CLONE_NEWUTS))
+		return -LCTERR_NONS;
+	if (ct->state != CT_STOPPED)
+		return -LCTERR_BADCTSTATE; /* FIXME */
+
+	if (host) {
+		host = xstrdup(host);
+		if (!host)
+			return -1;
+	}
+	xfree(ct->hostname);
+	ct->hostname = host;
+
+	if (dom) {
+		dom = xstrdup(dom);
+		if (!dom)
+			return -1;
+	}
+	xfree(ct->domainname);
+	ct->domainname = dom;
+
+	return 0;
+}
+
+static enum ct_state vz_get_state(ct_handler_t h)
+{
+	if (!h)
+		return CT_ERROR;
+	return cth2ct(h)->state;
+}
+
+static int vz_set_console_fd(ct_handler_t h, int fd)
+{
+	struct container *ct = NULL;
+	if (!h || fd == -1)
+		return -LCTERR_BADARG;
+	ct = cth2ct(h);
+	ct->tty_fd = fd;
+	return 0;
+}
+
+static int vz_set_nsmask(ct_handler_t h, unsigned long nsmask)
+{
+	struct container *ct = NULL;
+	if (!h)
+		return -LCTERR_BADARG;
+	ct = cth2ct(h);
+	if (ct->state != CT_STOPPED)
+		return -LCTERR_BADCTSTATE;
+	/* Are all of these bits supported by kernel? */
+	if (nsmask & ~kernel_ns_mask)
+		return -LCTERR_NONS;
+
+	if (!(nsmask & CLONE_NEWIPC &&
+	      nsmask & CLONE_NEWNET &&
+	      nsmask & CLONE_NEWNS &&
+	      nsmask & CLONE_NEWPID &&
+	      nsmask & CLONE_NEWUTS)) {
+		pr_err("Only full nsmask is supported in VZ containers");
+		return -LCTERR_NONS;
+	}
+	ct->nsmask = nsmask;
+	return 0;
+}
+
+static int vz_config_controller(ct_handler_t h, enum ct_controller ctype,
+		char *param, char *value)
+{
+	pr_perror("Controller configuration are not supported");
+	return -LCTERR_CGCONFIG;
+}
+
+static const struct container_ops vz_ct_ops = {
+	.spawn_cb		= vz_spawn_cb,
+	.spawn_execve		= NULL,
+	.enter_cb		= NULL,
+	.enter_execve		= NULL,
+	.kill			= NULL,
+	.wait			= NULL,
+	.destroy		= vz_ct_destroy,
+	.detach			= vz_ct_destroy,
+	.set_nsmask		= vz_set_nsmask,
+	.add_controller		= local_add_controller,
+	.config_controller	= vz_config_controller,
+	.fs_set_root		= local_fs_set_root,
+	.fs_set_private		= local_fs_set_private,
+	.fs_add_mount		= local_add_mount,
+	.fs_add_bind_mount	= local_add_bind_mount,
+	.fs_del_bind_mount	= local_del_bind_mount,
+	.fs_add_devnode		= NULL,
+	.get_state		= vz_get_state,
+	.set_option		= vz_set_option,
+	.set_console_fd		= vz_set_console_fd,
+	.net_add		= local_net_add,
+	.net_del		= local_net_del,
+	.net_route_add		= local_net_route_add,
+	.uname			= vz_uname,
+	.add_uid_map		= local_add_uid_map,
+	.add_gid_map		= local_add_gid_map,
+};
+
+const struct container_ops *get_vz_ct_ops(void)
+{
+	return &vz_ct_ops;
+}
-- 
1.7.1



More information about the Libct mailing list