From 14a7b0f98aab292eac6f541790dac3dcda53425f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 12 Dec 2017 13:30:54 +0100 Subject: [PATCH] network: pass info in env if hook version is 1 Unblocks #2013. Unblocks #2015. Closes #1766. Signed-off-by: Christian Brauner --- doc/lxc.container.conf.sgml.in | 119 ++++++++++++++++++++---- src/lxc/conf.c | 70 +++++++++++++-- src/lxc/conf.h | 5 +- src/lxc/lxccontainer.c | 4 +- src/lxc/network.c | 160 ++++++++++++++++++++++----------- src/lxc/start.c | 12 +-- 6 files changed, 281 insertions(+), 89 deletions(-) diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 43df6a632..4b97de611 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -308,9 +308,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Init ID Sets the UID/GID to use for the init system, and subsequent commands. - Note that using a non-root uid when booting a system container will + Note that using a non-root UID when booting a system container will likely not work due to missing privileges. Setting the UID/GID is mostly - useful when running application container. + useful when running application containers. Defaults to: UID(0), GID(0) @@ -608,7 +608,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - @@ -651,15 +650,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Add a configuration option to specify a script to be executed after creating and configuring the network used - from the host side. The following arguments are passed - to the script: container name and config section name - (net) Additional arguments depend on the config section - employing a script hook; the following are used by the - network system: execution context (up), network type - (empty/veth/macvlan/phys), Depending on the network - type, other arguments may be passed: - veth/macvlan/phys. And finally (host-sided) device name. + from the host side. + + + In addition to the information available to all hooks. The + following information is provided to the script: + + + + LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'. + + + + + + LXC_HOOK_SECTION: the section type 'net'. + + + + + + LXC_NET_TYPE: the network type. This is one of the valid + network types listed here (e.g. 'macvlan', 'veth'). + + + + + + LXC_NET_PARENT: the parent device on the host. This is only + set for network types 'mavclan', 'veth', 'phys'. + + + + + + LXC_NET_PEER: the name of the peer device on the host. This is + only set for 'veth' network types. Note that this information + is only available when is set + to 1. + + + + + Whether this information is provided in the form of environment + variables or as arguments to the script depends on the value of + . If set to 1 then information is + provided in the form of environment variables. If set to 0 + information is provided as arguments to the script. + + Standard output from the script is logged at debug level. Standard error is not logged, but can be captured by the @@ -676,15 +716,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Add a configuration option to specify a script to be executed before destroying the network used from the - host side. The following arguments are passed to the - script: container name and config section name (net) - Additional arguments depend on the config section - employing a script hook; the following are used by the - network system: execution context (down), network type - (empty/veth/macvlan/phys), Depending on the network - type, other arguments may be passed: - veth/macvlan/phys. And finally (host-sided) device name. + host side. + + + In addition to the information available to all hooks. The + following information is provided to the script: + + + + LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'. + + + + + + LXC_HOOK_SECTION: the section type 'net'. + + + + + + LXC_NET_TYPE: the network type. This is one of the valid + network types listed here (e.g. 'macvlan', 'veth'). + + + + + + LXC_NET_PARENT: the parent device on the host. This is only + set for network types 'mavclan', 'veth', 'phys'. + + + + + + LXC_NET_PEER: the name of the peer device on the host. This is + only set for 'veth' network types. Note that this information + is only available when is set + to 1. + + + + + Whether this information is provided in the form of environment + variables or as arguments to the script depends on the value of + . If set to 1 then information is + provided in the form of environment variables. If set to 0 + information is provided as arguments to the script. + + Standard output from the script is logged at debug level. Standard error is not logged, but can be captured by the diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8e31275f6..54b55acda 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -339,10 +339,9 @@ static int run_buffer(char *buffer) return 0; } -static int run_script_argv(const char *name, unsigned int hook_version, - const char *section, const char *script, - const char *hookname, const char *lxcpath, - char **argsin) +int run_script_argv(const char *name, unsigned int hook_version, + const char *section, const char *script, + const char *hookname, char **argsin) { int buf_pos, i, ret; char *buffer; @@ -405,6 +404,59 @@ static int run_script_argv(const char *name, unsigned int hook_version, return -1; } TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section); + + if (strcmp(section, "net") == 0) { + char *parent; + + if (!argsin[0]) + return -EINVAL; + + ret = setenv("LXC_NET_TYPE", argsin[0], 1); + if (ret < 0) { + SYSERROR("Failed to set environment variable: " + "LXC_NET_TYPE=%s", argsin[0]); + return -1; + } + TRACE("Set environment variable: LXC_NET_TYPE=%s", argsin[0]); + + parent = argsin[1] ? argsin[1] : ""; + + if (strcmp(argsin[0], "macvlan")) { + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } else if (strcmp(argsin[0], "phys")) { + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } else if (strcmp(argsin[0], "veth")) { + char *peer = argsin[2] ? argsin[2] : ""; + + ret = setenv("LXC_NET_PEER", peer, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PEER=%s", peer); + return -1; + } + TRACE("Set environment variable: LXC_NET_PEER=%s", peer); + + ret = setenv("LXC_NET_PARENT", parent, 1); + if (ret < 0) { + SYSERROR("Failed to set environment " + "variable: LXC_NET_PARENT=%s", parent); + return -1; + } + TRACE("Set environment variable: LXC_NET_PARENT=%s", parent); + } + } } for (i = 0; argsin && argsin[i]; i++) { @@ -3099,7 +3151,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath remount_all_slave(); - if (run_lxc_hooks(name, "pre-mount", conf, lxcpath, NULL)) { + if (run_lxc_hooks(name, "pre-mount", conf, NULL)) { ERROR("failed to run pre-mount hooks for container '%s'.", name); return -1; } @@ -3208,13 +3260,13 @@ int lxc_setup(struct lxc_handler *handler) return -1; } - if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) { + if (run_lxc_hooks(name, "mount", lxc_conf, NULL)) { ERROR("failed to run mount hooks for container '%s'.", name); return -1; } if (lxc_conf->autodev > 0) { - if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) { + if (run_lxc_hooks(name, "autodev", lxc_conf, NULL)) { ERROR("failed to run autodev hooks for container '%s'.", name); return -1; } @@ -3292,7 +3344,7 @@ int lxc_setup(struct lxc_handler *handler) } int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, - const char *lxcpath, char *argv[]) + char *argv[]) { struct lxc_list *it; int which = -1; @@ -3325,7 +3377,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, char *hook = it->elem; ret = run_script_argv(name, conf->hooks_version, "lxc", hook, - hookname, lxcpath, argv); + hookname, argv); if (ret < 0) return -1; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index d4b48cc40..b7ddf1d3f 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -412,7 +412,7 @@ extern struct lxc_conf *current_config; #endif extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, - const char *lxcpath, char *argv[]); + char *argv[]); extern int detect_shared_rootfs(void); extern struct lxc_conf *lxc_conf_init(void); extern void lxc_conf_free(struct lxc_conf *conf); @@ -457,6 +457,9 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d, unsigned long flags); extern int run_script(const char *name, const char *section, const char *script, ...); +extern int run_script_argv(const char *name, unsigned int hook_version, + const char *section, const char *script, + const char *hookname, char **argsin); extern int in_caplist(int cap, struct lxc_list *caps); extern int setup_sysctl_parameters(struct lxc_list *sysctls); extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key); diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index c134947b2..2a578ea65 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2746,7 +2746,7 @@ static bool container_destroy(struct lxc_container *c, SYSERROR("Failed to set environment variable for console log"); /* End of environment variable setup for hooks */ - if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) { + if (run_lxc_hooks(c->name, "destroy", conf, NULL)) { ERROR("Failed to execute clone hook for \"%s\"", c->name); goto out; } @@ -3458,7 +3458,7 @@ static int clone_update_rootfs(struct clone_update_data *data) SYSERROR("failed to set environment variable for rootfs mount"); } - if (run_lxc_hooks(c->name, "clone", conf, c->get_config_path(c), hookargs)) { + if (run_lxc_hooks(c->name, "clone", conf, hookargs)) { ERROR("Error executing clone hook for %s", c->name); storage_put(bdev); return -1; diff --git a/src/lxc/network.c b/src/lxc/network.c index 23febe6d2..2e397ad4c 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -204,9 +204,17 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd } if (netdev->upscript) { - err = run_script(handler->name, "net", netdev->upscript, "up", - "veth", veth1, (char*) NULL); - if (err) + char *argv[] = { + "veth", + netdev->link, + "veth1", + NULL, + }; + + err = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->upscript, "up", argv); + if (err < 0) goto out_delete; } @@ -254,9 +262,16 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n } if (netdev->upscript) { - err = run_script(handler->name, "net", netdev->upscript, "up", - "macvlan", netdev->link, (char*) NULL); - if (err) + char *argv[] = { + "macvlan", + netdev->link, + NULL, + }; + + err = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->upscript, "up", argv); + if (err < 0) goto on_error; } @@ -323,6 +338,13 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) { + int ret; + char *argv[] = { + "phys", + netdev->link, + NULL, + }; + if (netdev->link[0] == '\0') { ERROR("No link for physical interface specified"); return -1; @@ -346,27 +368,34 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd */ netdev->priv.phys_attr.ifindex = netdev->ifindex; - if (netdev->upscript) { - int err; - err = run_script(handler->name, "net", netdev->upscript, - "up", "phys", netdev->link, (char*) NULL); - if (err) - return -1; - } + if (!netdev->upscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->upscript, "up", argv); + if (ret < 0) + return -1; return 0; } static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) { + int ret; + char *argv[] = { + "empty", + NULL, + }; + netdev->ifindex = 0; - if (netdev->upscript) { - int err; - err = run_script(handler->name, "net", netdev->upscript, - "up", "empty", (char*) NULL); - if (err) - return -1; - } + if (!netdev->upscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->upscript, "up", argv); + if (ret < 0) + return -1; + return 0; } @@ -387,34 +416,48 @@ static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = { static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) { - char *veth1; - int err; + int ret; + char *argv[] = { + "veth", + netdev->link, + NULL, + NULL, + }; + + if (!netdev->downscript) + return 0; if (netdev->priv.veth_attr.pair[0] != '\0') - veth1 = netdev->priv.veth_attr.pair; + argv[2] = netdev->priv.veth_attr.pair; else - veth1 = netdev->priv.veth_attr.veth1; + argv[2] = netdev->priv.veth_attr.veth1; + + ret = run_script_argv(handler->name, + handler->conf->hooks_version, "net", + netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "veth", veth1, (char*) NULL); - if (err) - return -1; - } return 0; } static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "macvlan", + netdev->link, + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "macvlan", netdev->link, - (char*) NULL); - if (err) - return -1; - } return 0; } @@ -425,27 +468,40 @@ static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev) static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "phys", + netdev->link, + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "phys", netdev->link, (char*) NULL); - if (err) - return -1; - } return 0; } static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) { - int err; + int ret; + char *argv[] = { + "empty", + NULL, + }; + + if (!netdev->downscript) + return 0; + + ret = run_script_argv(handler->name, handler->conf->hooks_version, + "net", netdev->downscript, "down", argv); + if (ret < 0) + return -1; - if (netdev->downscript) { - err = run_script(handler->name, "net", netdev->downscript, - "down", "empty", (char*) NULL); - if (err) - return -1; - } return 0; } diff --git a/src/lxc/start.c b/src/lxc/start.c index b29540603..5052e2d5a 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -668,7 +668,7 @@ int lxc_init(const char *name, struct lxc_handler *handler) TRACE("set environment variables"); - if (run_lxc_hooks(name, "pre-start", conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "pre-start", conf, NULL)) { ERROR("Failed to run lxc.hook.pre-start for container \"%s\".", name); goto out_aborting; } @@ -767,9 +767,9 @@ void lxc_fini(const char *name, struct lxc_handler *handler) SYSERROR("Failed to set environment variable: LXC_TARGET=stop."); if (handler->conf->hooks_version == 0) - rc = run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, namespaces); + rc = run_lxc_hooks(name, "stop", handler->conf, namespaces); else - rc = run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, NULL); + rc = run_lxc_hooks(name, "stop", handler->conf, NULL); while (namespace_count--) free(namespaces[namespace_count]); @@ -792,7 +792,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler) handler->conf->maincmd_fd = -1; } - if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "post-stop", handler->conf, NULL)) { ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name); if (handler->conf->reboot) { WARN("Container will be stopped instead of rebooted."); @@ -1053,7 +1053,7 @@ static int do_start(void *data) if (lxc_seccomp_load(handler->conf) != 0) goto out_warn_father; - if (run_lxc_hooks(handler->name, "start", handler->conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(handler->name, "start", handler->conf, NULL)) { ERROR("Failed to run lxc.hook.start for container \"%s\".", handler->name); goto out_warn_father; } @@ -1513,7 +1513,7 @@ static int lxc_spawn(struct lxc_handler *handler) SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr); /* Run any host-side start hooks */ - if (run_lxc_hooks(name, "start-host", conf, handler->lxcpath, NULL)) { + if (run_lxc_hooks(name, "start-host", conf, NULL)) { ERROR("Failed to run lxc.hook.start-host for container \"%s\".", name); return -1; }