From 0ad19a3fc3de5592e2453070a818a5a41687900e Mon Sep 17 00:00:00 2001 From: dlezcano Date: Thu, 4 Sep 2008 07:57:50 +0000 Subject: [PATCH] Joined liblxc and lxc directory --- src/lxc/Makefile.am | 70 ++- src/lxc/create.c | 148 +++++ src/lxc/destroy.c | 120 ++++ src/lxc/execute.c | 271 +++++++++ src/lxc/freezer.c | 71 +++ src/lxc/genl.c | 148 +++++ src/lxc/genl.h | 121 ++++ src/lxc/kill.c | 70 +++ src/lxc/list.c | 23 + src/lxc/list.h | 57 ++ src/lxc/lxc.h | 256 ++++++++ src/lxc/lxc_cgroup.c | 188 ++++++ src/lxc/lxc_cgroup.h | 30 + src/lxc/lxc_conf.c | 1234 +++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_conf.h | 147 +++++ src/lxc/lxc_info.c | 66 +++ src/lxc/lxc_list.c | 23 + src/lxc/lxc_list.h | 57 ++ src/lxc/lxc_lock.c | 64 ++ src/lxc/lxc_lock.h | 30 + src/lxc/lxc_log.c | 9 + src/lxc/lxc_log.h | 20 + src/lxc/lxc_namespace.h | 71 +++ src/lxc/lxc_state.c | 176 +++++- src/lxc/lxc_state.h | 39 ++ src/lxc/lxc_utils.h | 51 ++ src/lxc/monitor.c | 171 ++++++ src/lxc/monitor.h | 29 + src/lxc/namespace.h | 71 +++ src/lxc/network.c | 727 +++++++++++++++++++++++ src/lxc/network.h | 126 ++++ src/lxc/nl.c | 260 +++++++++ src/lxc/nl.h | 228 ++++++++ src/lxc/rtnl.c | 72 +++ src/lxc/rtnl.h | 110 ++++ src/lxc/start.c | 253 ++++++++ src/lxc/stop.c | 92 +++ src/lxc/utils.h | 51 ++ 38 files changed, 5709 insertions(+), 41 deletions(-) create mode 100644 src/lxc/create.c create mode 100644 src/lxc/destroy.c create mode 100644 src/lxc/execute.c create mode 100644 src/lxc/freezer.c create mode 100644 src/lxc/genl.c create mode 100644 src/lxc/genl.h create mode 100644 src/lxc/kill.c create mode 100644 src/lxc/list.c create mode 100644 src/lxc/list.h create mode 100644 src/lxc/lxc.h create mode 100644 src/lxc/lxc_cgroup.c create mode 100644 src/lxc/lxc_cgroup.h create mode 100644 src/lxc/lxc_conf.c create mode 100644 src/lxc/lxc_conf.h create mode 100644 src/lxc/lxc_info.c create mode 100644 src/lxc/lxc_list.c create mode 100644 src/lxc/lxc_list.h create mode 100644 src/lxc/lxc_lock.c create mode 100644 src/lxc/lxc_lock.h create mode 100644 src/lxc/lxc_log.c create mode 100644 src/lxc/lxc_log.h create mode 100644 src/lxc/lxc_namespace.h create mode 100644 src/lxc/lxc_state.h create mode 100644 src/lxc/lxc_utils.h create mode 100644 src/lxc/monitor.c create mode 100644 src/lxc/monitor.h create mode 100644 src/lxc/namespace.h create mode 100644 src/lxc/network.c create mode 100644 src/lxc/network.h create mode 100644 src/lxc/nl.c create mode 100644 src/lxc/nl.h create mode 100644 src/lxc/rtnl.c create mode 100644 src/lxc/rtnl.h create mode 100644 src/lxc/start.c create mode 100644 src/lxc/stop.c create mode 100644 src/lxc/utils.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 5a7c481f0..a38c64d7a 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -1,4 +1,42 @@ -INCLUDES= -I$(top_srcdir)/src/liblxc -I$(top_srcdir)/src +INCLUDES= -I$(top_srcdir)/src + +lib_LTLIBRARIES = liblxc.la +pkginclude_HEADERS = \ + lxc.h \ + lxc_cgroup.h \ + lxc_conf.h \ + lxc_list.h \ + lxc_lock.h \ + lxc_log.h \ + lxc_namespace.h \ + lxc_state.h \ + lxc_utils.h + +liblxc_la_SOURCES = \ + create.c \ + destroy.c \ + start.c \ + stop.c \ + execute.c \ + monitor.c monitor.h \ + kill.c \ + freezer.c \ + lxc_cgroup.c lxc_cgroup.h \ + lxc.h \ + lxc_utils.h \ + lxc_lock.c lxc_lock.h \ + lxc_namespace.h \ + lxc_conf.c lxc_conf.h \ + lxc_list.h \ + lxc_state.c lxc_state.h \ + lxc_log.c lxc_log.h \ + \ + network.c network.h \ + nl.c nl.h \ + rtnl.c rtnl.h \ + genl.c genl.h + +liblxc_la_LDFLAGS = -release @PACKAGE_VERSION@ bin_SCRIPTS = \ lxc-ps @@ -11,56 +49,56 @@ bin_PROGRAMS = \ lxc-execute \ lxc-monitor \ lxc-console \ - lxc-state \ lxc-kill \ lxc-freeze \ + lxc-info \ lxc-unfreeze \ lxc-priority lxc_create_SOURCES = lxc_create.c lxc_config.c lxc_config.h lxc_create_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_destroy_SOURCES = lxc_destroy.c lxc_destroy_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_start_SOURCES = lxc_start.c lxc_start_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_stop_SOURCES = lxc_stop.c lxc_stop_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_execute_SOURCES = lxc_execute.c lxc_execute_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_monitor_SOURCES = lxc_monitor.c lxc_monitor_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_console_SOURCES = lxc_console.c lxc_console_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la -lxc_state_SOURCES = lxc_state.c -lxc_state_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la +lxc_info_SOURCES = lxc_info.c +lxc_info_LDADD = \ + $(top_builddir)/src/lxc/liblxc.la lxc_kill_SOURCES = lxc_kill.c lxc_kill_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_freeze_SOURCES = lxc_freeze.c lxc_freeze_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_unfreeze_SOURCES = lxc_unfreeze.c lxc_unfreeze_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la lxc_priority_SOURCES = lxc_priority.c lxc_priority_LDADD = \ - $(top_builddir)/src/liblxc/liblxc.la + $(top_builddir)/src/lxc/liblxc.la diff --git a/src/lxc/create.c b/src/lxc/create.c new file mode 100644 index 000000000..2891eba65 --- /dev/null +++ b/src/lxc/create.c @@ -0,0 +1,148 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int dir_filter(const struct dirent *dirent) +{ + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) + return 0; + return 1; +} + +static int is_empty_directory(const char *dirname) +{ + struct dirent **namelist; + int n; + + n = scandir(dirname, &namelist, dir_filter, alphasort); + if (n < 0) + lxc_log_syserror("failed to scan %s directory", dirname); + return n == 0; +} + +static int create_lxc_directory(const char *dirname) +{ + char path[MAXPATHLEN]; + + if (mkdir(LXCPATH, 0755) && errno != EEXIST) { + lxc_log_syserror("failed to created %s directory", LXCPATH); + return -1; + } + + sprintf(path, LXCPATH "/%s", dirname); + + if (mkdir(path, 0755)) { + lxc_log_syserror("failed to created %s directory", path); + return -1; + } + + return 0; +} + +static int remove_lxc_directory(const char *dirname) +{ + char path[MAXPATHLEN]; + + sprintf(path, LXCPATH "/%s", dirname); + + if (rmdir(path)) { + lxc_log_syserror("failed to remove %s directory", path); + return -1; + } + + if (is_empty_directory(LXCPATH)) { + if (rmdir(LXCPATH)) { + lxc_log_syserror("failed to remove %s directory", LXCPATH); + return -1; + } + } + + return 0; +} + +int lxc_create(const char *name, struct lxc_conf *conf) +{ + int lock, err = -1; + + if (create_lxc_directory(name)) { + lxc_log_error("failed to create %s directory", name); + return -1; + } + + lock = lxc_get_lock(name); + if (!lock) { + lxc_log_error("'%s' is busy", name); + goto err; + } + + if (lock < 0) { + lxc_log_error("failed to acquire lock on '%s':%s", + name, strerror(-lock)); + goto err; + } + + if (lxc_mkstate(name)) { + lxc_log_error("failed to create the state file for %s", name); + goto err; + } + + if (lxc_setstate(name, STOPPED)) { + lxc_log_error("failed to set state for %s", name); + goto err_state; + } + + if (lxc_configure(name, conf)) { + lxc_log_error("failed to set configuration for %s", name); + goto err_state; + } + + err = 0; +out: + lxc_put_lock(lock); + return err; + +err_state: + lxc_unconfigure(name); + + if (lxc_rmstate(name)) + lxc_log_error("failed to remove state file for %s", name); +err: + if (remove_lxc_directory(name)) + lxc_log_error("failed to cleanup lxc directory for %s", name); + goto out; +} diff --git a/src/lxc/destroy.c b/src/lxc/destroy.c new file mode 100644 index 000000000..266a5ae04 --- /dev/null +++ b/src/lxc/destroy.c @@ -0,0 +1,120 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int dir_filter(const struct dirent *dirent) +{ + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) + return 0; + return 1; +} + +static int is_empty_directory(const char *dirname) +{ + struct dirent **namelist; + int n; + + n = scandir(dirname, &namelist, dir_filter, alphasort); + if (n < 0) + lxc_log_syserror("failed to scan %s directory", dirname); + return n == 0; +} + +static int remove_lxc_directory(const char *dirname) +{ + char path[MAXPATHLEN]; + + sprintf(path, LXCPATH "/%s", dirname); + + if (rmdir(path)) { + lxc_log_syserror("failed to remove %s directory", path); + return -1; + } + + if (is_empty_directory(LXCPATH)) { + if (rmdir(LXCPATH)) { + lxc_log_syserror("failed to remove %s directory", LXCPATH); + return -1; + } + } + + return 0; +} + +int lxc_destroy(const char *name) +{ + int ret = -1, lock; + + lock = lxc_get_lock(name); + if (!lock) { + lxc_log_error("'%s' is busy", name); + goto out; + } + + if (lock < 0) { + lxc_log_error("failed to acquire the lock for '%s':%s", + name, strerror(-lock)); + goto out; + } + + if (lxc_rmstate(name)) { + lxc_log_error("failed to remove state file for %s", name); + goto out_lock; + } + + lxc_monitor_cleanup(name); + + if (lxc_unconfigure(name)) { + lxc_log_error("failed to cleanup %s", name); + goto out_lock; + } + + if (remove_lxc_directory(name)) { + lxc_log_syserror("failed to remove '%s'", name); + goto out_lock; + } + + ret = 0; + +out_lock: + lxc_put_lock(lock); +out: + return ret; +} diff --git a/src/lxc/execute.c b/src/lxc/execute.c new file mode 100644 index 000000000..888a84324 --- /dev/null +++ b/src/lxc/execute.c @@ -0,0 +1,271 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +LXC_TTY_HANDLER(SIGINT); +LXC_TTY_HANDLER(SIGQUIT); + +int lxc_execute(const char *name, int argc, char *argv[], + lxc_callback_t preexec, void *data) +{ + char *init = NULL, *val = NULL, *vinit = "[vinit]"; + int fd, lock, sv[2], sync = 0, err = -1; + pid_t pid; + int clone_flags; + + lock = lxc_get_lock(name); + if (!lock) { + lxc_log_error("'%s' is busy", name); + return -1; + } + + if (lock < 0) { + lxc_log_error("failed to acquire lock on '%s':%s", + name, strerror(-lock)); + return -1; + } + + if (lxc_setstate(name, STARTING)) { + lxc_log_error("failed to set state %s", lxc_state2str(STARTING)); + goto out; + } + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) { + lxc_log_syserror("failed to create communication socketpair"); + goto err; + } + + LXC_TTY_ADD_HANDLER(SIGINT); + LXC_TTY_ADD_HANDLER(SIGQUIT); + + clone_flags = CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS; + if (conf_has_utsname(name)) + clone_flags |= CLONE_NEWUTS; + if (conf_has_network(name)) + clone_flags |= CLONE_NEWNET; + + pid = fork_ns(clone_flags); + if (pid < 0) { + lxc_log_syserror("failed to fork into a new namespace"); + goto err_fork_ns; + } + + if (!pid) { + + pid = fork(); + if (pid < 0) { + lxc_log_syserror("failed to fork"); + return 1; + } + + if (!pid) { + close(sv[1]); + fcntl(sv[0], F_SETFD, FD_CLOEXEC); + + if (write(sv[0], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to write socket"); + return 1; + } + + if (read(sv[0], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to read socket"); + return 1; + } + + if (lxc_setup(name)) { + lxc_log_error("failed to setup the container"); + goto error; + } + + if (mount("proc", "/proc", "proc", 0, NULL)) { + lxc_log_syserror("failed to mount '/proc'"); + goto error; + } + + if (conf_has_network(name)) + if (mount("sysfs", "/sys", "sysfs", 0, NULL)) { + lxc_log_syserror("failed to mount '/sys'"); + /* continue: non fatal error until sysfs not per + namespace */ + } + + if (preexec) + if (preexec(name, argc, argv, data)) { + lxc_log_error("preexec callback has failed"); + return -1; + } + + execvp(argv[0], argv); + lxc_log_syserror("failed to exec %s", argv[0]); + error: + if (write(sv[0], &sync, sizeof(sync)) < 0) + lxc_log_syserror("failed to write the socket"); + + exit(1); + } + + setsid(); + close(0); + close(1); + close(2); + + if (prctl(PR_SET_NAME, vinit, 0, 0, 0)) + lxc_log_syserror("failed to set process name"); + + close(sv[0]); + close(sv[1]); + + for (;;) { + int status; + if (wait(&status) < 0) { + if (errno == ECHILD) + return 0; + if (errno == EINTR) + continue; + lxc_log_syserror("failed to wait child"); + return 1; + } + } + } + + close(sv[0]); + + if (read(sv[1], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to read the socket"); + goto err_pipe_read; + } + + if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) { + lxc_log_error("failed to create the configured network"); + goto err_create_network; + } + + if (write(sv[1], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to write the socket"); + goto err_pipe_write; + } + + err = read(sv[1], &sync, sizeof(sync)); + if (err < 0) { + lxc_log_error("failed to read the socket"); + goto err_pipe_read2; + } + + if (err > 0) { + lxc_log_error("something went wrong with %d", pid); + /* TODO : check status etc ... */ + waitpid(pid, NULL, 0); + goto err_child_failed; + } + + asprintf(&init, LXCPATH "/%s/init", name); + fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd < 0) { + lxc_log_syserror("failed to open %s", init); + goto err_open; + } + + asprintf(&val, "%d", pid); + if (write(fd, val, strlen(val)) < 0) { + lxc_log_syserror("failed to write init pid"); + goto err_write; + } + + if (lxc_link_nsgroup(name, pid)) + lxc_log_warning("cgroupfs not found: cgroup disabled"); + + if (lxc_setstate(name, RUNNING)) { + lxc_log_error("failed to set state to %s", lxc_state2str(RUNNING)); + goto err_state_failed; + } + +wait_again: + if (waitpid(pid, NULL, 0) < 0) { + if (errno == EINTR) + goto wait_again; + lxc_log_syserror("failed to wait the pid %d", pid); + goto err_waitpid_failed; + } + + if (lxc_setstate(name, STOPPING)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPING)); + + if (clone_flags & CLONE_NEWNET && conf_destroy_network(name)) + lxc_log_error("failed to destroy the network"); + + err = 0; +out: + if (lxc_setstate(name, STOPPED)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPED)); + + lxc_unlink_nsgroup(name); + unlink(init); + free(init); + free(val); + lxc_put_lock(lock); + + return err; + +err_write: + close(fd); + +err_state_failed: +err_child_failed: +err_pipe_read2: +err_pipe_write: + conf_destroy_network(name); +err_create_network: +err_pipe_read: +err_open: +err_waitpid_failed: + if (lxc_setstate(name, ABORTING)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPED)); + + kill(pid, SIGKILL); +err_fork_ns: + LXC_TTY_DEL_HANDLER(SIGQUIT); + LXC_TTY_DEL_HANDLER(SIGINT); + close(sv[0]); + close(sv[1]); +err: + goto out; +} diff --git a/src/lxc/freezer.c b/src/lxc/freezer.c new file mode 100644 index 000000000..38332bdf6 --- /dev/null +++ b/src/lxc/freezer.c @@ -0,0 +1,71 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int freeze_unfreeze(const char *name, int freeze) +{ + char *freezer, *f = freeze?"FROZEN":"RUNNING"; + int fd, ret = -1; + + asprintf(&freezer, LXCPATH "/%s/nsgroup/freezer.state", name); + + fd = open(freezer, O_WRONLY); + if (fd < 0) { + lxc_log_syserror("failed to open freezer for '%s'", name); + goto out; + } + + ret = write(fd, f, strlen(f) + 1) < 0; + close(fd); + if (ret) + lxc_log_syserror("failed to write to '%s'", freezer); +out: + free(freezer); + return ret; +} + +int lxc_freeze(const char *name) +{ + return freeze_unfreeze(name, 1); +} + +int lxc_unfreeze(const char *name) +{ + return freeze_unfreeze(name, 0); +} + diff --git a/src/lxc/genl.c b/src/lxc/genl.c new file mode 100644 index 000000000..3781be154 --- /dev/null +++ b/src/lxc/genl.c @@ -0,0 +1,148 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int genetlink_resolve_family(const char *family) +{ + struct nl_handler handler; + struct nlattr *attr; + struct genlmsg *request, *reply; + struct genlmsghdr *genlmsghdr; + + int len, ret; + + request = genlmsg_alloc(GENLMSG_GOOD_SIZE); + if (!request) + return -ENOMEM; + + reply = genlmsg_alloc(GENLMSG_GOOD_SIZE); + if (!reply) { + genlmsg_free(request); + return -ENOMEM; + } + + request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + request->nlmsghdr.nlmsg_type = GENL_ID_CTRL; + + genlmsghdr = NLMSG_DATA(&request->nlmsghdr); + genlmsghdr->cmd = CTRL_CMD_GETFAMILY; + + ret = netlink_open(&handler, NETLINK_GENERIC); + if (ret) + return ret; + + ret = nla_put_string((struct nlmsg *)&request->nlmsghdr, + CTRL_ATTR_FAMILY_NAME, family); + if (ret) + goto out; + + ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr, + (struct nlmsg *)&reply->nlmsghdr); + if (ret < 0) + goto out; + + genlmsghdr = NLMSG_DATA(&reply->nlmsghdr); + len = reply->nlmsghdr.nlmsg_len; + + ret = -ENOMSG; + if (reply->nlmsghdr.nlmsg_type != GENL_ID_CTRL) + goto out; + + if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY) + goto out; + + ret = -EMSGSIZE; + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + goto out; + + attr = (struct nlattr *)GENLMSG_DATA(reply); + attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len)); + + ret = -ENOMSG; + if (attr->nla_type != CTRL_ATTR_FAMILY_ID) + goto out; + + ret = *(__u16 *) NLA_DATA(attr); +out: + genlmsg_free(request); + genlmsg_free(reply); + netlink_close(&handler); + return ret; +} + +extern int genetlink_open(struct genl_handler *handler, const char *family) +{ + int ret; + handler->family = genetlink_resolve_family(family); + if (handler->family < 0) + return handler->family; + + ret = netlink_open(&handler->nlh, NETLINK_GENERIC); + + return ret; +} + +extern int genetlink_close(struct genl_handler *handler) +{ + return netlink_close(&handler->nlh); +} + +extern int genetlink_rcv(struct genl_handler *handler, struct genlmsg *genlmsg) +{ + return netlink_rcv(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr); +} + +extern int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg) +{ + + return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr); +} + +extern int genetlink_transaction(struct genl_handler *handler, + struct genlmsg *request, struct genlmsg *answer) +{ + return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr, + (struct nlmsg *)&answer->nlmsghdr); +} + +extern struct genlmsg *genlmsg_alloc(size_t size) +{ + size_t len = NLMSG_LENGTH(GENL_HDRLEN) + size; + return (struct genlmsg *)nlmsg_alloc(len); +} + +extern void genlmsg_free(struct genlmsg *genlmsg) +{ + free(genlmsg); +} diff --git a/src/lxc/genl.h b/src/lxc/genl.h new file mode 100644 index 000000000..4800aacc2 --- /dev/null +++ b/src/lxc/genl.h @@ -0,0 +1,121 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __genl_h +#define __genl_h + +/* + * Use this as a good size to allocate generic netlink messages + */ +#define GENLMSG_GOOD_SIZE NLMSG_GOOD_SIZE +#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) + +/* + * struct genl_handler : the structure which store the netlink handler + * and the family number resulting of the auto-generating id family + * for the generic netlink protocol + * + * @nlh: the netlink socket handler + * @family: the generic netlink family assigned number + */ +struct genl_handler +{ + struct nl_handler nlh; + int family; +}; + +/* + * struct genlmsg : the struct containing the generic netlink message + * format + * + * @nlmsghdr: a netlink message header + * @genlmsghdr: a generic netlink message header pointer + * + */ +/* __attribute__ ((aligned(4))); */ +struct genlmsg { + struct nlmsghdr nlmsghdr; + struct genlmsghdr genlmsghdr; +}; + +static inline int genetlink_len(const struct genlmsg *genlmsg) +{ + return ((genlmsg->nlmsghdr.nlmsg_len) - GENL_HDRLEN - NLMSG_HDRLEN); +} + +/* + * genetlink_open : resolve family number id and open a generic netlink socket + * + * @handler: a struct genl_handler pointer + * @family: the family name of the generic netlink protocol + * + * Returns 0 on success, < 0 otherwise + */ +int genetlink_open(struct genl_handler *handler, const char *family); + +/* + * genetlink_close : close a generic netlink socket + * + * @handler: the handler of the socket to be closed + * + * Returns 0 on success, < 0 otherwise + */ +int genetlink_close(struct genl_handler *handler); + +/* + * genetlink_rcv : receive a generic netlink socket, it is up + * to the caller to manage the allocation of the generic netlink message + * + * @handler: the handler of the generic netlink socket + * @genlmsg: the pointer to a generic netlink message pre-allocated + * + * Returns 0 on success, < 0 otherwise + */ +int genetlink_rcv(struct genl_handler *handler, struct genlmsg *genlmsg); + +/* + * genetlink_send : send a generic netlink socket, it is up + * to the caller to manage the allocation of the generic netlink message + * + * @handler: the handler of the generic netlink socket + * @genlmsg: the pointer to a generic netlink message pre-allocated + * + * Returns 0 on success, < 0 otherwise + */ +int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg); + +struct genlmsg *genlmsg_alloc(size_t size); + +void genlmsg_free(struct genlmsg *genlmsg); + +/* + * genetlink_transaction : send and receive a generic netlink message in one shot + * + * @handler: the handler of the generic netlink socket + * @request: a generic netlink message containing the request to be sent + * @answer: a pre-allocated generic netlink message to receive the response + * + * Returns 0 on success, < 0 otherwise + */ +int genetlink_transaction(struct genl_handler *handler, + struct genlmsg *request, struct genlmsg *answer); +#endif diff --git a/src/lxc/kill.c b/src/lxc/kill.c new file mode 100644 index 000000000..7af7f34f5 --- /dev/null +++ b/src/lxc/kill.c @@ -0,0 +1,70 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int lxc_kill(const char *name, int signum) +{ + char *freezer = NULL, *signal = NULL; + int fd = -1, ret = -1; + + if (signum < SIGHUP || signum > SIGRTMAX) { + lxc_log_error("bad signal value %d", signum); + goto out; + } + + asprintf(&freezer, LXCPATH "/%s/nsgroup/freezer.kill", name); + asprintf(&signal, "%d", signum); + + fd = open(freezer, O_WRONLY); + if (fd < 0) { + lxc_log_syserror("failed to open %s for %s", freezer, name); + goto out; + } + + if (write(fd, &signal, strlen(signal)) < 0) { + lxc_log_syserror("failed to write to %s", freezer); + goto out; + } + + ret = 0; +out: + close(fd); + free(freezer); + free(signal); + return ret; +} diff --git a/src/lxc/list.c b/src/lxc/list.c new file mode 100644 index 000000000..d588ae2e1 --- /dev/null +++ b/src/lxc/list.c @@ -0,0 +1,23 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include diff --git a/src/lxc/list.h b/src/lxc/list.h new file mode 100644 index 000000000..00d0d167f --- /dev/null +++ b/src/lxc/list.h @@ -0,0 +1,57 @@ +#ifndef _list_h +#define _list_h + +struct list { + void *elem; + struct list *next; + struct list *prev; +}; + +#define init_list(l) { .next = l, .prev = l, } + +#define list_for_each(__iterator, __list) \ + for (__iterator = (__list)->next; \ + __iterator != __list; \ + __iterator = __iterator->next) + +static inline void list_init(struct list *list) +{ + list->elem = NULL; + list->next = list->prev = list; +} + +static inline void list_add_elem(struct list *list, void *elem) +{ + list->elem = elem; +} + +static inline void *list_first_elem(struct list *list) +{ + return list->next->elem; +} + +static inline int list_empty(struct list *list) +{ + return list == list->next; +} + +static inline void list_add(struct list *list, struct list *new) +{ + struct list *next = list->next; + next->prev = new; + new->next = next; + new->prev = list; + list->next = new; +} + +static inline void list_del(struct list *list) +{ + struct list *next, *prev; + + next = list->next; + prev = list->prev; + next->prev = prev; + prev->next = next; +} + +#endif diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h new file mode 100644 index 000000000..b83741347 --- /dev/null +++ b/src/lxc/lxc.h @@ -0,0 +1,256 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __lxc_h +#define __lxc_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Following code is for liblxc. + + liblxc/lxc.h will contain exports of liblxc + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LXCPATH "/var/lxc" +#define MAXPIDLEN 20 + +struct lxc_mem_stat; + +typedef int (*lxc_callback_t)(const char *name, int argc, + char *argv[], void *data); + +/* + * Create the container object. Creates the /lxc/ directory + * and fills it with the files corresponding to the configuration + * structure passed as parameter. + * The first container will create the /lxc directory. + * @name : the name of the container + * @conf : the configuration data for the container + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_create(const char *name, struct lxc_conf *conf); + +/* + * Destroy the container object. Removes the files into the /lxc/ + * directory and removes the directory. + * The last container will remove the /lxc directory. + * @name : the name of the container to be detroyed + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_destroy(const char *name); + +/* + * Start the container previously created with lxc_create. + * @name : the name of the container + * @argc : the number of arguments of the command line + * @argv : an array of char * corresponding to the commande line + * @prestart : hooks will be called just before the command execs + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_start(const char *name, int argc, char *argv[], + lxc_callback_t prestart, void *data); + +/* + * Create the container and start it directly, using the argc, argv + * parameter. This command is for application container. + * At the end of the exec'ed command, the container will + * automatically autodestroy. + * @name : the name of the container + * @conf : the configuration data + * @argc : the number of arguments of the command line + * @argv : an array of char * corresponding to the commande line + * @preexec : hooks will be called just before the command execs + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_execute(const char *name, int argc, char *argv[], + lxc_callback_t preexec, void *data); + +/* + * Stop the container previously started with lxc_start or lxc_exec + * @name : the name of the container + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_stop(const char *name); + +/* + * Monitor the container, each time the state of the container + * is changed, a state data is send through a file descriptor passed to + * the function with output_fd. + * The function will block until the container is destroyed. + * @name : the name of the container + * @output_fd : the file descriptor where to send the states + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_monitor(const char *name, int output_fd); + +/* + * Open the monitoring mechanism for a specific container + * The function will return an fd corresponding to the events + * @name : the name of the container + * Returns a file descriptor on success, < 0 otherwise + */ +extern int lxc_monitor_open(const char *name); + +/* + * Read the state of the container if this one has changed + * The function will block until there is an event available + * @fd : the file descriptor provided by lxc_monitor_open + * @state : the variable which will be filled with the state + * Returns 0 if the monitored container has exited, > 0 if + * data was readen, < 0 otherwise + */ +extern int lxc_monitor_read(int fd, lxc_state_t *state); + +/* + * Close the fd associated with the monitoring + * @fd : the file descriptor provided by lxc_monitor_open + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_monitor_close(int fd); + +/* + * Show the console of the container. + * @name : the name of container + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_console(const char *name); + +/* + * Freeze all the tasks running inside the container + * @name : the container name + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_freeze(const char *name); + +/* + * Unfreeze all previously frozen tasks. + * @name : the name of the container + * Return 0 on sucess, < 0 otherwise + */ +extern int lxc_unfreeze(const char *name); + +/* + * Retrieve the container state + * @name : the name of the container + * Returns the state of the container on success, < 0 otherwise + */ +extern lxc_state_t lxc_state(const char *name); + +/* + * Send a signal to all processes of the container. This is the same + * behavior of the well-known 'killpg' command except it is related + * to all tasks belonging to a container. + * @name : the name of the container + * @signum : the signal number to be sent + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_kill(const char *name, int signum); + +/* + * Change the priority of the container + * @name : the name of the container + * @priority : an integer representing the desired priority + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_cgroup_set_priority(const char *name, int priority); + +/* + * Retrieve the priority of the container + * @name : the name of the container + * @priority : a pointer to an int where the priority will be stored + * Returns 0 on success, < 0 otherwise + */ +extern int lxc_cgroup_get_priority(const char *name, int *priority); + +/* + * Set the maximum memory usable by the container + * @name : the name of the container + * @memmax : the maximum usable memory in bytes + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_set_memory(const char *name, size_t memmax); + +/* + * Get the maximum memory usable by the container + * @name : the name of the container + * @memmax : a pointer to a size_t where the value will be stored + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_get_memory(const char *name, size_t *memmax); + +/* + * Get the memory statistics of the container + * @name : the name of the container + * @memstat : a pointer to a structure defining the memory statistic + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_get_memstat(const char *name, + struct lxc_mem_stat *memstat); + +/* + * Set the cpuset for the container + * @name : the name of the container + * @cpumask : a bitmask representing the cpu maps + * @len : the len of the bitmask + * @shared : a boolean specifying if the cpu could be shared with + * processes not belonging to the container + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_set_cpuset(const char *name, long *cpumask, + int len, int shared); + +/* + * Get the actual cpuset for the container + * @cpumask : a bitmask representing the cpu maps + * @len : the len of the bitmask + * @shared : a boolean specifying if the cpu is shared with + * processes not belonging to the container + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_get_cpuset(const char *name, long *cpumask, + int len, int *shared); + +/* + * Get the cpu usage of the container + * @name : the name of the container + * @usage : a value to be filled with the current container cpu usage + * Returns 0 on sucess, < 0 otherwise + */ +extern int lxc_cgroup_get_cpu_usage(const char *name, long long *usage); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c new file mode 100644 index 000000000..f436d6644 --- /dev/null +++ b/src/lxc/lxc_cgroup.c @@ -0,0 +1,188 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAXPRIOLEN 24 +#define MTAB "/etc/mtab" + +static int get_cgroup_mount(const char *mtab, char *mnt) +{ + struct mntent *mntent; + FILE *file = NULL; + int err = -1; + + file = setmntent(mtab, "r"); + if (!file) { + lxc_log_syserror("failed to open %s", mtab); + goto out; + } + + while ((mntent = getmntent(file))) { + if (strcmp(mntent->mnt_type, "cgroup")) + continue; + strcpy(mnt, mntent->mnt_dir); + err = 0; + break; + }; + + fclose(file); +out: + return err; +} + +int lxc_link_nsgroup(const char *name, pid_t pid) +{ + char *lxc, *nsgroup, cgroup[MAXPATHLEN]; + int ret; + + if (get_cgroup_mount(MTAB, cgroup)) { + lxc_log_info("cgroup is not mounted"); + return -1; + } + + asprintf(&lxc, LXCPATH "/%s/nsgroup", name); + asprintf(&nsgroup, "%s/%d", cgroup, pid); + + unlink(lxc); + ret = symlink(nsgroup, lxc); + if (ret) + lxc_log_syserror("failed to create symlink %s->%s", + nsgroup, lxc); + free(lxc); + free(nsgroup); + return ret; +} + +int lxc_unlink_nsgroup(const char *name) +{ + char *nsgroup; + int ret; + + asprintf(&nsgroup, LXCPATH "/%s/nsgroup", name); + ret = unlink(nsgroup); + free(nsgroup); + + return ret; +} + +int lxc_cgroup_set_priority(const char *name, int priority) +{ + int fd; + char *path = NULL, *prio = NULL; + + asprintf(&path, LXCPATH "/%s/nsgroup/cpu.shares", name); + + fd = open(path, O_WRONLY); + if (fd < 0) { + lxc_log_syserror("failed to open '%s'", path); + goto out; + } + + asprintf(&prio, "%d", priority); + + if (write(fd, prio, strlen(prio) + 1) < 0) { + lxc_log_syserror("failed to write to '%s'", path); + close(fd); + goto out; + } + + close(fd); +out: + free(path); + free(prio); + return 0; +} + +int lxc_cgroup_get_priority(const char *name, int *priority) +{ + int fd, ret = -1; + char *path, prio[MAXPRIOLEN]; + + asprintf(&path, LXCPATH "/%s/nsgroup/cpu.shares", name); + + fd = open(path, O_RDONLY); + if (fd < 0) { + lxc_log_syserror("failed to open '%s'", path); + goto out; + } + + if (read(fd, prio, MAXPRIOLEN) < 0) { + lxc_log_syserror("failed to read from '%s'", path); + close(fd); + goto out; + } + + close(fd); + *priority = atoi(prio); + + ret = 0; +out: + free(path); + return ret; +} + +int lxc_set_memory(const char *name, size_t memmax) +{ + return 0; +} + +int lxc_get_memory(const char *name, size_t *memmax) +{ + return 0; +} + +int lxc_get_memstat(const char *name, struct lxc_mem_stat *memstat) +{ + return 0; +} + +int lxc_set_cpuset(const char *name, long *cpumask, int len, int shared) +{ + return 0; +} + +int lxc_get_cpuset(const char *name, long *cpumask, int len, int *shared) +{ + return 0; +} + +int lxc_get_cpu_usage(const char *name, long long *usage) +{ + return 0; +} diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h new file mode 100644 index 000000000..8060cdf43 --- /dev/null +++ b/src/lxc/lxc_cgroup.h @@ -0,0 +1,30 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _cgroup_h +#define _cgroup_h + +int lxc_get_cgroup_mount(const char *mtab, char *mnt); +int lxc_link_nsgroup(const char *name, pid_t pid); +int lxc_unlink_nsgroup(const char *name); + +#endif diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c new file mode 100644 index 000000000..beea5cb42 --- /dev/null +++ b/src/lxc/lxc_conf.c @@ -0,0 +1,1234 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define MAXHWLEN 18 +#define MAXINDEXLEN 20 +#define MAXLINELEN 128 + +typedef int (*instanciate_cb)(const char *dirname, + const char *file, pid_t pid); + +typedef int (*dir_cb)(const char *name, const char *dirname, + const char *file, void *data); + +typedef int (*file_cb)(void* buffer, void *data); + +struct netdev_conf { + const char *type; + instanciate_cb cb; + int count; +}; + +static int instanciate_veth(const char *, const char *, pid_t); +static int instanciate_macvlan(const char *, const char *, pid_t); +static int instanciate_phys(const char *, const char *, pid_t); +static int instanciate_empty(const char *, const char *, pid_t); + +static struct netdev_conf netdev_conf[MAXCONFTYPE + 1] = { + [VETH] = { "veth", instanciate_veth, 0 }, + [MACVLAN] = { "macvlan", instanciate_macvlan, 0, }, + [PHYS] = { "phys", instanciate_phys, 0, }, + [EMPTY] = { "empty", instanciate_empty, 0, }, +}; + +static int dir_filter(const struct dirent *dirent) +{ + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) + return 0; + return 1; +} + +static int dir_for_each(const char *name, const char *dirname, + dir_cb callback, void *data) +{ + struct dirent **namelist; + int n; + + n = scandir(dirname, &namelist, dir_filter, alphasort); + if (n < 0) { + lxc_log_syserror("failed to scan %s directory", dirname); + return -1; + } + + while (n--) { + if (callback(name, dirname, namelist[n]->d_name, data)) { + lxc_log_error("callback failed"); + free(namelist[n]); + return -1; + } + free(namelist[n]); + } + + return 0; +} + +static int file_for_each_line(const char *file, file_cb callback, + void *buffer, size_t len, void* data) +{ + FILE *f; + int err = -1; + + f = fopen(file, "r"); + if (!f) { + lxc_log_syserror("failed to open %s", file); + return -1; + } + + while (fgets(buffer, len, f)) + if (callback(buffer, data)) + goto out; + err = 0; +out: + fclose(f); + return err; +} + +static int write_info(const char *path, const char *file, const char *info) +{ + int fd, err = -1; + char *f; + + asprintf(&f, "%s/%s", path, file); + fd = creat(f, 0755); + if (fd < 0) + goto out; + + if (write(fd, info, strlen(info)) < 0 || + write(fd, "\n", strlen("\n") + 1) < 0) + goto out_write; + err = 0; +out: + close(fd); + free(f); + return err; + +out_write: + unlink(f); + goto out; +} + +static int read_info(const char *path, const char *file, char *info, size_t len) +{ + int fd, ret = -1; + char *f, *token; + + asprintf(&f, "%s/%s", path, file); + fd = open(f, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + ret = 1; + goto out; + } + + ret = read(fd, info, len); + if (ret < 0) + goto out; + + token = strstr(info, "\n"); + if (token) + *token = '\0'; + ret = 0; +out: + close(fd); + free(f); + return ret; +} + +static int delete_info(const char *path, const char *file) +{ + char *info; + int ret; + + asprintf(&info, "%s/%s", path, file); + ret = unlink(info); + free(info); + + return ret; +} + +static int configure_ip4addr(int fd, struct lxc_inetdev *in) +{ + char addr[INET6_ADDRSTRLEN]; + char bcast[INET_ADDRSTRLEN]; + char *line = NULL; + int err = -1; + + if (!inet_ntop(AF_INET, &in->addr, addr, sizeof(addr))) { + lxc_log_syserror("failed to convert ipv4 address"); + goto err; + } + + if (!inet_ntop(AF_INET, &in->bcast, bcast, sizeof(bcast))) { + lxc_log_syserror("failed to convert ipv4 broadcast"); + goto err; + } + + if (in->prefix) + asprintf(&line, "%s/%d %s\n", addr, in->prefix, bcast); + else + asprintf(&line, "%s %s\n", addr, bcast); + + if (write(fd, line, strlen(line)) < 0) { + lxc_log_syserror("failed to write address info"); + goto err; + } + + err = 0; +err: + free(line); + return err; +} + +static int configure_ip6addr(int fd, struct lxc_inet6dev *in6) +{ + char addr[INET6_ADDRSTRLEN]; + char *line = NULL; + int err = -1; + + if (!inet_ntop(AF_INET6, &in6->addr, addr, sizeof(addr))) { + lxc_log_syserror("failed to convert ipv4 address"); + goto err; + } + + asprintf(&line, "%s/%d\n", addr, in6->prefix?in6->prefix:64); + + if (write(fd, line, strlen(line)) < 0) { + lxc_log_syserror("failed to write address info"); + goto err; + } + + err = 0; +err: + free(line); + return err; +} + +static int configure_ip_address(const char *path, struct lxc_list *ip, int family) +{ + char file[MAXPATHLEN]; + struct lxc_list *iterator; + int fd, err = -1; + + if (mkdir(path, 0755)) { + lxc_log_syserror("failed to create directory %s", path); + return -1; + } + + snprintf(file, MAXPATHLEN, "%s/addresses", path); + fd = creat(file, 0755); + if (fd < 0) { + lxc_log_syserror("failed to create %s file", file); + goto err; + } + + lxc_list_for_each(iterator, ip) { + err = family == AF_INET? + configure_ip4addr(fd, iterator->elem): + configure_ip6addr(fd, iterator->elem); + if (err) + goto err; + } +out: + close(fd); + return err; +err: + unlink(file); + rmdir(path); + goto out; +} + +static int configure_netdev(const char *path, struct lxc_netdev *netdev) +{ + int err = -1; + char dir[MAXPATHLEN]; + + if (mkdir(path, 0755)) { + lxc_log_syserror("failed to create %s directory", path); + return -1; + } + + if (netdev->ifname) { + if (write_info(path, "link", netdev->ifname)) + goto out_link; + } + + if (netdev->newname) { + if (write_info(path, "name", netdev->newname)) + goto out_newname; + } + + if (netdev->hwaddr) { + if (write_info(path, "hwaddr", netdev->hwaddr)) + goto out_up; + } + + if (netdev->flags & IFF_UP) { + if (write_info(path, "up", "")) + goto out_hwaddr; + } + + if (!lxc_list_empty(&netdev->ipv4)) { + snprintf(dir, MAXPATHLEN, "%s/ipv4", path); + if (configure_ip_address(dir, &netdev->ipv4, AF_INET)) + goto out_ipv4; + } + + if (!lxc_list_empty(&netdev->ipv6)) { + snprintf(dir, MAXPATHLEN, "%s/ipv6", path); + if (configure_ip_address(dir, &netdev->ipv6, AF_INET6)) + goto out_ipv6; + } + err = 0; +out: + return err; +out_ipv6: + delete_info(path, "ipv4"); +out_ipv4: + delete_info(path, "up"); +out_hwaddr: + delete_info(path, "hwaddr"); +out_up: + delete_info(path, "name"); +out_newname: + delete_info(path, "link"); +out_link: + rmdir(path); + goto out; +} + +static int configure_utsname(const char *name, struct utsname *utsname) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); + + if (write_info(path, "utsname", utsname->nodename)) { + lxc_log_error("failed to write the utsname info"); + return -1; + } + + return 0; +} + +static int configure_network(const char *name, struct lxc_list *network) +{ + struct lxc_list *iterator; + struct lxc_network *n; + char networkpath[MAXPATHLEN]; + char path[MAXPATHLEN]; + int err = -1; + + if (lxc_list_empty(network)) + return 0; + + snprintf(networkpath, MAXPATHLEN, LXCPATH "/%s/network", name); + if (mkdir(networkpath, 0755)) { + lxc_log_syserror("failed to create %s directory", networkpath); + goto out; + } + + lxc_list_for_each(iterator, network) { + + n = iterator->elem; + + if (n->type < 0 || n->type > MAXCONFTYPE) { + lxc_log_error("invalid network configuration type '%d'", + n->type); + goto out; + } + + snprintf(path, MAXPATHLEN, "%s/%s%d", networkpath, + netdev_conf[n->type].type, + netdev_conf[n->type].count++); + + if (configure_netdev(path, lxc_list_first_elem(&n->netdev))) { + lxc_log_error("failed to configure network type %s", + netdev_conf[n->type].type); + goto out; + } + } + + err = 0; +out: + return err; +} + +static int configure_cgroup(const char *name, struct lxc_cgroup *cgroup) +{ + return 0; +} + +static int configure_chroot(const char *name, const char *chroot) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s/chroot", name); + + return symlink(chroot, path); + +} + +static int configure_mount(const char *name, const char *fstab) +{ + char *path; + struct stat stat; + int infd, outfd; + void *src, *dst; + char c = '\0'; + int ret = -1; + + asprintf(&path, LXCPATH "/%s/fstab", name); + + outfd = open(path, O_RDWR|O_CREAT|O_EXCL, 0640); + if (outfd < 0) { + lxc_log_syserror("failed to creat '%s'", path); + goto out; + } + + infd = open(fstab, O_RDONLY); + if (infd < 0) { + lxc_log_syserror("failed to open '%s'", fstab); + goto out; + } + + if (fstat(infd, &stat)) { + lxc_log_syserror("failed to stat '%s'", fstab); + goto out; + } + + if (lseek(outfd, stat.st_size - 1, SEEK_SET) < 0) { + lxc_log_syserror("failed to seek dest file '%s'", path); + goto out; + } + + /* fixup length */ + if (write(outfd, &c, 1) < 0) { + lxc_log_syserror("failed to write to '%s'", path); + goto out; + } + + src = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, infd, 0L); + if (src == MAP_FAILED) { + lxc_log_syserror("failed to mmap '%s'", fstab); + goto out; + } + + dst = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, outfd, 0L); + if (dst == MAP_FAILED) { + lxc_log_syserror("failed to mmap '%s'", path); + goto out; + } + + memcpy(dst, src, stat.st_size); + + munmap(src, stat.st_size); + munmap(dst, stat.st_size); + + ret = 0; +out: + free(path); + return ret; +} + +static int unconfigure_ip_addresses(const char *dirname) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, "%s/ipv4", dirname); + delete_info(path, "addresses"); + rmdir(path); + + snprintf(path, MAXPATHLEN, "%s/ipv6", dirname); + delete_info(path, "addresses"); + rmdir(path); + + return 0; +} + +static int unconfigure_network_cb(const char *name, const char *dirname, + const char *file, void *data) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + delete_info(path, "name"); + delete_info(path, "addr"); + delete_info(path, "link"); + delete_info(path, "hwaddr"); + delete_info(path, "up"); + unconfigure_ip_addresses(path); + rmdir(path); + + return 0; +} + +static int unconfigure_network(const char *name) +{ + char dirname[MAXPATHLEN]; + + snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name); + dir_for_each(name, dirname, unconfigure_network_cb, NULL); + rmdir(dirname); + + return 0; +} + +static int unconfigure_cgroup(const char *name) +{ + return 0; +} + +static int unconfigure_chroot(const char *name) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); + delete_info(path, "chroot"); + + return 0; +} + +static int unconfigure_mount(const char *name) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); + delete_info(path, "fstab"); + + return 0; +} + +static int unconfigure_utsname(const char *name) +{ + char path[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); + delete_info(path, "utsname"); + + return 0; +} + +static int setup_utsname(const char *name) +{ + int ret; + char path[MAXPATHLEN]; + struct utsname utsname; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); + + ret = read_info(path, "utsname", utsname.nodename, + sizeof(utsname.nodename)); + if (ret < 0) { + lxc_log_syserror("failed to read utsname info"); + return -1; + } + + if (!ret && sethostname(utsname.nodename, strlen(utsname.nodename))) { + lxc_log_syserror("failed to set the hostname to '%s'", + utsname.nodename); + return -1; + } + + return 0; +} + +static int setup_chroot(const char *name) +{ + char path[MAXPATHLEN], chrt[MAXPATHLEN]; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s/chroot", name); + + if (readlink(path, chrt, MAXPATHLEN) > 0) { + + if (chroot(chrt)) { + lxc_log_syserror("failed to set chroot %s", path); + return -1; + } + + if (chdir(getenv("HOME")) && chdir("/")) { + lxc_log_syserror("failed to change to home directory"); + return -1; + } + } + + return 0; +} + +static int setup_mount(const char *name) +{ + char path[MAXPATHLEN]; + struct mntent *mntent; + FILE *file; + int ret = -1; + unsigned long mntflags = 0; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name); + + file = setmntent(path, "r"); + if (!file) { + if (errno == ENOENT) + return 0; + lxc_log_syserror("failed to open '%s'", path); + goto out; + } + + while((mntent = getmntent(file))) { + + if (hasmntopt(mntent, "bind")) + mntflags |= MS_BIND; + + if (mount(mntent->mnt_fsname, mntent->mnt_dir, + mntent->mnt_type, mntflags, NULL)) { + lxc_log_syserror("failed to mount '%s' on '%s'", + mntent->mnt_fsname, mntent->mnt_dir); + goto out; + } + } + ret = 0; +out: + endmntent(file); + return ret; +} + +static int setup_ipv4_addr_cb(void *buffer, void *data) +{ + char *ifname = data; + char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL; + int p = 24; + + addr = buffer; + cursor = strstr(addr, " "); + if (cursor) { + *cursor = '\0'; + bcast = cursor + 1; + cursor = strstr(bcast, "\n"); + if (cursor) + *cursor = '\0'; + } + + slash = strstr(addr, "/"); + if (slash) { + *slash = '\0'; + prefix = slash + 1; + } + + if (prefix) + p = atoi(prefix); + + if (ip_addr_add(ifname, addr, p, bcast)) { + lxc_log_error("failed to set %s to addr %s/%d %s", ifname, + addr, p, bcast?bcast:""); + return -1; + } + + return 0; +} + +static int setup_ipv6_addr_cb(void *buffer, void *data) +{ + char *ifname = data; + char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL; + int p = 24; + + addr = buffer; + cursor = strstr(addr, " "); + if (cursor) { + *cursor = '\0'; + bcast = cursor + 1; + cursor = strstr(bcast, "\n"); + if (cursor) + *cursor = '\0'; + } + + slash = strstr(addr, "/"); + if (slash) { + *slash = '\0'; + prefix = slash + 1; + } + + if (prefix) + p = atoi(prefix); + + if (ip6_addr_add(ifname, addr, p, bcast)) { + lxc_log_error("failed to set %s to addr %s/%d %s", ifname, + addr, p, bcast?bcast:""); + return -1; + } + + return 0; +} + +static int setup_hw_addr(char *hwaddr, const char *ifname) +{ + struct sockaddr sockaddr; + struct ifreq ifr; + int ret, fd; + + if (lxc_convert_mac(hwaddr, &sockaddr)) { + fprintf(stderr, "conversion has failed\n"); + return -1; + } + + memcpy(ifr.ifr_name, ifname, IFNAMSIZ); + memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr)); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + + ret = ioctl(fd, SIOCSIFHWADDR, &ifr); + close(fd); + if (ret) + perror("ioctl"); + + return ret; +} + +static int setup_ip_addr(const char *dirname, const char *ifname) +{ + char path[MAXPATHLEN], line[MAXLINELEN]; + struct stat s; + int ret = 0; + + snprintf(path, MAXPATHLEN, "%s/ipv4/addresses", dirname); + if (!stat(path, &s)) + ret = file_for_each_line(path, setup_ipv4_addr_cb, + line, MAXPATHLEN, (void*)ifname); + return ret; +} + +static int setup_ip6_addr(const char *dirname, const char *ifname) +{ + char path[MAXPATHLEN], line[MAXLINELEN]; + struct stat s; + int ret = 0; + + snprintf(path, MAXLINELEN, "%s/ipv6/addresses", dirname); + if (!stat(path, &s)) + ret = file_for_each_line(path, setup_ipv6_addr_cb, + line, MAXPATHLEN, (void*)ifname); + return ret; +} + +static int setup_network_cb(const char *name, const char *dirname, + const char *file, void *data) +{ + char path[MAXPATHLEN]; + char strindex[MAXINDEXLEN]; + char ifname[IFNAMSIZ]; + char newname[IFNAMSIZ]; + char hwaddr[MAXHWLEN]; + char *current_ifname = ifname; + int ifindex; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + + if (read_info(path, "ifindex", strindex, sizeof(strindex))) { + lxc_log_error("failed to read ifindex info"); + return -1; + } + + ifindex = atoi(strindex); + if (!ifindex) { + if (!read_info(path, "up", strindex, sizeof(strindex))) + if (device_up("lo")) { + lxc_log_error("failed to set the loopback up"); + return -1; + } + return 0; + } + + if (!if_indextoname(ifindex, current_ifname)) { + lxc_log_error("no interface corresponding to index '%d'", + ifindex); + return -1; + } + + if (!read_info(path, "name", newname, sizeof(newname))) { + if (device_rename(ifname, newname)) { + lxc_log_error("failed to rename %s->%s", + ifname, newname); + return -1; + } + current_ifname = newname; + } + + if (!read_info(path, "hwaddr", hwaddr, sizeof(hwaddr))) { + if (setup_hw_addr(hwaddr, current_ifname)) { + lxc_log_error("failed to setup hw address for '%s'", + current_ifname); + return -1; + } + } + + if (setup_ip_addr(path, current_ifname)) { + lxc_log_error("failed to setup ip addresses for '%s'", + ifname); + return -1; + } + + if (setup_ip6_addr(path, current_ifname)) { + lxc_log_error("failed to setup ipv6 addresses for '%s'", + ifname); + return -1; + } + + if (!read_info(path, "up", strindex, sizeof(strindex))) { + if (device_up(current_ifname)) { + lxc_log_error("failed to set '%s' up", current_ifname); + return -1; + } + + /* the network is up, make the loopback up too */ + if (device_up("lo")) { + lxc_log_error("failed to set the loopback up"); + return -1; + } + } + + return 0; +} + +static int setup_network(const char *name) +{ + char dirname[MAXPATHLEN]; + + snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name); + return dir_for_each(name, dirname, setup_network_cb, NULL); +} + +int conf_has(const char *name, const char *info) +{ + int ret; + char path[MAXPATHLEN]; + struct stat st; + + snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info); + + ret = stat(path, &st); + if (!ret) { + ret = 1; + goto out; + } + + if (errno == ENOENT) { + ret = 0; + goto out; + } + + lxc_log_syserror("failed to stat %s info", info); +out: + return ret; +} + +int lxc_configure(const char *name, struct lxc_conf *conf) +{ + if (!conf) + return 0; + + if (conf->utsname && configure_utsname(name, conf->utsname)) { + lxc_log_error("failed to configure the utsname"); + return -1; + } + + if (configure_network(name, &conf->networks)) { + lxc_log_error("failed to configure the network"); + return -1; + } + + if (conf->cgroup && configure_cgroup(name, conf->cgroup)) { + lxc_log_error("failed to configure the control group"); + return -1; + } + + if (conf->chroot && configure_chroot(name, conf->chroot)) { + lxc_log_error("failed to configure the chroot"); + return -1; + } + + if (conf->fstab && configure_mount(name, conf->fstab)) { + lxc_log_error("failed to configure the mount points"); + return -1; + } + + return 0; +} + +int lxc_unconfigure(const char *name) +{ + if (conf_has_utsname(name) && unconfigure_utsname(name)) + lxc_log_error("failed to cleanup utsname"); + + if (conf_has_network(name) && unconfigure_network(name)) + lxc_log_error("failed to cleanup the network"); + + if (unconfigure_cgroup(name)) + lxc_log_error("failed to cleanup cgroup"); + + if (conf_has_chroot(name) && unconfigure_chroot(name)) + lxc_log_error("failed to cleanup chroot"); + + if (conf_has_fstab(name) && unconfigure_mount(name)) + lxc_log_error("failed to cleanup mount"); + + return 0; +} + +static int instanciate_veth(const char *dirname, const char *file, pid_t pid) +{ + char *path = NULL, *strindex = NULL, *veth1 = NULL, *veth2 = NULL; + char bridge[IFNAMSIZ]; + int ifindex, ret = -1; + + asprintf(&veth1, "%s_%d", file, pid); + asprintf(&veth2, "%s~%d", file, pid); + asprintf(&path, "%s/%s", dirname, file); + + if (read_info(path, "link", bridge, IFNAMSIZ)) { + lxc_log_error("failed to read bridge info"); + goto out; + } + + if (lxc_configure_veth(veth1, veth2, bridge)) { + lxc_log_error("failed to create %s-%s/%s", veth1, veth2, bridge); + goto out; + } + + ifindex = if_nametoindex(veth2); + if (!ifindex) { + lxc_log_error("failed to retrieve the index for %s", veth2); + goto out; + } + + asprintf(&strindex, "%d", ifindex); + if (write_info(path, "ifindex", strindex)) { + lxc_log_error("failed to write interface index to %s", path); + goto out; + } + + if (!read_info(path, "up", strindex, sizeof(strindex))) { + if (device_up(veth1)) { + lxc_log_error("failed to set %s up", veth1); + goto out; + } + } + + ret = 0; +out: + free(path); + free(strindex); + free(veth1); + free(veth2); + return ret; +} +static int instanciate_macvlan(const char *dirname, const char *file, pid_t pid) +{ + char path[MAXPATHLEN], *strindex = NULL, *peer = NULL; + char link[IFNAMSIZ]; + int ifindex, ret = -1; + + asprintf(&peer, "%s~%d", file, pid); + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + if (read_info(path, "link", link, IFNAMSIZ)) { + lxc_log_error("failed to read bridge info"); + goto out; + } + + if (lxc_configure_macvlan(link, peer)) { + lxc_log_error("failed to create macvlan interface %s", peer); + goto out; + } + + ifindex = if_nametoindex(peer); + if (!ifindex) { + lxc_log_error("failed to retrieve the index for %s", peer); + goto out; + } + + asprintf(&strindex, "%d", ifindex); + if (write_info(path, "ifindex", strindex)) { + lxc_log_error("failed to write interface index to %s", path); + goto out; + } + + ret = 0; +out: + free(strindex); + free(peer); + return ret; +} + +static int instanciate_phys(const char *dirname, const char *file, pid_t pid) +{ + char path[MAXPATHLEN], *strindex = NULL; + char link[IFNAMSIZ]; + int ifindex, ret = -1; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + if (read_info(path, "link", link, IFNAMSIZ)) { + lxc_log_error("failed to read link info"); + goto out; + } + + ifindex = if_nametoindex(link); + if (!ifindex) { + lxc_log_error("failed to retrieve the index for %s", link); + goto out; + } + + asprintf(&strindex, "%d", ifindex); + if (write_info(path, "ifindex", strindex)) { + lxc_log_error("failed to write interface index to %s", path); + goto out; + } + + ret = 0; +out: + free(strindex); + return ret; +} + +static int instanciate_empty(const char *dirname, const char *file, pid_t pid) +{ + char path[MAXPATHLEN], *strindex = NULL; + int ret = -1; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + if (!asprintf(&strindex, "%d", 0)) { + lxc_log_error("not enough memory"); + return -1; + } + + if (write_info(path, "ifindex", strindex)) { + lxc_log_error("failed to write interface index to %s", path); + goto out; + } + + ret = 0; +out: + free(strindex); + return ret; +} + +static int instanciate_netdev_cb(const char *name, const char *dirname, + const char *file, void *data) +{ + pid_t *pid = data; + + if (!strncmp("veth", file, strlen("veth"))) + return instanciate_veth(dirname, file, *pid); + else if (!strncmp("macvlan", file, strlen("macvlan"))) + return instanciate_macvlan(dirname, file, *pid); + else if (!strncmp("phys", file, strlen("phys"))) + return instanciate_phys(dirname, file, *pid); + else if (!strncmp("empty", file, strlen("empty"))) + return instanciate_empty(dirname, file, *pid); + + return -1; +} + +static int instanciate_netdev(const char *name, pid_t pid) +{ + char *dirname; + int ret; + + asprintf(&dirname, LXCPATH "/%s/network", name); + ret = dir_for_each(name, dirname, instanciate_netdev_cb, &pid); + free(dirname); + + return ret; +} + +static int move_netdev_cb(const char *name, const char *dirname, + const char *file, void *data) +{ + char path[MAXPATHLEN], ifname[IFNAMSIZ], strindex[MAXINDEXLEN]; + pid_t *pid = data; + int ifindex; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + if (read_info(path, "ifindex", strindex, MAXINDEXLEN) < 0) { + lxc_log_error("failed to read index to from %s", path); + return -1; + } + + ifindex = atoi(strindex); + if (!ifindex) + return 0; + + if (!if_indextoname(ifindex, ifname)) { + lxc_log_error("interface with index %d does not exist", + ifindex); + return -1; + } + + if (device_move(ifname, *pid)) { + lxc_log_error("failed to move %s to %d", ifname, *pid); + return -1; + } + + return 0; +} + +static int move_netdev(const char *name, pid_t pid) +{ + char *dirname; + int ret; + + asprintf(&dirname, LXCPATH "/%s/network", name); + ret = dir_for_each(name, dirname, move_netdev_cb, &pid); + free(dirname); + + return ret; +} + +int conf_create_network(const char *name, pid_t pid) +{ + if (instanciate_netdev(name, pid)) { + lxc_log_error("failed to instantiate the network devices"); + return -1; + } + + if (move_netdev(name, pid)) { + lxc_log_error("failed to move the netdev to the container"); + return -1; + } + + return 0; +} + +static int delete_netdev_cb(const char *name, const char *dirname, + const char *file, void *data) +{ + char strindex[MAXINDEXLEN]; + char path[MAXPATHLEN]; + char ifname[IFNAMSIZ]; + int i, ifindex; + + snprintf(path, MAXPATHLEN, "%s/%s", dirname, file); + + if (read_info(path, "ifindex", strindex, MAXINDEXLEN)) { + lxc_log_error("failed to read ifindex info"); + return -1; + } + + ifindex = atoi(strindex); + if (!ifindex) + return 0; + + /* TODO : temporary code - needs wait on namespace */ + for (i = 0; i < 120; i++) { + if (if_indextoname(ifindex, ifname)) + break; + if (!i) + printf("waiting for interface #%d to come back\n", ifindex); + else + printf("."); fflush(stdout); + sleep(1); + } + + /* do not delete a physical network device */ + if (strncmp("phys", file, strlen("phys"))) + if (device_delete(ifname)) { + lxc_log_error("failed to remove the netdev %s", ifname); + } + + delete_info(path, "ifindex"); + + return 0; +} + +static int delete_netdev(const char *name) +{ + char *dirname; + int ret; + + asprintf(&dirname, LXCPATH "/%s/network", name); + ret = dir_for_each(name, dirname, delete_netdev_cb, NULL); + free(dirname); + + return ret; +} + +int conf_destroy_network(const char *name) +{ + if (delete_netdev(name)) { + lxc_log_error("failed to remove the network devices"); + return -1; + } + + return 0; +} + +int lxc_setup(const char *name) +{ + if (conf_has_utsname(name) && setup_utsname(name)) { + lxc_log_error("failed to setup the utsname for '%s'", name); + return -1; + } + + if (conf_has_network(name) && setup_network(name)) { + lxc_log_error("failed to setup the network for '%s'", name); + return -1; + } + + if (conf_has_fstab(name) && setup_mount(name)) { + lxc_log_error("failed to setup the mount points for '%s'", name); + return -1; + } + + if (conf_has_chroot(name) && setup_chroot(name)) { + lxc_log_error("failed to set chroot for '%s'", name); + return -1; + } + + return 0; +} diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h new file mode 100644 index 000000000..a00a4a7b8 --- /dev/null +++ b/src/lxc/lxc_conf.h @@ -0,0 +1,147 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _conf_h +#define _conf_h + +#include + +enum { + EMPTY, + VETH, + MACVLAN, + PHYS, + MAXCONFTYPE, +}; + +/* + * Defines the structure to configure an ipv4 address + * @address : ipv4 address + * @broadcast : ipv4 broadcast address + * @mask : network mask + */ +struct lxc_inetdev { + struct in_addr addr; + struct in_addr bcast; + int prefix; +}; + +struct lxc_route { + struct in_addr addr; +}; + +/* + * Defines the structure to configure an ipv6 address + * @flags : set the address up + * @address : ipv6 address + * @broadcast : ipv6 broadcast address + * @mask : network mask + */ +struct lxc_inet6dev { + struct in6_addr addr; + struct in6_addr bcast; + struct in6_addr acast; + int prefix; +}; + +struct lxc_route6 { + struct in6_addr addr; +}; +/* + * Defines a structure to configure a network device + * @ifname : network device name + * @flags : flag of the network device (IFF_UP, ... ) + * @ipv4 : a list of ipv4 addresses to be set on the network device + * @ipv6 : a list of ipv6 addresses to be set on the network device + */ +struct lxc_netdev { + int flags; + char *ifname; + char *newname; + char *hwaddr; + struct lxc_list ipv4; + struct lxc_list ipv6; + struct lxc_list route4; + struct lxc_list route6; +}; + +/* + * Defines the kind of the network to use + * @type : the type of the network virtualization + * @phys : phys configuration type + * @veth : veth configuration type + * @macvlan : macvlan configuration type + */ +struct lxc_network { + int type; + struct lxc_list netdev; +}; + +/* + * Defines a structure to configure the control data and path + */ +struct lxc_cgroup { + ; +}; + +/* + * Defines the global container configuration + * @chroot : the root directory to run the container + * @mount : the list of mount points + * @network : the network configuration + * @utsname : the container utsname + */ +struct lxc_conf { + char *chroot; + char *fstab; + struct utsname *utsname; + struct lxc_cgroup *cgroup; + struct lxc_list networks; +}; + +/* + * Configure the external resources for the container + */ +extern int lxc_configure(const char *name, struct lxc_conf *conf); + +/* + * Remove the resources created by the configuration + */ +extern int lxc_unconfigure(const char *name); + +extern int conf_create_network(const char *name, pid_t pid); + +extern int conf_destroy_network(const char *name); + +/* + * Configure the container from inside + */ +extern int lxc_setup(const char *name); + +extern int conf_has(const char *name, const char *info); + +#define conf_has_fstab(__name) conf_has(__name, "fstab") +#define conf_has_chroot(__name) conf_has(__name, "chroot") +#define conf_has_utsname(__name) conf_has(__name, "utsname") +#define conf_has_network(__name) conf_has(__name, "network") + +#endif diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c new file mode 100644 index 000000000..8939405fe --- /dev/null +++ b/src/lxc/lxc_info.c @@ -0,0 +1,66 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include + +#include + +void usage(char *cmd) +{ + fprintf(stderr, "%s \n", basename(cmd)); + fprintf(stderr, "\t -n : name of the container\n"); + _exit(1); +} + +int main(int argc, char *argv[]) +{ + char opt; + char *name = NULL; + int state, nbargs = 0; + + while ((opt = getopt(argc, argv, "n:")) != -1) { + switch (opt) { + case 'n': + name = optarg; + break; + } + + nbargs++; + } + + if (!name) + usage(argv[0]); + + state = lxc_getstate(name); + if (state < 0) { + fprintf(stderr, "failed to freeze '%s'\n", name); + return 1; + } + + printf("'%s' is %s\n", name, lxc_state2str(state)); + + return 0; +} + diff --git a/src/lxc/lxc_list.c b/src/lxc/lxc_list.c new file mode 100644 index 000000000..d588ae2e1 --- /dev/null +++ b/src/lxc/lxc_list.c @@ -0,0 +1,23 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include diff --git a/src/lxc/lxc_list.h b/src/lxc/lxc_list.h new file mode 100644 index 000000000..45c04fb1f --- /dev/null +++ b/src/lxc/lxc_list.h @@ -0,0 +1,57 @@ +#ifndef _list_h +#define _list_h + +struct lxc_list { + void *elem; + struct lxc_list *next; + struct lxc_list *prev; +}; + +#define lxc_init_list(l) { .next = l, .prev = l, } + +#define lxc_list_for_each(__iterator, __list) \ + for (__iterator = (__list)->next; \ + __iterator != __list; \ + __iterator = __iterator->next) + +static inline void lxc_list_init(struct lxc_list *list) +{ + list->elem = NULL; + list->next = list->prev = list; +} + +static inline void lxc_list_add_elem(struct lxc_list *list, void *elem) +{ + list->elem = elem; +} + +static inline void *lxc_list_first_elem(struct lxc_list *list) +{ + return list->next->elem; +} + +static inline int lxc_list_empty(struct lxc_list *list) +{ + return list == list->next; +} + +static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list) +{ + struct lxc_list *next = head->next; + next->prev = list; + list->next = next; + list->prev = head; + head->next = list; +} + +static inline void lxc_list_del(struct lxc_list *list) +{ + struct lxc_list *next, *prev; + + next = list->next; + prev = list->prev; + next->prev = prev; + prev->next = next; +} + +#endif diff --git a/src/lxc/lxc_lock.c b/src/lxc/lxc_lock.c new file mode 100644 index 000000000..dcbd49fa2 --- /dev/null +++ b/src/lxc/lxc_lock.c @@ -0,0 +1,64 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include + +#include + +int lxc_get_lock(const char *name) +{ + char *lock; + int fd, ret; + + asprintf(&lock, LXCPATH "/%s", name); + fd = open(lock, O_RDONLY|O_DIRECTORY, S_IRUSR|S_IWUSR); + if (fd < 0) { + ret = -errno; + goto out; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (flock(fd, LOCK_EX|LOCK_NB)) { + ret = errno == EWOULDBLOCK ? 0 : -errno; + close(fd); + goto out; + } + + ret = fd; +out: + free(lock); + return ret; +} + +void lxc_put_lock(int lock) +{ + flock(lock, LOCK_UN); + close(lock); +} diff --git a/src/lxc/lxc_lock.h b/src/lxc/lxc_lock.h new file mode 100644 index 000000000..ed72b0e5d --- /dev/null +++ b/src/lxc/lxc_lock.h @@ -0,0 +1,30 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _lock_h +#define _lock_h + +extern int lxc_get_lock(const char *name); + +extern void lxc_put_lock(int lock); + +#endif diff --git a/src/lxc/lxc_log.c b/src/lxc/lxc_log.c new file mode 100644 index 000000000..7b962dcef --- /dev/null +++ b/src/lxc/lxc_log.c @@ -0,0 +1,9 @@ +#include +#include +#include + +#include + +#define MAXTIMELEN 47; +#define ERRNO_FORMAT "%d (%s)" + diff --git a/src/lxc/lxc_log.h b/src/lxc/lxc_log.h new file mode 100644 index 000000000..620e10c35 --- /dev/null +++ b/src/lxc/lxc_log.h @@ -0,0 +1,20 @@ +#ifndef _log_h +#define _log_h + +#define lxc_log(format, level, ...) do { \ + fprintf(stderr, "[%s] \t%s:%d - " format "\n", \ + level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +#define lxc_log_error(format, ...) lxc_log(format, "error", ##__VA_ARGS__); +#define lxc_log_warning(format, ...) lxc_log(format, "warning", ##__VA_ARGS__); +#define lxc_log_info(format, ...) lxc_log(format, "info", ##__VA_ARGS__); +#define lxc_log_debug(format, ...) lxc_log(format, "debug", ##__VA_ARGS__); +#define lxc_log_trace(format, ...) lxc_log(format, "trace", ##__VA_ARGS__); +#define lxc_log_syserror(format, ...) do { \ + fprintf(stderr, "[syserr] \t%s:%d: %s - " format "\n", \ + __FUNCTION__, __LINE__, strerror(errno), \ + ##__VA_ARGS__); \ + } while (0) + +#endif diff --git a/src/lxc/lxc_namespace.h b/src/lxc/lxc_namespace.h new file mode 100644 index 000000000..405936864 --- /dev/null +++ b/src/lxc/lxc_namespace.h @@ -0,0 +1,71 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __namespace_h +#define __namespace_h + +#include +#ifndef CLONE_FS +# define CLONE_FS 0x00000200 +#endif +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif +#ifndef __NR_unshare +# ifdef __i386__ +# define __NR_unshare 310 +# elif __x86_64__ +# define __NR_unshare 272 +# elif __ia64__ +# define __NR_unshare 1296 +# elif __s390__ +# define __NR_unshare 303 +# elif __powerpc__ +# define __NR_unshare 282 +#else +# error "unsupported architecture" +# endif +#endif +#if __i386__ || __x86_64__ || __s390__ || __powerpc__ +# define fork_ns(flags) syscall(SYS_clone, flags|SIGCHLD, NULL); +#elif __ia64__ +# define fork_ns(flags) syscall(SYS_clone2, flags|SIGCHLD, NULL); +#else +# error "unsupported architecture" +#endif +#define unshare_ns(flags) syscall(__NR_unshare, flags, NULL); +#endif diff --git a/src/lxc/lxc_state.c b/src/lxc/lxc_state.c index 8939405fe..3ef908038 100644 --- a/src/lxc/lxc_state.c +++ b/src/lxc/lxc_state.c @@ -21,46 +21,172 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include +#include +#include #include -#include #include +#include +#include +#include +#include #include +#include "monitor.h" + +static char *strstate[] = { + "STOPPED", "STARTING", "RUNNING", "STOPPING", + "ABORTING", "FREEZING", "FROZEN", +}; + +const char *lxc_state2str(lxc_state_t state) +{ + if (state < STOPPED || state > MAX_STATE - 1) + return NULL; + return strstate[state]; +} -void usage(char *cmd) +lxc_state_t lxc_str2state(const char *state) { - fprintf(stderr, "%s \n", basename(cmd)); - fprintf(stderr, "\t -n : name of the container\n"); - _exit(1); + int i, len; + len = sizeof(strstate)/sizeof(strstate[0]); + for (i = 0; i < len; i++) + if (!strcmp(strstate[i], state)) + return i; + return -1; } -int main(int argc, char *argv[]) +int lxc_setstate(const char *name, lxc_state_t state) { - char opt; - char *name = NULL; - int state, nbargs = 0; - - while ((opt = getopt(argc, argv, "n:")) != -1) { - switch (opt) { - case 'n': - name = optarg; - break; - } - - nbargs++; + int fd, err; + char file[MAXPATHLEN]; + const char *str = lxc_state2str(state); + + if (!str) + return -1; + + snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name); + + fd = open(file, O_WRONLY); + if (fd < 0) { + lxc_log_syserror("failed to open %s file", file); + return -1; } - if (!name) - usage(argv[0]); + if (flock(fd, LOCK_EX)) { + lxc_log_syserror("failed to take the lock to %s", file); + goto out; + } + + if (ftruncate(fd, 0)) { + lxc_log_syserror("failed to truncate the file %s", file); + goto out; + } - state = lxc_getstate(name); - if (state < 0) { - fprintf(stderr, "failed to freeze '%s'\n", name); - return 1; + if (write(fd, str, strlen(str)) < 0) { + lxc_log_syserror("failed to write state to %s", file); + goto out; } - printf("'%s' is %s\n", name, lxc_state2str(state)); + err = 0; +out: + close(fd); + lxc_monitor_send_state(name, state); + + /* let the event to be propagated, crappy but that works, + * otherwise the events will be folded into only one event, + * and I want to have them to be one by one in order + * to follow the different states of the container. + */ + usleep(200000); + + return -err; +} + +int lxc_mkstate(const char *name) +{ + int fd; + char file[MAXPATHLEN]; + + snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name); + fd = creat(file, S_IRUSR|S_IWUSR); + if (fd < 0) { + lxc_log_syserror("failed to create file %s", file); + return -1; + } + close(fd); + return 0; +} + +int lxc_rmstate(const char *name) +{ + char file[MAXPATHLEN]; + snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name); + unlink(file); return 0; } +lxc_state_t lxc_getstate(const char *name) +{ + int fd, err; + char file[MAXPATHLEN]; + + snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name); + + fd = open(file, O_RDONLY); + if (fd < 0) { + lxc_log_syserror("failed to open %s", file); + return -1; + } + + if (flock(fd, LOCK_SH)) { + lxc_log_syserror("failed to take the lock to %s", file); + close(fd); + return -1; + } + + err = read(fd, file, strlen(file)); + if (err < 0) { + lxc_log_syserror("failed to read file %s", file); + close(fd); + return -1; + } + file[err] = '\0'; + + close(fd); + return lxc_str2state(file); +} + +static int freezer_state(const char *name) +{ + char freezer[MAXPATHLEN]; + char status[MAXPATHLEN]; + FILE *file; + int err; + + snprintf(freezer, MAXPATHLEN, + LXCPATH "/%s/freezer.freeze", name); + + file = fopen(freezer, "r"); + if (!file) + return -1; + + err = fscanf(file, "%s", status); + fclose(file); + + if (err == EOF) { + lxc_log_syserror("failed to read %s", freezer); + return -1; + } + + return lxc_str2state(status); +} + +lxc_state_t lxc_state(const char *name) +{ + int state = freezer_state(name); + if (state != FROZEN && state != FREEZING) + state = lxc_getstate(name); + return state; +} diff --git a/src/lxc/lxc_state.h b/src/lxc/lxc_state.h new file mode 100644 index 000000000..871d1a8d5 --- /dev/null +++ b/src/lxc/lxc_state.h @@ -0,0 +1,39 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _state_h +#define _state_h + +typedef enum { + STOPPED, STARTING, RUNNING, STOPPING, + ABORTING, FREEZING, FROZEN, MAX_STATE, +} lxc_state_t; + +extern int lxc_mkstate(const char *name); +extern int lxc_rmstate(const char *name); +extern int lxc_setstate(const char *name, lxc_state_t state); +extern lxc_state_t lxc_getstate(const char *name); + +extern lxc_state_t lxc_str2state(const char *state); +extern const char *lxc_state2str(lxc_state_t state); + +#endif diff --git a/src/lxc/lxc_utils.h b/src/lxc/lxc_utils.h new file mode 100644 index 000000000..5fc3946fb --- /dev/null +++ b/src/lxc/lxc_utils.h @@ -0,0 +1,51 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _utils_h +#define _utils_h + +#define LXC_TTY_HANDLER(s) \ + static struct sigaction lxc_tty_sa_##s; \ + static void tty_##s##_handler(int sig, siginfo_t *info, void *ctx) \ + { \ + if (lxc_tty_sa_##s.sa_handler == SIG_DFL || \ + lxc_tty_sa_##s.sa_handler == SIG_IGN) \ + return; \ + (*lxc_tty_sa_##s.sa_sigaction)(sig, info, ctx); \ + } + +#define LXC_TTY_ADD_HANDLER(s) \ + do { \ + struct sigaction sa; \ + sa.sa_sigaction = tty_##s##_handler; \ + sa.sa_flags = SA_SIGINFO; \ + sigfillset(&sa.sa_mask); \ + /* No error expected with sigaction. */ \ + sigaction(s, &sa, &lxc_tty_sa_##s); \ + } while (0) + +#define LXC_TTY_DEL_HANDLER(s) \ + do { \ + sigaction(s, &lxc_tty_sa_##s, NULL); \ + } while (0) + +#endif diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c new file mode 100644 index 000000000..fec80fe8e --- /dev/null +++ b/src/lxc/monitor.c @@ -0,0 +1,171 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +int lxc_monitor(const char *name, int output_fd) +{ + char path[MAXPATHLEN]; + int err = -1, nfd, wfd, state; + + nfd = inotify_init(); + if (nfd < 0) { + lxc_log_syserror("failed to initialize inotify"); + return -1; + } + + snprintf(path, MAXPATHLEN, LXCPATH "/%s/state", name); + + wfd = inotify_add_watch(nfd, path, IN_DELETE_SELF|IN_CLOSE_WRITE); + if (wfd < 0) { + lxc_log_syserror("failed to add a watch on %s", path); + goto out; + } + + for(;;) { + struct inotify_event evt; + + if (read(nfd, &evt, sizeof(evt)) < 0) { + lxc_log_syserror("failed to read inotify event"); + goto out; + } + + if (evt.mask & IN_CLOSE_WRITE) { + + state = lxc_getstate(name); + if (state < 0) { + lxc_log_error("failed to get the state for %s", + name); + goto out; + } + + if (write(output_fd, &state, sizeof(state)) < 0) { + lxc_log_syserror("failed to send state to %d", + output_fd); + goto out; + } + continue; + } + + if (evt.mask & IN_DELETE_SELF) { + close(output_fd); + err = 0; + goto out; + } + + lxc_log_error("unknown evt for inotity (%d)", evt.mask); + goto out; + } + +out: + inotify_rm_watch(nfd, wfd); + close(nfd); + return err; +} + +void lxc_monitor_send_state(const char *name, lxc_state_t state) +{ + int fd; + struct sockaddr_un addr; + + fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) + lxc_log_syserror("failed to create notification socket"); + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name); + + sendto(fd, &state, sizeof(state), 0, + (const struct sockaddr *)&addr, sizeof(addr)); + + close(fd); +} + +void lxc_monitor_cleanup(const char *name) +{ + char path[UNIX_PATH_MAX]; + snprintf(path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name); + unlink(path); +} + +int lxc_monitor_open(const char *name) +{ + int fd; + struct sockaddr_un addr; + + fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + lxc_log_syserror("failed to create notification socket"); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name); + unlink(addr.sun_path); + + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr))) { + lxc_log_syserror("failed to bind to '%s'", addr.sun_path); + close(fd); + return -1; + } + + return fd; +} + +int lxc_monitor_read(int fd, lxc_state_t *state) +{ + int ret; + + ret = recv(fd, state, sizeof(*state), 0); + if (ret < 0) { + lxc_log_syserror("failed to received state"); + return -1; + } + + return ret; +} + +int lxc_monitor_close(int fd) +{ + return close(fd); +} diff --git a/src/lxc/monitor.h b/src/lxc/monitor.h new file mode 100644 index 000000000..a282986c1 --- /dev/null +++ b/src/lxc/monitor.h @@ -0,0 +1,29 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __monitor_h +#define __monitor_h + +void lxc_monitor_send_state(const char *name, lxc_state_t state); +void lxc_monitor_cleanup(const char *name); + +#endif diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h new file mode 100644 index 000000000..405936864 --- /dev/null +++ b/src/lxc/namespace.h @@ -0,0 +1,71 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __namespace_h +#define __namespace_h + +#include +#ifndef CLONE_FS +# define CLONE_FS 0x00000200 +#endif +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif +#ifndef __NR_unshare +# ifdef __i386__ +# define __NR_unshare 310 +# elif __x86_64__ +# define __NR_unshare 272 +# elif __ia64__ +# define __NR_unshare 1296 +# elif __s390__ +# define __NR_unshare 303 +# elif __powerpc__ +# define __NR_unshare 282 +#else +# error "unsupported architecture" +# endif +#endif +#if __i386__ || __x86_64__ || __s390__ || __powerpc__ +# define fork_ns(flags) syscall(SYS_clone, flags|SIGCHLD, NULL); +#elif __ia64__ +# define fork_ns(flags) syscall(SYS_clone2, flags|SIGCHLD, NULL); +#else +# error "unsupported architecture" +#endif +#define unshare_ns(flags) syscall(__NR_unshare, flags, NULL); +#endif diff --git a/src/lxc/network.c b/src/lxc/network.c new file mode 100644 index 000000000..6e1048171 --- /dev/null +++ b/src/lxc/network.c @@ -0,0 +1,727 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCe +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef IFLA_LINKMODE +# define IFLA_LINKMODE 17 +#endif + +#ifndef IFLA_LINKINFO +# define IFLA_LINKINFO 18 +#endif + +#ifndef IFLA_NET_NS_PID +# define IFLA_NET_NS_PID 19 +#endif + +#ifndef IFLA_INFO_KIND +# define IFLA_INFO_KIND 1 +#endif + +#ifndef IFLA_INFO_DATA +# define IFLA_INFO_DATA 2 +#endif + +#ifndef VETH_INFO_PEER +# define VETH_INFO_PEER 1 +#endif + +struct link_req { + struct nlmsg nlmsg; + struct ifinfomsg ifinfomsg; +}; + +struct ip_req { + struct nlmsg nlmsg; + struct ifaddrmsg ifa; +}; + +int device_move(const char *name, pid_t pid) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL; + struct link_req *link_req; + int index, len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(name); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + index = if_nametoindex(name); + if (!index) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + link_req->ifinfomsg.ifi_index = index; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + + if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) + goto out; + + if (nla_put_string(nlmsg, IFLA_IFNAME, name)) + goto out; + + if (netlink_transaction(&nlh, nlmsg, nlmsg)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(nlmsg); + return err; +} + +extern int device_delete(const char *name) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct link_req *link_req; + int index, len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(name); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + index = if_nametoindex(name); + if (!index) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + link_req->ifinfomsg.ifi_index = index; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; + nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK; + + if (nla_put_string(nlmsg, IFLA_IFNAME, name)) + goto out; + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +static int device_set_flag(const char *name, int flag) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct link_req *link_req; + int index, len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(name); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + index = if_nametoindex(name); + if (!index) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + link_req->ifinfomsg.ifi_index = index; + link_req->ifinfomsg.ifi_change |= IFF_UP; + link_req->ifinfomsg.ifi_flags |= flag; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + + err = netlink_transaction(&nlh, nlmsg, answer); + if (err < 0) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(nlmsg); + nlmsg_free(answer); + return err; +} + +int device_up(const char *name) +{ + return device_set_flag(name, IFF_UP); +} + +int device_down(const char *name) +{ + return device_set_flag(name, 0); +} + +int device_rename(const char *oldname, const char *newname) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct link_req *link_req; + int index, len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(oldname); + if (len == 1 || len > IFNAMSIZ) + goto out; + + len = strlen(newname); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + index = if_nametoindex(oldname); + if (!index) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + link_req->ifinfomsg.ifi_index = index; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; + nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + + if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) + goto out; + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +int veth_create(const char *name1, const char *name2) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct link_req *link_req; + struct rtattr *nest1, *nest2, *nest3; + int len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(name1); + if (len == 1 || len > IFNAMSIZ) + goto out; + + len = strlen(name2); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; + nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + + nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); + if (!nest1) + goto out; + + if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth")) + goto out; + + nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); + if (!nest2) + goto out; + + nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER); + if (!nest3) + goto out; + + nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg); + + if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) + goto out; + + nla_end_nested(nlmsg, nest3); + + nla_end_nested(nlmsg, nest2); + + nla_end_nested(nlmsg, nest1); + + if (nla_put_string(nlmsg, IFLA_IFNAME, name1)) + goto out; + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +int macvlan_create(const char *master, const char *name) +{ + struct nl_handler nlh; + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct link_req *link_req; + struct rtattr *nest; + int index, len, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + len = strlen(master); + if (len == 1 || len > IFNAMSIZ) + goto out; + + len = strlen(name); + if (len == 1 || len > IFNAMSIZ) + goto out; + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + index = if_nametoindex(master); + if (!index) + goto out; + + link_req = (struct link_req *)nlmsg; + link_req->ifinfomsg.ifi_family = AF_UNSPEC; + nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + nlmsg->nlmsghdr.nlmsg_flags = + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; + nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + + nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); + if (!nest) + goto out; + + if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan")) + goto out; + + nla_end_nested(nlmsg, nest); + + if (nla_put_u32(nlmsg, IFLA_LINK, index)) + goto out; + + if (nla_put_string(nlmsg, IFLA_IFNAME, name)) + goto out; + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +static int proc_sys_net_write(const char *path, const char *value) +{ + int fd, err = 0; + + fd = open(path, O_WRONLY); + if (fd < 0) + return -errno; + + if (write(fd, value, strlen(value)) < 0) + err = -errno; + + close(fd); + return err; +} + +static int ip_forward_set(const char *ifname, int family, int flag) +{ + char *path; + int ret; + + if (family != AF_INET && family != AF_INET6) + return -1; + + asprintf(&path, "/proc/sys/net/%s/conf/%s/forwarding", + family == AF_INET?"ipv4":"ipv6" , ifname); + + ret = proc_sys_net_write(path, flag?"1":"0"); + free(path); + + return ret; +} + +int ip_forward_on(const char *ifname, int family) +{ + return ip_forward_set(ifname, family, 1); +} + +int ip_forward_off(const char *ifname, int family) +{ + return ip_forward_set(ifname, family, 0); +} + +static int neigh_proxy_set(const char *ifname, int family, int flag) +{ + char path[MAXPATHLEN]; + + if (family != AF_INET && family != AF_INET6) + return -1; + + sprintf(path, "/proc/sys/net/%s/conf/%s/%s", + family == AF_INET?"ipv4":"ipv6" , ifname, + family == AF_INET?"proxy_arp":"proxy_ndp"); + + return proc_sys_net_write(path, flag?"1":"0"); +} + +int neigh_proxy_on(const char *name, int family) +{ + return neigh_proxy_set(name, family, 1); +} + +int neigh_proxy_off(const char *name, int family) +{ + return neigh_proxy_set(name, family, 0); +} + +int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr) +{ + unsigned char *data; + char c; + int i = 0; + unsigned val; + + sockaddr->sa_family = ARPHRD_ETHER; + data = (unsigned char *)sockaddr->sa_data; + + while ((*macaddr != '\0') && (i < ETH_ALEN)) { + val = 0; + c = *macaddr++; + if (isdigit(c)) + val = c - '0'; + else if (c >= 'a' && c <= 'f') + val = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = c - 'A' + 10; + else { + return -1; + } + val <<= 4; + c = *macaddr; + if (isdigit(c)) + val |= c - '0'; + else if (c >= 'a' && c <= 'f') + val |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val |= c - 'A' + 10; + else if (c == ':' || c == 0) + val >>= 4; + else { + return -1; + } + if (c != 0) + macaddr++; + *data++ = (unsigned char) (val & 0377); + i++; + + if (*macaddr == ':') + macaddr++; + } + + return 0; +} + +int ip_addr_add(const char *ifname, const char *addr, + int prefix, const char *bcast) +{ + struct nl_handler nlh; + struct in_addr in_addr; +/* struct in_addr in_bcast; */ + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct ip_req *ip_req; + int ifindex, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + if (inet_pton(AF_INET, addr, (void *)&in_addr) < 0) + goto out; + +/* if (inet_pton(AF_INET, bcast, (void *)&in_bcast) < 0) */ +/* goto out; */ + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + ifindex = if_nametoindex(ifname); + if (!ifindex) + goto out; + + ip_req = (struct ip_req *)nlmsg; + ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + ip_req->nlmsg.nlmsghdr.nlmsg_flags = + NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; + ip_req->ifa.ifa_prefixlen = prefix; + ip_req->ifa.ifa_index = ifindex; + ip_req->ifa.ifa_family = AF_INET; + ip_req->ifa.ifa_scope = 0; + + if (nla_put_buffer(nlmsg, IFA_LOCAL, &in_addr, sizeof(in_addr))) + goto out; + + if (nla_put_buffer(nlmsg, IFA_ADDRESS, &in_addr, sizeof(in_addr))) + goto out; + +/* if (in_bcast.s_addr != INADDR_ANY) */ +/* if (nla_put_buffer(nlmsg, IFA_BROADCAST, &in_bcast, */ +/* sizeof(in_bcast))) */ +/* goto out; */ + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +int ip6_addr_add(const char *ifname, const char *addr, + int prefix, const char *bcast) +{ + struct nl_handler nlh; + struct in6_addr in6_addr; +/* struct in6_addr in6_bcast; */ + struct nlmsg *nlmsg = NULL, *answer = NULL; + struct ip_req *ip_req; + int ifindex, err = -1; + + if (netlink_open(&nlh, NETLINK_ROUTE)) + return -1; + + if (inet_pton(AF_INET6, addr, (void *)&in6_addr) < 0) + goto out; + + +/* if (inet_pton(AF_INET6, bcast, (void *)&in6_bcast) < 0) */ +/* goto out; */ + + nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!nlmsg) + goto out; + + answer = nlmsg_alloc(NLMSG_GOOD_SIZE); + if (!answer) + goto out; + + ifindex = if_nametoindex(ifname); + if (!ifindex) + goto out; + + ip_req = (struct ip_req *)nlmsg; + ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + ip_req->nlmsg.nlmsghdr.nlmsg_flags = + NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; + ip_req->ifa.ifa_prefixlen = prefix; + ip_req->ifa.ifa_index = ifindex; + ip_req->ifa.ifa_family = AF_INET6; + ip_req->ifa.ifa_scope = 0; + + if (nla_put_buffer(nlmsg, IFA_LOCAL, &in6_addr, sizeof(in6_addr))) + goto out; + + if (nla_put_buffer(nlmsg, IFA_ADDRESS, &in6_addr, sizeof(in6_addr))) + goto out; + +/* if (in6_bcast.s6_addr != in6addr_any.s6_addr) */ +/* if (nla_put_buffer(nlmsg, IFA_BROADCAST, &in6_bcast, */ +/* sizeof(in6_bcast))) */ +/* goto out; */ + + if (netlink_transaction(&nlh, nlmsg, answer)) + goto out; + + err = 0; +out: + netlink_close(&nlh); + nlmsg_free(answer); + nlmsg_free(nlmsg); + return err; +} + +static int bridge_add_del_interface(const char *bridge, + const char *ifname, int detach) +{ + int fd, index, err; + struct ifreq ifr; + + if (strlen(ifname) > IFNAMSIZ) + return -1; + + index = if_nametoindex(ifname); + if (!index) + return -1; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_ifindex = index; + err = ioctl(fd, detach?SIOCBRDELIF:SIOCBRADDIF, &ifr); + close(fd); + + return err; +} + +int bridge_attach(const char *bridge, const char *ifname) +{ + return bridge_add_del_interface(bridge, ifname, 0); +} + +int bridge_detach(const char *bridge, const char *ifname) +{ + return bridge_add_del_interface(bridge, ifname, 1); +} + +int lxc_configure_veth(const char *veth1, const char *veth2, const char *bridge) +{ + int err = -1; + if (veth_create(veth1, veth2)) { + fprintf(stderr, "failed to create veth interfaces %s/%s\n", + veth1, veth2); + return -1; + } + + if (bridge_attach(bridge, veth1)) { + fprintf(stderr, "failed to attach %s to %s\n", + veth1, bridge); + goto err; + } + + err = 0; +out: + return err; +err: + device_delete(veth1); + goto out; +} + +int lxc_configure_macvlan(const char *link, const char *peer) +{ + if (macvlan_create(link, peer)) { + fprintf(stderr, "failed to create %s", peer); + return -1; + } + return 0; +} diff --git a/src/lxc/network.h b/src/lxc/network.h new file mode 100644 index 000000000..223276ef7 --- /dev/null +++ b/src/lxc/network.h @@ -0,0 +1,126 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _network_h +#define _network_h + +/* + * Create a macvlan network device + */ +extern int lxc_configure_macvlan(const char *link, const char *peer); + +/* + * Create a veth pair virtual device + */ +extern int lxc_configure_veth(const char *veth1, const char *veth2, + const char *bridge); + +/* + * Convert a string mac address to a socket structure + */ +extern int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr); + +/* + * Move a device between namespaces + */ +extern int device_move(const char *name, pid_t pid); + +/* + * Delete a network device + */ +extern int device_delete(const char *name); + +/* + * Set the device network up + */ +extern int device_up(const char *name); + +/* + * Set the device network down + */ +extern int device_down(const char *name); + +/* + * Change the device name + */ +extern int device_rename(const char *oldname, const char *newname); + +/* + * Create a veth network device + */ +extern int veth_create(const char *name1, const char *name2); + +/* + * Create a macvlan network device + */ +extern int macvlan_create(const char *master, const char *name); + +/* + * Activate forwarding + */ +extern int ip_forward_on(const char *name, int family); + +/* + * Disable forwarding + */ +extern int ip_forward_off(const char *name, int family); + +/* + * Set ip address + */ +extern int ip_addr_add(const char *ifname, const char *addr, + int prefix, const char *bcast); + +extern int ip6_addr_add(const char *ifname, const char *addr, + int prefix, const char *bcast); + +/* + * Attach an interface to the bridge + */ +extern int bridge_attach(const char *bridge, const char *ifname); + +/* + * Detach an interface from the bridge + */ +extern int bridge_detach(const char *bridge, const char *ifname); + +/* + * Create default gateway + */ +extern int route_create_default(const char *addr, const char *ifname, int gateway); + +/* + * Delete default gateway + */ +extern int route_delete_default(const char *addr, const char *ifname, int gateway); + +/* + * Activate neighbor proxying + */ +extern int neigh_proxy_on(const char *name, int family); + +/* + * Disable neighbor proxying + */ +extern int neigh_proxy_off(const char *name, int family); + +#endif diff --git a/src/lxc/nl.c b/src/lxc/nl.c new file mode 100644 index 000000000..261ffb527 --- /dev/null +++ b/src/lxc/nl.c @@ -0,0 +1,260 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +extern size_t nlmsg_len(const struct nlmsg *nlmsg) +{ + return nlmsg->nlmsghdr.nlmsg_len - NLMSG_HDRLEN; +} + +extern void *nlmsg_data(struct nlmsg *nlmsg) +{ + char *data = ((char *)nlmsg) + NLMSG_ALIGN(sizeof(struct nlmsghdr)); + if (!nlmsg_len(nlmsg)) + return NULL; + return data; +} + +static int nla_put(struct nlmsg *nlmsg, int attr, + const void *data, size_t len) +{ + struct rtattr *rta; + size_t rtalen = RTA_LENGTH(len); + + rta = NLMSG_TAIL(&nlmsg->nlmsghdr); + rta->rta_type = attr; + rta->rta_len = rtalen; + memcpy(RTA_DATA(rta), data, len); + nlmsg->nlmsghdr.nlmsg_len = + NLMSG_ALIGN(nlmsg->nlmsghdr.nlmsg_len) + RTA_ALIGN(rtalen); + return 0; +} + +extern int nla_put_buffer(struct nlmsg *nlmsg, int attr, + const void *data, size_t size) +{ + return nla_put(nlmsg, attr, data, size); +} + +extern int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string) +{ + return nla_put(nlmsg, attr, string, strlen(string) + 1); +} + +extern int nla_put_u32(struct nlmsg *nlmsg, int attr, int value) +{ + return nla_put(nlmsg, attr, &value, sizeof(value)); +} + +extern int nla_put_attr(struct nlmsg *nlmsg, int attr) +{ + return nla_put(nlmsg, attr, NULL, 0); +} + +struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr) +{ + struct rtattr *rtattr = NLMSG_TAIL(&nlmsg->nlmsghdr); + + if (nla_put_attr(nlmsg, attr)) + return NULL; + + return rtattr; +} + +void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr) +{ + attr->rta_len = (void *)NLMSG_TAIL(&nlmsg->nlmsghdr) - (void *)attr; +} + +extern struct nlmsg *nlmsg_alloc(size_t size) +{ + struct nlmsg *nlmsg; + size_t len = NLMSG_ALIGN(size) + NLMSG_ALIGN(sizeof(struct nlmsghdr *)); + + nlmsg = (struct nlmsg *)malloc(len); + if (!nlmsg) + return NULL; + + memset(nlmsg, 0, len); + nlmsg->nlmsghdr.nlmsg_len = NLMSG_ALIGN(size); + + return nlmsg; +} + +extern void nlmsg_free(struct nlmsg *nlmsg) +{ + free(nlmsg); +} + +extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) +{ + int ret; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = answer, + .iov_len = answer->nlmsghdr.nlmsg_len, + }; + + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + +again: + ret = recvmsg(handler->fd, &msg, 0); + if (ret < 0) { + if (errno == EINTR) + goto again; + return -errno; + } + + if (!ret) + return 0; + + if (msg.msg_flags & MSG_TRUNC) + return -EMSGSIZE; + + return ret; +} + +extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) +{ + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = (void*)nlmsg, + .iov_len = nlmsg->nlmsghdr.nlmsg_len, + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + int ret; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + ret = sendmsg(handler->fd, &msg, 0); + if (ret < 0) { + return -errno; + } + + return ret; +} + +extern int netlink_transaction(struct nl_handler *handler, + struct nlmsg *request, struct nlmsg *answer) +{ + + int ret; + + ret = netlink_send(handler, request); + if (ret < 0) + return ret; + + ret = netlink_rcv(handler, answer); + if (ret < 0) + return ret; + + if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer); + errno = -err->error; + return -errno; + } + + return 0; +} + +extern int netlink_open(struct nl_handler *handler, int protocol) +{ + socklen_t socklen; + int sndbuf = 32768; + int rcvbuf = 32768; + + memset(handler, 0, sizeof(*handler)); + + handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (handler->fd < 0) + return -errno; + + if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, + &sndbuf, sizeof(sndbuf)) < 0) + return -errno; + + if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, + &rcvbuf,sizeof(rcvbuf)) < 0) + return -errno; + + memset(&handler->local, 0, sizeof(handler->local)); + handler->local.nl_family = AF_NETLINK; + handler->local.nl_groups = 0; + + if (bind(handler->fd, (struct sockaddr*)&handler->local, + sizeof(handler->local)) < 0) + return -errno; + + socklen = sizeof(handler->local); + if (getsockname(handler->fd, (struct sockaddr*)&handler->local, + &socklen) < 0) + return -errno; + + if (socklen != sizeof(handler->local)) + return -EINVAL; + + if (handler->local.nl_family != AF_NETLINK) + return -EINVAL; + + handler->seq = time(NULL); + + return 0; +} + +extern int netlink_close(struct nl_handler *handler) +{ + close(handler->fd); + handler->fd = -1; + return 0; +} + diff --git a/src/lxc/nl.h b/src/lxc/nl.h new file mode 100644 index 000000000..2f760de2c --- /dev/null +++ b/src/lxc/nl.h @@ -0,0 +1,228 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __nl_h +#define __nl_h + +/* + * Use this as a good size to allocate generic netlink messages + */ +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#define NLMSG_GOOD_SIZE (2*PAGE_SIZE) +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN)) +#define NLA_NEXT_ATTR(attr) ((void *)((char *)attr) + NLA_ALIGN(attr->nla_len)) + +/* + * struct nl_handler : the handler for netlink sockets, this structure + * is used all along the netlink socket life cycle to specify the + * netlink socket to be used. + * + * @fd: the file descriptor of the netlink socket + * @seq: the sequence number of the netlink messages + * @local: the bind address + * @peer: the peer address + */ +struct nl_handler { + int fd; + int seq; + struct sockaddr_nl local; + struct sockaddr_nl peer; +}; + +/* + * struct nlmsg : the netlink message structure, it consists just + * on a definition for a nlmsghdr. This message is to be used to + * be allocated with netlink_alloc. + * @nlmsghdr : a pointer to a netlink message header, this field + * _must_ be always the first field of this structure + */ +struct nlmsg { + struct nlmsghdr nlmsghdr; +}; + +/* + * netlink_open : open a netlink socket, the function will + * fill the handler with the right value + * + * @handler: a netlink handler to be used all along the netlink + * socket life cycle + * @protocol: specify the protocol to be used when opening the + * netlink socket + * + * Return 0 on success, < 0 otherwise + */ +int netlink_open(struct nl_handler *handler, int protocol); + +/* + * netlink_close : close a netlink socket, after this call, + * the handler is no longer valid + * + * @handler: a handler to the netlink socket + * + * Returns 0 on success, < 0 otherwise + */ +int netlink_close(struct nl_handler *handler); + +/* + * netlink_rcv : receive a netlink message from the kernel. + * It is up to the caller to manage the allocation of the + * netlink message + * + * @handler: a handler to the netlink socket + * @nlmsg: a netlink message + * + * Returns 0 on success, < 0 otherwise + */ +int netlink_rcv(struct nl_handler *handler, struct nlmsg *nlmsg); + +/* + * netlink_send: send a netlink message to the kernel. It is up + * to the caller to manage the allocate of the netlink message + * + * @handler: a handler to the netlink socket + * @nlmsg: a netlink message + * + * Returns 0 on success, < 0 otherwise + */ +int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg); + +/* + * netlink_transaction: send a request to the kernel and read the response. + * This is useful for transactional protocol. It is up to the caller + * to manage the allocation of the netlink message. + * + * @handler: a handler to a opened netlink socket + * @request: a netlink message pointer containing the request + * @answer: a netlink message pointer to receive the result + * + * Returns 0 on success, < 0 otherwise + */ +int netlink_transaction(struct nl_handler *handler, + struct nlmsg *request, struct nlmsg *anwser); + +/* + * nla_put_string: copy a null terminated string to a netlink message + * attribute + * + * @nlmsg: the netlink message to be filled + * @attr: the attribute name of the string + * @string: a null terminated string to be copied to the netlink message + * + * Returns 0 on success, < 0 otherwise + */ +int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string); + +/* + * nla_put_buffer: copy a buffer with a specified size to a netlink + * message attribute + * + * @nlmsg: the netlink message to be filled + * @attr: the attribute name of the string + * @data: a pointer to a buffer + * @size: the size of the buffer + * + * Returns 0 on success, < 0 otherwise + */ +int nla_put_buffer(struct nlmsg *nlmsg, int attr, + const void *data, size_t size); + +/* + * nla_put_u32: copy an integer to a netlink message attribute + * + * @nlmsg: the netlink message to be filled + * @attr: the attribute name of the integer + * @string: an integer to be copied to the netlink message + * + * Returns 0 on success, < 0 otherwise + */ +int nla_put_u32(struct nlmsg *nlmsg, int attr, int value); + +/* + * nla_put_attr: add an attribute name to a netlink + * + * @nlmsg: the netlink message to be filled + * @attr: the attribute name of the integer + * + * Returns 0 on success, < 0 otherwise + */ +int nla_put_attr(struct nlmsg *nlmsg, int attr); + +/* + * nla_begin_nested: begin the nesting attribute + * + * @nlmsg: the netlink message to be filled + * @attr: the netsted attribute name + * + * Returns current nested pointer to be reused + * to nla_end_nested. + */ +struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr); + +/* + * nla_end_nested: end the nesting attribute + * + * @nlmsg: the netlink message + * @nested: the nested pointer + * + * Returns the current + */ +void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr); + +/* + * nlmsg_allocate : allocate a netlink message. The netlink format message + * is a header, a padding, a payload and a padding again. + * When a netlink message is allocated, the size specify the + * payload we want. So the real size of the allocated message + * is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding), + * in other words, the function will allocate more than specified. When + * the buffer is allocated, the content is zeroed. + * The function will also fill the field nlmsg_len with computed size. + * If the allocation must be for the specified size, just use malloc. + * + * @size: the size of the payload to be allocated + * + * Returns a pointer to the newly allocated netlink message, NULL otherwise + */ +struct nlmsg *nlmsg_alloc(size_t size); + +/* + * nlmsg_free : free a previously allocate message + * + * @nlmsg: the netlink message to be freed + */ +void nlmsg_free(struct nlmsg *nlmsg); + +/* + * nlmsg_data : returns a pointer to the data contained in the netlink message + * + * @nlmsg : the netlink message to get the data + * + * Returns a pointer to the netlink data or NULL if there is no data + */ +void *nlmsg_data(struct nlmsg *nlmsg); + + +#endif diff --git a/src/lxc/rtnl.c b/src/lxc/rtnl.c new file mode 100644 index 000000000..bc2354287 --- /dev/null +++ b/src/lxc/rtnl.c @@ -0,0 +1,72 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int rtnetlink_open(struct rtnl_handler *handler) +{ + return netlink_open(&handler->nlh, NETLINK_ROUTE); +} + +extern int rtnetlink_close(struct rtnl_handler *handler) +{ + return netlink_close(&handler->nlh); +} + +extern int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg) +{ + return netlink_rcv(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr); +} + +extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg) +{ + + return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr); +} + +extern int rtnetlink_transaction(struct rtnl_handler *handler, + struct rtnlmsg *request, struct rtnlmsg *answer) +{ + return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr, + (struct nlmsg *)&answer->nlmsghdr); +} + +extern struct rtnlmsg *rtnlmsg_alloc(size_t size) +{ +/* size_t len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtnlmsghdr))) + size; */ +/* return (struct rtnlmsg *)nlmsg_alloc(len); */ + return NULL; +} + +extern void rtnlmsg_free(struct rtnlmsg *rtnlmsg) +{ + free(rtnlmsg); +} diff --git a/src/lxc/rtnl.h b/src/lxc/rtnl.h new file mode 100644 index 000000000..63aca0ad8 --- /dev/null +++ b/src/lxc/rtnl.h @@ -0,0 +1,110 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __genl_h +#define __genl_h + +/* + * Use this as a good size to allocate route netlink messages + */ +#define RTNLMSG_GOOD_SIZE NLMSG_GOOD_SIZE +#define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN)) + +/* + * struct genl_handler : the structure which store the netlink handler + * and the family number + * + * @nlh: the netlink socket handler + */ +struct rtnl_handler +{ + struct nl_handler nlh; +}; + +/* + * struct rtnlmsg : the struct containing the route netlink message + * format + * + * @nlmsghdr: a netlink message header + * @rtnlmsghdr: a route netlink message header pointer + * + */ +struct rtnlmsg { + struct nlmsghdr nlmsghdr; +}; + +/* + * rtnetlink_open : open a route netlink socket + * + * @handler: a struct rtnl_handler pointer + * + * Returns 0 on success, < 0 otherwise + */ +int rtnetlink_open(struct rtnl_handler *handler); + +/* + * genetlink_close : close a route netlink socket + * + * @handler: the handler of the socket to be closed + * + * Returns 0 on success, < 0 otherwise + */ +int rtnetlink_close(struct rtnl_handler *handler); + +/* + * rtnetlink_rcv : receive a route netlink socket, it is up + * to the caller to manage the allocation of the route netlink message + * + * @handler: the handler of the route netlink socket + * @rtnlmsg: the pointer to a route netlink message pre-allocated + * + * Returns 0 on success, < 0 otherwise + */ +int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg); + +/* + * rtnetlink_send : send a route netlink socket, it is up + * to the caller to manage the allocation of the route netlink message + * + * @handler: the handler of the route netlink socket + * @rtnlmsg: the pointer to a netlink message pre-allocated + * + * Returns 0 on success, < 0 otherwise + */ +int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg); + +struct genlmsg *genlmsg_alloc(size_t size); + +void rtnlmsg_free(struct rtnlmsg *rtnlmsg); + +/* + * rtnetlink_transaction : send and receive a route netlink message in one shot + * + * @handler: the handler of the route netlink socket + * @request: a route netlink message containing the request to be sent + * @answer: a pre-allocated route netlink message to receive the response + * + * Returns 0 on success, < 0 otherwise + */ +int rtnetlink_transaction(struct rtnl_handler *handler, + struct rtnlmsg *request, struct rtnlmsg *answer); +#endif diff --git a/src/lxc/start.c b/src/lxc/start.c new file mode 100644 index 000000000..08eb5bb1e --- /dev/null +++ b/src/lxc/start.c @@ -0,0 +1,253 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +LXC_TTY_HANDLER(SIGINT); +LXC_TTY_HANDLER(SIGQUIT); + +int lxc_start(const char *name, int argc, char *argv[], + lxc_callback_t prestart, void *data) +{ + char *init = NULL, *val = NULL; + int fd, lock, sv[2], sync = 0, err = -1; + pid_t pid; + int clone_flags; + + lock = lxc_get_lock(name); + if (!lock) { + lxc_log_error("'%s' is busy", name); + return -1; + } + + if (lock < 0) { + lxc_log_error("failed to acquire lock on '%s':%s", + name, strerror(-lock)); + return -1; + } + + fcntl(lock, F_SETFD, FD_CLOEXEC); + + /* Begin the set the state to STARTING*/ + if (lxc_setstate(name, STARTING)) { + lxc_log_error("failed to set state %s", lxc_state2str(STARTING)); + goto out; + } + + /* Synchro socketpair */ + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) { + lxc_log_syserror("failed to create communication socketpair"); + goto err; + } + + /* Avoid signals from terminal */ + LXC_TTY_ADD_HANDLER(SIGINT); + LXC_TTY_ADD_HANDLER(SIGQUIT); + + clone_flags = CLONE_NEWPID|CLONE_NEWIPC; + if (conf_has_fstab(name)) + clone_flags |= CLONE_NEWNS; + if (conf_has_utsname(name)) + clone_flags |= CLONE_NEWUTS; + if (conf_has_network(name)) + clone_flags |= CLONE_NEWNET; + + /* Create a process in a new set of namespaces */ + pid = fork_ns(clone_flags); + if (pid < 0) { + lxc_log_syserror("failed to fork into a new namespace"); + goto err_fork_ns; + } + + if (!pid) { + + close(sv[1]); + + /* Be sure we don't inherit this after the exec */ + fcntl(sv[0], F_SETFD, FD_CLOEXEC); + + /* Tell our father he can begin to configure the container */ + if (write(sv[0], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to write socket"); + return 1; + } + + /* Wait for the father to finish the configuration */ + if (read(sv[0], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to read socket"); + return 1; + } + + /* Setup the container, ip, names, utsname, ... */ + if (lxc_setup(name)) { + lxc_log_error("failed to setup the container"); + if (write(sv[0], &sync, sizeof(sync)) < 0) + lxc_log_syserror("failed to write the socket"); + return -1; + } + + /* If a callback has been passed, call it before doing exec */ + if (prestart) + if (prestart(name, argc, argv, data)) { + lxc_log_error("prestart callback has failed"); + return -1; + } + + execvp(argv[0], argv); + lxc_log_syserror("failed to exec %s", argv[0]); + + /* If the exec fails, tell that to our father */ + if (write(sv[0], &sync, sizeof(sync)) < 0) + lxc_log_syserror("failed to write the socket"); + + exit(1); + } + + close(sv[0]); + + /* Wait for the child to be ready */ + if (read(sv[1], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to read the socket"); + goto err_pipe_read; + } + + /* Create the network configuration */ + if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) { + lxc_log_error("failed to create the configured network"); + goto err_create_network; + } + + /* Tell the child to continue its initialization */ + if (write(sv[1], &sync, sizeof(sync)) < 0) { + lxc_log_syserror("failed to write the socket"); + goto err_pipe_write; + } + + /* Wait for the child to exec or returning an error */ + err = read(sv[1], &sync, sizeof(sync)); + if (err < 0) { + lxc_log_error("failed to read the socket"); + goto err_pipe_read2; + } + + if (err > 0) { + lxc_log_error("something went wrong with %d", pid); + /* TODO : check status etc ... */ + waitpid(pid, NULL, 0); + goto err_child_failed; + } + + asprintf(&val, "%d\n", pid); + asprintf(&init, LXCPATH "/%s/init", name); + fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd < 0) { + lxc_log_syserror("failed to open '%s'", init); + goto err_write; + } + + if (write(fd, val, strlen(val)) < 0) { + lxc_log_syserror("failed to write the init pid"); + goto err_write; + } + + close(fd); + + if (lxc_link_nsgroup(name, pid)) + lxc_log_warning("cgroupfs not found: cgroup disabled"); + + if (lxc_setstate(name, RUNNING)) { + lxc_log_error("failed to set state to %s", + lxc_state2str(RUNNING)); + goto err_state_failed; + } + +wait_again: + if (waitpid(pid, NULL, 0) < 0) { + if (errno == EINTR) + goto wait_again; + lxc_log_syserror("failed to wait the pid %d", pid); + goto err_waitpid_failed; + } + + if (lxc_setstate(name, STOPPING)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPING)); + + if (clone_flags & CLONE_NEWNET && conf_destroy_network(name)) + lxc_log_error("failed to destroy the network"); + + err = 0; +out: + if (lxc_setstate(name, STOPPED)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPED)); + + lxc_unlink_nsgroup(name); + unlink(init); + free(init); + free(val); + lxc_put_lock(lock); + + return err; + +err_write: + close(fd); + +err_state_failed: +err_child_failed: +err_pipe_read2: +err_pipe_write: + if (clone_flags & CLONE_NEWNET) + conf_destroy_network(name); +err_create_network: +err_pipe_read: +err_waitpid_failed: + if (lxc_setstate(name, ABORTING)) + lxc_log_error("failed to set state %s", lxc_state2str(STOPPED)); + + kill(pid, SIGKILL); +err_fork_ns: + LXC_TTY_DEL_HANDLER(SIGQUIT); + LXC_TTY_DEL_HANDLER(SIGINT); + close(sv[0]); + close(sv[1]); +err: + goto out; +} diff --git a/src/lxc/stop.c b/src/lxc/stop.c new file mode 100644 index 000000000..7428846ea --- /dev/null +++ b/src/lxc/stop.c @@ -0,0 +1,92 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int lxc_stop(const char *name) +{ + char init[MAXPATHLEN]; + char val[MAXPIDLEN]; + int fd, lock, ret = -1; + size_t pid; + + lock = lxc_get_lock(name); + if (lock > 0) { + lxc_log_error("'%s' is not running", name); + lxc_put_lock(lock); + return -1; + } + + if (lock < 0) { + lxc_log_error("failed to acquire the lock on '%s':%s", + name, strerror(-lock)); + return -1; + } + + snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name); + fd = open(init, O_RDONLY); + if (fd < 0) { + lxc_log_syserror("failed to open init file for %s", name); + goto out_unlock; + } + + if (read(fd, val, sizeof(val)) < 0) { + lxc_log_syserror("failed to read %s", init); + goto out_close; + } + + pid = atoi(val); + + if (kill(pid, SIGKILL)) { + lxc_log_syserror("failed to kill %zd", pid); + goto out_close; + } + + if (unlink(init)) { + lxc_log_syserror("failed to unlink %s", init); + goto out_close; + } + + ret = 0; + +out_close: + close(fd); +out_unlock: + lxc_put_lock(lock); + return ret; +} diff --git a/src/lxc/utils.h b/src/lxc/utils.h new file mode 100644 index 000000000..5fc3946fb --- /dev/null +++ b/src/lxc/utils.h @@ -0,0 +1,51 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _utils_h +#define _utils_h + +#define LXC_TTY_HANDLER(s) \ + static struct sigaction lxc_tty_sa_##s; \ + static void tty_##s##_handler(int sig, siginfo_t *info, void *ctx) \ + { \ + if (lxc_tty_sa_##s.sa_handler == SIG_DFL || \ + lxc_tty_sa_##s.sa_handler == SIG_IGN) \ + return; \ + (*lxc_tty_sa_##s.sa_sigaction)(sig, info, ctx); \ + } + +#define LXC_TTY_ADD_HANDLER(s) \ + do { \ + struct sigaction sa; \ + sa.sa_sigaction = tty_##s##_handler; \ + sa.sa_flags = SA_SIGINFO; \ + sigfillset(&sa.sa_mask); \ + /* No error expected with sigaction. */ \ + sigaction(s, &sa, &lxc_tty_sa_##s); \ + } while (0) + +#define LXC_TTY_DEL_HANDLER(s) \ + do { \ + sigaction(s, &lxc_tty_sa_##s, NULL); \ + } while (0) + +#endif -- 2.39.5