diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in index 05d6bc7f7..80c4335e3 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 + + + + + + + + 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. + + + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index b437654a3..79fe4ad5a 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -138,6 +138,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 }, @@ -1765,6 +1779,8 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd return -1; } veth1 = mktemp(veth1buf); + /* store away for deconf */ + memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ); } snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX"); @@ -1841,6 +1857,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; @@ -1889,6 +1924,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) { @@ -1926,6 +1975,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) { @@ -1950,6 +2004,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; @@ -1963,6 +2030,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; @@ -1989,28 +2069,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 ad48042af..92efc585e 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -24,6 +24,7 @@ #define _conf_h #include +#include #include #include @@ -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; }; /* @@ -242,7 +246,7 @@ extern struct lxc_conf *lxc_conf_init(void); extern int pin_rootfs(const char *rootfs); 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 2b5e73c91..9e51a6392 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -111,6 +111,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 }, @@ -595,6 +596,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 60ac1096b..77755b979 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -652,7 +652,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); @@ -684,7 +684,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); @@ -719,6 +719,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;