[libvirt] [PATCH v1 02/12] qemu: Move interface cmd line construction into a separate function

Michal Privoznik mprivozn at redhat.com
Mon Apr 22 14:25:47 UTC 2013


Currently, we have one huge function to construct qemu command line.
This is very ineffective esp. if there's a fault somewhere.
---
 src/qemu/qemu_command.c | 323 +++++++++++++++++++++++++-----------------------
 1 file changed, 171 insertions(+), 152 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 05c12b2..4af2d04 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5751,6 +5751,172 @@ error:
     return -1;
 }
 
+static int
+qemuBuildInterfaceCommandLine(virCommandPtr cmd,
+                              virQEMUDriverPtr driver,
+                              virConnectPtr conn,
+                              virDomainDefPtr def,
+                              virDomainNetDefPtr net,
+                              virQEMUCapsPtr qemuCaps,
+                              int vlan,
+                              int bootNet,
+                              enum virNetDevVPortProfileOp vmop)
+{
+    int ret = -1;
+    int tapfd = -1;
+    char *nic = NULL, *host = NULL;
+    char *tapfdName = NULL;
+    char *vhostfdName = NULL;
+    int bootindex = bootNet;
+    int actualType;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+    if (!bootindex)
+        bootindex = net->info.bootIndex;
+
+    /* If appropriate, grab a physical device from the configured
+     * network's pool of devices, or resolve bridge device name
+     * to the one defined in the network definition.
+     */
+    if (networkAllocateActualDevice(net) < 0)
+        goto cleanup;
+
+    actualType = virDomainNetGetActualType(net);
+    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+            virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
+            virDomainHostdevDefPtr found;
+            /* For a network with <forward mode='hostdev'>, there is a need to
+             * add the newly minted hostdev to the hostdevs array.
+             */
+            if (qemuAssignDeviceHostdevAlias(def, hostdev, def->nhostdevs-1) < 0)
+                goto cleanup;
+
+            if (virDomainHostdevFind(def, hostdev, &found) < 0) {
+                if (virDomainHostdevInsert(def, hostdev) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+                if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
+                                                 &hostdev, 1) < 0) {
+                    goto cleanup;
+                }
+            } else {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("PCI device %04x:%02x:%02x.%x "
+                                 "allocated from network %s is already "
+                                 "in use by domain %s"),
+                               hostdev->source.subsys.u.pci.domain,
+                               hostdev->source.subsys.u.pci.bus,
+                               hostdev->source.subsys.u.pci.slot,
+                               hostdev->source.subsys.u.pci.function,
+                               net->data.network.name,
+                               def->name);
+                goto cleanup;
+            }
+        }
+        /* hostdev interface doesn't require nor -net nor -netdev */
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+        actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+        /*
+         * If type='bridge' then we attempt to allocate the tap fd here only if
+         * running under a privilged user or -netdev bridge option is not
+         * supported.
+         */
+        if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+            cfg->privileged ||
+            (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV_BRIDGE))) {
+            tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
+                                            qemuCaps);
+            if (tapfd < 0)
+                goto cleanup;
+        }
+    } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
+        tapfd = qemuPhysIfaceConnect(def, driver, net,
+                                     qemuCaps, vmop);
+        if (tapfd < 0)
+            goto cleanup;
+    }
+
+    if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+        actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+        actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
+        actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
+        /* Attempt to use vhost-net mode for these types of
+           network device */
+        int vhostfd;
+
+        if (qemuOpenVhostNet(def, net, qemuCaps, &vhostfd) < 0)
+            goto cleanup;
+        if (vhostfd >= 0) {
+            virCommandTransferFD(cmd, vhostfd);
+
+            if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+        }
+    }
+
+    if (tapfd >= 0) {
+        virCommandTransferFD(cmd, tapfd);
+
+        if (virAsprintf(&tapfdName, "%d", tapfd) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    /* Possible combinations:
+     *
+     *  1. Old way:   -net nic,model=e1000,vlan=1 -net tap,vlan=1
+     *  2. Semi-new:  -device e1000,vlan=1        -net tap,vlan=1
+     *  3. Best way:  -netdev type=tap,id=netdev1 -device e1000,id=netdev1
+     *
+     * NB, no support for -netdev without use of -device
+     */
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
+        virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
+        if (!(host = qemuBuildHostNetStr(net, driver, qemuCaps,
+                                         ',', vlan, tapfdName,
+                                         vhostfdName)))
+            goto cleanup;
+        virCommandAddArgList(cmd, "-netdev", host, NULL);
+    }
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
+        if (!(nic = qemuBuildNicDevStr(net, vlan, bootindex, qemuCaps)))
+            goto cleanup;
+        virCommandAddArgList(cmd, "-device", nic, NULL);
+    } else {
+        if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
+            goto cleanup;
+        virCommandAddArgList(cmd, "-net", nic, NULL);
+    }
+    if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
+          virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
+        if (!(host = qemuBuildHostNetStr(net, driver, qemuCaps,
+                                         ',', vlan, tapfdName,
+                                         vhostfdName)))
+            goto cleanup;
+        virCommandAddArgList(cmd, "-net", host, NULL);
+    }
+
+    ret = 0;
+cleanup:
+    if (ret < 0)
+        virDomainConfNWFilterTeardown(net);
+    VIR_FREE(nic);
+    VIR_FREE(host);
+    VIR_FREE(tapfdName);
+    VIR_FREE(vhostfdName);
+    virObjectUnref(cfg);
+    return ret;
+}
+
 /*
  * Constructs a argv suitable for launching qemu with config defined
  * for a given virtual machine.
@@ -6713,16 +6879,7 @@ qemuBuildCommandLine(virConnectPtr conn,
 
         for (i = 0 ; i < def->nnets ; i++) {
             virDomainNetDefPtr net = def->nets[i];
-            char *nic, *host;
-            char tapfd_name[50] = "";
-            char vhostfd_name[50] = "";
             int vlan;
-            int bootindex = bootNet;
-            int actualType;
-
-            bootNet = 0;
-            if (!bootindex)
-                bootindex = net->info.bootIndex;
 
             /* VLANs are not used with -netdev, so don't record them */
             if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
