To allow a client app to pass in custom XML during migration
of a guest it is neccessary to ensure the guest ABI remains
unchanged. The virDomainDefCheckABIStablity method accepts
two virDomainDefPtr structs and compares everything in them
that could impact the guest machine ABI
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/libvirt_private.syms: Add virDomainDefCheckABIStablity
* src/conf/cpu_conf.c, src/conf/cpu_conf.h: Add virCPUDefIsEqual
* src/util/sysinfo.c, src/util/sysinfo.h: Add virSysinfoIsEqual
---
src/conf/cpu_conf.c | 91 +++++
src/conf/cpu_conf.h | 9 +-
src/conf/domain_conf.c | 881 +++++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 11 +-
src/libvirt_private.syms | 1 +
src/util/sysinfo.c | 60 +++-
src/util/sysinfo.h | 11 +-
7 files changed, 1051 insertions(+), 13 deletions(-)
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 98d598a..77d0976 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -35,6 +35,9 @@
virReportErrorHelper(VIR_FROM_CPU, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__)
+VIR_ENUM_IMPL(virCPU, VIR_CPU_TYPE_LAST,
+ "host", "guest", "auto")
+
VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
"minimum",
"exact",
@@ -446,3 +449,91 @@ no_memory:
virReportOOMError();
return -1;
}
+
+bool
+virCPUDefIsEqual(virCPUDefPtr src,
+ virCPUDefPtr dst)
+{
+ bool identical = false;
+ int i;
+
+ if (!src && !dst)
+ return true;
+
+ if ((src && !dst) || (!src && dst)) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target CPU does not match source"));
+ goto cleanup;
+ }
+
+ if (src->type != dst->type) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU type %s does not match source %s"),
+ virCPUTypeToString(dst->type),
+ virCPUTypeToString(src->type));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->arch, dst->arch)) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU arch %s does not match source %s"),
+ NULLSTR(dst->arch), NULLSTR(src->arch));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->model, dst->model)) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU model %s does not match source %s"),
+ NULLSTR(dst->model), NULLSTR(src->model));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->vendor, dst->vendor)) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU vendor %s does not match source %s"),
+ NULLSTR(dst->vendor), NULLSTR(src->vendor));
+ goto cleanup;
+ }
+
+ if (src->sockets != dst->sockets) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU sockets %d does not match source %d"),
+ dst->sockets, src->sockets);
+ goto cleanup;
+ }
+
+ if (src->cores != dst->cores) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU cores %d does not match source %d"),
+ dst->cores, src->cores);
+ goto cleanup;
+ }
+
+ if (src->threads != dst->threads) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU threads %d does not match source %d"),
+ dst->threads, src->threads);
+ goto cleanup;
+ }
+
+ if (src->nfeatures != dst->nfeatures) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU feature count %zu does not match source
%zu"),
+ dst->nfeatures, src->nfeatures);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nfeatures ; i++) {
+ if (STRNEQ(src->features[i].name, dst->features[i].name)) {
+ virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target CPU feature %s does not match source
%s"),
+ dst->features[i].name, src->features[i].name);
+ goto cleanup;
+ }
+ }
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 055887c..ecd4e10 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -31,9 +31,13 @@
enum virCPUType {
VIR_CPU_TYPE_HOST,
VIR_CPU_TYPE_GUEST,
- VIR_CPU_TYPE_AUTO
+ VIR_CPU_TYPE_AUTO,
+
+ VIR_CPU_TYPE_LAST
};
+VIR_ENUM_DECL(virCPU)
+
enum virCPUMatch {
VIR_CPU_MATCH_MINIMUM,
VIR_CPU_MATCH_EXACT,
@@ -96,6 +100,9 @@ enum virCPUFormatFlags {
* in host capabilities */
};
+bool
+virCPUDefIsEqual(virCPUDefPtr src,
+ virCPUDefPtr dst);
char *
virCPUDefFormat(virCPUDefPtr def,
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 8ff155b..a9a4655 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -268,9 +268,6 @@ VIR_ENUM_IMPL(virDomainMemballoonModel,
VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
"xen",
"none")
-VIR_ENUM_IMPL(virDomainSysinfo, VIR_DOMAIN_SYSINFO_LAST,
- "smbios")
-
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
"none",
"emulate",
@@ -4364,7 +4361,7 @@ virSysinfoParseXML(const xmlNodePtr node,
_("sysinfo must contain a type attribute"));
goto error;
}
- if ((def->type = virDomainSysinfoTypeFromString(type)) < 0) {
+ if ((def->type = virSysinfoTypeFromString(type)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown sysinfo type '%s'"), type);
goto error;
@@ -6521,6 +6518,882 @@ virDomainObjPtr virDomainObjParseFile(virCapsPtr caps,
}
+static bool virDomainTimerDefCheckABIStability(virDomainTimerDefPtr src,
+ virDomainTimerDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->name != dst->name) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target timer %s does not match source %s"),
+ virDomainTimerNameTypeToString(dst->name),
+ virDomainTimerNameTypeToString(src->name));
+ goto cleanup;
+ }
+
+ if (src->present != dst->present) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target timer presence %d does not match source
%d"),
+ dst->present, src->present);
+ goto cleanup;
+ }
+
+ if (src->name == VIR_DOMAIN_TIMER_NAME_TSC) {
+ if (src->frequency != dst->frequency) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target TSC frequency %lu does not match source
%lu"),
+ dst->frequency, src->frequency);
+ goto cleanup;
+ }
+
+ if (src->mode != dst->mode) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target TSC mode %s does not match source
%s"),
+ virDomainTimerModeTypeToString(dst->mode),
+ virDomainTimerModeTypeToString(src->mode));
+ goto cleanup;
+ }
+ }
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
+ virDomainDeviceInfoPtr dst)
+{
+ bool identical = false;
+
+ if (src->type != dst->type) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device address type %s does not match source
%s"),
+ virDomainDeviceAddressTypeToString(dst->type),
+ virDomainDeviceAddressTypeToString(src->type));
+ goto cleanup;
+ }
+
+ switch (src->type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ if (src->addr.pci.domain != dst->addr.pci.domain ||
+ src->addr.pci.bus != dst->addr.pci.bus ||
+ src->addr.pci.slot != dst->addr.pci.slot ||
+ src->addr.pci.function != dst->addr.pci.function) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device PCI address %04x:%02x:%02x.%02x
does not match source %04x:%02x:%02x.%02x"),
+ dst->addr.pci.domain, dst->addr.pci.bus,
+ dst->addr.pci.slot, dst->addr.pci.function,
+ src->addr.pci.domain, src->addr.pci.bus,
+ src->addr.pci.slot, src->addr.pci.function);
+ goto cleanup;
+ }
+ break;
+
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
+ if (src->addr.drive.controller != dst->addr.drive.controller ||
+ src->addr.drive.bus != dst->addr.drive.bus ||
+ src->addr.drive.unit != dst->addr.drive.unit) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device drive address %d:%d:%d does not
match source %d:%d:%d"),
+ dst->addr.drive.controller, dst->addr.drive.bus,
+ dst->addr.drive.unit,
+ src->addr.drive.controller, src->addr.drive.bus,
+ src->addr.drive.unit);
+ goto cleanup;
+ }
+ break;
+
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
+ if (src->addr.vioserial.controller != dst->addr.vioserial.controller ||
+ src->addr.vioserial.bus != dst->addr.vioserial.bus ||
+ src->addr.vioserial.port != dst->addr.vioserial.port) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device virtio serial address %d:%d:%d
does not match source %d:%d:%d"),
+ dst->addr.vioserial.controller,
dst->addr.vioserial.bus,
+ dst->addr.vioserial.port,
+ src->addr.vioserial.controller,
src->addr.vioserial.bus,
+ src->addr.vioserial.port);
+ goto cleanup;
+ }
+ break;
+
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
+ if (src->addr.ccid.controller != dst->addr.ccid.controller ||
+ src->addr.ccid.slot != dst->addr.ccid.slot) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device ccid address %d:%d does not match
source %d:%d"),
+ dst->addr.ccid.controller,
+ dst->addr.ccid.slot,
+ src->addr.ccid.controller,
+ src->addr.ccid.slot);
+ goto cleanup;
+ }
+ break;
+ }
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
+ virDomainDiskDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->device != dst->device) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target disk device %s does not match source
%s"),
+ virDomainDiskDeviceTypeToString(dst->device),
+ virDomainDiskDeviceTypeToString(src->device));
+ goto cleanup;
+ }
+
+ if (src->bus != dst->bus) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target disk bus %s does not match source %s"),
+ virDomainDiskBusTypeToString(dst->bus),
+ virDomainDiskBusTypeToString(src->bus));
+ goto cleanup;
+ }
+
+ if (STRNEQ(src->dst, dst->dst)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target disk %s does not match source %s"),
+ dst->dst, src->dst);
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->serial, dst->serial)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target disk serial %s does not match source
%s"),
+ NULLSTR(dst->serial), NULLSTR(src->serial));
+ goto cleanup;
+ }
+
+ if (src->readonly != dst->readonly || src->shared != dst->shared) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target disk access mode does not match
source"));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
+ virDomainControllerDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->type != dst->type) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target controller type %s does not match source
%s"),
+ virDomainControllerTypeToString(dst->type),
+ virDomainControllerTypeToString(src->type));
+ goto cleanup;
+ }
+
+ if (src->idx != dst->idx) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target controller index %d does not match source
%d"),
+ dst->idx, src->idx);
+ goto cleanup;
+ }
+
+ if (src->model != dst->model) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target controller model %d does not match source
%d"),
+ dst->model, src->model);
+ goto cleanup;
+ }
+
+ if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
+ if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target controller ports %d does not match source
%d"),
+ dst->opts.vioserial.ports,
src->opts.vioserial.ports);
+ goto cleanup;
+ }
+
+ if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target controller vectors %d does not match
source %d"),
+ dst->opts.vioserial.vectors,
src->opts.vioserial.vectors);
+ goto cleanup;
+ }
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainFsDefCheckABIStability(virDomainFSDefPtr src,
+ virDomainFSDefPtr dst)
+{
+ bool identical = false;
+
+ if (STRNEQ(src->dst, dst->dst)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target filesystem guest target %s does not match
source %s"),
+ dst->dst, src->dst);
+ goto cleanup;
+ }
+
+ if (src->readonly != dst->readonly) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target filesystem access mode does not match
source"));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
+ virDomainNetDefPtr dst)
+{
+ bool identical = false;
+
+ if (memcmp(src->mac, dst->mac, VIR_MAC_BUFLEN) != 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target network card mac
%02x:%02x:%02x:%02x:%02x:%02x"
+ "does not match source
%02x:%02x:%02x:%02x:%02x:%02x"),
+ dst->mac[0], dst->mac[2], dst->mac[2],
+ dst->mac[3], dst->mac[4], dst->mac[5],
+ src->mac[0], src->mac[2], src->mac[2],
+ src->mac[3], src->mac[4], src->mac[5]);
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->model, dst->model)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target network card model %s does not match source
%s"),
+ NULLSTR(dst->model), NULLSTR(src->model));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainInputDefCheckABIStability(virDomainInputDefPtr src,
+ virDomainInputDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->type != dst->type) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target input device type %s does not match source
%s"),
+ virDomainInputTypeToString(dst->type),
+ virDomainInputTypeToString(src->type));
+ goto cleanup;
+ }
+
+ if (src->bus != dst->bus) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target input device bus %s does not match source
%s"),
+ virDomainInputBusTypeToString(dst->bus),
+ virDomainInputBusTypeToString(src->bus));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainSoundDefCheckABIStability(virDomainSoundDefPtr src,
+ virDomainSoundDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->model != dst->model) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target sound card model %s does not match source
%s"),
+ virDomainSoundModelTypeToString(dst->model),
+ virDomainSoundModelTypeToString(src->model));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
+ virDomainVideoDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->type != dst->type) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target video card model %s does not match source
%s"),
+ virDomainVideoTypeToString(dst->type),
+ virDomainVideoTypeToString(src->type));
+ goto cleanup;
+ }
+
+ if (src->vram != dst->vram) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target video card vram %u does not match source
%u"),
+ dst->vram, src->vram);
+ goto cleanup;
+ }
+
+ if (src->heads != dst->heads) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target video card heads %u does not match source
%u"),
+ dst->heads, src->heads);
+ goto cleanup;
+ }
+
+ if ((src->accel && !dst->accel) ||
+ (!src->accel && dst->accel)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target video card acceleration does not match
source"));
+ goto cleanup;
+ }
+
+ if (src->accel) {
+ if (src->accel->support2d != dst->accel->support2d) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target video card 2d accel %u does not match
source %u"),
+ dst->accel->support2d,
src->accel->support2d);
+ goto cleanup;
+ }
+
+ if (src->accel->support3d != dst->accel->support3d) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target video card 3d accel %u does not match
source %u"),
+ dst->accel->support3d,
src->accel->support3d);
+ goto cleanup;
+ }
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainHostdevDefCheckABIStability(virDomainHostdevDefPtr src,
+ virDomainHostdevDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->mode != dst->mode) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target host device mode %s does not match source
%s"),
+ virDomainHostdevModeTypeToString(dst->mode),
+ virDomainHostdevModeTypeToString(src->mode));
+ goto cleanup;
+ }
+
+ if (src->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+ if (src->source.subsys.type != dst->source.subsys.type) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target host device subsystem %s does not match
source %s"),
+
virDomainHostdevSubsysTypeToString(dst->source.subsys.type),
+
virDomainHostdevSubsysTypeToString(src->source.subsys.type));
+ goto cleanup;
+ }
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainSmartcardDefCheckABIStability(virDomainSmartcardDefPtr src,
+ virDomainSmartcardDefPtr dst)
+{
+ bool identical = false;
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainSerialDefCheckABIStability(virDomainChrDefPtr src,
+ virDomainChrDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->target.port != dst->target.port) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target serial port %d does not match source
%d"),
+ dst->target.port, src->target.port);
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainParallelDefCheckABIStability(virDomainChrDefPtr src,
+ virDomainChrDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->target.port != dst->target.port) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target serial port %d does not match source
%d"),
+ dst->target.port, src->target.port);
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainChannelDefCheckABIStability(virDomainChrDefPtr src,
+ virDomainChrDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->targetType != dst->targetType) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target channel type %s does not match source
%s"),
+ virDomainChrChannelTargetTypeToString(dst->targetType),
+ virDomainChrChannelTargetTypeToString(src->targetType));
+ goto cleanup;
+ }
+
+ switch (src->targetType) {
+ case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
+ if (STRNEQ(src->target.name, dst->target.name)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target channel name %s does not match source
%s"),
+ dst->target.name, src->target.name);
+ goto cleanup;
+ }
+ break;
+ case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
+ if (memcmp(src->target.addr, dst->target.addr, sizeof(src->target.addr))
!= 0) {
+ char *saddr = virSocketFormatAddrFull(src->target.addr, true,
":");
+ char *daddr = virSocketFormatAddrFull(dst->target.addr, true,
":");
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target channel addr %s does not match source
%s"),
+ NULLSTR(daddr), NULLSTR(saddr));
+ VIR_FREE(saddr);
+ VIR_FREE(daddr);
+ goto cleanup;
+ }
+ break;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainConsoleDefCheckABIStability(virDomainChrDefPtr src,
+ virDomainChrDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->targetType != dst->targetType) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target console type %s does not match source
%s"),
+ virDomainChrConsoleTargetTypeToString(dst->targetType),
+ virDomainChrConsoleTargetTypeToString(src->targetType));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainWatchdogDefCheckABIStability(virDomainWatchdogDefPtr src,
+ virDomainWatchdogDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->model != dst->model) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target watchdog model %s does not match source
%s"),
+ virDomainWatchdogModelTypeToString(dst->model),
+ virDomainWatchdogModelTypeToString(src->model));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+static bool virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
+ virDomainMemballoonDefPtr dst)
+{
+ bool identical = false;
+
+ if (src->model != dst->model) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target balloon model %s does not match source
%s"),
+ virDomainMemballoonModelTypeToString(dst->model),
+ virDomainMemballoonModelTypeToString(src->model));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
+/* This compares two configurations and looks for any differences
+ * which will affect the guest ABI. This is primarily to allow
+ * validation of custom XML config passed in during migration
+ */
+bool virDomainDefCheckABIStability(virDomainDefPtr src,
+ virDomainDefPtr dst)
+{
+ bool identical = false;
+ int i;
+
+ if (src->virtType != dst->virtType) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain virt type %s does not match source
%s"),
+ virDomainVirtTypeToString(dst->virtType),
+ virDomainVirtTypeToString(src->virtType));
+ goto cleanup;
+ }
+
+ if (memcmp(src->uuid, dst->uuid, VIR_UUID_BUFLEN) != 0) {
+ char uuidsrc[VIR_UUID_STRING_BUFLEN];
+ char uuiddst[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(src->uuid, uuidsrc);
+ virUUIDFormat(dst->uuid, uuiddst);
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain uuid %s does not match source
%s"),
+ uuiddst, uuidsrc);
+ goto cleanup;
+ }
+
+ if (src->vcpus != dst->vcpus) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain vpu count %d does not match source
%d"),
+ dst->vcpus, src->vcpus);
+ goto cleanup;
+ }
+ if (src->maxvcpus != dst->maxvcpus) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain vpu max %d does not match source
%d"),
+ dst->maxvcpus, src->maxvcpus);
+ goto cleanup;
+ }
+
+ if (STRNEQ(src->os.type, dst->os.type)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain OS type %s does not match source
%s"),
+ dst->os.type, src->os.type);
+ goto cleanup;
+ }
+ if (STRNEQ(src->os.arch, dst->os.arch)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain architecture %s does not match source
%s"),
+ dst->os.arch, src->os.arch);
+ goto cleanup;
+ }
+ if (STRNEQ(src->os.machine, dst->os.machine)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain OS type %s does not match source
%s"),
+ dst->os.machine, src->os.machine);
+ goto cleanup;
+ }
+
+ if (src->os.smbios_mode != dst->os.smbios_mode) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain SMBIOS mode %s does not match source
%s"),
+ virDomainSmbiosModeTypeToString(dst->os.smbios_mode),
+ virDomainSmbiosModeTypeToString(src->os.smbios_mode));
+ goto cleanup;
+ }
+
+ if (src->features != dst->features) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain features %d does not match source
%d"),
+ dst->features, src->features);
+ goto cleanup;
+ }
+
+ if (src->clock.ntimers != dst->clock.ntimers) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target domain timers do not match source"));
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->clock.ntimers ; i++) {
+ if (!virDomainTimerDefCheckABIStability(src->clock.timers[i],
dst->clock.timers[i]))
+ goto cleanup;
+ }
+
+ if (!virCPUDefIsEqual(src->cpu, dst->cpu))
+ goto cleanup;
+
+ if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
+ goto cleanup;
+
+ if (src->ndisks != dst->ndisks) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain disk count %d does not match source
%d"),
+ dst->ndisks, src->ndisks);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->ndisks ; i++)
+ if (!virDomainDiskDefCheckABIStability(src->disks[i], dst->disks[i]))
+ goto cleanup;
+
+ if (src->ncontrollers != dst->ncontrollers) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain disk controller count %d does not
match source %d"),
+ dst->ncontrollers, src->ncontrollers);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->ncontrollers ; i++)
+ if (!virDomainControllerDefCheckABIStability(src->controllers[i],
dst->controllers[i]))
+ goto cleanup;
+
+ if (src->nfss != dst->nfss) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain filesystem count %d does not match
source %d"),
+ dst->nfss, src->nfss);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nfss ; i++)
+ if (!virDomainFsDefCheckABIStability(src->fss[i], dst->fss[i]))
+ goto cleanup;
+
+ if (src->nnets != dst->nnets) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain net card count %d does not match
source %d"),
+ dst->nnets, src->nnets);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nnets ; i++)
+ if (!virDomainNetDefCheckABIStability(src->nets[i], dst->nets[i]))
+ goto cleanup;
+
+ if (src->ninputs != dst->ninputs) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain input device count %d does not match
source %d"),
+ dst->ninputs, src->ninputs);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->ninputs ; i++)
+ if (!virDomainInputDefCheckABIStability(src->inputs[i], dst->inputs[i]))
+ goto cleanup;
+
+ if (src->nsounds != dst->nsounds) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain sound card count %d does not match
source %d"),
+ dst->nsounds, src->nsounds);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nsounds ; i++)
+ if (!virDomainSoundDefCheckABIStability(src->sounds[i], dst->sounds[i]))
+ goto cleanup;
+
+ if (src->nvideos != dst->nvideos) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain video card count %d does not match
source %d"),
+ dst->nvideos, src->nvideos);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nvideos ; i++)
+ if (!virDomainVideoDefCheckABIStability(src->videos[i], dst->videos[i]))
+ goto cleanup;
+
+ if (src->nhostdevs != dst->nhostdevs) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain host device count %d does not match
source %d"),
+ dst->nhostdevs, src->nhostdevs);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nhostdevs ; i++)
+ if (!virDomainHostdevDefCheckABIStability(src->hostdevs[i],
dst->hostdevs[i]))
+ goto cleanup;
+
+ if (src->nsmartcards != dst->nsmartcards) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain smartcard count %d does not match
source %d"),
+ dst->nsmartcards, src->nsmartcards);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nsmartcards ; i++)
+ if (!virDomainSmartcardDefCheckABIStability(src->smartcards[i],
dst->smartcards[i]))
+ goto cleanup;
+
+ if (src->nserials != dst->nserials) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain serial port count %d does not match
source %d"),
+ dst->nserials, src->nserials);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nserials ; i++)
+ if (!virDomainSerialDefCheckABIStability(src->serials[i],
dst->serials[i]))
+ goto cleanup;
+
+ if (src->nparallels != dst->nparallels) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain parallel port count %d does not match
source %d"),
+ dst->nparallels, src->nparallels);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nparallels ; i++)
+ if (!virDomainParallelDefCheckABIStability(src->parallels[i],
dst->parallels[i]))
+ goto cleanup;
+
+ if (src->nchannels != dst->nchannels) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain channel count %d does not match source
%d"),
+ dst->nchannels, src->nchannels);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < src->nchannels ; i++)
+ if (!virDomainChannelDefCheckABIStability(src->channels[i],
dst->channels[i]))
+ goto cleanup;
+
+ if ((!src->console && dst->console) ||
+ (src->console && !dst->console)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain console count %d does not match source
%d"),
+ dst->console ? 1 : 0, src->console ? 1 : 0);
+ goto cleanup;
+ }
+
+ if (src->console &&
+ !virDomainConsoleDefCheckABIStability(src->console, dst->console))
+ goto cleanup;
+
+ if ((!src->watchdog && dst->watchdog) ||
+ (src->watchdog && !dst->watchdog)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain watchdog count %d does not match
source %d"),
+ dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0);
+ goto cleanup;
+ }
+
+ if (src->watchdog &&
+ !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog))
+ goto cleanup;
+
+ if ((!src->memballoon && dst->memballoon) ||
+ (src->memballoon && !dst->memballoon)) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain memory balloon count %d does not match
source %d"),
+ dst->memballoon ? 1 : 0, src->memballoon ? 1 : 0);
+ goto cleanup;
+ }
+
+ if (src->memballoon &&
+ !virDomainMemballoonDefCheckABIStability(src->memballoon,
dst->memballoon))
+ goto cleanup;
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
+
static int virDomainDefMaybeAddController(virDomainDefPtr def,
int type,
int idx)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d4245d8..47d17dd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1097,7 +1097,12 @@ virDomainVcpupinDefPtr
virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
int nvcpupin,
int vcpu);
-/* Guest VM main configuration */
+/*
+ * Guest VM main configuration
+ *
+ * NB: if adding to this struct, virDomainDefCheckABIStability
+ * may well need an update
+ */
typedef struct _virDomainDef virDomainDef;
typedef virDomainDef *virDomainDefPtr;
struct _virDomainDef {
@@ -1343,6 +1348,9 @@ virDomainDefPtr virDomainDefParseNode(virCapsPtr caps,
virDomainObjPtr virDomainObjParseFile(virCapsPtr caps,
const char *filename);
+bool virDomainDefCheckABIStability(virDomainDefPtr src,
+ virDomainDefPtr dst);
+
int virDomainDefAddImplicitControllers(virDomainDefPtr def);
char *virDomainDefFormat(virDomainDefPtr def,
@@ -1500,7 +1508,6 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol)
VIR_ENUM_DECL(virDomainChrSpicevmc)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainMemballoonModel)
-VIR_ENUM_DECL(virDomainSysinfo)
VIR_ENUM_DECL(virDomainSmbiosMode)
VIR_ENUM_DECL(virDomainWatchdogModel)
VIR_ENUM_DECL(virDomainWatchdogAction)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4cb8dda..c1bac23 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -224,6 +224,7 @@ virDomainControllerTypeToString;
virDomainCpuSetFormat;
virDomainCpuSetParse;
virDomainDefAddImplicitControllers;
+virDomainDefCheckABIStability;
virDomainDefClearDeviceAliases;
virDomainDefClearPCIAddresses;
virDomainDefFormat;
diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c
index d929073..70da532 100644
--- a/src/util/sysinfo.c
+++ b/src/util/sysinfo.c
@@ -33,7 +33,6 @@
#include "virterror_internal.h"
#include "sysinfo.h"
#include "util.h"
-#include "conf/domain_conf.h"
#include "logging.h"
#include "memory.h"
#include "command.h"
@@ -46,6 +45,9 @@
#define SYSINFO_SMBIOS_DECODER "dmidecode"
+VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST,
+ "smbios");
+
/**
* virSysinfoDefFree:
* @def: a sysinfo structure
@@ -131,7 +133,7 @@ virSysinfoRead(void) {
if (VIR_ALLOC(ret) < 0)
goto no_memory;
- ret->type = VIR_DOMAIN_SYSINFO_SMBIOS;
+ ret->type = VIR_SYSINFO_SMBIOS;
base = outbuf;
@@ -230,7 +232,7 @@ no_memory:
char *
virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
{
- const char *type = virDomainSysinfoTypeToString(def->type);
+ const char *type = virSysinfoTypeToString(def->type);
virBuffer buf = VIR_BUFFER_INITIALIZER;
size_t len = strlen(prefix);
@@ -326,4 +328,56 @@ virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
return virBufferContentAndReset(&buf);
}
+bool virSysinfoIsEqual(virSysinfoDefPtr src,
+ virSysinfoDefPtr dst)
+{
+ bool identical = false;
+
+ if (!src && !dst)
+ return true;
+
+ if ((src && !dst) || (!src && dst)) {
+ virSmbiosReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target sysinfo does not match source"));
+ goto cleanup;
+ }
+
+ if (src->type != dst->type) {
+ virSmbiosReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target sysinfo %s does not match source %s"),
+ virSysinfoTypeToString(dst->type),
+ virSysinfoTypeToString(src->type));
+ goto cleanup;
+ }
+
+#define CHECK_FIELD(name, desc) \
+ do { \
+ if (STRNEQ_NULLABLE(src->name, dst->name)) { \
+ virSmbiosReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+ _("Target sysinfo " desc " %s does not
match source %s"), \
+ src->name, dst->name); \
+ } \
+ } while (0)
+
+ CHECK_FIELD(bios_vendor, "BIOS vendor");
+ CHECK_FIELD(bios_version, "BIOS version");
+ CHECK_FIELD(bios_date, "BIOS date");
+ CHECK_FIELD(bios_release, "BIOS release");
+
+ CHECK_FIELD(system_manufacturer, "system vendor");
+ CHECK_FIELD(system_product, "system product");
+ CHECK_FIELD(system_version, "system version");
+ CHECK_FIELD(system_serial, "system serial");
+ CHECK_FIELD(system_uuid, "system uuid");
+ CHECK_FIELD(system_sku, "system sku");
+ CHECK_FIELD(system_family, "system family");
+
+#undef CHECK_FIELD
+
+ identical = true;
+
+cleanup:
+ return identical;
+}
+
#endif /* !WIN32 */
diff --git a/src/util/sysinfo.h b/src/util/sysinfo.h
index 66a59db..f69b76c 100644
--- a/src/util/sysinfo.h
+++ b/src/util/sysinfo.h
@@ -27,10 +27,10 @@
# include "internal.h"
# include "util.h"
-enum virDomainSysinfoType {
- VIR_DOMAIN_SYSINFO_SMBIOS,
+enum virSysinfoType {
+ VIR_SYSINFO_SMBIOS,
- VIR_DOMAIN_SYSINFO_LAST
+ VIR_SYSINFO_LAST
};
typedef struct _virSysinfoDef virSysinfoDef;
@@ -59,4 +59,9 @@ void virSysinfoDefFree(virSysinfoDefPtr def);
char *virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+bool virSysinfoIsEqual(virSysinfoDefPtr src,
+ virSysinfoDefPtr dst);
+
+VIR_ENUM_DECL(virSysinfo)
+
#endif /* __VIR_SYSINFOS_H__ */
--
1.7.4.4