All guest devices now use a common device address structure summarized by: enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI, }; struct _virDomainDevicePCIAddress { unsigned int domain; unsigned int bus; unsigned int slot; unsigned int function; }; struct _virDomainDeviceInfo { int type; union { virDomainDevicePCIAddress pci; } addr; }; This replaces the anonymous structs in Disk/Net/Hostdev data structures. Where available, the address is *always* printed in the XML file, instead of being hidden in the internal state file. <address type='pci' domain='0x0000' bus='0x1e' slot='0x07' function='0x0'/> The structure definition is based on Wolfgang Mauerer's disk controller patch series. * docs/schemas/domain.rng: Define the <address> syntax and associate it with disk/net/hostdev devices * src/conf/domain_conf.h, src/conf/domain_conf.c, src/libvirt_private.syms: APIs for parsing/formatting address information. Also remove the QEMU specific 'pci_addr' attributes * src/qemu/qemu_driver.c: Replace use of 'pci_addr' attrs with new standardized format. --- docs/schemas/domain.rng | 55 +++++-- src/conf/domain_conf.c | 420 +++++++++++++++++++++++++++++++++------------- src/conf/domain_conf.h | 84 +++++----- src/libvirt_private.syms | 6 + src/qemu/qemu_driver.c | 64 ++++--- 5 files changed, 428 insertions(+), 201 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 566b117..7e00e7f 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -385,6 +385,9 @@ <optional> <ref name="encryption"/> </optional> + <optional> + <ref name="address"/> + </optional> </define> <!-- A disk description can be either of type file or block @@ -715,6 +718,9 @@ <empty/> </element> </optional> + <optional> + <ref name="address"/> + </optional> </interleave> </define> <!-- @@ -1134,10 +1140,15 @@ <choice> <ref name="usbproduct"/> <ref name="usbaddress"/> - <ref name="pciaddress"/> + <element name="address"> + <ref name="pciaddress"/> + </element> </choice> </element> </group> + <optional> + <ref name="address"/> + </optional> </element> </define> <define name="usbproduct"> @@ -1163,22 +1174,20 @@ </element> </define> <define name="pciaddress"> - <element name="address"> - <optional> - <attribute name="domain"> - <ref name="pciDomain"/> - </attribute> - </optional> - <attribute name="bus"> - <ref name="pciBus"/> - </attribute> - <attribute name="slot"> - <ref name="pciSlot"/> - </attribute> - <attribute name="function"> - <ref name="pciFunc"/> + <optional> + <attribute name="domain"> + <ref name="pciDomain"/> </attribute> - </element> + </optional> + <attribute name="bus"> + <ref name="pciBus"/> + </attribute> + <attribute name="slot"> + <ref name="pciSlot"/> + </attribute> + <attribute name="function"> + <ref name="pciFunc"/> + </attribute> </define> <!-- Devices attached to a domain. @@ -1286,6 +1295,20 @@ </interleave> </element> </define> + + <define name="address"> + <element name="address"> + <choice> + <group> + <attribute name="type"> + <value>pci</value> + </attribute> + <ref name="pciaddress"/> + </group> + </choice> + </element> + </define> + <!-- Type library diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 0b4fe8b..f199c08 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -88,6 +88,10 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "hostdev", "watchdog") +VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, + "none", + "pci") + VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", "file", @@ -357,6 +361,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->driverName); VIR_FREE(def->driverType); virStorageEncryptionFree(def->encryption); + virDomainDeviceInfoClear(&def->info); VIR_FREE(def); } @@ -408,8 +413,10 @@ void virDomainNetDefFree(virDomainNetDefPtr def) } VIR_FREE(def->ifname); - VIR_FREE(def->nic_name); VIR_FREE(def->hostnet_name); + + virDomainDeviceInfoClear(&def->info); + VIR_FREE(def); } @@ -483,6 +490,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def) return; VIR_FREE(def->target); + virDomainDeviceInfoClear(&def->info); VIR_FREE(def); } @@ -731,6 +739,220 @@ void virDomainRemoveInactive(virDomainObjListPtr doms, } +int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, + int type) +{ + if (info->type != type) + return 0; + + switch (info->type) { + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: + return virDomainDevicePCIAddressIsValid(&info->addr.pci); + } + + return 0; +} + + +int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr) +{ + return addr->domain || addr->bus || addr->slot; +} + + +int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info) +{ + if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) + return 1; + return 0; +} + + +void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) +{ + memset(&info->addr, 0, sizeof(info->addr)); + info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE; +} + + +/* Generate a string representation of a device address + * @param address Device address to stringify + */ +static int virDomainDeviceInfoFormat(virBufferPtr buf, + virDomainDeviceInfoPtr info) +{ + if (!info) { + virDomainReportError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", + _("missing device information")); + return -1; + } + + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) + return 0; + + /* We'll be in domain/devices/[device type]/ so 3 level indent */ + virBufferVSprintf(buf, " <address type='%s'", + virDomainDeviceAddressTypeToString(info->type)); + + switch (info->type) { + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: + virBufferVSprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'", + info->addr.pci.domain, + info->addr.pci.bus, + info->addr.pci.slot, + info->addr.pci.function); + break; + + default: + virDomainReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("unknown address type '%d'"), info->type); + return -1; + } + + virBufferAddLit(buf, "/>\n"); + + return 0; +} + + +int virDomainDevicePCIAddressEqual(virDomainDevicePCIAddressPtr a, + virDomainDevicePCIAddressPtr b) +{ + if (a->domain == b->domain && + a->bus == b->bus && + a->slot == b->slot && + a->function == b->function) + return 1; + + return 0; +} + + +static int +virDomainDevicePCIAddressParseXML(virConnectPtr conn, + xmlNodePtr node, + virDomainDevicePCIAddressPtr addr) +{ + char *domain, *slot, *bus, *function; + int ret = -1; + + memset(addr, 0, sizeof(*addr)); + + domain = virXMLPropString(node, "domain"); + bus = virXMLPropString(node, "bus"); + slot = virXMLPropString(node, "slot"); + function = virXMLPropString(node, "function"); + + if (domain && + virStrToLong_ui(domain, NULL, 16, &addr->domain) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'domain' attribute")); + goto cleanup; + } + + if (bus && + virStrToLong_ui(bus, NULL, 16, &addr->bus) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'bus' attribute")); + goto cleanup; + } + + if (slot && + virStrToLong_ui(slot, NULL, 16, &addr->slot) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'slot' attribute")); + goto cleanup; + } + + if (function && + virStrToLong_ui(function, NULL, 16, &addr->function) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'function' attribute")); + goto cleanup; + } + + if (!virDomainDevicePCIAddressIsValid(addr)) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Insufficient specification for PCI address")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(domain); + VIR_FREE(bus); + VIR_FREE(slot); + VIR_FREE(function); + return ret; +} + + +/* Parse the XML definition for a device address + * @param node XML nodeset to parse for device address definition + */ +static int +virDomainDeviceInfoParseXML(virConnectPtr conn, + xmlNodePtr node, + virDomainDeviceInfoPtr info, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xmlNodePtr cur; + xmlNodePtr address = NULL; + char *type = NULL; + int ret = -1; + + virDomainDeviceInfoClear(info); + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (address == NULL && + xmlStrEqual(cur->name, BAD_CAST "address")) { + address = cur; + } + } + cur = cur->next; + } + + if (!address) + return 0; + + type = virXMLPropString(address, "type"); + + if (type) { + if ((info->type = virDomainDeviceAddressTypeFromString(type)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown address type '%s'"), type); + goto cleanup; + } + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("No type specified for device address")); + goto cleanup; + } + + switch (info->type) { + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI: + if (virDomainDevicePCIAddressParseXML(conn, address, &info->addr.pci) < 0) + goto cleanup; + break; + + default: + /* Should not happen */ + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unknown device address type")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(type); + return ret; +} + + /* Parse the XML definition for a disk * @param node XML nodeset to parse for disk definition */ @@ -819,6 +1041,7 @@ virDomainDiskDefParseXML(virConnectPtr conn, def->shared = 1; } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { + /* Legacy back-compat. Don't add any more attributes here */ devaddr = virXMLPropString(cur, "devaddr"); } else if (encryption == NULL && xmlStrEqual(cur->name, BAD_CAST "encryption")) { @@ -928,15 +1151,20 @@ virDomainDiskDefParseXML(virConnectPtr conn, goto error; } - if (devaddr && - sscanf(devaddr, "%x:%x:%x", - &def->pci_addr.domain, - &def->pci_addr.bus, - &def->pci_addr.slot) < 3) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("Unable to parse devaddr parameter '%s'"), - devaddr); - goto error; + if (devaddr) { + if (sscanf(devaddr, "%x:%x:%x", + &def->info.addr.pci.domain, + &def->info.addr.pci.bus, + &def->info.addr.pci.slot) < 3) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unable to parse devaddr parameter '%s'"), + devaddr); + goto error; + } + def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + } else { + if (virDomainDeviceInfoParseXML(conn, node, &def->info, flags) < 0) + goto error; } def->src = source; @@ -1153,6 +1381,7 @@ virDomainNetDefParseXML(virConnectPtr conn, model = virXMLPropString(cur, "type"); } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { + /* Legacy back-compat. Don't add any more attributes here */ nic_name = virXMLPropString(cur, "nic"); hostnet_name = virXMLPropString(cur, "hostnet"); devaddr = virXMLPropString(cur, "devaddr"); @@ -1173,14 +1402,28 @@ virDomainNetDefParseXML(virConnectPtr conn, virCapabilitiesGenerateMac(caps, def->mac); } - if (devaddr && - sscanf(devaddr, "%x:%x:%x", - &def->pci_addr.domain, - &def->pci_addr.bus, - &def->pci_addr.slot) < 3) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("Unable to parse devaddr parameter '%s'"), - devaddr); + if (devaddr) { + if (sscanf(devaddr, "%x:%x:%x", + &def->info.addr.pci.domain, + &def->info.addr.pci.bus, + &def->info.addr.pci.slot) < 3) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unable to parse devaddr parameter '%s'"), + devaddr); + goto error; + } + def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + } else { + if (virDomainDeviceInfoParseXML(conn, node, &def->info, flags) < 0) + goto error; + } + + /* XXX what about ISA/USB based NIC models - once we support + * them we should make sure address type is correct */ + if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Network interfaces must use 'pci' address type")); goto error; } @@ -2321,83 +2564,27 @@ virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn, while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { if (xmlStrEqual(cur->name, BAD_CAST "address")) { + virDomainDevicePCIAddressPtr addr = + &def->source.subsys.u.pci; - char *domain = virXMLPropString(cur, "domain"); - if (domain) { - if (virStrToLong_ui(domain, NULL, 0, - &def->source.subsys.u.pci.domain) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse domain %s"), - domain); - VIR_FREE(domain); - goto out; - } - VIR_FREE(domain); - } - - char *bus = virXMLPropString(cur, "bus"); - if (bus) { - if (virStrToLong_ui(bus, NULL, 0, - &def->source.subsys.u.pci.bus) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse bus %s"), bus); - VIR_FREE(bus); - goto out; - } - VIR_FREE(bus); - } else { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("pci address needs bus id")); - goto out; - } - - char *slot = virXMLPropString(cur, "slot"); - if (slot) { - if (virStrToLong_ui(slot, NULL, 0, - &def->source.subsys.u.pci.slot) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse slot %s"), - slot); - VIR_FREE(slot); - goto out; - } - VIR_FREE(slot); - } else { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("pci address needs slot id")); - goto out; - } - - char *function = virXMLPropString(cur, "function"); - if (function) { - if (virStrToLong_ui(function, NULL, 0, - &def->source.subsys.u.pci.function) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse function %s"), - function); - VIR_FREE(function); - goto out; - } - VIR_FREE(function); - } else { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", - _("pci address needs function id")); + if (virDomainDevicePCIAddressParseXML(conn, cur, addr) < 0) goto out; - } } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { + /* Legacy back-compat. Don't add any more attributes here */ char *devaddr = virXMLPropString(cur, "devaddr"); if (devaddr && sscanf(devaddr, "%x:%x:%x", - &def->source.subsys.u.pci.guest_addr.domain, - &def->source.subsys.u.pci.guest_addr.bus, - &def->source.subsys.u.pci.guest_addr.slot) < 3) { + &def->info.addr.pci.domain, + &def->info.addr.pci.bus, + &def->info.addr.pci.slot) < 3) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("Unable to parse devaddr parameter '%s'"), devaddr); VIR_FREE(devaddr); goto out; } + def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; } else { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unknown pci source type '%s'"), @@ -2475,14 +2662,29 @@ virDomainHostdevDefParseXML(virConnectPtr conn, if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def, flags) < 0) goto error; } - } else { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("unknown node %s"), cur->name); } } cur = cur->next; } + if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + if (virDomainDeviceInfoParseXML(conn, node, &def->info, flags) < 0) + goto error; + } + + if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("PCI host devices must use 'pci' address type")); + goto error; + } + break; + } + } + cleanup: VIR_FREE(type); VIR_FREE(mode); @@ -3869,8 +4071,7 @@ virDomainLifecycleDefFormat(virConnectPtr conn, static int virDomainDiskDefFormat(virConnectPtr conn, virBufferPtr buf, - virDomainDiskDefPtr def, - int flags) + virDomainDiskDefPtr def) { const char *type = virDomainDiskTypeToString(def->type); const char *device = virDomainDiskDeviceTypeToString(def->device); @@ -3947,15 +4148,8 @@ virDomainDiskDefFormat(virConnectPtr conn, virStorageEncryptionFormat(conn, buf, def->encryption) < 0) return -1; - if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) { - virBufferAddLit(buf, " <state"); - if (virDiskHasValidPciAddr(def)) - virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'", - def->pci_addr.domain, - def->pci_addr.bus, - def->pci_addr.slot); - virBufferAddLit(buf, "/>\n"); - } + if (virDomainDeviceInfoFormat(buf, &def->info) < 0) + return -1; virBufferAddLit(buf, " </disk>\n"); @@ -4089,21 +4283,18 @@ virDomainNetDefFormat(virConnectPtr conn, def->model); if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) { + /* Legacy back-compat. Don't add any more attributes here */ virBufferAddLit(buf, " <state"); - if (def->nic_name) - virBufferEscapeString(buf, " nic='%s'", def->nic_name); if (def->hostnet_name) virBufferEscapeString(buf, " hostnet='%s'", def->hostnet_name); - if (virNetHasValidPciAddr(def)) - virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'", - def->pci_addr.domain, - def->pci_addr.bus, - def->pci_addr.slot); if (def->vlan > 0) virBufferVSprintf(buf, " vlan='%d'", def->vlan); virBufferAddLit(buf, "/>\n"); } + if (virDomainDeviceInfoFormat(buf, &def->info) < 0) + return -1; + virBufferAddLit(buf, " </interface>\n"); return 0; @@ -4477,8 +4668,7 @@ virDomainGraphicsDefFormat(virConnectPtr conn, static int virDomainHostdevDefFormat(virConnectPtr conn, virBufferPtr buf, - virDomainHostdevDefPtr def, - int flags) + virDomainHostdevDefPtr def) { const char *mode = virDomainHostdevModeTypeToString(def->mode); const char *type; @@ -4512,25 +4702,19 @@ virDomainHostdevDefFormat(virConnectPtr conn, def->source.subsys.u.usb.bus, def->source.subsys.u.usb.device); } - } - if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + } else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { virBufferVSprintf(buf, " <address domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'/>\n", def->source.subsys.u.pci.domain, def->source.subsys.u.pci.bus, def->source.subsys.u.pci.slot, def->source.subsys.u.pci.function); - if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) { - virBufferAddLit(buf, " <state"); - if (virHostdevHasValidGuestAddr(def)) - virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'", - def->source.subsys.u.pci.guest_addr.domain, - def->source.subsys.u.pci.guest_addr.bus, - def->source.subsys.u.pci.guest_addr.slot); - virBufferAddLit(buf, "/>\n"); - } } virBufferAddLit(buf, " </source>\n"); + + if (virDomainDeviceInfoFormat(buf, &def->info) < 0) + return -1; + virBufferAddLit(buf, " </hostdev>\n"); return 0; @@ -4695,7 +4879,7 @@ char *virDomainDefFormat(virConnectPtr conn, def->emulator); for (n = 0 ; n < def->ndisks ; n++) - if (virDomainDiskDefFormat(conn, &buf, def->disks[n], flags) < 0) + if (virDomainDiskDefFormat(conn, &buf, def->disks[n]) < 0) goto cleanup; for (n = 0 ; n < def->nfss ; n++) @@ -4763,7 +4947,7 @@ char *virDomainDefFormat(virConnectPtr conn, goto cleanup; for (n = 0 ; n < def->nhostdevs ; n++) - if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n], flags) < 0) + if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n]) < 0) goto cleanup; if (def->watchdog) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a807e9d..c50aae0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -64,6 +64,32 @@ enum virDomainVirtType { VIR_DOMAIN_VIRT_LAST, }; +enum virDomainDeviceAddressType { + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI, + + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST +}; + +typedef struct _virDomainDevicePCIAddress virDomainDevicePCIAddress; +typedef virDomainDevicePCIAddress *virDomainDevicePCIAddressPtr; +struct _virDomainDevicePCIAddress { + unsigned int domain; + unsigned int bus; + unsigned int slot; + unsigned int function; +}; + +typedef struct _virDomainDeviceInfo virDomainDeviceInfo; +typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; +struct _virDomainDeviceInfo { + int type; + union { + virDomainDevicePCIAddress pci; + } addr; +}; + + /* Two types of disk backends */ enum virDomainDiskType { VIR_DOMAIN_DISK_TYPE_BLOCK, @@ -119,20 +145,10 @@ struct _virDomainDiskDef { int cachemode; unsigned int readonly : 1; unsigned int shared : 1; - struct { - unsigned domain; - unsigned bus; - unsigned slot; - } pci_addr; + virDomainDeviceInfo info; virStorageEncryptionPtr encryption; }; -static inline int -virDiskHasValidPciAddr(virDomainDiskDefPtr def) -{ - return def->pci_addr.domain || def->pci_addr.bus || def->pci_addr.slot; -} - /* Two types of disk backends */ enum virDomainFSType { @@ -199,22 +215,15 @@ struct _virDomainNetDef { } internal; } data; char *ifname; + virDomainDeviceInfo info; + /* XXX figure out how to remove this */ char *nic_name; + /* XXX figure out how to remove this */ char *hostnet_name; - struct { - unsigned domain; - unsigned bus; - unsigned slot; - } pci_addr; + /* XXX figure out how to remove this */ int vlan; }; -static inline int -virNetHasValidPciAddr(virDomainNetDefPtr def) -{ - return def->pci_addr.domain || def->pci_addr.bus || def->pci_addr.slot; -} - enum virDomainChrTargetType { VIR_DOMAIN_CHR_TARGET_TYPE_NULL = 0, VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR, @@ -442,17 +451,7 @@ struct _virDomainHostdevDef { unsigned vendor; unsigned product; } usb; - struct { - unsigned domain; - unsigned bus; - unsigned slot; - unsigned function; - struct { - unsigned domain; - unsigned bus; - unsigned slot; - } guest_addr; - } pci; + virDomainDevicePCIAddress pci; /* host address */ } u; } subsys; struct { @@ -463,16 +462,9 @@ struct _virDomainHostdevDef { } caps; } source; char* target; + virDomainDeviceInfo info; /* Guest address */ }; -static inline int -virHostdevHasValidGuestAddr(virDomainHostdevDefPtr def) -{ - return def->source.subsys.u.pci.guest_addr.domain || - def->source.subsys.u.pci.guest_addr.bus || - def->source.subsys.u.pci.guest_addr.slot; -} - /* Flags for the 'type' field in next struct */ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_DISK, @@ -673,6 +665,7 @@ virDomainObjIsActive(virDomainObjPtr dom) return dom->def->id != -1; } + int virDomainObjListInit(virDomainObjListPtr objs); void virDomainObjListDeinit(virDomainObjListPtr objs); @@ -695,6 +688,13 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); +int virDomainDevicePCIAddressEqual(virDomainDevicePCIAddressPtr a, + virDomainDevicePCIAddressPtr b); +int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, + int type); +int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr); +int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info); +void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); void virDomainDefFree(virDomainDefPtr vm); void virDomainObjRef(virDomainObjPtr vm); /* Returns 1 if the object was freed, 0 if more refs exist */ @@ -832,6 +832,8 @@ VIR_ENUM_DECL(virDomainBoot) VIR_ENUM_DECL(virDomainFeature) VIR_ENUM_DECL(virDomainLifecycle) VIR_ENUM_DECL(virDomainDevice) +VIR_ENUM_DECL(virDomainDeviceAddress) +VIR_ENUM_DECL(virDomainDeviceAddressMode) VIR_ENUM_DECL(virDomainDisk) VIR_ENUM_DECL(virDomainDiskDevice) VIR_ENUM_DECL(virDomainDiskBus) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 10940eb..67ffe69 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -174,6 +174,12 @@ virDomainObjListInit; virDomainObjListDeinit; virDomainObjRef; virDomainObjUnref; +virDomainDeviceAddressEqual; +virDomainDevicePCIAddressEqual; +virDomainDeviceAddressIsValid; +virDomainDevicePCIAddressIsValid; +virDomainDeviceInfoIsSet; +virDomainDeviceAddressClear; # domain_event.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index daa6f94..3588531 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5098,13 +5098,15 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn, ret = qemuMonitorAddPCIDisk(priv->mon, dev->data.disk->src, type, - &dev->data.disk->pci_addr.domain, - &dev->data.disk->pci_addr.bus, - &dev->data.disk->pci_addr.slot); + &dev->data.disk->info.addr.pci.domain, + &dev->data.disk->info.addr.pci.bus, + &dev->data.disk->info.addr.pci.slot); qemuDomainObjExitMonitorWithDriver(driver, vm); - if (ret == 0) + if (ret == 0) { + dev->data.disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; virDomainDiskInsertPreAlloced(vm->def, dev->data.disk); + } return ret; } @@ -5227,12 +5229,13 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorAddPCINetwork(priv->mon, nicstr, - &net->pci_addr.domain, - &net->pci_addr.bus, - &net->pci_addr.slot) < 0) { + &net->info.addr.pci.domain, + &net->info.addr.pci.bus, + &net->info.addr.pci.slot) < 0) { qemuDomainObjExitMonitorWithDriver(driver, vm); goto try_remove; } + net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; qemuDomainObjExitMonitorWithDriver(driver, vm); ret = 0; @@ -5315,12 +5318,13 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn, hostdev->source.subsys.u.pci.bus, hostdev->source.subsys.u.pci.slot, hostdev->source.subsys.u.pci.function, - &hostdev->source.subsys.u.pci.guest_addr.domain, - &hostdev->source.subsys.u.pci.guest_addr.bus, - &hostdev->source.subsys.u.pci.guest_addr.slot); + &hostdev->info.addr.pci.domain, + &hostdev->info.addr.pci.bus, + &hostdev->info.addr.pci.slot); qemuDomainObjExitMonitorWithDriver(driver, vm); if (ret < 0) goto error; + hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; @@ -5550,18 +5554,18 @@ static int qemudDomainDetachPciDiskDevice(virConnectPtr conn, goto cleanup; } - if (!virDiskHasValidPciAddr(detach)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("disk %s cannot be detached - no PCI address for device"), - detach->dst); + if (!virDomainDeviceAddressIsValid(&detach->info, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", + _("device cannot be detached without a PCI address")); goto cleanup; } qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorRemovePCIDevice(priv->mon, - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot) < 0) { + detach->info.addr.pci.domain, + detach->info.addr.pci.bus, + detach->info.addr.pci.slot) < 0) { qemuDomainObjExitMonitor(vm); goto cleanup; } @@ -5616,7 +5620,14 @@ qemudDomainDetachNetDevice(virConnectPtr conn, goto cleanup; } - if (!virNetHasValidPciAddr(detach) || detach->vlan < 0 || !detach->hostnet_name) { + if (!virDomainDeviceAddressIsValid(&detach->info, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("device cannot be detached without a PCI address")); + goto cleanup; + } + + if (detach->vlan < 0 || !detach->hostnet_name) { qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("network device cannot be detached - device state missing")); goto cleanup; @@ -5624,9 +5635,9 @@ qemudDomainDetachNetDevice(virConnectPtr conn, qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorRemovePCIDevice(priv->mon, - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot) < 0) { + detach->info.addr.pci.domain, + detach->info.addr.pci.bus, + detach->info.addr.pci.slot) < 0) { qemuDomainObjExitMonitorWithDriver(driver, vm); goto cleanup; } @@ -5704,17 +5715,18 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn, return -1; } - if (!virHostdevHasValidGuestAddr(detach)) { + if (!virDomainDeviceAddressIsValid(&detach->info, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) { qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("hostdev cannot be detached - device state missing")); + "%s", _("device cannot be detached without a PCI address")); return -1; } qemuDomainObjEnterMonitorWithDriver(driver, vm); if (qemuMonitorRemovePCIDevice(priv->mon, - detach->source.subsys.u.pci.guest_addr.domain, - detach->source.subsys.u.pci.guest_addr.bus, - detach->source.subsys.u.pci.guest_addr.slot) < 0) { + detach->info.addr.pci.domain, + detach->info.addr.pci.bus, + detach->info.addr.pci.slot) < 0) { qemuDomainObjExitMonitorWithDriver(driver, vm); return -1; } -- 1.6.5.2 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list