This commit adds a configuration option to specify a script to be executed after creating and configuring the network used by the container. The following arguments are passed to the script:
* container name * 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: * host-sided veth device name --- src/lxc/conf.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++------ src/lxc/conf.h | 19 +++++---- src/lxc/confile.c | 25 +++++++++++ src/lxc/start.c | 2 +- 4 files changed, 138 insertions(+), 23 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index adfe862..e13fddd 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -24,11 +24,13 @@ #include <stdio.h> #undef _GNU_SOURCE #include <stdlib.h> +#include <stdarg.h> #include <errno.h> #include <string.h> #include <dirent.h> #include <mntent.h> #include <unistd.h> +#include <sys/wait.h> #include <pty.h> #include <sys/types.h> @@ -92,7 +94,7 @@ lxc_log_define(lxc_conf, lxc); extern int pivot_root(const char * new_root, const char * put_old); -typedef int (*instanciate_cb)(struct lxc_netdev *); +typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *); struct mount_opt { char *name; @@ -105,11 +107,11 @@ struct caps_opt { int value; }; -static int instanciate_veth(struct lxc_netdev *); -static int instanciate_macvlan(struct lxc_netdev *); -static int instanciate_vlan(struct lxc_netdev *); -static int instanciate_phys(struct lxc_netdev *); -static int instanciate_empty(struct lxc_netdev *); +static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *); +static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *); +static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *); +static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *); +static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *); static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = { [LXC_NET_VETH] = instanciate_veth, @@ -184,6 +186,52 @@ static struct caps_opt caps_opt[] = { { "mac_admin", CAP_MAC_ADMIN }, }; +static int run_script(const char *name, const char *section, const char *script, ...) +{ + va_list argp; + int vargc = 4; + /* count variable arguments and add 4 for script, container + * and section name as well as the terminating NULL + */ + va_start(argp, script); + while (va_arg(argp, char*)) vargc++; + va_end(argp); + INFO("Executing script '%s' for container '%s', config section '%s'", script, name, section); + + int pid = fork(); + if (pid < 0) { + ERROR("Error forking"); + } else if (pid == 0) { + /* prepare command line arguments */ + char *args[vargc]; + args[0] = strdup(script); + args[1] = strdup(name); + args[2] = strdup(section); + args[vargc-1] = (char*) NULL; + va_start(argp, script); + int i; + for (i=3; i<vargc; i++) { + args[i] = va_arg(argp, char*); + } + va_end(argp); + + execv(script, args); + /* if we cannot exex, we exit this fork */ + exit(1); + } else { + int status = 0; + waitpid( pid, &status, 0 ); + if (status != 0) { + /* something weird happened */ + SYSERROR("Script '%s' terminated with non-zero exitcode %d", name, status); + return -1; + } else { + return 0; /* all is well */ + } + } + return -1; +} + static int find_fstype_cb(char* buffer, void *data) { struct cbarg { @@ -1204,7 +1252,7 @@ struct lxc_conf *lxc_conf_init(void) return new; } -static int instanciate_veth(struct lxc_netdev *netdev) +static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) { char veth1buf[IFNAMSIZ], *veth1; char veth2buf[IFNAMSIZ], *veth2; @@ -1267,6 +1315,16 @@ static int instanciate_veth(struct lxc_netdev *netdev) } } + if (netdev->upscript) { + err = run_script(handler->name, "net", netdev->upscript, "up", "veth", + veth1, (char*) NULL); + if (err) { + ERROR("Failed to run script '%s' for container '%s' and interface '%s'", + netdev->upscript, handler->name, veth1); + goto out_delete; + } + } + DEBUG("instanciated veth '%s/%s', index is '%d'", veth1, veth2, netdev->ifindex); @@ -1277,7 +1335,7 @@ out_delete: return -1; } -static int instanciate_macvlan(struct lxc_netdev *netdev) +static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) { char peerbuf[IFNAMSIZ], *peer; int err; @@ -1310,6 +1368,16 @@ static int instanciate_macvlan(struct lxc_netdev *netdev) return -1; } + if (netdev->upscript) { + err = run_script(handler->name, "net", netdev->upscript, "up", "macvlan", + netdev->link, (char*) NULL); + if (err) { + ERROR("Failed to run script '%s' for container '%s' and interface '%s'", + netdev->upscript, handler->name, netdev->link); + return -1; + } + } + DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'", peer, netdev->ifindex, netdev->priv.macvlan_attr.mode); @@ -1317,7 +1385,7 @@ static int instanciate_macvlan(struct lxc_netdev *netdev) } /* XXX: merge with instanciate_macvlan */ -static int instanciate_vlan(struct lxc_netdev *netdev) +static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev) { char peer[IFNAMSIZ]; int err; @@ -1349,7 +1417,7 @@ static int instanciate_vlan(struct lxc_netdev *netdev) return 0; } -static int instanciate_phys(struct lxc_netdev *netdev) +static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) { if (!netdev->link) { ERROR("no link specified for the physical interface"); @@ -1362,17 +1430,37 @@ static int instanciate_phys(struct lxc_netdev *netdev) return -1; } + if (netdev->upscript) { + int err; + err = run_script(handler->name, "net", netdev->upscript, "up", "phys", + netdev->link, (char*) NULL); + if (err) { + ERROR("Failed to run script '%s' for container '%s' and interface '%s'", + netdev->upscript, handler->name, netdev->link); + return -1; + } + } + return 0; } -static int instanciate_empty(struct lxc_netdev *netdev) +static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) { netdev->ifindex = 0; + if (netdev->upscript) { + int err; + err = run_script(handler->name, "net", netdev->upscript, "up", "empty", (char*) NULL); + if (err) { + ERROR("Failed to run script '%s' for container '%s'", netdev->upscript, handler->name); + return -1; + } + } return 0; } -int lxc_create_network(struct lxc_list *network) +int lxc_create_network(struct lxc_handler *handler) { + struct lxc_list *network = &handler->conf->network; struct lxc_list *iterator; struct lxc_netdev *netdev; @@ -1386,10 +1474,11 @@ int lxc_create_network(struct lxc_list *network) return -1; } - if (netdev_conf[netdev->type](netdev)) { + if (netdev_conf[netdev->type](handler, netdev)) { ERROR("failed to create netdev"); return -1; } + } return 0; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index b12a346..712cb3a 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -28,6 +28,8 @@ #include <lxc/list.h> +#include <start.h> /* for lxc_handler */ + enum { LXC_NET_EMPTY, LXC_NET_VETH, @@ -94,11 +96,12 @@ union netdev_p { /* * Defines a structure to configure a network device - * @link : lxc.network.link, name of bridge or host iface to attach if any - * @name : lxc.network.name, name of iface on the container side - * @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 + * @link : lxc.network.link, name of bridge or host iface to attach if any + * @name : lxc.network.name, name of iface on the container side + * @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 + * @upscript : a script filename to be executed during interface configuration */ struct lxc_netdev { int type; @@ -111,6 +114,7 @@ struct lxc_netdev { union netdev_p priv; struct lxc_list ipv4; struct lxc_list ipv6; + char *upscript; }; /* @@ -210,7 +214,7 @@ struct lxc_conf { */ extern struct lxc_conf *lxc_conf_init(void); -extern int lxc_create_network(struct lxc_list *networks); +extern int lxc_create_network(struct lxc_handler *handler); extern void lxc_delete_network(struct lxc_list *networks); extern int lxc_assign_network(struct lxc_list *networks, pid_t pid); @@ -221,8 +225,5 @@ extern void lxc_delete_tty(struct lxc_tty_info *tty_info); * Configure the container from inside */ -struct lxc_handler; - extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf); - #endif diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 610ca15..4d81ac6 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -63,6 +63,7 @@ static int config_network_hwaddr(const char *, char *, struct lxc_conf *); static int config_network_vlan_id(const char *, char *, struct lxc_conf *); static int config_network_mtu(const char *, char *, struct lxc_conf *); static int config_network_ipv4(const char *, char *, struct lxc_conf *); +static int config_network_script(const char *, char *, struct lxc_conf *); static int config_network_ipv6(const char *, char *, struct lxc_conf *); static int config_cap_drop(const char *, char *, struct lxc_conf *); static int config_console(const char *, char *, struct lxc_conf *); @@ -91,6 +92,7 @@ static struct config config[] = { { "lxc.network.name", config_network_name }, { "lxc.network.macvlan.mode", config_network_macvlan_mode }, { "lxc.network.veth.pair", config_network_veth_pair }, + { "lxc.network.script.up", config_network_script }, { "lxc.network.hwaddr", config_network_hwaddr }, { "lxc.network.mtu", config_network_mtu }, { "lxc.network.vlan.id", config_network_vlan_id }, @@ -478,6 +480,29 @@ static int config_network_ipv6(const char *key, char *value, return 0; } +static int config_network_script(const char *key, char *value, + struct lxc_conf *lxc_conf) +{ + struct lxc_netdev *netdev; + + netdev = network_netdev(key, value, &lxc_conf->network); + if (!netdev) + return -1; + + char *copy = strdup(value); + if (!copy) { + SYSERROR("failed to dup string '%s'", value); + return -1; + } + if (strcmp(key, "lxc.network.script.up") == 0) { + netdev->upscript = copy; + return 0; + } + SYSERROR("Unknown key: %s", key); + free(copy); + return -1; +} + static int config_personality(const char *key, char *value, struct lxc_conf *lxc_conf) { diff --git a/src/lxc/start.c b/src/lxc/start.c index 1d4087c..b963b85 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -487,7 +487,7 @@ int lxc_spawn(struct lxc_handler *handler) /* 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->conf->network)) { + if (lxc_create_network(handler)) { ERROR("failed to create the network"); lxc_sync_fini(handler); return -1; -- 1.7.1 ------------------------------------------------------------------------------ Beautiful is writing same markup. Internet Explorer 9 supports standards for HTML5, CSS3, SVG 1.1, ECMAScript5, and DOM L2 & L3. Spend less time writing and rewriting code and more time creating great experiences on the web. Be a part of the beta today. http://p.sf.net/sfu/beautyoftheweb _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel