From 35153940e3b14402366f219fa1a6f9363c485d85 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Fri, 17 Jul 2009 22:08:34 +0100 Subject: [PATCH] Basic qemu NIC hotplug support 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 | 82 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index efdb912e0c..7a62b67017 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 6d876cb5a3..f483a5148b 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 1b2d061605..50d7c0abee 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 0601a1c3cd..fe162fb935 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -4489,6 +4489,86 @@ 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; + } + + DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); + + 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) @@ -4614,6 +4694,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) { -- GitLab