}
if (netdev->link) {
- err = lxc_bridge_attach(handler->lxcpath, handler->name, netdev->link, veth1);
+ err = lxc_bridge_attach(netdev->link, veth1);
if (err) {
ERROR("failed to attach \"%s\" to bridge \"%s\": %s",
veth1, netdev->link, strerror(-err));
char *hostveth;
if (netdev->priv.veth_attr.pair) {
hostveth = netdev->priv.veth_attr.pair;
+
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);
+
+ if (is_ovs_bridge(netdev->link)) {
+ ret = lxc_ovs_delete_port(netdev->link, hostveth);
+ if (ret < 0)
+ WARN("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
+ else
+ INFO("Removed port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
+ }
} else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
hostveth = netdev->priv.veth_attr.veth1;
ret = lxc_netdev_delete_by_name(hostveth);
WARN("Failed to remove \"%s\" from host: %s.", hostveth, strerror(-ret));
} else {
INFO("Removed interface \"%s\" from host.", hostveth);
- memset((void *)&netdev->priv.veth_attr.veth1, 0, sizeof(netdev->priv.veth_attr.veth1));
+
+ if (is_ovs_bridge(netdev->link)) {
+ ret = lxc_ovs_delete_port(netdev->link, hostveth);
+ if (ret < 0) {
+ WARN("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
+ } else {
+ INFO("Removed port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
+ memset((void *)&netdev->priv.veth_attr.veth1, 0, sizeof(netdev->priv.veth_attr.veth1));
+ }
+ }
}
}
}
return ip_route_dest_add(AF_INET6, ifindex, dest);
}
-static bool is_ovs_bridge(const char *bridge)
+bool is_ovs_bridge(const char *bridge)
{
char brdirname[22 + IFNAMSIZ + 1] = {0};
struct stat sb;
return false;
}
+struct ovs_veth_args {
+ const char *bridge;
+ const char *nic;
+};
+
/* Called from a background thread - when nic goes away, remove it from the
* bridge.
*/
-static void ovs_cleanup_nic(const char *lxcpath, const char *name,
- const char *bridge, const char *nic)
+static int lxc_ovs_delete_port_exec(void *data)
{
- int ret;
+ struct ovs_veth_args *args = data;
- ret = lxc_check_inherited(NULL, true, &(int){-1}, 1);
- if (ret < 0)
- return;
+ execlp("ovs-vsctl", "ovs-vsctl", "del-port", args->bridge, args->nic,
+ (char *)NULL);
+ return -1;
+}
- TRACE("Registering cleanup thread to remove nic \"%s\" from "
- "openvswitch bridge \"%s\"", nic, bridge);
+int lxc_ovs_delete_port(const char *bridge, const char *nic)
+{
+ int ret;
+ char cmd_output[MAXPATHLEN];
+ struct ovs_veth_args args;
- ret = lxc_wait(name, "STOPPED", -1, lxcpath);
+ args.bridge = bridge;
+ args.nic = nic;
+ ret = run_command(cmd_output, sizeof(cmd_output),
+ lxc_ovs_delete_port_exec, (void *)&args);
if (ret < 0) {
- ERROR("Failed to register cleanup thread to remove nic \"%s\" "
- "from openvswitch bridge \"%s\"", nic, bridge);
- return;
+ ERROR("Failed to delete \"%s\" from openvswitch bridge \"%s\": "
+ "%s", bridge, nic, cmd_output);
+ return -1;
}
- execlp("ovs-vsctl", "ovs-vsctl", "del-port", bridge, nic, (char *)NULL);
- exit(EXIT_FAILURE);
+ return 0;
}
-static int attach_to_ovs_bridge(const char *lxcpath, const char *name, const char *bridge, const char *nic)
+static int lxc_ovs_attach_bridge_exec(void *data)
{
- pid_t pid;
- char *cmd;
- int ret;
+ struct ovs_veth_args *args = data;
- cmd = on_path("ovs-vsctl", NULL);
- if (!cmd)
- return -1;
- free(cmd);
+ execlp("ovs-vsctl", "ovs-vsctl", "add-port", args->bridge, args->nic,
+ (char *)NULL);
+ return -1;
+}
- pid = fork();
- if (pid < 0)
+static int lxc_ovs_attach_bridge(const char *bridge, const char *nic)
+{
+ int ret;
+ char cmd_output[MAXPATHLEN];
+ struct ovs_veth_args args;
+
+ args.bridge = bridge;
+ args.nic = nic;
+ ret = run_command(cmd_output, sizeof(cmd_output),
+ lxc_ovs_attach_bridge_exec, (void *)&args);
+ if (ret < 0) {
+ ERROR("Failed to attach \"%s\" to openvswitch bridge \"%s\": %s",
+ bridge, nic, cmd_output);
return -1;
- if (pid > 0) {
- ret = wait_for_pid(pid);
- if (ret < 0)
- return ret;
- pid = fork();
- if (pid < 0)
- return -1; // how to properly recover?
- if (pid > 0)
- return 0;
- ovs_cleanup_nic(lxcpath, name, bridge, nic);
- exit(0);
}
- if (execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, (char *)NULL))
- exit(1);
- // not reached
- exit(1);
+ return 0;
}
-/*
- * There is a lxc_bridge_attach, but no need of a bridge detach
- * as automatically done by kernel when a netdev is deleted.
- */
-int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, const char *ifname)
+int lxc_bridge_attach(const char *bridge, const char *ifname)
{
int fd, index, err;
struct ifreq ifr;
return -EINVAL;
if (is_ovs_bridge(bridge))
- return attach_to_ovs_bridge(lxcpath, name, bridge, ifname);
+ return lxc_ovs_attach_bridge(bridge, ifname);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)