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,
};
enum virDomainDeviceAddressMode {
VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC,
VIR_DOMAIN_DEVICE_ADDRESS_MODE_STATIC,
};
struct _virDomainDevicePCIAddress {
unsigned int domain;
unsigned int bus;
unsigned int slot;
unsigned int function;
};
struct _virDomainDeviceAddress {
int type;
int mode;
union {
virDomainDevicePCIAddress pci;
} data;
};
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' mode='static' domain='0x0000'
bus='0x1e' slot='0x07' function='0x0'/>
A 'static' address is one assigned by the user, never changing,
while a 'dynamic' address is one assigned on the fly by QEMU.
'dynamic' addresses are thrown away when a VM stops.
The structure definition is based on Wolfgang Mauerer's disk
controller patch series.
---
src/conf/domain_conf.c | 432 ++++++++++++++++++++++++++++++++++-----------
src/conf/domain_conf.h | 90 ++++++-----
src/libvirt_private.syms | 5 +
src/qemu/qemu_driver.c | 64 ++++---
4 files changed, 418 insertions(+), 173 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index dca2e49..975b62b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -88,6 +88,14 @@ 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(virDomainDeviceAddressMode, VIR_DOMAIN_DEVICE_ADDRESS_MODE_LAST,
+ "dynamic",
+ "static")
+
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
"block",
"file",
@@ -729,6 +737,245 @@ void virDomainRemoveInactive(virDomainObjListPtr doms,
}
+int virDomainDeviceAddressIsValid(virDomainDeviceAddressPtr addr,
+ int type)
+{
+ if (addr->type != type)
+ return 0;
+
+ switch (addr->type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ return virDomainDevicePCIAddressIsValid(&addr->data.pci);
+ }
+
+ return 0;
+}
+
+
+int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr)
+{
+ return addr->domain || addr->bus || addr->slot;
+}
+
+
+void virDomainDeviceAddressClear(virDomainDeviceAddressPtr addr)
+{
+ memset(addr, 0, sizeof(addr));
+ addr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
+}
+
+
+/* Generate a string representation of a device address
+ * @param address Device address to stringify
+ */
+static int virDomainDeviceAddressFormat(virBufferPtr buf,
+ virDomainDeviceAddressPtr addr,
+ int flags)
+{
+ if (!addr) {
+ virDomainReportError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing address information"));
+ return -1;
+ }
+
+ if (addr->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+ return 0;
+
+ /* Don't output dynamically allocated addresses when doing inactive XML dump */
+ if ((addr->mode == VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC) &&
+ (flags & VIR_DOMAIN_XML_INACTIVE))
+ return 0;
+
+ /* We'll be in domain/devices/[device type]/ so 3 level indent */
+ virBufferVSprintf(buf, " <address type='%s'",
+ virDomainDeviceAddressTypeToString(addr->type));
+ virBufferVSprintf(buf, " mode='%s'",
+ virDomainDeviceAddressModeTypeToString(addr->mode));
+
+ switch (addr->type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ virBufferVSprintf(buf, " domain='0x%.4x' bus='0x%.2x'
slot='0x%.2x' function='0x%.1x'",
+ addr->data.pci.domain,
+ addr->data.pci.bus,
+ addr->data.pci.slot,
+ addr->data.pci.function);
+ break;
+
+ default:
+ virDomainReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unknown address type '%d'"),
addr->type);
+ return -1;
+ }
+
+ virBufferAddLit(buf, "/>\n");
+
+ return 0;
+}
+
+/* Compare two device addresses. Returns true if addresses are
+ * identical and false if the they differ (or are of different types)
+ * @param a, @para b Pointers to the addresses
+ */
+int virDomainDeviceAddressEqual(virDomainDeviceAddressPtr a,
+ virDomainDeviceAddressPtr b)
+{
+ if (!a || !b || a->type != b-> type) {
+ return 0;
+ }
+
+ switch (a->type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ return virDomainDevicePCIAddressEqual(&a->data.pci,
+ &b->data.pci);
+ }
+
+ 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
+virDomainDeviceAddressParseXML(virConnectPtr conn,
+ xmlNodePtr node,
+ virDomainDeviceAddressPtr addr,
+ int flags)
+{
+ char *type = NULL;
+ char *mode = NULL;
+ int ret = -1;
+
+ memset(addr, 0, sizeof(*addr));
+
+ type = virXMLPropString(node, "type");
+ mode = virXMLPropString(node, "mode");
+
+ if (type) {
+ if ((addr->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;
+ }
+
+ if (mode) {
+ if ((addr->mode = virDomainDeviceAddressModeTypeFromString(mode)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown address mode '%s'"),
mode);
+ goto cleanup;
+ }
+ } else {
+ addr->mode = VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC;
+ }
+
+ /* Dynamic addresses are only valid in the live config */
+ if ((flags & VIR_DOMAIN_XML_INACTIVE) &&
+ addr->mode == VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC) {
+ addr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
+ ret = 0;
+ goto cleanup;
+ }
+
+ switch (addr->type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ if (virDomainDevicePCIAddressParseXML(conn, node, &addr->data.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);
+ VIR_FREE(mode);
+ return ret;
+}
+
+
/* Parse the XML definition for a disk
* @param node XML nodeset to parse for disk definition
*/
@@ -747,6 +994,7 @@ virDomainDiskDefParseXML(virConnectPtr conn,
char *bus = NULL;
char *cachetag = NULL;
char *devaddr = NULL;
+ xmlNodePtr addr = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
@@ -827,6 +1075,9 @@ virDomainDiskDefParseXML(virConnectPtr conn,
} else if ((serial == NULL) &&
(xmlStrEqual(cur->name, BAD_CAST "serial"))) {
serial = (char *)xmlNodeGetContent(cur);
+ } else if ((addr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "address"))) {
+ addr = cur;
}
}
cur = cur->next;
@@ -926,15 +1177,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->addr.data.pci.domain,
+ &def->addr.data.pci.bus,
+ &def->addr.data.pci.slot) < 3) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to parse devaddr parameter
'%s'"),
+ devaddr);
+ goto error;
+ }
+ def->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ } else if (addr) {
+ if (virDomainDeviceAddressParseXML(conn, addr, &def->addr, flags) < 0)
+ goto error;
}
def->src = source;
@@ -1083,6 +1339,7 @@ virDomainNetDefParseXML(virConnectPtr conn,
char *hostnet_name = NULL;
char *devaddr = NULL;
char *vlan = NULL;
+ xmlNodePtr addr = NULL;
if (VIR_ALLOC(def) < 0) {
virReportOOMError(conn);
@@ -1155,6 +1412,9 @@ virDomainNetDefParseXML(virConnectPtr conn,
hostnet_name = virXMLPropString(cur, "hostnet");
devaddr = virXMLPropString(cur, "devaddr");
vlan = virXMLPropString(cur, "vlan");
+ } else if ((addr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "address"))) {
+ addr = cur;
}
}
cur = cur->next;
@@ -1171,14 +1431,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->addr.data.pci.domain,
+ &def->addr.data.pci.bus,
+ &def->addr.data.pci.slot) < 3) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to parse devaddr parameter
'%s'"),
+ devaddr);
+ goto error;
+ }
+ def->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ } else if (addr) {
+ if (virDomainDeviceAddressParseXML(conn, addr, &def->addr, 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->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ def->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Network interfaces must use 'pci' address
type"));
goto error;
}
@@ -2319,83 +2593,26 @@ 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")) {
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->addr.data.pci.domain,
+ &def->addr.data.pci.bus,
+ &def->addr.data.pci.slot) < 3) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("Unable to parse devaddr parameter
'%s'"),
devaddr);
VIR_FREE(devaddr);
goto out;
}
+ def->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
} else {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("unknown pci source type
'%s'"),
@@ -2473,6 +2690,9 @@ virDomainHostdevDefParseXML(virConnectPtr conn,
if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def, flags)
< 0)
goto error;
}
+ } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
+ if (virDomainDeviceAddressParseXML(conn, cur, &def->addr, flags)
< 0)
+ goto error;
} else {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("unknown node %s"), cur->name);
@@ -2481,6 +2701,18 @@ virDomainHostdevDefParseXML(virConnectPtr conn,
cur = cur->next;
}
+ if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+ switch (def->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+ if (def->addr.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);
@@ -3934,15 +4166,9 @@ 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 (def->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ virDomainDeviceAddressFormat(buf, &def->addr, flags) < 0)
+ return -1;
virBufferAddLit(buf, " </disk>\n");
@@ -4081,16 +4307,15 @@ virDomainNetDefFormat(virConnectPtr conn,
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 (def->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ virDomainDeviceAddressFormat(buf, &def->addr, flags) < 0)
+ return -1;
+
virBufferAddLit(buf, " </interface>\n");
return 0;
@@ -4499,25 +4724,20 @@ 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 (def->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ virDomainDeviceAddressFormat(buf, &def->addr, flags) < 0)
+ return -1;
+
virBufferAddLit(buf, " </hostdev>\n");
return 0;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ac39dcd..31a2f9d 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -63,6 +63,40 @@ 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
+};
+
+enum virDomainDeviceAddressMode {
+ VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC,
+ VIR_DOMAIN_DEVICE_ADDRESS_MODE_STATIC,
+
+ VIR_DOMAIN_DEVICE_ADDRESS_MODE_LAST
+};
+
+typedef struct _virDomainDevicePCIAddress virDomainDevicePCIAddress;
+typedef virDomainDevicePCIAddress *virDomainDevicePCIAddressPtr;
+struct _virDomainDevicePCIAddress {
+ unsigned int domain;
+ unsigned int bus;
+ unsigned int slot;
+ unsigned int function;
+};
+
+typedef struct _virDomainDeviceAddress virDomainDeviceAddress;
+typedef virDomainDeviceAddress *virDomainDeviceAddressPtr;
+struct _virDomainDeviceAddress {
+ int type;
+ int mode;
+ union {
+ virDomainDevicePCIAddress pci;
+ } data;
+};
+
+
/* Two types of disk backends */
enum virDomainDiskType {
VIR_DOMAIN_DISK_TYPE_BLOCK,
@@ -118,20 +152,10 @@ struct _virDomainDiskDef {
int cachemode;
unsigned int readonly : 1;
unsigned int shared : 1;
- struct {
- unsigned domain;
- unsigned bus;
- unsigned slot;
- } pci_addr;
+ virDomainDeviceAddress addr;
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 {
@@ -200,20 +224,10 @@ struct _virDomainNetDef {
char *ifname;
char *nic_name;
char *hostnet_name;
- struct {
- unsigned domain;
- unsigned bus;
- unsigned slot;
- } pci_addr;
+ virDomainDeviceAddress addr;
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,
@@ -441,17 +455,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 {
@@ -462,16 +466,9 @@ struct _virDomainHostdevDef {
} caps;
} source;
char* target;
+ virDomainDeviceAddress addr; /* 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,
@@ -671,6 +668,7 @@ virDomainObjIsActive(virDomainObjPtr dom)
return dom->def->id != -1;
}
+
int virDomainObjListInit(virDomainObjListPtr objs);
void virDomainObjListDeinit(virDomainObjListPtr objs);
@@ -693,6 +691,14 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
void virDomainVideoDefFree(virDomainVideoDefPtr def);
void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
+int virDomainDeviceAddressEqual(virDomainDeviceAddressPtr a,
+ virDomainDeviceAddressPtr b);
+int virDomainDevicePCIAddressEqual(virDomainDevicePCIAddressPtr a,
+ virDomainDevicePCIAddressPtr b);
+int virDomainDeviceAddressIsValid(virDomainDeviceAddressPtr addr,
+ int type);
+int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr);
+void virDomainDeviceAddressClear(virDomainDeviceAddressPtr addr);
void virDomainDefFree(virDomainDefPtr vm);
void virDomainObjRef(virDomainObjPtr vm);
/* Returns 1 if the object was freed, 0 if more refs exist */
@@ -830,6 +836,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 72257d7..963206b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -154,6 +154,11 @@ virDomainObjListInit;
virDomainObjListDeinit;
virDomainObjRef;
virDomainObjUnref;
+virDomainDeviceAddressEqual;
+virDomainDevicePCIAddressEqual;
+virDomainDeviceAddressIsValid;
+virDomainDevicePCIAddressIsValid;
+virDomainDeviceAddressClear;
# domain_event.h
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 7e60d0e..5920ab3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4947,13 +4947,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->addr.data.pci.domain,
+ &dev->data.disk->addr.data.pci.bus,
+ &dev->data.disk->addr.data.pci.slot);
qemuDomainObjExitMonitorWithDriver(driver, vm);
- if (ret == 0)
+ if (ret == 0) {
+ dev->data.disk->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
+ }
return ret;
}
@@ -5076,12 +5078,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->addr.data.pci.domain,
+ &net->addr.data.pci.bus,
+ &net->addr.data.pci.slot) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
goto try_remove;
}
+ net->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
qemuDomainObjExitMonitorWithDriver(driver, vm);
ret = 0;
@@ -5164,12 +5167,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->addr.data.pci.domain,
+ &hostdev->addr.data.pci.bus,
+ &hostdev->addr.data.pci.slot);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
goto error;
+ hostdev->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
@@ -5399,18 +5403,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->addr,
+ 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->addr.data.pci.domain,
+ detach->addr.data.pci.bus,
+ detach->addr.data.pci.slot) < 0) {
qemuDomainObjExitMonitor(vm);
goto cleanup;
}
@@ -5465,7 +5469,14 @@ qemudDomainDetachNetDevice(virConnectPtr conn,
goto cleanup;
}
- if (!virNetHasValidPciAddr(detach) || detach->vlan < 0 ||
!detach->hostnet_name) {
+ if (!virDomainDeviceAddressIsValid(&detach->addr,
+ 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;
@@ -5473,9 +5484,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->addr.data.pci.domain,
+ detach->addr.data.pci.bus,
+ detach->addr.data.pci.slot) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
goto cleanup;
}
@@ -5553,17 +5564,18 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
return -1;
}
- if (!virHostdevHasValidGuestAddr(detach)) {
+ if (!virDomainDeviceAddressIsValid(&detach->addr,
+ 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->addr.data.pci.domain,
+ detach->addr.data.pci.bus,
+ detach->addr.data.pci.slot) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
return -1;
}
--
1.6.5.2