<p dir="ltr">Ping...</p>
<div class="gmail_quote">27 февр. 2015 г. 16:30 пользователь "Vasiliy Tolstov" <<a href="mailto:v.tolstov@selfip.ru">v.tolstov@selfip.ru</a>> написал:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">If a user specify ehernet device create it via libvirt and run<br>
script if it provided. After this commit user does not need to<br>
run external script to create tap device or add root to qemu<br>
process.<br>
<br>
Signed-off-by: Vasiliy Tolstov <<a href="mailto:v.tolstov@selfip.ru">v.tolstov@selfip.ru</a>><br>
---<br>
 src/qemu/qemu_command.c | 135 +++++++++++++++++++++++++++++-------------------<br>
 src/qemu/qemu_hotplug.c |  13 ++---<br>
 src/qemu/qemu_process.c |   6 +++<br>
 3 files changed, 93 insertions(+), 61 deletions(-)<br>
<br>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c<br>
index 24b2ad9..284a97c 100644<br>
--- a/src/qemu/qemu_command.c<br>
+++ b/src/qemu/qemu_command.c<br>
@@ -278,10 +278,41 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,<br>
     return *tapfd < 0 ? -1 : 0;<br>
 }<br>
<br>
+/**<br>
+ * qemuExecuteEthernetScript:<br>
+ * @ifname: the interface name<br>
+ * @script: the script name<br>
+ * This function executes script for new tap device created by libvirt.<br>
+ * Returns 0 in case of success or -1 on failure<br>
+ */<br>
+static int qemuExecuteEthernetScript(const char *ifname, const char *script)<br>
+{<br>
+    virCommandPtr cmd;<br>
+    int ret;<br>
+<br>
+    cmd = virCommandNew(script);<br>
+    virCommandAddArgFormat(cmd, "%s", ifname);<br>
+    virCommandClearCaps(cmd);<br>
+#ifdef CAP_NET_ADMIN<br>
+    virCommandAllowCap(cmd, CAP_NET_ADMIN);<br>
+#endif<br>
+    virCommandAddEnvPassCommon(cmd);<br>
+<br>
+    if (virCommandRun(cmd, NULL) < 0) {<br>
+        ret = -1;<br>
+    } else {<br>
+        ret = 0;<br>
+    }<br>
+<br>
+    virCommandFree(cmd);<br>
+    return ret;<br>
+}<br>
+<br>
 /* qemuNetworkIfaceConnect - *only* called if actualType is<br>
- * VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if<br>
- * the connection is made with a tap device connecting to a bridge<br>
- * device)<br>
+ * VIR_DOMAIN_NET_TYPE_NETWORK, VIR_DOMAIN_NET_TYPE_BRIDGE or<br>
+ * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is<br>
+ * made with a tap device connecting to a bridge device or<br>
+ * used ethernet tap device)<br>
  */<br>
 int<br>
 qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
@@ -307,11 +338,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
         }<br>
     }<br>
<br>
-    if (!(brname = virDomainNetGetActualBridgeName(net))) {<br>
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));<br>
-        goto cleanup;<br>
-    }<br>
-<br>
     if (!net->ifname ||<br>
         STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||<br>
         strchr(net->ifname, '%')) {<br>
@@ -327,45 +353,61 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
         tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;<br>
     }<br>
<br>
-    if (cfg->privileged) {<br>
-        if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,<br>
-                                           def->uuid, tunpath, tapfd, *tapfdSize,<br>
-                                           virDomainNetGetActualVirtPortProfile(net),<br>
-                                           virDomainNetGetActualVlan(net),<br>
-                                           tap_create_flags) < 0) {<br>
+    if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
+        if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize,<br>
+                               tap_create_flags) < 0) {<br>
             virDomainAuditNetDevice(def, net, tunpath, false);<br>
             goto cleanup;<br>
         }<br>
-        if (virDomainNetGetActualBridgeMACTableManager(net)<br>
-            == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {<br>
-            /* libvirt is managing the FDB of the bridge this device<br>
-             * is attaching to, so we need to turn off learning and<br>
-             * unicast_flood on the device to prevent the kernel from<br>
-             * adding any FDB entries for it. We will add add an fdb<br>
-             * entry ourselves (during qemuInterfaceStartDevices(),<br>
-             * using the MAC address from the interface config.<br>
-             */<br>
-            if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)<br>
-                goto cleanup;<br>
-            if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)<br>
+        if (net->script) {<br>
+            if (qemuExecuteEthernetScript(net->ifname, net->script) < 0)<br>
                 goto cleanup;<br>
         }<br>
     } else {<br>
-        if (qemuCreateInBridgePortWithHelper(cfg, brname,<br>
-                                             &net->ifname,<br>
-                                             tapfd, tap_create_flags) < 0) {<br>
-            virDomainAuditNetDevice(def, net, tunpath, false);<br>
+        if (!(brname = virDomainNetGetActualBridgeName(net))) {<br>
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));<br>
             goto cleanup;<br>
         }<br>
