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