]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
network: delete ovs for unprivileged networks
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 27 Aug 2017 03:02:23 +0000 (05:02 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 29 Aug 2017 20:54:50 +0000 (22:54 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/lxc_user_nic.c

index 7fe3297eeb4095346866d32028e05f84ec836164..7b9aa980214c1a49e4a951e41f4fff1c7dff0226 100644 (file)
@@ -3100,26 +3100,44 @@ bool lxc_delete_network(struct lxc_handler *handler)
                 * namespace is destroyed but in case we did not move the
                 * interface to the network namespace, we have to destroy it.
                 */
-               ret = lxc_netdev_delete_by_index(netdev->ifindex);
-               if (-ret == ENODEV) {
-                       INFO("Interface \"%s\" with index %d already deleted "
-                            "or existing in different network namespace",
-                            netdev->name ? netdev->name : "(null)", netdev->ifindex);
-               } else if (ret < 0) {
-                       deleted_all = false;
-                       WARN("Failed to remove interface \"%s\" with index %d: "
-                            "%s", netdev->name ? netdev->name : "(null)",
-                            netdev->ifindex, strerror(-ret));
-                       continue;
+               if (!am_unpriv()) {
+                       ret = lxc_netdev_delete_by_index(netdev->ifindex);
+                       if (-ret == ENODEV) {
+                               INFO("Interface \"%s\" with index %d already "
+                                    "deleted or existing in different network "
+                                    "namespace",
+                                    netdev->name ? netdev->name : "(null)",
+                                    netdev->ifindex);
+                       } else if (ret < 0) {
+                               deleted_all = false;
+                               WARN("Failed to remove interface \"%s\" with "
+                                    "index %d: %s",
+                                    netdev->name ? netdev->name : "(null)",
+                                    netdev->ifindex, strerror(-ret));
+                               continue;
+                       }
+                       INFO("Removed interface \"%s\" with index %d",
+                            netdev->name ? netdev->name : "(null)",
+                            netdev->ifindex);
                }
-               INFO("Removed interface \"%s\" with index %d",
-                    netdev->name ? netdev->name : "(null)", netdev->ifindex);
 
                if (netdev->type != LXC_NET_VETH)
                        continue;
 
-               if (am_unpriv())
+               if (am_unpriv()) {
+                       if (is_ovs_bridge(netdev->link)) {
+                               ret = lxc_unpriv_delete_nic(handler->lxcpath,
+                                                           handler->name, "ovs",
+                                                           netdev, getpid());
+                               if (ret < 0)
+                                       WARN("Failed to remove port \"%s\" "
+                                            "from openvswitch bridge \"%s\"",
+                                            netdev->priv.veth_attr.pair,
+                                            netdev->link);
+                       }
+
                        continue;
+               }
 
                /* Explicitly delete host veth device to prevent lingering
                 * devices. We had issues in LXD around this.
@@ -5098,3 +5116,91 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings)
 
        return result;
 }
+
+int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type,
+                         struct lxc_netdev *netdev, pid_t pid)
+{
+       pid_t child;
+       int bytes, pipefd[2];
+       char netdev_link[IFNAMSIZ + 1];
+       char buffer[MAX_BUFFER_SIZE] = {0};
+
+       if (netdev->type != LXC_NET_VETH) {
+               ERROR("nic type %d not support for unprivileged use",
+                     netdev->type);
+               return -1;
+       }
+
+       if (pipe(pipefd) < 0) {
+               SYSERROR("pipe failed");
+               return -1;
+       }
+
+       child = fork();
+       if (child < 0) {
+               SYSERROR("fork");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return -1;
+       }
+
+       if (child == 0) { /* child */
+               /* Call lxc-user-nic pid type bridge. */
+               int ret;
+               char pidstr[LXC_NUMSTRLEN64];
+
+               close(pipefd[0]); /* Close the read-end of the pipe. */
+
+               /* Redirect stdout to write-end of the pipe. */
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               if (ret >= 0)
+                       ret = dup2(pipefd[1], STDERR_FILENO);
+               close(pipefd[1]); /* Close the write-end of the pipe. */
+               if (ret < 0) {
+                       SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (netdev->link)
+                       strncpy(netdev_link, netdev->link, IFNAMSIZ);
+               else
+                       strncpy(netdev_link, "none", IFNAMSIZ);
+
+               ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
+               if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+                       exit(EXIT_FAILURE);
+               pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+
+               INFO("Execing lxc-user-nic delete %s %s %s ovs %s %s", lxcpath,
+                    lxcname, pidstr, netdev_link, netdev->priv.veth_attr.pair);
+               execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
+                      lxcname, pidstr, "ovs", netdev_link,
+                      netdev->priv.veth_attr.pair, (char *)NULL);
+               SYSERROR("Failed to exec lxc-user-nic.");
+               exit(EXIT_FAILURE);
+       }
+
+       /* close the write-end of the pipe */
+       close(pipefd[1]);
+
+       bytes = read(pipefd[0], &buffer, MAX_BUFFER_SIZE);
+       if (bytes < 0) {
+               SYSERROR("Failed to read from pipe file descriptor.");
+               close(pipefd[0]);
+               return -1;
+       }
+       buffer[bytes - 1] = '\0';
+
+       if (wait_for_pid(child) != 0) {
+               ERROR("lxc-user-nic failed to delete requested network: %s",
+                     buffer[0] != '\0' ? buffer : "(null)");
+               close(pipefd[0]);
+               return -1;
+       }
+       TRACE("Received output \"%s\" from lxc-user-nic", buffer);
+
+       /* close the read-end of the pipe */
+       close(pipefd[0]);
+
+       return 0;
+}
index 9850fecdebe549a98bfb9aec4b007cba179127b2..077f594e7cf25eb5e1f84fbbfe6e3faac4f2001f 100644 (file)
@@ -449,9 +449,11 @@ extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
 extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
 void remount_all_slave(void);
 extern void suggest_default_idmap(void);
-FILE *make_anonymous_mount_file(struct lxc_list *mount);
-struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings);
-unsigned long add_required_remount_flags(const char *s, const char *d,
-               unsigned long flags);
-
-#endif
+extern FILE *make_anonymous_mount_file(struct lxc_list *mount);
+extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
+extern unsigned long add_required_remount_flags(const char *s, const char *d,
+                                               unsigned long flags);
+extern int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type,
+                                struct lxc_netdev *netdev, pid_t pid);
+
+#endif /* __LXC_CONF_H */
index 70dcd8975dc0086357d862f4c2d9e79c03b7823c..2bcbdba006bf76b69432bf773bfdc54184a5a757 100644 (file)
@@ -835,9 +835,10 @@ static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
                name = "eth%d";
 
        ret = lxc_netdev_rename_by_name(oldname, name);
+       name = NULL;
        if (ret < 0) {
                usernic_error("Error %d renaming netdev %s to %s in container\n",
-                             ret, oldname, name);
+                             ret, oldname, newname ? newname : "eth%d");
                goto do_full_cleanup;
        }
 
@@ -1008,6 +1009,25 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
+       if (!strcmp(args.cmd, "delete")) {
+               close(fd);
+
+               if (strcmp(args.type, "ovs")) {
+                       usernic_error("%s", "Deletion of non ovs type network "
+                                           "devics not implemented\n");
+                       exit(EXIT_FAILURE);
+               }
+
+               ret = lxc_ovs_delete_port(args.link, args.veth_name);
+               if (ret < 0) {
+                       usernic_error("Failed to remove port \"%s\" from "
+                                     "openvswitch bridge \"%s\"",
+                                     args.veth_name, args.link);
+                       exit(EXIT_FAILURE);
+               }
+               exit(EXIT_SUCCESS);
+       }
+
        n = get_alloted(me, args.type, args.link, &alloted);
        if (n > 0)
                nicname = get_nic_if_avail(fd, alloted, pid, args.type,