/** * cpuCompareXML: * * @host: host CPU definition * @xml: XML description of either guest or host CPU to be compared with @host * * Compares the CPU described by @xml with @host CPU. * * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when * the two CPUs are incompatible, VIR_CPU_COMPARE_IDENTICAL when the two CPUs * are identical, VIR_CPU_COMPARE_SUPERSET when the @xml CPU is a superset of * the @host CPU. */ virCPUCompareResult cpuCompareXML(virCPUDefPtr host, const char *xml, bool failIncompatible) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml)); if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) goto cleanup; cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO); if (cpu == NULL) goto cleanup; ret = cpuCompare(host, cpu, failIncompatible); cleanup: virCPUDefFree(cpu); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return ret; }
virCPUCompareResult cpuCompareXML(virCPUDefPtr host, const char *xml) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml)); if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) goto cleanup; cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO); if (cpu == NULL) goto cleanup; if (!cpu->model) { virCPUReportError(VIR_ERR_OPERATION_INVALID, "%s", _("no CPU model specified")); goto cleanup; } ret = cpuCompare(host, cpu); cleanup: virCPUDefFree(cpu); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return ret; }
/** * virCPUCompareXML: * * @arch: CPU architecture * @host: host CPU definition * @xml: XML description of either guest or host CPU to be compared with @host * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE * * Compares the CPU described by @xml with @host CPU. * * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when * the two CPUs are incompatible, VIR_CPU_COMPARE_IDENTICAL when the two CPUs * are identical, VIR_CPU_COMPARE_SUPERSET when the @xml CPU is a superset of * the @host CPU. If @failIncompatible is true, the function will return * VIR_CPU_COMPARE_ERROR (and set VIR_ERR_CPU_INCOMPATIBLE error) when the * two CPUs are incompatible. */ virCPUCompareResult virCPUCompareXML(virArch arch, virCPUDefPtr host, const char *xml, bool failIncompatible) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; VIR_DEBUG("arch=%s, host=%p, xml=%s", virArchToString(arch), host, NULLSTR(xml)); if (!xml) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing CPU definition")); goto cleanup; } if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) goto cleanup; if (virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_AUTO, &cpu) < 0) goto cleanup; ret = virCPUCompare(arch, host, cpu, failIncompatible); cleanup: virCPUDefFree(cpu); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return ret; }
/* * Parses a list of CPU XMLs into a NULL-terminated list of CPU defs. */ virCPUDefPtr * virCPUDefListParse(const char **xmlCPUs, unsigned int ncpus, virCPUType cpuType) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr *cpus = NULL; size_t i; VIR_DEBUG("xmlCPUs=%p, ncpus=%u", xmlCPUs, ncpus); if (xmlCPUs) { for (i = 0; i < ncpus; i++) VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i])); } if (!xmlCPUs && ncpus != 0) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs")); goto error; } if (ncpus == 0) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("no CPUs given")); goto error; } if (VIR_ALLOC_N(cpus, ncpus + 1)) goto error; for (i = 0; i < ncpus; i++) { if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], _("(CPU_definition)"), &ctxt))) goto error; if (virCPUDefParseXML(ctxt, NULL, cpuType, &cpus[i]) < 0) goto error; xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); ctxt = NULL; doc = NULL; } return cpus; error: virCPUDefListFree(cpus); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return NULL; }
static virCPUDefPtr * cpuTestLoadMultiXML(const char *arch, const char *name, unsigned int *count) { char *xml = NULL; xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; xmlNodePtr *nodes = NULL; virCPUDefPtr *cpus = NULL; int n; int i; if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml", abs_srcdir, arch, name) < 0) goto cleanup; if (!(doc = virXMLParseFileCtxt(xml, &ctxt))) goto error; n = virXPathNodeSet("/cpuTest/cpu", ctxt, &nodes); if (n <= 0 || !(cpus = calloc(n, sizeof(virCPUDefPtr)))) goto error; for (i = 0; i < n; i++) { ctxt->node = nodes[i]; cpus[i] = virCPUDefParseXML(nodes[i], ctxt, VIR_CPU_TYPE_HOST); if (!cpus[i]) goto error; } *count = n; cleanup: free(xml); free(nodes); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return cpus; error: if (cpus) { for (i = 0; i < n; i++) virCPUDefFree(cpus[i]); free(cpus); cpus = NULL; } goto cleanup; }
static virCPUDefPtr * cpuTestLoadMultiXML(const char *arch, const char *name, unsigned int *count) { char *xml = NULL; xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; xmlNodePtr *nodes = NULL; virCPUDefPtr *cpus = NULL; int n; size_t i; if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml", abs_srcdir, arch, name) < 0) goto cleanup; if (!(doc = virXMLParseFileCtxt(xml, &ctxt))) goto cleanup; n = virXPathNodeSet("/cpuTest/cpu", ctxt, &nodes); if (n <= 0 || (VIR_ALLOC_N(cpus, n) < 0)) { fprintf(stderr, "\nNo /cpuTest/cpu elements found in %s\n", xml); goto cleanup; } for (i = 0; i < n; i++) { ctxt->node = nodes[i]; cpus[i] = virCPUDefParseXML(nodes[i], ctxt, VIR_CPU_TYPE_HOST); if (!cpus[i]) goto cleanup_cpus; } *count = n; cleanup: VIR_FREE(xml); VIR_FREE(nodes); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return cpus; cleanup_cpus: for (i = 0; i < n; i++) virCPUDefFree(cpus[i]); VIR_FREE(cpus); goto cleanup; }
static virCPUDefPtr cpuTestLoadXML(const char *arch, const char *name) { char *xml = NULL; xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml", abs_srcdir, arch, name) < 0) goto cleanup; if (!(doc = virXMLParseFileCtxt(xml, &ctxt))) goto cleanup; cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO); cleanup: xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); free(xml); return cpu; }
char * cpuBaselineXML(const char **xmlCPUs, unsigned int ncpus, const char **models, unsigned int nmodels) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr *cpus = NULL; virCPUDefPtr cpu = NULL; char *cpustr; unsigned int i; VIR_DEBUG("ncpus=%u, nmodels=%u", ncpus, nmodels); if (xmlCPUs) { for (i = 0; i < ncpus; i++) VIR_DEBUG("xmlCPUs[%u]=%s", i, NULLSTR(xmlCPUs[i])); } if (models) { for (i = 0; i < nmodels; i++) VIR_DEBUG("models[%u]=%s", i, NULLSTR(models[i])); } if (xmlCPUs == NULL && ncpus != 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs")); return NULL; } if (ncpus < 1) { virCPUReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); return NULL; } if (VIR_ALLOC_N(cpus, ncpus)) goto no_memory; for (i = 0; i < ncpus; i++) { if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], _("(CPU_definition)"), &ctxt))) goto error; cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST); if (cpus[i] == NULL) goto error; xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); ctxt = NULL; doc = NULL; } if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels))) goto error; cpustr = virCPUDefFormat(cpu, 0); cleanup: if (cpus) { for (i = 0; i < ncpus; i++) virCPUDefFree(cpus[i]); VIR_FREE(cpus); } virCPUDefFree(cpu); xmlXPathFreeContext(ctxt); xmlFreeDoc(doc); return cpustr; no_memory: virReportOOMError(); error: cpustr = NULL; goto cleanup; }
static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, xmlDocPtr doc, xmlXPathContextPtr ctxt, unsigned int flags) { char uuidstr[VIR_UUID_STRING_BUFLEN]; char *tmp = NULL; xmlNodePtr *nodes = NULL; size_t i; int n; virCapsPtr caps = NULL; if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto error; /* We don't store the uuid, name, hostname, or hostuuid * values. We just compare them to local data to do some * sanity checking on migration operation */ /* Extract domain name */ if (!(tmp = virXPathString("string(./name[1])", ctxt))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing name element in migration data")); goto error; } if (STRNEQ(tmp, mig->name)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Incoming cookie data had unexpected name %s vs %s"), tmp, mig->name); goto error; } VIR_FREE(tmp); /* Extract domain uuid */ tmp = virXPathString("string(./uuid[1])", ctxt); if (!tmp) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing uuid element in migration data")); goto error; } virUUIDFormat(mig->uuid, uuidstr); if (STRNEQ(tmp, uuidstr)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Incoming cookie data had unexpected UUID %s vs %s"), tmp, uuidstr); goto error; } VIR_FREE(tmp); /* Check & forbid "localhost" migration */ if (!(mig->remoteHostname = virXPathString("string(./hostname[1])", ctxt))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing hostname element in migration data")); goto error; } if (STREQ(mig->remoteHostname, mig->localHostname)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempt to migrate guest to the same host %s"), mig->remoteHostname); goto error; } if (!(tmp = virXPathString("string(./hostuuid[1])", ctxt))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing hostuuid element in migration data")); goto error; } if (virUUIDParse(tmp, mig->remoteHostuuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed hostuuid element in migration data")); goto error; } if (memcmp(mig->remoteHostuuid, mig->localHostuuid, VIR_UUID_BUFLEN) == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempt to migrate guest to the same host %s"), tmp); goto error; } VIR_FREE(tmp); /* Check to ensure all mandatory features from XML are also * present in 'flags' */ if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0) goto error; for (i = 0; i < n; i++) { int val; char *str = virXMLPropString(nodes[i], "name"); if (!str) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing feature name")); goto error; } if ((val = qemuMigrationCookieFlagTypeFromString(str)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown migration cookie feature %s"), str); VIR_FREE(str); goto error; } if ((flags & (1 << val)) == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unsupported migration cookie feature %s"), str); VIR_FREE(str); goto error; } VIR_FREE(str); } VIR_FREE(nodes); if ((flags & QEMU_MIGRATION_COOKIE_GRAPHICS) && virXPathBoolean("count(./graphics) > 0", ctxt) && (!(mig->graphics = qemuMigrationCookieGraphicsXMLParse(ctxt)))) goto error; if ((flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) && virXPathBoolean("count(./lockstate) > 0", ctxt)) { mig->lockDriver = virXPathString("string(./lockstate[1]/@driver)", ctxt); if (!mig->lockDriver) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing lock driver name in migration cookie")); goto error; } mig->lockState = virXPathString("string(./lockstate[1]/leases[1])", ctxt); if (mig->lockState && STREQ(mig->lockState, "")) VIR_FREE(mig->lockState); } if ((flags & QEMU_MIGRATION_COOKIE_PERSISTENT) && virXPathBoolean("count(./domain) > 0", ctxt)) { if ((n = virXPathNodeSet("./domain", ctxt, &nodes)) > 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Too many domain elements in " "migration cookie: %d"), n); goto error; } mig->persistent = virDomainDefParseNode(doc, nodes[0], caps, driver->xmlopt, NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE | VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION | VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE); if (!mig->persistent) { /* virDomainDefParseNode already reported * an error for us */ goto error; } VIR_FREE(nodes); } if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) && virXPathBoolean("count(./network) > 0", ctxt) && (!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt)))) goto error; if (flags & QEMU_MIGRATION_COOKIE_NBD && virXPathBoolean("boolean(./nbd)", ctxt) && (!(mig->nbd = qemuMigrationCookieNBDXMLParse(ctxt)))) goto error; if (flags & QEMU_MIGRATION_COOKIE_STATS && virXPathBoolean("boolean(./statistics)", ctxt) && (!(mig->jobInfo = qemuMigrationCookieStatisticsXMLParse(ctxt)))) goto error; if (flags & QEMU_MIGRATION_COOKIE_CPU && virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &mig->cpu) < 0) goto error; if (flags & QEMU_MIGRATION_COOKIE_ALLOW_REBOOT && qemuDomainObjPrivateXMLParseAllowReboot(ctxt, &mig->allowReboot) < 0) goto error; virObjectUnref(caps); return 0; error: VIR_FREE(tmp); VIR_FREE(nodes); virObjectUnref(caps); return -1; }