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

Reply via email to