-        /* qemuCreateInBridgePortWithHelper can only create a single FD */<br>
-        if (*tapfdSize > 1) {<br>
-            VIR_WARN("Ignoring multiqueue network request");<br>
-            *tapfdSize = 1;<br>
+<br>
+        if (cfg->privileged) {<br>
+            if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,<br>
+                                               def->uuid, tunpath, tapfd, *tapfdSize,<br>
+                                               virDomainNetGetActualVirtPortProfile(net),<br>
+                                               virDomainNetGetActualVlan(net),<br>
+                                               tap_create_flags) < 0) {<br>
+                virDomainAuditNetDevice(def, net, tunpath, false);<br>
+                goto cleanup;<br>
+            }<br>
+            if (virDomainNetGetActualBridgeMACTableManager(net)<br>
+                == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {<br>
+                /* libvirt is managing the FDB of the bridge this device<br>
+                 * is attaching to, so we need to turn off learning and<br>
+                 * unicast_flood on the device to prevent the kernel from<br>
+                 * adding any FDB entries for it. We will add add an fdb<br>
+                 * entry ourselves (during qemuInterfaceStartDevices(),<br>
+                 * using the MAC address from the interface config.<br>
+                 */<br>
+                if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)<br>
+                    goto cleanup;<br>
+                if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)<br>
+                    goto cleanup;<br>
+            }<br>
+        } else {<br>
+            if (qemuCreateInBridgePortWithHelper(cfg, brname,<br>
+                                                 &net->ifname,<br>
+                                                 tapfd, tap_create_flags) < 0) {<br>
+                virDomainAuditNetDevice(def, net, tunpath, false);<br>
+                goto cleanup;<br>
+            }<br>
+            /* qemuCreateInBridgePortWithHelper can only create a single FD */<br>
+            if (*tapfdSize > 1) {<br>
+                VIR_WARN("Ignoring multiqueue network request");<br>
+                *tapfdSize = 1;<br>
+            }<br>
         }<br>
+        virDomainAuditNetDevice(def, net, tunpath, true);<br>
     }<br>
<br>
-    virDomainAuditNetDevice(def, net, tunpath, true);<br>
-<br>
     if (cfg->macFilter &&<br>
         ebtablesAddForwardAllowIn(driver->ebtables,<br>
                                   net->ifname,<br>
@@ -4959,6 +5001,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,<br>
     case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
     case VIR_DOMAIN_NET_TYPE_NETWORK:<br>
     case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
+    case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
         virBufferAsprintf(&buf, "tap%c", type_sep);<br>
         /* for one tapfd 'fd=' shall be used,<br>
          * for more than one 'fds=' is the right choice */<br>
@@ -4976,20 +5019,6 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,<br>
         is_tap = true;<br>
         break;<br>
<br>
-    case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
-        virBufferAddLit(&buf, "tap");<br>
-        if (net->ifname) {<br>
-            virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);<br>
-            type_sep = ',';<br>
-        }<br>
-        if (net->script) {<br>
-            virBufferAsprintf(&buf, "%cscript=%s", type_sep,<br>
-                              net->script);<br>
-            type_sep = ',';<br>
-        }<br>
-        is_tap = true;<br>
-        break;<br>
-<br>
     case VIR_DOMAIN_NET_TYPE_CLIENT:<br>
        virBufferAsprintf(&buf, "socket%cconnect=%s:%d",<br>
                          type_sep,<br>
@@ -7785,7 +7814,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,<br>
     /* Currently nothing besides TAP devices supports multiqueue. */<br>
     if (net->driver.virtio.queues > 0 &&<br>
         !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
-          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {<br>
+          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {<br>
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>
                        _("Multiqueue network is not supported for: %s"),<br>
                        virDomainNetTypeToString(actualType));<br>
@@ -7802,7 +7832,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,<br>
     }<br>
<br>
     if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
-        actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {<br>
+        actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+        actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
         tapfdSize = net->driver.virtio.queues;<br>
         if (!tapfdSize)<br>
             tapfdSize = 1;<br>
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c<br>
index 08047ce..c34486a 100644<br>
--- a/src/qemu/qemu_hotplug.c<br>
+++ b/src/qemu/qemu_hotplug.c<br>
@@ -896,7 +896,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
     /* Currently nothing besides TAP devices supports multiqueue. */<br>
     if (net->driver.virtio.queues > 0 &&<br>
         !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
-          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {<br>
+          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
+          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {<br>
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>
                        _("Multiqueue network is not supported for: %s"),<br>
                        virDomainNetTypeToString(actualType));<br>
@@ -904,7 +905,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
     }<br>
<br>
     if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||<br>
-        actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {<br>
+        actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||<br>
+        actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
         tapfdSize = vhostfdSize = net->driver.virtio.queues;<br>
         if (!tapfdSize)<br>
             tapfdSize = vhostfdSize = 1;<br>
@@ -935,13 +937,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
         iface_connected = true;<br>
         if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)<br>
             goto cleanup;<br>
-    } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {<br>
-        vhostfdSize = 1;<br>
-        if (VIR_ALLOC(vhostfd) < 0)<br>
-            goto cleanup;<br>
-        *vhostfd = -1;<br>
-        if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)<br>
-            goto cleanup;<br>
     }<br>
<br>
     /* Set device online immediately */<br>
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c<br>
index 515402e..468e509 100644<br>
--- a/src/qemu/qemu_process.c<br>
+++ b/src/qemu/qemu_process.c<br>
@@ -5288,6 +5288,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,<br>
                              cfg->stateDir));<br>
             VIR_FREE(net->ifname);<br>
             break;<br>
+        case VIR_DOMAIN_NET_TYPE_ETHERNET:<br>
+            if (net->ifname) {<br>
+                ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));<br>
+                VIR_FREE(net->ifname);<br>
+            }<br>
+            break;<br>
         case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
         case VIR_DOMAIN_NET_TYPE_NETWORK:<br>
 #ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP<br>
--<br>
2.2.2<br>
<br>
</blockquote></div>