net: clean-up tap handling logic
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Mon, 4 Jan 2016 10:38:25 +0000 (19:38 +0900)
committerJinhyung Choi <jinh0.choi@samsung.com>
Tue, 5 Jan 2016 12:13:28 +0000 (21:13 +0900)
Tizen emulator specific logic is extracted to independent source file.
Tap interface prefix is changed to "tap-tizen".

Change-Id: I38e218936003e8bc8de51a4d0b3413872defe4c3
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
Signed-off-by: Munkyu Im <munkyu.im@samsung.com>
net/tap-linux.c
net/tap.c
tizen/src/util/Makefile.objs
tizen/src/util/tap_helper.c [new file with mode: 0644]
tizen/src/util/tap_helper.h [new file with mode: 0644]

index 419a245..5bd9d21 100644 (file)
 
 #define PATH_NET_TUN "/dev/net/tun"
 
-#if defined(CONFIG_MARU)
-#include "tizen/src/emul_state.h"
-
-static int launch_openvpn(bool ismake, const char *ifname)
-{
-    int pid, status;
-    const char* args[] = {
-        "/usr/bin/sudo",
-        "/usr/sbin/openvpn",
-        "--mktun",
-        "--dev",
-        ifname,
-        NULL
-    };
-    if (ismake) {
-        fprintf(stdout, "launch_openvpn make tap: %s\n", ifname);
-    } else {
-        fprintf(stdout, "launch_openvpn remove tap: %s\n", ifname);
-        args[2] = "--rmtun";
-    }
-    /* try to launch network script */
-    pid = fork();
-    if (pid == 0) {
-        execv(args[0], (char**)args);
-        _exit(1);
-    } else if (pid > 0) {
-        while (waitpid(pid, &status, 0) != pid) {
-            /* loop */
-        }
-
-        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-            return 0;
-        }
-    }
-    fprintf(stderr, "Could not launch openvpn\n");
-    return -1;
-}
-
-static int tap_cleanup(void)
-{
-    int fd, ret;
-    struct ifreq ifr;
-    char dname[100];
-    int port = get_emul_vm_base_port() + 10;
-
-    TFR(fd = open(PATH_NET_TUN, O_RDWR));
-    if (fd < 0) {
-        error_report("could not open %s: %m", PATH_NET_TUN);
-        return -1;
-    }
-    memset(&ifr, 0, sizeof(ifr));
-    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-
-    for ( ; port < 26200; port += 10) {
-        snprintf(dname, sizeof(dname), "tap%d", port);
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, dname);
-        ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
-        if (ret == 0) {
-            close(fd);
-            if (launch_openvpn(false, dname)) {
-                fprintf(stderr, "Failed to remove %s device. It can be used on the other emulator\n", dname);
-            }
-            TFR(fd = open(PATH_NET_TUN, O_RDWR));
-            if (fd < 0) {
-                error_report("could not open %s: %m", PATH_NET_TUN);
-                return -1;
-            }
-        } else {
-            close(fd);
-        }
-    }
-    return 0;
-}
-
-#endif
-
 int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
              int vnet_hdr_required, int mq_required, Error **errp)
 {
@@ -119,11 +43,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
     int fd, ret;
     int len = sizeof(struct virtio_net_hdr);
     unsigned int features;
-#if defined(CONFIG_MARU)
-    if (tap_cleanup() < 0) {
-        return -1;
-    }
-#endif
+
     TFR(fd = open(PATH_NET_TUN, O_RDWR));
     if (fd < 0) {
         error_setg_errno(errp, errno, "could not open %s", PATH_NET_TUN);
@@ -177,20 +97,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
 
     if (ifname[0] != '\0')
         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
-    else {
-#if defined(CONFIG_MARU)
-        /* Create tap */
-        char dname[100];
-        snprintf(dname, sizeof dname, "tap%d", get_emul_vm_base_port());
-        if (launch_openvpn(true, dname)) {
-            close(fd);
-            return -1;
-        }
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, dname);
-#else
+    else
         pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
-#endif
-    }
     ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
     if (ret != 0) {
         if (ifname[0] != '\0') {
index 6642bc4..3a67a3e 100644 (file)
--- a/net/tap.c
+++ b/net/tap.c
@@ -45,6 +45,9 @@
 #include "net/vhost_net.h"
 #if defined(CONFIG_MARU)
 #include "tizen/src/emul_state.h"
+# if defined(CONFIG_LINUX)
+#include "tizen/src/util/tap_helper.h"
+# endif
 #endif
 
 typedef struct TAPState {
@@ -384,7 +387,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
     return s;
 }
 
-#if !defined(CONFIG_WIN32) && defined(CONFIG_MARU)
+#if defined(CONFIG_MARU)
 #include <arpa/inet.h>
 #include <sys/socket.h>
 #include <ifaddrs.h>
@@ -420,7 +423,7 @@ static void launch_script(const char *setup_script, const char *ifname,
                           int fd, Error **errp)
 {
     int pid, status;
-#if !defined(CONFIG_WIN32) && defined(CONFIG_MARU)
+#if defined(CONFIG_MARU)
     const char* sudo_path = "/usr/bin/sudo";
     char *host_ifname = get_interface_name_from_ip();
     fprintf(stdout, "host_ifname: %s\n", host_ifname);
@@ -452,7 +455,7 @@ static void launch_script(const char *setup_script, const char *ifname,
             }
         }
         parg = args;
-#if !defined(CONFIG_WIN32) && defined(CONFIG_MARU)
+#if defined(CONFIG_MARU)
         *parg++ = (char *)sudo_path;
 #endif
         *parg++ = (char *)setup_script;
@@ -462,7 +465,7 @@ static void launch_script(const char *setup_script, const char *ifname,
         }
         *parg = NULL;
 
-#if !defined(CONFIG_WIN32) && defined(CONFIG_MARU)
+#if defined(CONFIG_MARU)
         execv(sudo_path, args);
 #else
         execv(setup_script, args);
@@ -912,7 +915,15 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
         if (tap->has_ifname) {
             pstrcpy(ifname, sizeof ifname, tap->ifname);
         } else {
+#if defined(CONFIG_LINUX) && defined(CONFIG_MARU)
+            /* Create tap */
+            tap_create(ifname);
+            if (ifname[0] == '\0') {
+                return -1;
+            }
+#else
             ifname[0] = '\0';
+#endif
         }
 
         for (i = 0; i < queues; i++) {
index b860b56..6c2564f 100644 (file)
@@ -16,6 +16,9 @@ obj-$(CONFIG_LINUX) += osutil-linux.o
 obj-$(CONFIG_WIN32) += osutil-win32.o
 obj-$(CONFIG_DARWIN) += osutil-darwin.o
 
+# tap helper
+obj-$(CONFIG_LINUX) += tap_helper.o
+
 #sdb
 obj-y += sdb.o
 
diff --git a/tizen/src/util/tap_helper.c b/tizen/src/util/tap_helper.c
new file mode 100644 (file)
index 0000000..6c142f6
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * TAP helper
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  MunKyu Im       <munkyu.im@samsung.com>
+ *  SeokYeon Hwang  <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+
+#include "tap_helper.h"
+
+#define PATH_NET_TUN "/dev/net/tun"
+
+#include "util/new_debug_ch.h"
+DECLARE_DEBUG_CHANNEL(tap_helper);
+
+#define START_BASE_PORT 26100
+#define END_BASE_PORT 26200
+
+static bool launch_openvpn(bool ismake, const char *ifname)
+{
+    int pid, status;
+    const char* args[] = {
+        "/usr/bin/sudo",
+        "/usr/sbin/openvpn",
+        "",
+        "--dev",
+        ifname,
+        NULL
+    };
+    if (ismake) {
+        LOG_INFO("launch_openvpn make tap: %s\n", ifname);
+        args[2] = "--mktun";
+    } else {
+        LOG_INFO("launch_openvpn remove tap: %s\n", ifname);
+        args[2] = "--rmtun";
+    }
+    /* try to launch network script */
+    pid = fork();
+    if (pid == 0) {
+        execv(args[0], (char**)args);
+        _exit(1);
+    } else if (pid > 0) {
+        while (waitpid(pid, &status, 0) != pid) {
+            /* loop */
+        }
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return true;
+        }
+    }
+
+    LOG_WARNING("Could not launch openvpn\n");
+    return false;
+}
+
+void tap_create(char *ifname)
+{
+    int fd, ret, i;
+    struct ifreq ifr;
+    char dname[128];
+    int cause;
+
+    ifname[0] = '\0';
+
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+    // clean-up legacy ifnames
+    for (i = START_BASE_PORT ; i < END_BASE_PORT; i += 10) {
+        g_snprintf(dname, sizeof(dname), "tap%d", i);
+        g_strlcpy(ifr.ifr_name, dname, IFNAMSIZ);
+
+        TFR(fd = open(PATH_NET_TUN, O_RDWR));
+        if (fd < 0) {
+            error_report("could not open %s: %m", PATH_NET_TUN);
+            return;
+        }
+
+        ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+
+        close(fd);
+
+        if (ret == 0) {
+            if (!launch_openvpn(false, dname)) {
+                LOG_INFO("Failed to remove tap interface [%s]."
+                        "The other emulator may be using this interface.\n", dname);
+            }
+        }
+    }
+
+    // clean-up and find first unused ifname
+    for (i = 0; i < 10; i++) {
+        g_snprintf(dname, sizeof(dname), "tap_tizen%d", i);
+        g_strlcpy(ifr.ifr_name, dname, IFNAMSIZ);
+
+        TFR(fd = open(PATH_NET_TUN, O_RDWR));
+        if (fd < 0) {
+            error_report("could not open %s: %m", PATH_NET_TUN);
+            return;
+        }
+
+        ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+        cause = errno;
+        close(fd);
+
+        // ret 0: exist but not used
+        // ret -1 and cause EPERM: not exist
+        if (ret == 0 || (ret == -1 && cause == EPERM)) {
+            if (ret == 0 && !launch_openvpn(false, dname)) {
+                LOG_INFO("Failed to remove tap interface [%s]."
+                        "The other emulator may be using this interface.\n", dname);
+                continue;
+            }
+            if (ifname[0] == '\0') {
+                g_strlcpy(ifname, dname, 128);
+            }
+        }
+    }
+
+    // create tap
+    if (ifname == '\0' || !launch_openvpn(true, ifname)) {
+        LOG_INFO("Tap interface creattion failed.\n");
+    }
+
+    return;
+}
diff --git a/tizen/src/util/tap_helper.h b/tizen/src/util/tap_helper.h
new file mode 100644 (file)
index 0000000..a14169e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * TAP helper
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  MunKyu Im       <munkyu.im@samsung.com>
+ *  SeokYeon Hwang  <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef __TAP_HELPER_H__
+#define __TAP_HELPER_H__
+
+void tap_create(char *);
+
+#endif //__TAP_HELPER_H__