[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