[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