Commit 74ba4120 by Christian Brauner Committed by Stéphane Graber

conf, start: be smarter when deleting networks

- So far we blindly called lxc_delete_network() to make sure that we deleted all network interfaces. This resulted in pointless netlink calls, especially when a container had multiple networks defined. Let's be smarter and have lxc_delete_network() return a boolean that indicates whether *all* configured networks have been deleted. If so, don't needlessly try to delete them again in start.c. This also decreases confusing error messages a user might see. - When we receive -ENODEV from one of our lxc_netdev_delete_*() functions, let's assume that either the network device already got deleted or that it got moved to a different network namespace. Inform the user about this but do not report an error in this case. - When we have explicitly deleted the host side of a veth pair let's immediately free(priv.veth_attr.pair) and NULL it, or memset(priv.veth_attr.pair, ...) the corresponding member so we don't needlessly try to destroy them again when we have to call lxc_delete_network() again in start.c Signed-off-by: 's avatarChristian Brauner <christian.brauner@canonical.com>
parent c7dc0721
...@@ -2880,20 +2880,22 @@ int lxc_create_network(struct lxc_handler *handler) ...@@ -2880,20 +2880,22 @@ int lxc_create_network(struct lxc_handler *handler)
return 0; return 0;
} }
void lxc_delete_network(struct lxc_handler *handler) bool lxc_delete_network(struct lxc_handler *handler)
{ {
int ret; int ret;
struct lxc_list *network = &handler->conf->network; struct lxc_list *network = &handler->conf->network;
struct lxc_list *iterator; struct lxc_list *iterator;
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
bool deleted_all = true;
lxc_list_for_each(iterator, network) { lxc_list_for_each(iterator, network) {
netdev = iterator->elem; netdev = iterator->elem;
if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) { if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link)) if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
WARN("Failed to rename to the initial name the " \ WARN("Failed to rename interface with index %d "
"netdev '%s'", netdev->link); "to its initial name \"%s\".",
netdev->ifindex, netdev->link);
continue; continue;
} }
...@@ -2907,35 +2909,54 @@ void lxc_delete_network(struct lxc_handler *handler) ...@@ -2907,35 +2909,54 @@ void lxc_delete_network(struct lxc_handler *handler)
*/ */
if (netdev->ifindex != 0) { if (netdev->ifindex != 0) {
ret = lxc_netdev_delete_by_index(netdev->ifindex); ret = lxc_netdev_delete_by_index(netdev->ifindex);
if (ret < 0) if (-ret == ENODEV) {
WARN("Failed to remove interface %d '%s': %s.", INFO("Interface \"%s\" with index %d already "
netdev->ifindex, "deleted or existing in different network "
netdev->name ? netdev->name : "(null)", strerror(-ret)); "namespace.",
else netdev->name ? netdev->name : "(null)",
INFO("Removed interface %d '%s'.", netdev->ifindex);
netdev->ifindex, } else if (ret < 0) {
netdev->name ? netdev->name : "(null)"); deleted_all = false;
WARN("Failed to remove interface \"%s\" with "
"index %d: %s.",
netdev->name ? netdev->name : "(null)",
netdev->ifindex, strerror(-ret));
} else {
INFO("Removed interface \"%s\" with index %d.",
netdev->name ? netdev->name : "(null)",
netdev->ifindex);
}
} }
/* Explicitly delete host veth device to prevent lingering /* Explicitly delete host veth device to prevent lingering
* devices. We had issues in LXD around this. * devices. We had issues in LXD around this.
*/ */
if (netdev->type == LXC_NET_VETH) { if (netdev->type == LXC_NET_VETH) {
char *hostveth = NULL; char *hostveth;
if (netdev->priv.veth_attr.pair) if (netdev->priv.veth_attr.pair) {
hostveth = netdev->priv.veth_attr.pair; hostveth = netdev->priv.veth_attr.pair;
else if (strlen(netdev->priv.veth_attr.veth1) > 0) ret = lxc_netdev_delete_by_name(hostveth);
if (ret < 0) {
WARN("Failed to remove interface \"%s\" from host: %s.", hostveth, strerror(-ret));
} else {
INFO("Removed interface \"%s\" from host.", hostveth);
free(netdev->priv.veth_attr.pair);
netdev->priv.veth_attr.pair = NULL;
}
} else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
hostveth = netdev->priv.veth_attr.veth1; hostveth = netdev->priv.veth_attr.veth1;
if (hostveth) {
ret = lxc_netdev_delete_by_name(hostveth); ret = lxc_netdev_delete_by_name(hostveth);
if (ret < 0) if (ret < 0) {
WARN("Failed to remove '%s' from host.", hostveth); WARN("Failed to remove \"%s\" from host: %s.", hostveth, strerror(-ret));
else } else {
INFO("Deleted '%s' from host.", hostveth); INFO("Removed interface \"%s\" from host.", hostveth);
memset((void *)&netdev->priv.veth_attr.veth1, 0, sizeof(netdev->priv.veth_attr.veth1));
}
} }
} }
} }
return deleted_all;
} }
#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic" #define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
......
...@@ -401,7 +401,7 @@ extern int pin_rootfs(const char *rootfs); ...@@ -401,7 +401,7 @@ extern int pin_rootfs(const char *rootfs);
extern int lxc_requests_empty_network(struct lxc_handler *handler); extern int lxc_requests_empty_network(struct lxc_handler *handler);
extern int lxc_create_network(struct lxc_handler *handler); extern int lxc_create_network(struct lxc_handler *handler);
extern void lxc_delete_network(struct lxc_handler *handler); extern bool lxc_delete_network(struct lxc_handler *handler);
extern int lxc_assign_network(const char *lxcpath, char *lxcname, extern int lxc_assign_network(const char *lxcpath, char *lxcname,
struct lxc_list *networks, pid_t pid); struct lxc_list *networks, pid_t pid);
extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid); extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
......
...@@ -1318,6 +1318,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf, ...@@ -1318,6 +1318,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
struct lxc_handler *handler; struct lxc_handler *handler;
int err = -1; int err = -1;
int status; int status;
bool removed_all_netdevs = true;
handler = lxc_init(name, conf, lxcpath); handler = lxc_init(name, conf, lxcpath);
if (!handler) { if (!handler) {
...@@ -1412,7 +1413,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf, ...@@ -1412,7 +1413,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
lxc_restore_phys_nics_to_netns(handler->netnsfd, handler->conf); lxc_restore_phys_nics_to_netns(handler->netnsfd, handler->conf);
DEBUG("Tearing down virtual network devices used by container"); DEBUG("Tearing down virtual network devices used by container");
lxc_delete_network(handler); removed_all_netdevs = lxc_delete_network(handler);
if (handler->pinfd >= 0) { if (handler->pinfd >= 0) {
close(handler->pinfd); close(handler->pinfd);
...@@ -1422,7 +1423,12 @@ int __lxc_start(const char *name, struct lxc_conf *conf, ...@@ -1422,7 +1423,12 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
lxc_monitor_send_exit_code(name, status, handler->lxcpath); lxc_monitor_send_exit_code(name, status, handler->lxcpath);
err = lxc_error_set_and_log(handler->pid, status); err = lxc_error_set_and_log(handler->pid, status);
out_fini: out_fini:
lxc_delete_network(handler); if (!removed_all_netdevs) {
DEBUG("Failed tearing down all network devices used by container. Trying again!");
removed_all_netdevs = lxc_delete_network(handler);
if (!removed_all_netdevs)
DEBUG("Failed tearing down network devices used by container. Not trying again!");
}
out_detach_blockdev: out_detach_blockdev:
detach_block_device(handler->conf); detach_block_device(handler->conf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment