They have to be unique within the domain. As usual, backwards compatibility takes its price. In this particular situation we have a device that is represented twice in a domain and so is its alias. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/conf/domain_conf.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 5 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 3 + 4 files changed, 155 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f1386c116..0cf67dff1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -5458,6 +5458,145 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, } +struct virDomainDefValidateAliasesData { + virHashTablePtr aliases; +}; + + +static int +virDomainDeviceDefValidateAliasesIterator(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + struct virDomainDefValidateAliasesData *data = opaque; + const char *alias = info->alias; + + if (!alias) + return 0; + + /* Some crazy backcompat for consoles. */ + if (def->nserials && def->nconsoles && + def->consoles[0]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL && + dev->type == VIR_DOMAIN_DEVICE_CHR && + virDomainChrEquals(def->serials[0], dev->data.chr)) + return 0; + + if (virHashLookup(data->aliases, alias)) { + virReportError(VIR_ERR_XML_ERROR, + _("non unique alias detected: %s"), + alias); + return -1; + } + + if (virHashAddEntry(data->aliases, alias, (void *) 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to construct table of device aliases")); + return -1; + } + + return 0; +} + + +/** + * virDomainDefValidateAliases: + * + * Check for uniqueness of device aliases. If @aliases is not + * NULL return hash table of all the aliases in it. + * + * Returns 0 on success, + * -1 otherwise (with error reported). + */ +static int +virDomainDefValidateAliases(virDomainXMLOptionPtr xmlopt ATTRIBUTE_UNUSED, + const virDomainDef *def, + virHashTablePtr *aliases, + unsigned int parseFlags) +{ + struct virDomainDefValidateAliasesData data; + int ret = -1; + + /* validate configuration only in certain places */ + if (parseFlags & VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE) + return 0; + + /* We are not storing copies of aliases. Don't free them. */ + if (!(data.aliases = virHashCreate(10, NULL))) + goto cleanup; + + if (virDomainDeviceInfoIterateInternal((virDomainDefPtr) def, + virDomainDeviceDefValidateAliasesIterator, + true, &data) < 0) + goto cleanup; + + if (aliases) { + *aliases = data.aliases; + data.aliases = NULL; + } + + ret = 0; + cleanup: + virHashFree(data.aliases); + return ret; +} + + +static int +virDomainDeviceValidateAliasImpl(virDomainXMLOptionPtr xmlopt, + const virDomainDef *def, + const virDomainDeviceDef *dev) +{ + virHashTablePtr aliases = NULL; + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + int ret = -1; + + if (!info || !info->alias) + return 0; + + if (virDomainDefValidateAliases(xmlopt, def, &aliases, 0) < 0) + goto cleanup; + + if (virHashLookup(aliases, info->alias)) { + virReportError(VIR_ERR_XML_ERROR, + _("non unique alias detected: %s"), + info->alias); + goto cleanup; + } + + ret = 0; + cleanup: + + virHashFree(aliases); + return ret; +} + + +int +virDomainDeviceValidateAliasForHotplug(virDomainXMLOptionPtr xmlopt, + virDomainObjPtr vm, + const virDomainDeviceDef *dev, + unsigned int flags) +{ + virDomainDefPtr persDef = NULL; + virDomainDefPtr liveDef = NULL; + + if (virDomainObjGetDefs(vm, flags, &liveDef, &persDef) < 0) + return -1; + + if (persDef && + virDomainDeviceValidateAliasImpl(xmlopt, vm->def, dev) < 0) + return -1; + + if (liveDef && + virDomainDeviceValidateAliasImpl(xmlopt, vm->newDef, dev) < 0) + return -1; + + return 0; +} + + static int virDomainDeviceDefValidate(const virDomainDeviceDef *dev, const virDomainDef *def, @@ -5615,7 +5754,9 @@ virDomainDefCheckDuplicateDriveAddresses(const virDomainDef *def) static int -virDomainDefValidateInternal(const virDomainDef *def) +virDomainDefValidateInternal(virDomainXMLOptionPtr xmlopt, + const virDomainDef *def, + unsigned int parseFlags) { if (virDomainDefCheckDuplicateDiskInfo(def) < 0) return -1; @@ -5626,6 +5767,9 @@ virDomainDefValidateInternal(const virDomainDef *def) if (virDomainDefGetVcpusTopology(def, NULL) < 0) return -1; + if (virDomainDefValidateAliases(xmlopt, def, NULL, parseFlags) < 0) + return -1; + if (def->iommu && def->iommu->intremap == VIR_TRISTATE_SWITCH_ON && (def->features[VIR_DOMAIN_FEATURE_IOAPIC] != VIR_TRISTATE_SWITCH_ON || @@ -5690,7 +5834,7 @@ virDomainDefValidate(virDomainDefPtr def, true, &data) < 0) return -1; - if (virDomainDefValidateInternal(def) < 0) + if (virDomainDefValidateInternal(xmlopt, def, parseFlags) < 0) return -1; return 0; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 5ff85057f..2b90e98cb 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2659,6 +2659,11 @@ int virDomainDefPostParse(virDomainDefPtr def, virDomainXMLOptionPtr xmlopt, void *parseOpaque); +int virDomainDeviceValidateAliasForHotplug(virDomainXMLOptionPtr xmlopt, + virDomainObjPtr vm, + const virDomainDeviceDef *dev, + unsigned int flags); + int virDomainDefValidate(virDomainDefPtr def, virCapsPtr caps, unsigned int parseFlags, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3b5df28e5..8449e9685 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -294,6 +294,7 @@ virDomainDeviceFindControllerModel; virDomainDeviceGetInfo; virDomainDeviceInfoIterate; virDomainDeviceTypeToString; +virDomainDeviceValidateAliasForHotplug; virDomainDiskBusTypeToString; virDomainDiskByAddress; virDomainDiskByName; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index fb4d72236..dcd2c2109 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8375,6 +8375,9 @@ qemuDomainAttachDeviceLiveAndConfig(virConnectPtr conn, if (dev == NULL) goto cleanup; + if (virDomainDeviceValidateAliasForHotplug(driver->xmlopt, vm, dev, flags) < 0) + goto cleanup; + if (flags & VIR_DOMAIN_AFFECT_CONFIG && flags & VIR_DOMAIN_AFFECT_LIVE) { /* If we are affecting both CONFIG and LIVE -- 2.13.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list