[lxc-devel] [PATCH] add lxc.network.script.up configuration hook
Stefan Tomanek
stefan.tomanek at wertarbyte.de
Fri Oct 8 20:55:14 UTC 2010
This commit adds an 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) device name
---
src/lxc/conf.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++------
src/lxc/conf.h | 19 +++++----
src/lxc/confile.c | 25 +++++++++++
src/lxc/start.c | 2 +-
4 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index adfe862..4f1b46c 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,53 @@ 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];
+ int i;
+ args[0] = strdup(script);
+ args[1] = strdup(name);
+ args[2] = strdup(section);
+ va_start(argp, script);
+ for (i=3; i<vargc; i++) {
+ args[i] = va_arg(argp, char*);
+ }
+ va_end(argp);
+ args[vargc-1] = (char*) NULL;
+
+ execv(script, args);
+ /* if we cannot exec, we exit this fork */
+ SYSERROR("Failed to execute script '%s' for container '%s': %s", script, name, strerror(errno));
+ 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 +1253,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 +1316,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 +1336,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 +1369,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 +1386,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 +1418,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 +1431,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 +1475,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
More information about the lxc-devel
mailing list