[lxc-devel] [PATCH] Add network-down script
Jan Kiszka
jan.kiszka at siemens.com
Mon Jul 9 17:15:48 UTC 2012
Analogously to lxc.network.script.up, add the ability to register a down
script. It is called before the guest network is finally destroyed,
allowing to clean up resources that are not reset/destroyed
automatically. Parameters of the down script are identical to the up
script except for the execution context "down".
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
---
doc/lxc.conf.sgml.in | 20 +++++++++++
src/lxc/conf.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++---
src/lxc/conf.h | 6 +++-
src/lxc/confile.c | 5 +++
src/lxc/start.c | 7 +++-
5 files changed, 124 insertions(+), 8 deletions(-)
diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in
index 9edabf8..2b1a4a5 100644
--- a/doc/lxc.conf.sgml.in
+++ b/doc/lxc.conf.sgml.in
@@ -374,6 +374,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.script.down</option>
+ </term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index e8088bb..1043342 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -134,6 +134,20 @@ static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_EMPTY] = instanciate_empty,
};
+static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
+static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
+static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
+static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
+static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
+
+static instanciate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
+ [LXC_NET_VETH] = shutdown_veth,
+ [LXC_NET_MACVLAN] = shutdown_macvlan,
+ [LXC_NET_VLAN] = shutdown_vlan,
+ [LXC_NET_PHYS] = shutdown_phys,
+ [LXC_NET_EMPTY] = shutdown_empty,
+};
+
static struct mount_opt mount_opt[] = {
{ "defaults", 0, 0 },
{ "ro", 0, MS_RDONLY },
@@ -1606,6 +1620,8 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
else {
snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
veth1 = mktemp(veth1buf);
+ /* store away for deconf */
+ memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
}
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
@@ -1682,6 +1698,25 @@ out_delete:
return -1;
}
+static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ char *veth1;
+ int err;
+
+ if (netdev->priv.veth_attr.pair)
+ veth1 = netdev->priv.veth_attr.pair;
+ else
+ veth1 = netdev->priv.veth_attr.veth1;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "veth", veth1, (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char peerbuf[IFNAMSIZ], *peer;
@@ -1728,6 +1763,20 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
return 0;
}
+static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "macvlan", netdev->link,
+ (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
/* XXX: merge with instanciate_macvlan */
static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
@@ -1761,6 +1810,11 @@ static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
return 0;
}
+static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ return 0;
+}
+
static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
if (!netdev->link) {
@@ -1785,6 +1839,19 @@ static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
return 0;
}
+static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ 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 instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
netdev->ifindex = 0;
@@ -1798,6 +1865,19 @@ static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *net
return 0;
}
+static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "empty", (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
int lxc_create_network(struct lxc_handler *handler)
{
struct lxc_list *network = &handler->conf->network;
@@ -1824,28 +1904,32 @@ int lxc_create_network(struct lxc_handler *handler)
return 0;
}
-void lxc_delete_network(struct lxc_list *network)
+void lxc_delete_network(struct lxc_handler *handler)
{
+ struct lxc_list *network = &handler->conf->network;
struct lxc_list *iterator;
struct lxc_netdev *netdev;
lxc_list_for_each(iterator, network) {
netdev = iterator->elem;
- if (netdev->ifindex == 0)
- continue;
- if (netdev->type == LXC_NET_PHYS) {
+ if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
WARN("failed to rename to the initial name the " \
"netdev '%s'", netdev->link);
continue;
}
+ if (netdev_deconf[netdev->type](handler, netdev)) {
+ WARN("failed to destroy netdev");
+ }
+
/* Recent kernel remove the virtual interfaces when the network
* namespace is destroyed but in case we did not moved the
* interface to the network namespace, we have to destroy it
*/
- if (lxc_netdev_delete_by_index(netdev->ifindex))
+ if (netdev->ifindex != 0 &&
+ lxc_netdev_delete_by_index(netdev->ifindex))
WARN("failed to remove interface '%s'", netdev->name);
}
}
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 09f55cb..3f65d76 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -24,6 +24,7 @@
#define _conf_h
#include <netinet/in.h>
+#include <net/if.h>
#include <sys/param.h>
#include <stdbool.h>
@@ -76,6 +77,7 @@ struct lxc_route6 {
struct ifla_veth {
char *pair; /* pair name */
+ char veth1[IFNAMSIZ]; /* needed for deconf */
};
struct ifla_vlan {
@@ -103,6 +105,7 @@ union netdev_p {
* @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
+ * @downscript : a script filename to be executed during interface destruction
*/
struct lxc_netdev {
int type;
@@ -120,6 +123,7 @@ struct lxc_netdev {
struct in6_addr *ipv6_gateway;
bool ipv6_gateway_auto;
char *upscript;
+ char *downscript;
};
/*
@@ -224,7 +228,7 @@ struct lxc_conf {
extern struct lxc_conf *lxc_conf_init(void);
extern int lxc_create_network(struct lxc_handler *handler);
-extern void lxc_delete_network(struct lxc_list *networks);
+extern void lxc_delete_network(struct lxc_handler *handler);
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index b305aef..c5e7f47 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -98,6 +98,7 @@ static struct config config[] = {
{ "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.script.down", config_network_script },
{ "lxc.network.hwaddr", config_network_hwaddr },
{ "lxc.network.mtu", config_network_mtu },
{ "lxc.network.vlan.id", config_network_vlan_id },
@@ -579,6 +580,10 @@ static int config_network_script(const char *key, char *value,
netdev->upscript = copy;
return 0;
}
+ if (strcmp(key, "lxc.network.script.down") == 0) {
+ netdev->downscript = copy;
+ return 0;
+ }
SYSERROR("Unknown key: %s", key);
free(copy);
return -1;
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 920ff77..1295f41 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -609,7 +609,7 @@ int lxc_spawn(struct lxc_handler *handler)
out_delete_net:
if (clone_flags & CLONE_NEWNET)
- lxc_delete_network(&handler->conf->network);
+ lxc_delete_network(handler);
out_abort:
lxc_abort(name, handler);
lxc_sync_fini(handler);
@@ -641,7 +641,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
err = lxc_spawn(handler);
if (err) {
ERROR("failed to spawn '%s'", name);
- goto out_fini;
+ goto out_fini_nonet;
}
err = lxc_poll(name, handler);
@@ -676,6 +676,9 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
err = lxc_error_set_and_log(handler->pid, status);
out_fini:
+ lxc_delete_network(handler);
+
+out_fini_nonet:
lxc_cgroup_destroy(name);
lxc_fini(name, handler);
return err;
--
1.7.3.4
More information about the lxc-devel
mailing list