@@ -6731,149 +6888,11 @@ qemuBuildCommandLine(virConnectPtr conn,
             else
                 vlan = i;
 
-            /* If appropriate, grab a physical device from the configured
-             * network's pool of devices, or resolve bridge device name
-             * to the one defined in the network definition.
-             */
-            if (networkAllocateActualDevice(net) < 0)
-               goto error;
-
-            actualType = virDomainNetGetActualType(net);
-            if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
-                if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
-                    virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
-                    virDomainHostdevDefPtr found;
-                    /* For a network with <forward mode='hostdev'>, there is a need to
-                     * add the newly minted hostdev to the hostdevs array.
-                     */
-                    if (qemuAssignDeviceHostdevAlias(def, hostdev,
-                                                     (def->nhostdevs-1)) < 0) {
-                        goto error;
-                    }
-
-                    if (virDomainHostdevFind(def, hostdev, &found) < 0) {
-                        if (virDomainHostdevInsert(def, hostdev) < 0) {
-                            virReportOOMError();
-                            goto error;
-                        }
-                        if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
-                                                         &hostdev, 1) < 0) {
-                            goto error;
-                        }
-                    }
-                    else {
-                        virReportError(VIR_ERR_INTERNAL_ERROR,
-                                       _("PCI device %04x:%02x:%02x.%x "
-                                         "allocated from network %s is already "
-                                         "in use by domain %s"),
-                                       hostdev->source.subsys.u.pci.domain,
-                                       hostdev->source.subsys.u.pci.bus,
-                                       hostdev->source.subsys.u.pci.slot,
-                                       hostdev->source.subsys.u.pci.function,
-                                       net->data.network.name,
-                                       def->name);
-                        goto error;
-                    }
-                }
-                continue;
-            }
-
-            if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
-                actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
-                /*
-                 * If type='bridge' then we attempt to allocate the tap fd here only if
-                 * running under a privilged user or -netdev bridge option is not
-                 * supported.
-                 */
-                if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
-                    cfg->privileged ||
-                    (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV_BRIDGE))) {
-                    int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
-                                                        qemuCaps);
-                    if (tapfd < 0)
-                        goto error;
-
-                    last_good_net = i;
-                    virCommandTransferFD(cmd, tapfd);
-
-                    if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
-                                 tapfd) >= sizeof(tapfd_name))
-                        goto no_memory;
-                }
-            } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
-                int tapfd = qemuPhysIfaceConnect(def, driver, net,
-                                                 qemuCaps, vmop);
-                if (tapfd < 0)
-                    goto error;
-
-                last_good_net = i;
-                virCommandTransferFD(cmd, tapfd);
-
-                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
-                             tapfd) >= sizeof(tapfd_name))
-                    goto no_memory;
-            }
-
-            if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
-                actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
-                actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
-                actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
-                /* Attempt to use vhost-net mode for these types of
-                   network device */
-                int vhostfd;
-
-                if (qemuOpenVhostNet(def, net, qemuCaps, &vhostfd) < 0)
-                    goto error;
-                if (vhostfd >= 0) {
-                    virCommandTransferFD(cmd, vhostfd);
-
-                    if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d",
-                                 vhostfd) >= sizeof(vhostfd_name))
-                        goto no_memory;
-                }
-            }
-            /* Possible combinations:
-             *
-             *  1. Old way:   -net nic,model=e1000,vlan=1 -net tap,vlan=1
-             *  2. Semi-new:  -device e1000,vlan=1        -net tap,vlan=1
-             *  3. Best way:  -netdev type=tap,id=netdev1 -device e1000,id=netdev1
-             *
-             * NB, no support for -netdev without use of -device
-             */
-            if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
-                virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
-                virCommandAddArg(cmd, "-netdev");
-                if (!(host = qemuBuildHostNetStr(net, driver, qemuCaps,
-                                                 ',', vlan, tapfd_name,
-                                                 vhostfd_name)))
-                    goto error;
-                virCommandAddArg(cmd, host);
-                VIR_FREE(host);
-            }
-            if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
-                virCommandAddArg(cmd, "-device");
-                nic = qemuBuildNicDevStr(net, vlan, bootindex, qemuCaps);
-                if (!nic)
-                    goto error;
-                virCommandAddArg(cmd, nic);
-                VIR_FREE(nic);
-            } else {
-                virCommandAddArg(cmd, "-net");
-                if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
-                    goto error;
-                virCommandAddArg(cmd, nic);
-                VIR_FREE(nic);
-            }
-            if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
-                  virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
-                virCommandAddArg(cmd, "-net");
-                if (!(host = qemuBuildHostNetStr(net, driver, qemuCaps,
-                                                 ',', vlan, tapfd_name,
-                                                 vhostfd_name)))
-                    goto error;
-                virCommandAddArg(cmd, host);
-                VIR_FREE(host);
-            }
+            if (qemuBuildInterfaceCommandLine(cmd, driver, conn, def, net,
+                                              qemuCaps, vlan, bootNet, vmop) < 0)
+                goto error;
+            last_good_net = i;
+            bootNet = 0;
         }
     }
 
-- 
1.8.1.5




More information about the libvir-list mailing list