Add an API for comparing the ABI of two guest configurations

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
This commit is contained in:
Daniel P. Berrange 2011-05-27 10:47:30 +01:00
parent 0e4d4afb07
commit 08106e2044
7 changed files with 1059 additions and 13 deletions

View File

@ -35,6 +35,9 @@
virReportErrorHelper(VIR_FROM_CPU, code, __FILE__, \ virReportErrorHelper(VIR_FROM_CPU, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__) __FUNCTION__, __LINE__, __VA_ARGS__)
VIR_ENUM_IMPL(virCPU, VIR_CPU_TYPE_LAST,
"host", "guest", "auto")
VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST, VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
"minimum", "minimum",
"exact", "exact",
@ -446,3 +449,99 @@ no_memory:
virReportOOMError(); virReportOOMError();
return -1; 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;
}
if (src->features[i].policy != dst->features[i].policy) {
virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target CPU feature policy %s does not match source %s"),
virCPUFeaturePolicyTypeToString(dst->features[i].policy),
virCPUFeaturePolicyTypeToString(src->features[i].policy));
goto cleanup;
}
}
identical = true;
cleanup:
return identical;
}

View File

@ -31,9 +31,13 @@
enum virCPUType { enum virCPUType {
VIR_CPU_TYPE_HOST, VIR_CPU_TYPE_HOST,
VIR_CPU_TYPE_GUEST, VIR_CPU_TYPE_GUEST,
VIR_CPU_TYPE_AUTO VIR_CPU_TYPE_AUTO,
VIR_CPU_TYPE_LAST
}; };
VIR_ENUM_DECL(virCPU)
enum virCPUMatch { enum virCPUMatch {
VIR_CPU_MATCH_MINIMUM, VIR_CPU_MATCH_MINIMUM,
VIR_CPU_MATCH_EXACT, VIR_CPU_MATCH_EXACT,
@ -96,6 +100,9 @@ enum virCPUFormatFlags {
* in host capabilities */ * in host capabilities */
}; };
bool
virCPUDefIsEqual(virCPUDefPtr src,
virCPUDefPtr dst);
char * char *
virCPUDefFormat(virCPUDefPtr def, virCPUDefFormat(virCPUDefPtr def,

View File

@ -268,9 +268,6 @@ VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
"xen", "xen",
"none") "none")
VIR_ENUM_IMPL(virDomainSysinfo, VIR_DOMAIN_SYSINFO_LAST,
"smbios")
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST, VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
"none", "none",
"emulate", "emulate",
@ -4363,7 +4360,7 @@ virSysinfoParseXML(const xmlNodePtr node,
_("sysinfo must contain a type attribute")); _("sysinfo must contain a type attribute"));
goto error; goto error;
} }
if ((def->type = virDomainSysinfoTypeFromString(type)) < 0) { if ((def->type = virSysinfoTypeFromString(type)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown sysinfo type '%s'"), type); _("unknown sysinfo type '%s'"), type);
goto error; goto error;
@ -6564,6 +6561,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[1], dst->mac[2],
dst->mac[3], dst->mac[4], dst->mac[5],
src->mac[0], src->mac[1], 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, static int virDomainDefMaybeAddController(virDomainDefPtr def,
int type, int type,
int idx) int idx)

View File

@ -1096,7 +1096,12 @@ virDomainVcpupinDefPtr virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
int nvcpupin, int nvcpupin,
int vcpu); 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 struct _virDomainDef virDomainDef;
typedef virDomainDef *virDomainDefPtr; typedef virDomainDef *virDomainDefPtr;
struct _virDomainDef { struct _virDomainDef {
@ -1342,6 +1347,9 @@ virDomainDefPtr virDomainDefParseNode(virCapsPtr caps,
virDomainObjPtr virDomainObjParseFile(virCapsPtr caps, virDomainObjPtr virDomainObjParseFile(virCapsPtr caps,
const char *filename); const char *filename);
bool virDomainDefCheckABIStability(virDomainDefPtr src,
virDomainDefPtr dst);
int virDomainDefAddImplicitControllers(virDomainDefPtr def); int virDomainDefAddImplicitControllers(virDomainDefPtr def);
char *virDomainDefFormat(virDomainDefPtr def, char *virDomainDefFormat(virDomainDefPtr def,
@ -1503,7 +1511,6 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol)
VIR_ENUM_DECL(virDomainChrSpicevmc) VIR_ENUM_DECL(virDomainChrSpicevmc)
VIR_ENUM_DECL(virDomainSoundModel) VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainMemballoonModel) VIR_ENUM_DECL(virDomainMemballoonModel)
VIR_ENUM_DECL(virDomainSysinfo)
VIR_ENUM_DECL(virDomainSmbiosMode) VIR_ENUM_DECL(virDomainSmbiosMode)
VIR_ENUM_DECL(virDomainWatchdogModel) VIR_ENUM_DECL(virDomainWatchdogModel)
VIR_ENUM_DECL(virDomainWatchdogAction) VIR_ENUM_DECL(virDomainWatchdogAction)

View File

@ -224,6 +224,7 @@ virDomainControllerTypeToString;
virDomainCpuSetFormat; virDomainCpuSetFormat;
virDomainCpuSetParse; virDomainCpuSetParse;
virDomainDefAddImplicitControllers; virDomainDefAddImplicitControllers;
virDomainDefCheckABIStability;
virDomainDefClearDeviceAliases; virDomainDefClearDeviceAliases;
virDomainDefClearPCIAddresses; virDomainDefClearPCIAddresses;
virDomainDefFormat; virDomainDefFormat;

View File

@ -33,7 +33,6 @@
#include "virterror_internal.h" #include "virterror_internal.h"
#include "sysinfo.h" #include "sysinfo.h"
#include "util.h" #include "util.h"
#include "conf/domain_conf.h"
#include "logging.h" #include "logging.h"
#include "memory.h" #include "memory.h"
#include "command.h" #include "command.h"
@ -46,6 +45,9 @@
#define SYSINFO_SMBIOS_DECODER "dmidecode" #define SYSINFO_SMBIOS_DECODER "dmidecode"
VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST,
"smbios");
/** /**
* virSysinfoDefFree: * virSysinfoDefFree:
* @def: a sysinfo structure * @def: a sysinfo structure
@ -131,7 +133,7 @@ virSysinfoRead(void) {
if (VIR_ALLOC(ret) < 0) if (VIR_ALLOC(ret) < 0)
goto no_memory; goto no_memory;
ret->type = VIR_DOMAIN_SYSINFO_SMBIOS; ret->type = VIR_SYSINFO_SMBIOS;
base = outbuf; base = outbuf;
@ -230,7 +232,7 @@ no_memory:
char * char *
virSysinfoFormat(virSysinfoDefPtr def, const char *prefix) virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
{ {
const char *type = virDomainSysinfoTypeToString(def->type); const char *type = virSysinfoTypeToString(def->type);
virBuffer buf = VIR_BUFFER_INITIALIZER; virBuffer buf = VIR_BUFFER_INITIALIZER;
size_t len = strlen(prefix); size_t len = strlen(prefix);
@ -326,4 +328,56 @@ virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
return virBufferContentAndReset(&buf); 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 %s %s does not match source %s"), \
desc, NULLSTR(src->name), NULLSTR(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 */ #endif /* !WIN32 */

View File

@ -27,10 +27,10 @@
# include "internal.h" # include "internal.h"
# include "util.h" # include "util.h"
enum virDomainSysinfoType { enum virSysinfoType {
VIR_DOMAIN_SYSINFO_SMBIOS, VIR_SYSINFO_SMBIOS,
VIR_DOMAIN_SYSINFO_LAST VIR_SYSINFO_LAST
}; };
typedef struct _virSysinfoDef virSysinfoDef; typedef struct _virSysinfoDef virSysinfoDef;
@ -59,4 +59,9 @@ void virSysinfoDefFree(virSysinfoDefPtr def);
char *virSysinfoFormat(virSysinfoDefPtr def, const char *prefix) char *virSysinfoFormat(virSysinfoDefPtr def, const char *prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
bool virSysinfoIsEqual(virSysinfoDefPtr src,
virSysinfoDefPtr dst);
VIR_ENUM_DECL(virSysinfo)
#endif /* __VIR_SYSINFOS_H__ */ #endif /* __VIR_SYSINFOS_H__ */