Implement basic NIC hotplug support using the 'host_net_add' and
'pci_add' qemu monitor commands.
For now, we don't support 'bridge' or 'network' types.
Also, if pci_add fails, we currently fail to remove the backend
which we added.
Finally, NIC hot-unplug support is missing.
* src/qemu_driver.c: add qemudDomainAttachNetDevice()
* src/qemu_conf.[ch]: export qemuBuildNicStr(), qemuBuildHostNetStr()
and qemuAssignNames()
* src/libvirt_private.syms: export virDomainNetTypeToString()
---
src/libvirt_private.syms | 1 +
src/qemu_conf.c | 6 ++--
src/qemu_conf.h | 18 ++++++++++
src/qemu_driver.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 102 insertions(+), 3 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 59c78d5..0caa590 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -91,6 +91,7 @@ virDomainLifecycleTypeFromString;
virDomainLifecycleTypeToString;
virDomainLoadAllConfigs;
virDomainNetDefFree;
+virDomainNetTypeToString;
virDomainObjFree;
virDomainObjListFree;
virDomainRemoveInactive;
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 6d876cb..f483a51 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -830,7 +830,7 @@ qemuNetTypeToHostNet(int type)
}
}
-static int
+int
qemuAssignNetNames(virDomainDefPtr def,
virDomainNetDefPtr net)
{
@@ -872,7 +872,7 @@ qemuAssignNetNames(virDomainDefPtr def,
return 0;
}
-static int
+int
qemuBuildNicStr(virConnectPtr conn,
virDomainNetDefPtr net,
const char *prefix,
@@ -899,7 +899,7 @@ qemuBuildNicStr(virConnectPtr conn,
return 0;
}
-static int
+int
qemuBuildHostNetStr(virConnectPtr conn,
virDomainNetDefPtr net,
const char *prefix,
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index 1b2d061..50d7c0a 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -145,6 +145,24 @@ int qemudBuildCommandLine (virConnectPtr conn,
int *ntapfds,
const char *migrateFrom);
+int qemuBuildHostNetStr (virConnectPtr conn,
+ virDomainNetDefPtr net,
+ const char *prefix,
+ char type_sep,
+ int vlan,
+ int tapfd,
+ char **str);
+
+int qemuBuildNicStr (virConnectPtr conn,
+ virDomainNetDefPtr net,
+ const char *prefix,
+ char type_sep,
+ int vlan,
+ char **str);
+
+int qemuAssignNetNames (virDomainDefPtr def,
+ virDomainNetDefPtr net);
+
virDomainDefPtr qemuParseCommandLine(virConnectPtr conn,
virCapsPtr caps,
const char **progenv,
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index cbc185c..cde789e 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4492,6 +4492,84 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr
conn,
return 0;
}
+static int qemudDomainAttachNetDevice(virConnectPtr conn,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ unsigned int qemuCmdFlags)
+{
+ virDomainNetDefPtr net =
dev->data.net;
+ char *cmd, *reply;
+ int i;
+
+ if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, _("%s"),
+ "installed qemu version does not support
host_net_add");
+ return -1;
+ }
+
+ if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ _("network device type '%s' cannot be
attached"),
+ virDomainNetTypeToString(net->type));
+ return -1;
+ }
+
+ if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) &&
+ qemuAssignNetNames(vm->def, net) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ /* Choose a vlan value greater than all other values since
+ * older versions did not store the value in the state file.
+ */
+ net->vlan = vm->def->nnets;
+ for (i = 0; i < vm->def->nnets; i++)
+ if (vm->def->nets[i]->vlan >= net->vlan)
+ net->vlan = vm->def->nets[i]->vlan;
+
+ if (qemuBuildHostNetStr(conn, net,
+ "host_net_add ", ' ', net->vlan, -1,
&cmd) < 0)
+ return -1;
+
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ _("failed to add network backend with '%s'"),
cmd);
+ VIR_FREE(cmd);
+ return -1;
+ }
+
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+
+ if (qemuBuildNicStr(conn, net,
+ "pci_add pci_addr=auto ", ' ', net->vlan,
&cmd) < 0) {
+ /* FIXME: try and remove the backend again */
+ return -1;
+ }
+
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+ /* FIXME: try and remove the backend again */
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ _("failed to add NIC with '%s'"), cmd);
+ VIR_FREE(cmd);
+ return -1;
+ }
+
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+
+ vm->def->nets[vm->def->nnets++] = net;
+
+ return 0;
+}
+
static int qemudDomainAttachHostDevice(virConnectPtr conn,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
@@ -4617,6 +4695,8 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
virDomainDiskDeviceTypeToString(dev->data.disk->device));
goto cleanup;
}
+ } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+ ret = qemudDomainAttachNetDevice(dom->conn, vm, dev, qemuCmdFlags);
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS
&&
dev->data.hostdev->source.subsys.type ==
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
--
1.6.2.5