From 9f30a1908937fb62906e608f708bdec4fbdec1bc Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Wed, 6 Nov 2013 15:16:33 -0800 Subject: [PATCH 01/10] Enable network namespace sharing in lxc-start Right now lxc-start always does one of two things: it creates a new namespace or inherits it from the parent environment. This patch adds a third option: share a namespace with another container (actually: a process). In some situations this is handy. For example by sharing a network namespace it is possible to migrate services between containers without (or with little) downtime. This patch creates an infrastructure for inheriting any type of namespace, but only the network namespace is supported for now. --- src/lxc/arguments.h | 3 + src/lxc/conf.c | 3 + src/lxc/conf.h | 2 + src/lxc/lxc_start.c | 29 +++++++++- src/lxc/start.c | 131 +++++++++++++++++++++++++++++++++++++------- src/lxc/start.h | 18 ++++++ 6 files changed, 164 insertions(+), 22 deletions(-) diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index dc2d117eb..bf262f859 100644 --- a/src/lxc/arguments.h +++ b/src/lxc/arguments.h @@ -53,6 +53,9 @@ struct lxc_arguments { /* set to 0 to accept only 1 lxcpath, -1 for unlimited */ int lxcpath_additional; + /* for lxc-start */ + const char *share_net; + /* for lxc-checkpoint/restart */ const char *statefile; int statefd; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index a75673126..3bebe46d1 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2399,6 +2399,9 @@ struct lxc_conf *lxc_conf_init(void) new->lsm_se_context = NULL; new->lsm_umount_proc = 0; + for (i = 0; i < LXC_NS_MAX; i++) + new->inherit_ns_fd[i] = -1; + return new; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 940d49371..606ad5123 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -318,6 +318,8 @@ struct lxc_conf { // store the config file specified values here. char *logfile; // the logfile as specifed in config int loglevel; // loglevel as specifed in config (if any) + + int inherit_ns_fd[LXC_NS_MAX]; }; int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index add2542f2..69fde9a49 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -51,6 +51,8 @@ #include "confile.h" #include "arguments.h" +#define OPT_SHARE_NET OPT_USAGE+1 + lxc_log_define(lxc_start_ui, lxc_start); static struct lxc_list defines; @@ -101,6 +103,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) case 'C': args->close_all_fds = 1; break; case 's': return lxc_config_define_add(&defines, arg); case 'p': args->pidfile = arg; break; + case OPT_SHARE_NET: args->share_net = arg; break; } return 0; } @@ -113,6 +116,7 @@ static const struct option my_longopts[] = { {"console-log", required_argument, 0, 'L'}, {"close-all-fds", no_argument, 0, 'C'}, {"pidfile", required_argument, 0, 'p'}, + {"share-net", required_argument, 0, OPT_SHARE_NET}, LXC_COMMON_OPTIONS }; @@ -133,7 +137,9 @@ Options :\n\ -C, --close-all-fds If any fds are inherited, close them\n\ If not specified, exit with failure instead\n\ Note: --daemon implies --close-all-fds\n\ - -s, --define KEY=VAL Assign VAL to configuration variable KEY\n", + -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ + --share-net=PID Share a network namespace with another container\n\ +", .options = my_longopts, .parser = my_parser, .checker = NULL, @@ -249,6 +255,27 @@ int main(int argc, char *argv[]) } } + if (my_args.share_net != NULL) { + char *eptr; + int fd; + int pid = strtol(my_args.share_net, &eptr, 10); + if (*eptr != '\0') { + SYSERROR("'%s' is not a valid pid number", my_args.share_net); + goto out; + } + char path[MAXPATHLEN]; + int ret = snprintf(path, MAXPATHLEN, "/proc/%d/ns/net", pid); + if (ret < 0 || ret >= MAXPATHLEN) + goto out; + + fd = open(path, O_RDONLY); + if (fd < 0) { + SYSERROR("failed to open %s", path); + goto out; + } + conf->inherit_ns_fd[LXC_NS_NET] = fd; + } + if (my_args.daemonize) { c->want_daemonize(c); } diff --git a/src/lxc/start.c b/src/lxc/start.c index 3b2ba8fbd..50992fcc0 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -75,6 +75,78 @@ lxc_log_define(lxc_start, lxc); +const struct ns_info ns_info[LXC_NS_MAX] = { + [LXC_NS_MNT] = {"mnt", CLONE_NEWNS}, + [LXC_NS_PID] = {"pid", CLONE_NEWPID}, + [LXC_NS_UTS] = {"uts", CLONE_NEWUTS}, + [LXC_NS_IPC] = {"ipc", CLONE_NEWIPC}, + [LXC_NS_USER] = {"user", CLONE_NEWUSER}, + [LXC_NS_NET] = {"net", CLONE_NEWNET} +}; + +static void close_ns(int ns_fd[LXC_NS_MAX]) { + int i; + + process_lock(); + for (i = 0; i < LXC_NS_MAX; i++) { + if (ns_fd[i] > -1) { + close(ns_fd[i]); + ns_fd[i] = -1; + } + } + process_unlock(); +} + +static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags) { + int i, saved_errno; + char path[MAXPATHLEN]; + + if (access("/proc/self/ns", X_OK)) { + ERROR("Does this kernel version support 'attach'?"); + return -1; + } + + for (i = 0; i < LXC_NS_MAX; i++) + ns_fd[i] = -1; + + for (i = 0; i < LXC_NS_MAX; i++) { + if ((clone_flags & ns_info[i].clone_flag) == 0) + continue; + snprintf(path, MAXPATHLEN, "/proc/self/ns/%s", ns_info[i].proc_name); + process_lock(); + ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC); + process_unlock(); + if (ns_fd[i] < 0) + goto error; + } + + return 0; + +error: + saved_errno = errno; + close_ns(ns_fd); + errno = saved_errno; + SYSERROR("failed to open '%s'", path); + return -1; +} + +static int attach_ns(const int ns_fd[LXC_NS_MAX]) { + int i; + + for (i = 0; i < LXC_NS_MAX; i++) { + if (ns_fd[i] < 0) + continue; + + if (setns(ns_fd[i], 0) != 0) + goto error; + } + return 0; + +error: + SYSERROR("failed to set namespace '%s'", ns_info[i].proc_name); + return -1; +} + static int match_fd(int fd) { return (fd == 0 || fd == 1 || fd == 2); @@ -645,6 +717,12 @@ int lxc_spawn(struct lxc_handler *handler) const char *name = handler->name; struct cgroup_meta_data *cgroup_meta = NULL; const char *cgroup_pattern = NULL; + int saved_ns_fd[LXC_NS_MAX]; + int preserve_mask = 0, i; + + for (i = 0; i < LXC_NS_MAX; i++) + if (handler->conf->inherit_ns_fd[i] > -1) + preserve_mask |= ns_info[i].clone_flag; if (lxc_sync_init(handler)) return -1; @@ -654,34 +732,40 @@ int lxc_spawn(struct lxc_handler *handler) INFO("Cloning a new user namespace"); handler->clone_flags |= CLONE_NEWUSER; } - if (!lxc_list_empty(&handler->conf->network)) { - handler->clone_flags |= CLONE_NEWNET; + if (handler->conf->inherit_ns_fd[LXC_NS_NET] == -1) { + if (!lxc_list_empty(&handler->conf->network)) { - /* Find gateway addresses from the link device, which is - * no longer accessible inside the container. Do this - * before creating network interfaces, since goto - * out_delete_net does not work before lxc_clone. */ - if (lxc_find_gateway_addresses(handler)) { - ERROR("failed to find gateway addresses"); - lxc_sync_fini(handler); - return -1; + handler->clone_flags |= CLONE_NEWNET; + + /* Find gateway addresses from the link device, which is + * no longer accessible inside the container. Do this + * before creating network interfaces, since goto + * out_delete_net does not work before lxc_clone. */ + if (lxc_find_gateway_addresses(handler)) { + ERROR("failed to find gateway addresses"); + lxc_sync_fini(handler); + return -1; + } + + /* that should be done before the clone because we will + * fill the netdev index and use them in the child + */ + if (lxc_create_network(handler)) { + ERROR("failed to create the network IW WAS ERE"); + lxc_sync_fini(handler); + return -1; + } } - /* that should be done before the clone because we will - * fill the netdev index and use them in the child - */ - if (lxc_create_network(handler)) { - ERROR("failed to create the network"); - lxc_sync_fini(handler); - return -1; + if (save_phys_nics(handler->conf)) { + ERROR("failed to save physical nic info"); + goto out_abort; } + } else { + INFO("Inheriting a net namespace"); } - if (save_phys_nics(handler->conf)) { - ERROR("failed to save physical nic info"); - goto out_abort; - } cgroup_meta = lxc_cgroup_load_meta(); if (!cgroup_meta) { @@ -716,6 +800,9 @@ int lxc_spawn(struct lxc_handler *handler) if (handler->pinfd == -1) INFO("failed to pin the container's rootfs"); + preserve_ns(saved_ns_fd, preserve_mask); + attach_ns(handler->conf->inherit_ns_fd); + /* Create a process in a new set of namespaces */ handler->pid = lxc_clone(do_start, handler, handler->clone_flags); if (handler->pid < 0) { @@ -723,6 +810,8 @@ int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; } + attach_ns(saved_ns_fd); + lxc_sync_fini_child(handler); if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE)) diff --git a/src/lxc/start.h b/src/lxc/start.h index c35c5c481..c1f790901 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -27,6 +27,7 @@ #include #include +#include "namespace.h" struct lxc_conf; @@ -39,6 +40,23 @@ struct lxc_operations { struct cgroup_desc; +enum { + LXC_NS_MNT, + LXC_NS_PID, + LXC_NS_UTS, + LXC_NS_IPC, + LXC_NS_USER, + LXC_NS_NET, + LXC_NS_MAX +}; + +struct ns_info { + const char *proc_name; + int clone_flag; +}; + +const struct ns_info ns_info[LXC_NS_MAX]; + struct lxc_handler { pid_t pid; char *name; From 02b4f2e1d8cde273d03fda101411a02694309f10 Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Mon, 11 Nov 2013 05:19:29 -0800 Subject: [PATCH 02/10] Allow specifying a container by name or pid in --share-net option. --- src/lxc/lxc_start.c | 61 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index 69fde9a49..395234297 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -93,6 +93,48 @@ err: return err; } +static int pid_from_lxcname(const char *lxcname_or_pid, const char *lxcpath) { + char *eptr; + int pid = strtol(lxcname_or_pid, &eptr, 10); + if (*eptr != '\0' || pid < 1) { + struct lxc_container *s; + s = lxc_container_new(lxcname_or_pid, lxcpath); + if (!s) { + SYSERROR("'%s' is not a valid pid nor a container name", lxcname_or_pid); + return -1; + } + + if (!s->may_control(s)) { + SYSERROR("Insufficient privileges to control container '%s'", s->name); + return -1; + } + + pid = s->init_pid(s); + if (pid < 1) { + SYSERROR("Is container '%s' running?", s->name); + return -1; + } + } + if (kill(pid, 0) < 0) { + SYSERROR("Can't send signal to pid %d", pid); + return -1; + } + return pid; +} + +static int open_ns(int pid, const char *ns_proc_name) { + int fd; + char path[MAXPATHLEN]; + snprintf(path, MAXPATHLEN, "/proc/%d/ns/net", pid); + + fd = open(path, O_RDONLY); + if (fd < 0) { + SYSERROR("failed to open %s", path); + return -1; + } + return fd; +} + static int my_parser(struct lxc_arguments* args, int c, char* arg) { switch (c) { @@ -138,7 +180,7 @@ Options :\n\ If not specified, exit with failure instead\n\ Note: --daemon implies --close-all-fds\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ - --share-net=PID Share a network namespace with another container\n\ + --share-net=NAME Share a network namespace with another container or pid\n\ ", .options = my_longopts, .parser = my_parser, @@ -256,23 +298,14 @@ int main(int argc, char *argv[]) } if (my_args.share_net != NULL) { - char *eptr; int fd; - int pid = strtol(my_args.share_net, &eptr, 10); - if (*eptr != '\0') { - SYSERROR("'%s' is not a valid pid number", my_args.share_net); - goto out; - } - char path[MAXPATHLEN]; - int ret = snprintf(path, MAXPATHLEN, "/proc/%d/ns/net", pid); - if (ret < 0 || ret >= MAXPATHLEN) + int pid = pid_from_lxcname(my_args.share_net, lxcpath); + if (pid < 1) goto out; - fd = open(path, O_RDONLY); - if (fd < 0) { - SYSERROR("failed to open %s", path); + fd = open_ns(pid, "net"); + if (fd < 0) goto out; - } conf->inherit_ns_fd[LXC_NS_NET] = fd; } From 38521a3b5d53598684955531ce2e54cc3ef696c0 Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 03:50:26 -0800 Subject: [PATCH 03/10] Cosmetic - clean up error message --- src/lxc/start.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lxc/start.c b/src/lxc/start.c index 50992fcc0..425fa1dbf 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -752,7 +752,7 @@ int lxc_spawn(struct lxc_handler *handler) * fill the netdev index and use them in the child */ if (lxc_create_network(handler)) { - ERROR("failed to create the network IW WAS ERE"); + ERROR("failed to create the network"); lxc_sync_fini(handler); return -1; } From 11373487a11dc816a9b27e386b7e593984037a1d Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 05:13:33 -0800 Subject: [PATCH 04/10] Describe --share-net in the lxc-start manual --- doc/lxc-start.sgml.in | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in index 09f917164..756ea9c49 100644 --- a/doc/lxc-start.sgml.in +++ b/doc/lxc-start.sgml.in @@ -57,6 +57,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -p pid_file -s KEY=VAL -C + --share-net name|pid command @@ -186,6 +187,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + + + + + Inherit a network namespace from + a name container or + a pid. The network namespace + will continue to be managed by the original owner. The + network configuration of the starting container is ignored + and the up/down scripts won't be executed. + + + + + + + + From d4afa440764bc515b4c4be60934c0ba83c0848d0 Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 05:13:53 -0800 Subject: [PATCH 05/10] Cosmetic. --- src/lxc/lxc_start.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index 395234297..ca88940aa 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -298,12 +298,11 @@ int main(int argc, char *argv[]) } if (my_args.share_net != NULL) { - int fd; int pid = pid_from_lxcname(my_args.share_net, lxcpath); if (pid < 1) goto out; - fd = open_ns(pid, "net"); + int fd = open_ns(pid, "net"); if (fd < 0) goto out; conf->inherit_ns_fd[LXC_NS_NET] = fd; From 3c93577b43943f653194f6189cb2c4b6a17bf96a Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 05:14:25 -0800 Subject: [PATCH 06/10] Create --share-ipc option --- doc/lxc-start.sgml.in | 10 ++++++++++ src/lxc/arguments.h | 1 + src/lxc/lxc_start.c | 15 +++++++++++++++ src/lxc/start.c | 8 +++++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in index 756ea9c49..86024f66d 100644 --- a/doc/lxc-start.sgml.in +++ b/doc/lxc-start.sgml.in @@ -58,6 +58,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -s KEY=VAL -C --share-net name|pid + --share-ipc name|pid command @@ -203,6 +204,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + + + + + Inherit an IPC namespace from + a name container or + a pid. diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index bf262f859..1befc8da0 100644 --- a/src/lxc/arguments.h +++ b/src/lxc/arguments.h @@ -55,6 +55,7 @@ struct lxc_arguments { /* for lxc-start */ const char *share_net; + const char *share_ipc; /* for lxc-checkpoint/restart */ const char *statefile; diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index ca88940aa..28c84cb40 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -52,6 +52,7 @@ #include "arguments.h" #define OPT_SHARE_NET OPT_USAGE+1 +#define OPT_SHARE_IPC OPT_USAGE+2 lxc_log_define(lxc_start_ui, lxc_start); @@ -146,6 +147,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) case 's': return lxc_config_define_add(&defines, arg); case 'p': args->pidfile = arg; break; case OPT_SHARE_NET: args->share_net = arg; break; + case OPT_SHARE_IPC: args->share_ipc = arg; break; } return 0; } @@ -159,6 +161,7 @@ static const struct option my_longopts[] = { {"close-all-fds", no_argument, 0, 'C'}, {"pidfile", required_argument, 0, 'p'}, {"share-net", required_argument, 0, OPT_SHARE_NET}, + {"share-ipc", required_argument, 0, OPT_SHARE_IPC}, LXC_COMMON_OPTIONS }; @@ -181,6 +184,7 @@ Options :\n\ Note: --daemon implies --close-all-fds\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ --share-net=NAME Share a network namespace with another container or pid\n\ + --share-ipc=NAME Share an IPC namespace with another container or pid\n\ ", .options = my_longopts, .parser = my_parser, @@ -308,6 +312,17 @@ int main(int argc, char *argv[]) conf->inherit_ns_fd[LXC_NS_NET] = fd; } + if (my_args.share_ipc != NULL) { + int pid = pid_from_lxcname(my_args.share_ipc, lxcpath); + if (pid < 1) + goto out; + + int fd = open_ns(pid, "ipc"); + if (fd < 0) + goto out; + conf->inherit_ns_fd[LXC_NS_IPC] = fd; + } + if (my_args.daemonize) { c->want_daemonize(c); } diff --git a/src/lxc/start.c b/src/lxc/start.c index 425fa1dbf..f591ad7da 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -727,7 +727,7 @@ int lxc_spawn(struct lxc_handler *handler) if (lxc_sync_init(handler)) return -1; - handler->clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS; + handler->clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWNS; if (!lxc_list_empty(&handler->conf->id_map)) { INFO("Cloning a new user namespace"); handler->clone_flags |= CLONE_NEWUSER; @@ -766,6 +766,12 @@ int lxc_spawn(struct lxc_handler *handler) INFO("Inheriting a net namespace"); } + if (handler->conf->inherit_ns_fd[LXC_NS_IPC] == -1) { + handler->clone_flags |= CLONE_NEWIPC; + } else { + INFO("Inheriting an IPC namespace"); + } + cgroup_meta = lxc_cgroup_load_meta(); if (!cgroup_meta) { From f8059880687576b84d48baae0fa4499da390638d Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 07:06:23 -0800 Subject: [PATCH 07/10] Fix memory leak in pid_from_lxcname and use ns_proc_name in open_ns. --- src/lxc/lxc_start.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index 28c84cb40..79186ade3 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -107,26 +107,31 @@ static int pid_from_lxcname(const char *lxcname_or_pid, const char *lxcpath) { if (!s->may_control(s)) { SYSERROR("Insufficient privileges to control container '%s'", s->name); + lxc_container_put(s); return -1; } pid = s->init_pid(s); if (pid < 1) { SYSERROR("Is container '%s' running?", s->name); + lxc_container_put(s); return -1; } + + lxc_container_put(s); } if (kill(pid, 0) < 0) { SYSERROR("Can't send signal to pid %d", pid); return -1; } + return pid; } static int open_ns(int pid, const char *ns_proc_name) { int fd; char path[MAXPATHLEN]; - snprintf(path, MAXPATHLEN, "/proc/%d/ns/net", pid); + snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns_proc_name); fd = open(path, O_RDONLY); if (fd < 0) { From 4692616518ce993fd333d597dae6c6d95da87c3d Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Tue, 12 Nov 2013 08:19:55 -0800 Subject: [PATCH 08/10] Refactoring - make the option parsing code generic --- src/lxc/arguments.h | 3 +-- src/lxc/lxc_start.c | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index 1befc8da0..021f552e2 100644 --- a/src/lxc/arguments.h +++ b/src/lxc/arguments.h @@ -54,8 +54,7 @@ struct lxc_arguments { int lxcpath_additional; /* for lxc-start */ - const char *share_net; - const char *share_ipc; + const char *share_ns[32]; // size must be greater than LXC_NS_MAX /* for lxc-checkpoint/restart */ const char *statefile; diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index 79186ade3..a7976eafb 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -151,8 +151,8 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) case 'C': args->close_all_fds = 1; break; case 's': return lxc_config_define_add(&defines, arg); case 'p': args->pidfile = arg; break; - case OPT_SHARE_NET: args->share_net = arg; break; - case OPT_SHARE_IPC: args->share_ipc = arg; break; + case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break; + case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break; } return 0; } @@ -306,26 +306,19 @@ int main(int argc, char *argv[]) } } - if (my_args.share_net != NULL) { - int pid = pid_from_lxcname(my_args.share_net, lxcpath); + int i; + for (i = 0; i < LXC_NS_MAX; i++) { + if (my_args.share_ns[i] == NULL) + continue; + + int pid = pid_from_lxcname(my_args.share_ns[i], lxcpath); if (pid < 1) goto out; - int fd = open_ns(pid, "net"); + int fd = open_ns(pid, ns_info[i].proc_name); if (fd < 0) goto out; - conf->inherit_ns_fd[LXC_NS_NET] = fd; - } - - if (my_args.share_ipc != NULL) { - int pid = pid_from_lxcname(my_args.share_ipc, lxcpath); - if (pid < 1) - goto out; - - int fd = open_ns(pid, "ipc"); - if (fd < 0) - goto out; - conf->inherit_ns_fd[LXC_NS_IPC] = fd; + conf->inherit_ns_fd[i] = fd; } if (my_args.daemonize) { From 6c544cb300752a9f799cda19e9c5b57ab890c8dd Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Wed, 13 Nov 2013 05:20:26 -0800 Subject: [PATCH 09/10] Make it possible to share UTS namespace --- doc/lxc-start.sgml.in | 15 +++++++++++++++ src/lxc/conf.c | 8 +++++--- src/lxc/lxc_start.c | 4 ++++ src/lxc/start.c | 10 ++++++++-- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in index 86024f66d..766a4ec2b 100644 --- a/doc/lxc-start.sgml.in +++ b/doc/lxc-start.sgml.in @@ -217,6 +217,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + + + + + Inherit a UTS namespace from + a name container or + a pid. The starting LXC will + not set the hostname, but the container OS may do it + anyway. + + + + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 3bebe46d1..dfc49e435 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3141,9 +3141,11 @@ int ttys_shift_ids(struct lxc_conf *c) int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath, struct cgroup_process_info *cgroup_info) { - if (setup_utsname(lxc_conf->utsname)) { - ERROR("failed to setup the utsname for '%s'", name); - return -1; + if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) { + if (setup_utsname(lxc_conf->utsname)) { + ERROR("failed to setup the utsname for '%s'", name); + return -1; + } } if (setup_network(&lxc_conf->network)) { diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index a7976eafb..02867fb2e 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -53,6 +53,7 @@ #define OPT_SHARE_NET OPT_USAGE+1 #define OPT_SHARE_IPC OPT_USAGE+2 +#define OPT_SHARE_UTS OPT_USAGE+3 lxc_log_define(lxc_start_ui, lxc_start); @@ -153,6 +154,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) case 'p': args->pidfile = arg; break; case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break; case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break; + case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break; } return 0; } @@ -167,6 +169,7 @@ static const struct option my_longopts[] = { {"pidfile", required_argument, 0, 'p'}, {"share-net", required_argument, 0, OPT_SHARE_NET}, {"share-ipc", required_argument, 0, OPT_SHARE_IPC}, + {"share-uts", required_argument, 0, OPT_SHARE_UTS}, LXC_COMMON_OPTIONS }; @@ -190,6 +193,7 @@ Options :\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ --share-net=NAME Share a network namespace with another container or pid\n\ --share-ipc=NAME Share an IPC namespace with another container or pid\n\ + --share-uts=NAME Share a UTS namespace with another container or pid\n\ ", .options = my_longopts, .parser = my_parser, diff --git a/src/lxc/start.c b/src/lxc/start.c index f591ad7da..5e3ce7f0f 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -721,13 +721,13 @@ int lxc_spawn(struct lxc_handler *handler) int preserve_mask = 0, i; for (i = 0; i < LXC_NS_MAX; i++) - if (handler->conf->inherit_ns_fd[i] > -1) + if (handler->conf->inherit_ns_fd[i] != -1) preserve_mask |= ns_info[i].clone_flag; if (lxc_sync_init(handler)) return -1; - handler->clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWNS; + handler->clone_flags = CLONE_NEWPID|CLONE_NEWNS; if (!lxc_list_empty(&handler->conf->id_map)) { INFO("Cloning a new user namespace"); handler->clone_flags |= CLONE_NEWUSER; @@ -772,6 +772,12 @@ int lxc_spawn(struct lxc_handler *handler) INFO("Inheriting an IPC namespace"); } + if (handler->conf->inherit_ns_fd[LXC_NS_UTS] == -1) { + handler->clone_flags |= CLONE_NEWUTS; + } else { + INFO("Inheriting a UTS namespace"); + } + cgroup_meta = lxc_cgroup_load_meta(); if (!cgroup_meta) { From 304dc8b3ff5d14229942d314bb3bfc44cede68de Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Wed, 13 Nov 2013 07:04:27 -0800 Subject: [PATCH 10/10] Cosmetic: shorten the options summary in documentation --- doc/lxc-start.sgml.in | 3 +-- src/lxc/lxc_start.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in index 766a4ec2b..07f9845b8 100644 --- a/doc/lxc-start.sgml.in +++ b/doc/lxc-start.sgml.in @@ -57,8 +57,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -p pid_file -s KEY=VAL -C - --share-net name|pid - --share-ipc name|pid + --share-[net|ipc|uts] name|pid command diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index 02867fb2e..33f2fe5ab 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -191,9 +191,7 @@ Options :\n\ If not specified, exit with failure instead\n\ Note: --daemon implies --close-all-fds\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ - --share-net=NAME Share a network namespace with another container or pid\n\ - --share-ipc=NAME Share an IPC namespace with another container or pid\n\ - --share-uts=NAME Share a UTS namespace with another container or pid\n\ + --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\ ", .options = my_longopts, .parser = my_parser,