return NULL;
}
+
static int
-virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
+virDomainFeaturesDefParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt)
{
- /* Look for any hostdev scsi dev */
+ g_autofree xmlNodePtr *nodes = NULL;
+ g_autofree char *tmp = NULL;
+ xmlNodePtr node = NULL;
+ int gic_version;
size_t i;
- int maxController = -1;
- virDomainHostdevDefPtr hostdev;
- int newModel = -1;
+ int n;
- for (i = 0; i < def->nhostdevs; i++) {
- hostdev = def->hostdevs[i];
- if (virHostdevIsSCSIDevice(hostdev) &&
- (int)hostdev->info->addr.drive.controller > maxController) {
- virDomainControllerDefPtr cont;
+ if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
+ goto error;
- maxController = hostdev->info->addr.drive.controller;
- /* We may be creating a new controller because this one is full.
- * So let's grab the model from it and update the model we're
- * going to add as long as this one isn't undefined. The premise
- * being keeping the same controller model for all SCSI hostdevs. */
- cont = virDomainDeviceFindSCSIController(def, &hostdev->info->addr.drive);
- if (cont && cont->model != -1)
- newModel = cont->model;
+ for (i = 0; i < n; i++) {
+ int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
+ if (val < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unexpected feature '%s'"), nodes[i]->name);
+ goto error;
}
- }
- if (maxController == -1)
- return 0;
+ switch ((virDomainFeature) val) {
+ case VIR_DOMAIN_FEATURE_APIC:
+ if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
+ int eoi;
+ if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown value for attribute eoi: '%s'"),
+ tmp);
+ goto error;
+ }
+ def->apic_eoi = eoi;
+ VIR_FREE(tmp);
+ }
+ G_GNUC_FALLTHROUGH;
+ case VIR_DOMAIN_FEATURE_ACPI:
+ case VIR_DOMAIN_FEATURE_PAE:
+ case VIR_DOMAIN_FEATURE_VIRIDIAN:
+ case VIR_DOMAIN_FEATURE_PRIVNET:
+ case VIR_DOMAIN_FEATURE_HYPERV:
+ case VIR_DOMAIN_FEATURE_KVM:
+ case VIR_DOMAIN_FEATURE_MSRS:
+ case VIR_DOMAIN_FEATURE_XEN:
+ def->features[val] = VIR_TRISTATE_SWITCH_ON;
+ break;
- for (i = 0; i <= maxController; i++) {
- if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
- i, newModel) < 0)
- return -1;
- }
+ case VIR_DOMAIN_FEATURE_CAPABILITIES:
+ if ((tmp = virXMLPropString(nodes[i], "policy"))) {
+ if ((def->features[val] = virDomainCapabilitiesPolicyTypeFromString(tmp)) == -1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown policy attribute '%s' of feature '%s'"),
+ tmp, virDomainFeatureTypeToString(val));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
+ }
+ break;
- return 0;
-}
+ case VIR_DOMAIN_FEATURE_VMCOREINFO:
+ case VIR_DOMAIN_FEATURE_HAP:
+ case VIR_DOMAIN_FEATURE_PMU:
+ case VIR_DOMAIN_FEATURE_PVSPINLOCK:
+ case VIR_DOMAIN_FEATURE_VMPORT:
+ case VIR_DOMAIN_FEATURE_SMM:
+ if ((tmp = virXMLPropString(nodes[i], "state"))) {
+ if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown state attribute '%s' of feature '%s'"),
+ tmp, virDomainFeatureTypeToString(val));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->features[val] = VIR_TRISTATE_SWITCH_ON;
+ }
+ break;
-static int
-virDomainLoaderDefParseXML(xmlNodePtr node,
- virDomainLoaderDefPtr loader,
- bool fwAutoSelect)
-{
- g_autofree char *readonly_str = NULL;
- g_autofree char *secure_str = NULL;
- g_autofree char *type_str = NULL;
+ case VIR_DOMAIN_FEATURE_GIC:
+ if ((tmp = virXMLPropString(nodes[i], "version"))) {
+ gic_version = virGICVersionTypeFromString(tmp);
+ if (gic_version < 0 || gic_version == VIR_GIC_VERSION_NONE) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("malformed gic version: %s"), tmp);
+ goto error;
+ }
+ def->gic_version = gic_version;
+ VIR_FREE(tmp);
+ }
+ def->features[val] = VIR_TRISTATE_SWITCH_ON;
+ break;
- secure_str = virXMLPropString(node, "secure");
+ case VIR_DOMAIN_FEATURE_IOAPIC:
+ tmp = virXMLPropString(nodes[i], "driver");
+ if (tmp) {
+ int value = virDomainIOAPICTypeFromString(tmp);
+ if (value < 0 || value == VIR_DOMAIN_IOAPIC_NONE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unknown driver mode: %s"),
+ tmp);
+ goto error;
+ }
+ def->features[val] = value;
+ VIR_FREE(tmp);
+ }
+ break;
- if (!fwAutoSelect) {
- readonly_str = virXMLPropString(node, "readonly");
- type_str = virXMLPropString(node, "type");
- loader->path = (char *) xmlNodeGetContent(node);
- if (STREQ_NULLABLE(loader->path, ""))
- VIR_FREE(loader->path);
- }
+ case VIR_DOMAIN_FEATURE_HPT:
+ tmp = virXMLPropString(nodes[i], "resizing");
+ if (tmp) {
+ int value = virDomainHPTResizingTypeFromString(tmp);
+ if (value < 0 || value == VIR_DOMAIN_HPT_RESIZING_NONE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unknown HPT resizing setting: %s"),
+ tmp);
+ goto error;
+ }
+ def->hpt_resizing = (virDomainHPTResizing) value;
+ VIR_FREE(tmp);
+ }
- if (readonly_str &&
- (loader->readonly = virTristateBoolTypeFromString(readonly_str)) <= 0) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("unknown readonly value: %s"), readonly_str);
- return -1;
- }
+ if (virDomainParseScaledValue("./features/hpt/maxpagesize",
+ NULL,
+ ctxt,
+ &def->hpt_maxpagesize,
+ 1024,
+ ULLONG_MAX,
+ false) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s",
+ _("Unable to parse HPT maxpagesize setting"));
+ goto error;
+ }
+ def->hpt_maxpagesize = VIR_DIV_UP(def->hpt_maxpagesize, 1024);
- if (secure_str &&
- (loader->secure = virTristateBoolTypeFromString(secure_str)) <= 0) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("unknown secure value: %s"), secure_str);
- return -1;
+ if (def->hpt_resizing != VIR_DOMAIN_HPT_RESIZING_NONE ||
+ def->hpt_maxpagesize > 0) {
+ def->features[val] = VIR_TRISTATE_SWITCH_ON;
+ }
+ break;
+
+ case VIR_DOMAIN_FEATURE_HTM:
+ case VIR_DOMAIN_FEATURE_NESTED_HV:
+ case VIR_DOMAIN_FEATURE_CCF_ASSIST:
+ if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("missing state attribute '%s' of feature '%s'"),
+ tmp, virDomainFeatureTypeToString(val));
+ goto error;
+ }
+ if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown state attribute '%s' of feature '%s'"),
+ tmp, virDomainFeatureTypeToString(val));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ break;
+
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_FEATURE_LAST:
+ break;
+ }
}
+ VIR_FREE(nodes);
+
+ if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
+ int feature;
+ int value;
+ node = ctxt->node;
+ if ((n = virXPathNodeSet("./features/hyperv/*", ctxt, &nodes)) < 0)
+ goto error;
+
+ for (i = 0; i < n; i++) {
+ feature = virDomainHypervTypeFromString((const char *)nodes[i]->name);
+ if (feature < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported HyperV Enlightenment feature: %s"),
+ nodes[i]->name);
+ goto error;
+ }
+
+ ctxt->node = nodes[i];
+
+ if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'state' attribute for "
+ "HyperV Enlightenment feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+
+ if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value of state argument "
+ "for HyperV Enlightenment feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+
+ VIR_FREE(tmp);
+ def->hyperv_features[feature] = value;
+
+ switch ((virDomainHyperv) feature) {
+ case VIR_DOMAIN_HYPERV_RELAXED:
+ case VIR_DOMAIN_HYPERV_VAPIC:
+ case VIR_DOMAIN_HYPERV_VPINDEX:
+ case VIR_DOMAIN_HYPERV_RUNTIME:
+ case VIR_DOMAIN_HYPERV_SYNIC:
+ case VIR_DOMAIN_HYPERV_STIMER:
+ case VIR_DOMAIN_HYPERV_RESET:
+ case VIR_DOMAIN_HYPERV_FREQUENCIES:
+ case VIR_DOMAIN_HYPERV_REENLIGHTENMENT:
+ case VIR_DOMAIN_HYPERV_TLBFLUSH:
+ case VIR_DOMAIN_HYPERV_IPI:
+ case VIR_DOMAIN_HYPERV_EVMCS:
+ break;
+
+ case VIR_DOMAIN_HYPERV_SPINLOCKS:
+ if (value != VIR_TRISTATE_SWITCH_ON)
+ break;
+
+ if (virXPathUInt("string(./@retries)", ctxt,
+ &def->hyperv_spinlocks) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid HyperV spinlock retry count"));
+ goto error;
+ }
+
+ if (def->hyperv_spinlocks < 0xFFF) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("HyperV spinlock retry count must be "
+ "at least 4095"));
+ goto error;
+ }
+ break;
+
+ case VIR_DOMAIN_HYPERV_VENDOR_ID:
+ if (value != VIR_TRISTATE_SWITCH_ON)
+ break;
+
+ if (!(def->hyperv_vendor_id = virXMLPropString(nodes[i],
+ "value"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing 'value' attribute for "
+ "HyperV feature 'vendor_id'"));
+ goto error;
+ }
+
+ if (strlen(def->hyperv_vendor_id) > VIR_DOMAIN_HYPERV_VENDOR_ID_MAX) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("HyperV vendor_id value must not be more "
+ "than %d characters."),
+ VIR_DOMAIN_HYPERV_VENDOR_ID_MAX);
+ goto error;
+ }
- if (type_str) {
- int type;
- if ((type = virDomainLoaderTypeFromString(type_str)) <= 0) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("unknown type value: %s"), type_str);
- return -1;
+ /* ensure that the string can be passed to qemu */
+ if (strchr(def->hyperv_vendor_id, ',')) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("HyperV vendor_id value is invalid"));
+ goto error;
+ }
+
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_HYPERV_LAST:
+ break;
+ }
}
- loader->type = type;
+ VIR_FREE(nodes);
+ ctxt->node = node;
}
- return 0;
-}
+ if (def->features[VIR_DOMAIN_HYPERV_STIMER] == VIR_TRISTATE_SWITCH_ON) {
+ int value;
+ if ((n = virXPathNodeSet("./features/hyperv/stimer/*", ctxt, &nodes)) < 0)
+ goto error;
+ for (i = 0; i < n; i++) {
+ if (STRNEQ((const char *)nodes[i]->name, "direct")) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported Hyper-V stimer feature: %s"),
+ nodes[i]->name);
+ goto error;
+ }
-static int
-virDomainSchedulerParseCommonAttrs(xmlNodePtr node,
- virProcessSchedPolicy *policy,
- int *priority)
-{
- int pol = 0;
- g_autofree char *tmp = NULL;
+ if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'state' attribute for "
+ "Hyper-V stimer '%s' feature"), "direct");
+ goto error;
+ }
- if (!(tmp = virXMLPropString(node, "scheduler"))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Missing scheduler attribute"));
- return -1;
- }
+ if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value of state argument "
+ "for Hyper-V stimer '%s' feature"), "direct");
+ goto error;
+ }
- if ((pol = virProcessSchedPolicyTypeFromString(tmp)) <= 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Invalid scheduler attribute: '%s'"), tmp);
- return -1;
+ VIR_FREE(tmp);
+ def->hyperv_stimer_direct = value;
+ }
+ VIR_FREE(nodes);
}
- *policy = pol;
- VIR_FREE(tmp);
+ if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
+ int feature;
+ int value;
+ if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0)
+ goto error;
- if (pol == VIR_PROC_POLICY_FIFO ||
- pol == VIR_PROC_POLICY_RR) {
- if (!(tmp = virXMLPropString(node, "priority"))) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing scheduler priority"));
- return -1;
- }
+ for (i = 0; i < n; i++) {
+ feature = virDomainKVMTypeFromString((const char *)nodes[i]->name);
+ if (feature < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported KVM feature: %s"),
+ nodes[i]->name);
+ goto error;
+ }
- if (virStrToLong_i(tmp, NULL, 10, priority) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Invalid value for element priority"));
- return -1;
+ switch ((virDomainKVM) feature) {
+ case VIR_DOMAIN_KVM_HIDDEN:
+ case VIR_DOMAIN_KVM_DEDICATED:
+ if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'state' attribute for "
+ "KVM feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+
+ if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value of state argument "
+ "for KVM feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+
+ VIR_FREE(tmp);
+ def->kvm_features[feature] = value;
+ break;
+
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_KVM_LAST:
+ break;
+ }
}
+ VIR_FREE(nodes);
}
- return 0;
-}
-
+ if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
+ int feature;
+ int value;
+ g_autofree char *ptval = NULL;
-static int
-virDomainEmulatorSchedParse(xmlNodePtr node,
- virDomainDefPtr def)
-{
- g_autofree virDomainThreadSchedParamPtr sched = NULL;
+ if ((n = virXPathNodeSet("./features/xen/*", ctxt, &nodes)) < 0)
+ goto error;
- if (VIR_ALLOC(sched) < 0)
- return -1;
+ for (i = 0; i < n; i++) {
+ feature = virDomainXenTypeFromString((const char *)nodes[i]->name);
+ if (feature < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported Xen feature: %s"),
+ nodes[i]->name);
+ goto error;
+ }
- if (virDomainSchedulerParseCommonAttrs(node,
- &sched->policy,
- &sched->priority) < 0)
- return -1;
+ if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'state' attribute for "
+ "Xen feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
- def->cputune.emulatorsched = g_steal_pointer(&sched);
- return 0;
-}
+ if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid value of state argument "
+ "for Xen feature '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ def->xen_features[feature] = value;
-static virBitmapPtr
-virDomainSchedulerParse(xmlNodePtr node,
- const char *name,
- virProcessSchedPolicy *policy,
- int *priority)
-{
- virBitmapPtr ret = NULL;
- g_autofree char *tmp = NULL;
+ switch ((virDomainXen) feature) {
+ case VIR_DOMAIN_XEN_E820_HOST:
+ break;
- if (!(tmp = virXMLPropString(node, name))) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Missing attribute '%s' in element '%sched'"),
- name, name);
- goto error;
- }
+ case VIR_DOMAIN_XEN_PASSTHROUGH:
+ if (value != VIR_TRISTATE_SWITCH_ON)
+ break;
- if (virBitmapParse(tmp, &ret, VIR_DOMAIN_CPUMASK_LEN) < 0)
- goto error;
+ if ((ptval = virXMLPropString(nodes[i], "mode"))) {
+ int mode = virDomainXenPassthroughModeTypeFromString(ptval);
- if (virBitmapIsAllClear(ret)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("'%s' scheduler bitmap '%s' is empty"),
- name, tmp);
- goto error;
- }
+ if (mode < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported mode '%s' for Xen passthrough feature"),
+ ptval);
+ goto error;
+ }
- if (virDomainSchedulerParseCommonAttrs(node, policy, priority) < 0)
- goto error;
+ if (mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT &&
+ mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("'mode' attribute for Xen feature "
+ "'passthrough' must be 'sync_pt' or 'share_pt'"));
+ goto error;
+ }
+ def->xen_passthrough_mode = mode;
+ }
+ break;
- return ret;
+ /* coverity[dead_error_begin] */
+ case VIR_DOMAIN_XEN_LAST:
+ break;
+ }
+ }
+ VIR_FREE(nodes);
+ }
- error:
- virBitmapFree(ret);
- return NULL;
-}
+ if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
+ int rv = virDomainParseScaledValue("string(./features/smm/tseg)",
+ "string(./features/smm/tseg/@unit)",
+ ctxt,
+ &def->tseg_size,
+ 1024 * 1024, /* Defaults to mebibytes */
+ ULLONG_MAX,
+ false);
+ if (rv < 0)
+ goto error;
+ def->tseg_specified = rv;
+ }
+ if (def->features[VIR_DOMAIN_FEATURE_MSRS] == VIR_TRISTATE_SWITCH_ON) {
+ if ((node = virXPathNode("./features/msrs", ctxt)) == NULL)
+ goto error;
-static int
-virDomainThreadSchedParseHelper(xmlNodePtr node,
- const char *name,
- virDomainThreadSchedParamPtr (*func)(virDomainDefPtr, unsigned int),
- virDomainDefPtr def)
-{
- ssize_t next = -1;
- virDomainThreadSchedParamPtr sched = NULL;
- virProcessSchedPolicy policy = 0;
- int priority = 0;
- g_autoptr(virBitmap) map = NULL;
+ if (!(tmp = virXMLPropString(node, "unknown"))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("missing 'unknown' attribute for feature '%s'"),
+ virDomainFeatureTypeToString(VIR_DOMAIN_FEATURE_MSRS));
+ goto error;
+ }
- if (!(map = virDomainSchedulerParse(node, name, &policy, &priority)))
- return -1;
+ if ((def->msrs_features[VIR_DOMAIN_MSRS_UNKNOWN] = virDomainMsrsUnknownTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown 'unknown' value '%s'"),
+ tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ }
- while ((next = virBitmapNextSetBit(map, next)) > -1) {
- if (!(sched = func(def, next)))
- return -1;
+ if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
+ goto error;
- if (sched->policy != VIR_PROC_POLICY_NONE) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("%ssched attributes 'vcpus' must not overlap"),
- name);
- return -1;
+ for (i = 0; i < n; i++) {
+ int val = virDomainProcessCapsFeatureTypeFromString((const char *)nodes[i]->name);
+ if (val < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unexpected capability feature '%s'"), nodes[i]->name);
+ goto error;
}
- sched->policy = policy;
- sched->priority = priority;
+ if ((tmp = virXMLPropString(nodes[i], "state"))) {
+ if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown state attribute '%s' of feature capability '%s'"),
+ tmp, virDomainProcessCapsFeatureTypeToString(val));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
+ }
}
-
+ VIR_FREE(nodes);
return 0;
+
+ error:
+ return -1;
}
static int
-virDomainVcpuThreadSchedParse(xmlNodePtr node,
- virDomainDefPtr def)
+virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
{
- return virDomainThreadSchedParseHelper(node, "vcpus",
- virDomainDefGetVcpuSched,
- def);
-}
-
+ /* Look for any hostdev scsi dev */
+ size_t i;
+ int maxController = -1;
+ virDomainHostdevDefPtr hostdev;
+ int newModel = -1;
-static virDomainThreadSchedParamPtr
-virDomainDefGetIOThreadSched(virDomainDefPtr def,
- unsigned int iothread)
-{
- virDomainIOThreadIDDefPtr iothrinfo;
+ for (i = 0; i < def->nhostdevs; i++) {
+ hostdev = def->hostdevs[i];
+ if (virHostdevIsSCSIDevice(hostdev) &&
+ (int)hostdev->info->addr.drive.controller > maxController) {
+ virDomainControllerDefPtr cont;
- if (!(iothrinfo = virDomainIOThreadIDFind(def, iothread))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Cannot find 'iothread' : %u"),
- iothread);
- return NULL;
+ maxController = hostdev->info->addr.drive.controller;
+ /* We may be creating a new controller because this one is full.
+ * So let's grab the model from it and update the model we're
+ * going to add as long as this one isn't undefined. The premise
+ * being keeping the same controller model for all SCSI hostdevs. */
+ cont = virDomainDeviceFindSCSIController(def, &hostdev->info->addr.drive);
+ if (cont && cont->model != -1)
+ newModel = cont->model;
+ }
}
- return &iothrinfo->sched;
-}
+ if (maxController == -1)
+ return 0;
+ for (i = 0; i <= maxController; i++) {
+ if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
+ i, newModel) < 0)
+ return -1;
+ }
-static int
-virDomainIOThreadSchedParse(xmlNodePtr node,
- virDomainDefPtr def)
-{
- return virDomainThreadSchedParseHelper(node, "iothreads",
- virDomainDefGetIOThreadSched,
- def);
+ return 0;
}
-
static int
-virDomainVcpuParse(virDomainDefPtr def,
- xmlXPathContextPtr ctxt,
- virDomainXMLOptionPtr xmlopt)
+virDomainLoaderDefParseXML(xmlNodePtr node,
+ virDomainLoaderDefPtr loader,
+ bool fwAutoSelect)
{
- int n;
- xmlNodePtr vcpuNode;
- size_t i;
- unsigned int maxvcpus;
- unsigned int vcpus;
- g_autofree char *tmp = NULL;
- g_autofree xmlNodePtr *nodes = NULL;
-
- vcpus = maxvcpus = 1;
-
- if ((vcpuNode = virXPathNode("./vcpu[1]", ctxt))) {
- if ((tmp = virXMLNodeContentString(vcpuNode))) {
- if (virStrToLong_ui(tmp, NULL, 10, &maxvcpus) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("maximum vcpus count must be an integer"));
- return -1;
- }
- VIR_FREE(tmp);
- }
-
- if ((tmp = virXMLPropString(vcpuNode, "current"))) {
- if (virStrToLong_ui(tmp, NULL, 10, &vcpus) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("current vcpus count must be an integer"));
- return -1;
- }
- VIR_FREE(tmp);
- } else {
- vcpus = maxvcpus;
- }
-
- tmp = virXMLPropString(vcpuNode, "placement");
- if (tmp) {
- if ((def->placement_mode =
- virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported CPU placement mode '%s'"),
- tmp);
- return -1;
- }
- VIR_FREE(tmp);
- } else {
- def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
- }
-
- if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
- tmp = virXMLPropString(vcpuNode, "cpuset");
- if (tmp) {
- if (virBitmapParse(tmp, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
- return -1;
+ g_autofree char *readonly_str = NULL;
+ g_autofree char *secure_str = NULL;
+ g_autofree char *type_str = NULL;
- if (virBitmapIsAllClear(def->cpumask)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Invalid value of 'cpuset': %s"), tmp);
- return -1;
- }
+ secure_str = virXMLPropString(node, "secure");
- VIR_FREE(tmp);
- }
- }
+ if (!fwAutoSelect) {
+ readonly_str = virXMLPropString(node, "readonly");
+ type_str = virXMLPropString(node, "type");
+ loader->path = (char *) xmlNodeGetContent(node);
+ if (STREQ_NULLABLE(loader->path, ""))
+ VIR_FREE(loader->path);
}
- if (virDomainDefSetVcpusMax(def, maxvcpus, xmlopt) < 0)
+ if (readonly_str &&
+ (loader->readonly = virTristateBoolTypeFromString(readonly_str)) <= 0) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("unknown readonly value: %s"), readonly_str);
return -1;
+ }
- if ((n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes)) < 0)
+ if (secure_str &&
+ (loader->secure = virTristateBoolTypeFromString(secure_str)) <= 0) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("unknown secure value: %s"), secure_str);
return -1;
+ }
- if (n) {
- /* if individual vcpu states are provided take them as master */
- def->individualvcpus = true;
-
- for (i = 0; i < n; i++) {
- virDomainVcpuDefPtr vcpu;
- int state;
- unsigned int id;
- unsigned int order;
-
- if (!(tmp = virXMLPropString(nodes[i], "id")) ||
- virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing or invalid vcpu id"));
- return -1;
- }
-
- VIR_FREE(tmp);
-
- if (id >= def->maxvcpus) {
- virReportError(VIR_ERR_XML_ERROR,
- _("vcpu id '%u' is out of range of maximum "
- "vcpu count"), id);
- return -1;
- }
-
- vcpu = virDomainDefGetVcpu(def, id);
-
- if (!(tmp = virXMLPropString(nodes[i], "enabled"))) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing vcpu enabled state"));
- return -1;
- }
-
- if ((state = virTristateBoolTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("invalid vcpu 'enabled' value '%s'"), tmp);
- return -1;
- }
- VIR_FREE(tmp);
-
- vcpu->online = state == VIR_TRISTATE_BOOL_YES;
-
- if ((tmp = virXMLPropString(nodes[i], "hotpluggable"))) {
- int hotpluggable;
- if ((hotpluggable = virTristateBoolTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("invalid vcpu 'hotpluggable' value '%s'"), tmp);
- return -1;
- }
- vcpu->hotpluggable = hotpluggable;
- VIR_FREE(tmp);
- }
-
- if ((tmp = virXMLPropString(nodes[i], "order"))) {
- if (virStrToLong_uip(tmp, NULL, 10, &order) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid vcpu order"));
- return -1;
- }
- vcpu->order = order;
- VIR_FREE(tmp);
- }
- }
- } else {
- if (virDomainDefSetVcpus(def, vcpus) < 0)
+ if (type_str) {
+ int type;
+ if ((type = virDomainLoaderTypeFromString(type_str)) <= 0) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("unknown type value: %s"), type_str);
return -1;
+ }
+ loader->type = type;
}
return 0;
static int
-virDomainDefParseBootOptions(virDomainDefPtr def,
- xmlXPathContextPtr ctxt)
+virDomainSchedulerParseCommonAttrs(xmlNodePtr node,
+ virProcessSchedPolicy *policy,
+ int *priority)
{
- char *name = NULL;
- size_t i;
- int n;
- g_autofree xmlNodePtr *nodes = NULL;
+ int pol = 0;
g_autofree char *tmp = NULL;
- /*
- * Booting options for different OS types....
- *
- * - A bootloader (and optional kernel+initrd) (xen)
- * - A kernel + initrd (xen)
- * - A boot device (and optional kernel+initrd) (hvm)
- * - An init script (exe)
- */
+ if (!(tmp = virXMLPropString(node, "scheduler"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing scheduler attribute"));
+ return -1;
+ }
- if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
- def->os.init = virXPathString("string(./os/init[1])", ctxt);
- def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
- def->os.initdir = virXPathString("string(./os/initdir[1])", ctxt);
- def->os.inituser = virXPathString("string(./os/inituser[1])", ctxt);
- def->os.initgroup = virXPathString("string(./os/initgroup[1])", ctxt);
+ if ((pol = virProcessSchedPolicyTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid scheduler attribute: '%s'"), tmp);
+ return -1;
+ }
+ *policy = pol;
- if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0)
- return -1;
+ VIR_FREE(tmp);
- if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
+ if (pol == VIR_PROC_POLICY_FIFO ||
+ pol == VIR_PROC_POLICY_RR) {
+ if (!(tmp = virXMLPropString(node, "priority"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing scheduler priority"));
return -1;
- for (i = 0; i < n; i++) {
- if (!nodes[i]->children ||
- !nodes[i]->children->content) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("No data supplied for <initarg> element"));
- return -1;
- }
- def->os.initargv[i] = g_strdup((const char *)nodes[i]->children->content);
}
- def->os.initargv[n] = NULL;
- VIR_FREE(nodes);
- if ((n = virXPathNodeSet("./os/initenv", ctxt, &nodes)) < 0)
+ if (virStrToLong_i(tmp, NULL, 10, priority) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Invalid value for element priority"));
return -1;
+ }
+ }
- if (VIR_ALLOC_N(def->os.initenv, n+1) < 0)
- return -1;
- for (i = 0; i < n; i++) {
- if (!(name = virXMLPropString(nodes[i], "name"))) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("No name supplied for <initenv> element"));
- return -1;
- }
+ return 0;
+}
- if (!nodes[i]->children ||
- !nodes[i]->children->content) {
- virReportError(VIR_ERR_XML_ERROR,
- _("No value supplied for <initenv name='%s'> element"),
- name);
- return -1;
- }
- if (VIR_ALLOC(def->os.initenv[i]) < 0)
- return -1;
+static int
+virDomainEmulatorSchedParse(xmlNodePtr node,
+ virDomainDefPtr def)
+{
+ g_autofree virDomainThreadSchedParamPtr sched = NULL;
- def->os.initenv[i]->name = name;
- def->os.initenv[i]->value = g_strdup((const char *)nodes[i]->children->content);
- }
- def->os.initenv[n] = NULL;
- VIR_FREE(nodes);
- }
+ if (VIR_ALLOC(sched) < 0)
+ return -1;
- if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
- def->os.type == VIR_DOMAIN_OSTYPE_XENPVH ||
- def->os.type == VIR_DOMAIN_OSTYPE_HVM ||
- def->os.type == VIR_DOMAIN_OSTYPE_UML) {
- g_autofree char *firmware = NULL;
- xmlNodePtr loader_node;
+ if (virDomainSchedulerParseCommonAttrs(node,
+ &sched->policy,
+ &sched->priority) < 0)
+ return -1;
- def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt);
- def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt);
- def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
- def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
- def->os.root = virXPathString("string(./os/root[1])", ctxt);
+ def->cputune.emulatorsched = g_steal_pointer(&sched);
+ return 0;
+}
- if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
- (firmware = virXPathString("string(./os/@firmware)", ctxt))) {
- int fw = virDomainOsDefFirmwareTypeFromString(firmware);
- if (fw <= 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("unknown firmware value %s"),
- firmware);
- return -1;
- }
+static virBitmapPtr
+virDomainSchedulerParse(xmlNodePtr node,
+ const char *name,
+ virProcessSchedPolicy *policy,
+ int *priority)
+{
+ virBitmapPtr ret = NULL;
+ g_autofree char *tmp = NULL;
- def->os.firmware = fw;
- }
+ if (!(tmp = virXMLPropString(node, name))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Missing attribute '%s' in element '%sched'"),
+ name, name);
+ goto error;
+ }
- if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) {
- const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
+ if (virBitmapParse(tmp, &ret, VIR_DOMAIN_CPUMASK_LEN) < 0)
+ goto error;
- if (VIR_ALLOC(def->os.loader) < 0)
- return -1;
+ if (virBitmapIsAllClear(ret)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("'%s' scheduler bitmap '%s' is empty"),
+ name, tmp);
+ goto error;
+ }
- if (virDomainLoaderDefParseXML(loader_node,
- def->os.loader,
- fwAutoSelect) < 0)
- return -1;
+ if (virDomainSchedulerParseCommonAttrs(node, policy, priority) < 0)
+ goto error;
- def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
- if (!fwAutoSelect)
- def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
- }
- }
+ return ret;
- if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
- if ((n = virXPathNodeSet("./os/acpi/table", ctxt, &nodes)) < 0)
- return -1;
+ error:
+ virBitmapFree(ret);
+ return NULL;
+}
- if (n > 1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Only one acpi table is supported"));
- return -1;
- }
- if (n == 1) {
- tmp = virXMLPropString(nodes[0], "type");
+static int
+virDomainThreadSchedParseHelper(xmlNodePtr node,
+ const char *name,
+ virDomainThreadSchedParamPtr (*func)(virDomainDefPtr, unsigned int),
+ virDomainDefPtr def)
+{
+ ssize_t next = -1;
+ virDomainThreadSchedParamPtr sched = NULL;
+ virProcessSchedPolicy policy = 0;
+ int priority = 0;
+ g_autoptr(virBitmap) map = NULL;
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing acpi table type"));
- return -1;
- }
+ if (!(map = virDomainSchedulerParse(node, name, &policy, &priority)))
+ return -1;
- if (STREQ_NULLABLE(tmp, "slic")) {
- VIR_FREE(tmp);
- tmp = virXMLNodeContentString(nodes[0]);
- def->os.slic_table = virFileSanitizePath(tmp);
- } else {
- virReportError(VIR_ERR_XML_ERROR,
- _("Unknown acpi table type: %s"),
- tmp);
- return -1;
- }
- }
+ while ((next = virBitmapNextSetBit(map, next)) > -1) {
+ if (!(sched = func(def, next)))
+ return -1;
- if (virDomainDefParseBootXML(ctxt, def) < 0)
+ if (sched->policy != VIR_PROC_POLICY_NONE) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("%ssched attributes 'vcpus' must not overlap"),
+ name);
return -1;
+ }
+
+ sched->policy = policy;
+ sched->priority = priority;
}
return 0;
static int
-virDomainResctrlParseVcpus(virDomainDefPtr def,
- xmlNodePtr node,
- virBitmapPtr *vcpus)
+virDomainVcpuThreadSchedParse(xmlNodePtr node,
+ virDomainDefPtr def)
{
- g_autofree char *vcpus_str = NULL;
+ return virDomainThreadSchedParseHelper(node, "vcpus",
+ virDomainDefGetVcpuSched,
+ def);
+}
- vcpus_str = virXMLPropString(node, "vcpus");
- if (!vcpus_str) {
- virReportError(VIR_ERR_XML_ERROR, _("Missing %s attribute 'vcpus'"),
- node->name);
- return -1;
- }
- if (virBitmapParse(vcpus_str, vcpus, VIR_DOMAIN_CPUMASK_LEN) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid %s attribute 'vcpus' value '%s'"),
- node->name, vcpus_str);
- return -1;
- }
- /* We need to limit the bitmap to number of vCPUs. If there's nothing left,
- * then we can just clean up and return 0 immediately */
- virBitmapShrink(*vcpus, def->maxvcpus);
+static virDomainThreadSchedParamPtr
+virDomainDefGetIOThreadSched(virDomainDefPtr def,
+ unsigned int iothread)
+{
+ virDomainIOThreadIDDefPtr iothrinfo;
- return 0;
+ if (!(iothrinfo = virDomainIOThreadIDFind(def, iothread))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Cannot find 'iothread' : %u"),
+ iothread);
+ return NULL;
+ }
+
+ return &iothrinfo->sched;
}
static int
-virDomainResctrlVcpuMatch(virDomainDefPtr def,
- virBitmapPtr vcpus,
- virDomainResctrlDefPtr *resctrl)
+virDomainIOThreadSchedParse(xmlNodePtr node,
+ virDomainDefPtr def)
{
- ssize_t i = 0;
-
- for (i = 0; i < def->nresctrls; i++) {
- /* vcpus group has been created, directly use the existing one.
- * Just updating memory allocation information of that group
- */
- if (virBitmapEqual(def->resctrls[i]->vcpus, vcpus)) {
- *resctrl = def->resctrls[i];
- break;
- }
- if (virBitmapOverlaps(def->resctrls[i]->vcpus, vcpus)) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Overlapping vcpus in resctrls"));
- return -1;
- }
- }
- return 0;
+ return virDomainThreadSchedParseHelper(node, "iothreads",
+ virDomainDefGetIOThreadSched,
+ def);
}
static int
-virDomainCachetuneDefParseCache(xmlXPathContextPtr ctxt,
- xmlNodePtr node,
- virResctrlAllocPtr alloc)
+virDomainVcpuParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOptionPtr xmlopt)
{
- VIR_XPATH_NODE_AUTORESTORE(ctxt);
- unsigned int level;
- unsigned int cache;
- int type;
- unsigned long long size;
+ int n;
+ xmlNodePtr vcpuNode;
+ size_t i;
+ unsigned int maxvcpus;
+ unsigned int vcpus;
g_autofree char *tmp = NULL;
+ g_autofree xmlNodePtr *nodes = NULL;
- ctxt->node = node;
+ vcpus = maxvcpus = 1;
- tmp = virXMLPropString(node, "id");
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing cachetune attribute 'id'"));
- return -1;
- }
- if (virStrToLong_uip(tmp, NULL, 10, &cache) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid cachetune attribute 'id' value '%s'"),
- tmp);
- return -1;
- }
- VIR_FREE(tmp);
+ if ((vcpuNode = virXPathNode("./vcpu[1]", ctxt))) {
+ if ((tmp = virXMLNodeContentString(vcpuNode))) {
+ if (virStrToLong_ui(tmp, NULL, 10, &maxvcpus) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("maximum vcpus count must be an integer"));
+ return -1;
+ }
+ VIR_FREE(tmp);
+ }
- tmp = virXMLPropString(node, "level");
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing cachetune attribute 'level'"));
- return -1;
- }
- if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid cachetune attribute 'level' value '%s'"),
- tmp);
- return -1;
- }
- VIR_FREE(tmp);
+ if ((tmp = virXMLPropString(vcpuNode, "current"))) {
+ if (virStrToLong_ui(tmp, NULL, 10, &vcpus) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("current vcpus count must be an integer"));
+ return -1;
+ }
+ VIR_FREE(tmp);
+ } else {
+ vcpus = maxvcpus;
+ }
- tmp = virXMLPropString(node, "type");
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing cachetune attribute 'type'"));
- return -1;
- }
- type = virCacheTypeFromString(tmp);
- if (type < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid cachetune attribute 'type' value '%s'"),
- tmp);
- return -1;
+ tmp = virXMLPropString(vcpuNode, "placement");
+ if (tmp) {
+ if ((def->placement_mode =
+ virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported CPU placement mode '%s'"),
+ tmp);
+ return -1;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
+ }
+
+ if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
+ tmp = virXMLPropString(vcpuNode, "cpuset");
+ if (tmp) {
+ if (virBitmapParse(tmp, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
+ return -1;
+
+ if (virBitmapIsAllClear(def->cpumask)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid value of 'cpuset': %s"), tmp);
+ return -1;
+ }
+
+ VIR_FREE(tmp);
+ }
+ }
}
- if (virDomainParseScaledValue("./@size", "./@unit",
- ctxt, &size, 1024,
- ULLONG_MAX, true) < 0)
+ if (virDomainDefSetVcpusMax(def, maxvcpus, xmlopt) < 0)
return -1;
- if (virResctrlAllocSetCacheSize(alloc, level, type, cache, size) < 0)
+ if ((n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes)) < 0)
return -1;
- return 0;
-}
+ if (n) {
+ /* if individual vcpu states are provided take them as master */
+ def->individualvcpus = true;
+ for (i = 0; i < n; i++) {
+ virDomainVcpuDefPtr vcpu;
+ int state;
+ unsigned int id;
+ unsigned int order;
-/* Checking if the monitor's vcpus and tag is conflicted with existing
- * allocation and monitors.
- *
- * Returns 1 if @monitor->vcpus equals to @resctrl->vcpus, then the monitor
- * will share the underlying resctrl group with @resctrl->alloc. Returns -1
- * if any conflict found. Returns 0 if no conflict and @monitor->vcpus is
- * not equal to @resctrl->vcpus.
- */
-static int
-virDomainResctrlValidateMonitor(virDomainResctrlDefPtr resctrl,
- virDomainResctrlMonDefPtr monitor)
-{
- size_t i = 0;
- int vcpu = -1;
- bool vcpus_overlap_any = false;
- bool vcpus_equal_to_resctrl = false;
- bool vcpus_overlap_no_resctrl = false;
- bool default_alloc_monitor = virResctrlAllocIsEmpty(resctrl->alloc);
+ if (!(tmp = virXMLPropString(nodes[i], "id")) ||
+ virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing or invalid vcpu id"));
+ return -1;
+ }
- if (virBitmapIsAllClear(monitor->vcpus)) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("vcpus is empty"));
- return -1;
- }
+ VIR_FREE(tmp);
- while ((vcpu = virBitmapNextSetBit(monitor->vcpus, vcpu)) >= 0) {
- if (!virBitmapIsBitSet(resctrl->vcpus, vcpu)) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("Monitor vcpus conflicts with allocation"));
- return -1;
- }
- }
+ if (id >= def->maxvcpus) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("vcpu id '%u' is out of range of maximum "
+ "vcpu count"), id);
+ return -1;
+ }
- vcpus_equal_to_resctrl = virBitmapEqual(monitor->vcpus, resctrl->vcpus);
+ vcpu = virDomainDefGetVcpu(def, id);
- for (i = 0; i < resctrl->nmonitors; i++) {
- if (virBitmapEqual(monitor->vcpus, resctrl->monitors[i]->vcpus)) {
- if (monitor->tag != resctrl->monitors[i]->tag) {
- continue;
- } else {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("Identical vcpus found in same type monitors"));
+ if (!(tmp = virXMLPropString(nodes[i], "enabled"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing vcpu enabled state"));
return -1;
}
- }
- if (virBitmapOverlaps(monitor->vcpus, resctrl->monitors[i]->vcpus))
- vcpus_overlap_any = true;
+ if ((state = virTristateBoolTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid vcpu 'enabled' value '%s'"), tmp);
+ return -1;
+ }
+ VIR_FREE(tmp);
- if (vcpus_equal_to_resctrl ||
- virBitmapEqual(resctrl->monitors[i]->vcpus, resctrl->vcpus))
- continue;
+ vcpu->online = state == VIR_TRISTATE_BOOL_YES;
- if (virBitmapOverlaps(monitor->vcpus, resctrl->monitors[i]->vcpus))
- vcpus_overlap_no_resctrl = true;
- }
+ if ((tmp = virXMLPropString(nodes[i], "hotpluggable"))) {
+ int hotpluggable;
+ if ((hotpluggable = virTristateBoolTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid vcpu 'hotpluggable' value '%s'"), tmp);
+ return -1;
+ }
+ vcpu->hotpluggable = hotpluggable;
+ VIR_FREE(tmp);
+ }
- if (vcpus_overlap_no_resctrl ||
- (default_alloc_monitor && vcpus_overlap_any)) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("vcpus overlaps in resctrl groups"));
- return -1;
+ if ((tmp = virXMLPropString(nodes[i], "order"))) {
+ if (virStrToLong_uip(tmp, NULL, 10, &order) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid vcpu order"));
+ return -1;
+ }
+ vcpu->order = order;
+ VIR_FREE(tmp);
+ }
+ }
+ } else {
+ if (virDomainDefSetVcpus(def, vcpus) < 0)
+ return -1;
}
- if (vcpus_equal_to_resctrl && !default_alloc_monitor)
- return 1;
-
return 0;
}
-#define VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL 3
-
static int
-virDomainResctrlMonDefParse(virDomainDefPtr def,
- xmlXPathContextPtr ctxt,
- xmlNodePtr node,
- virResctrlMonitorType tag,
- virDomainResctrlDefPtr resctrl)
+virDomainDefParseBootOptions(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt)
{
- virDomainResctrlMonDefPtr domresmon = NULL;
- VIR_XPATH_NODE_AUTORESTORE(ctxt);
- unsigned int level = 0;
- size_t i = 0;
- int n = 0;
- int rv = -1;
- int ret = -1;
+ char *name = NULL;
+ size_t i;
+ int n;
g_autofree xmlNodePtr *nodes = NULL;
g_autofree char *tmp = NULL;
- g_autofree char *id = NULL;
-
- ctxt->node = node;
- if ((n = virXPathNodeSet("./monitor", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot extract monitor nodes"));
- goto cleanup;
- }
+ /*
+ * Booting options for different OS types....
+ *
+ * - A bootloader (and optional kernel+initrd) (xen)
+ * - A kernel + initrd (xen)
+ * - A boot device (and optional kernel+initrd) (hvm)
+ * - An init script (exe)
+ */
- for (i = 0; i < n; i++) {
- if (VIR_ALLOC(domresmon) < 0)
- goto cleanup;
+ if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
+ def->os.init = virXPathString("string(./os/init[1])", ctxt);
+ def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
+ def->os.initdir = virXPathString("string(./os/initdir[1])", ctxt);
+ def->os.inituser = virXPathString("string(./os/inituser[1])", ctxt);
+ def->os.initgroup = virXPathString("string(./os/initgroup[1])", ctxt);
- domresmon->tag = tag;
+ if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0)
+ return -1;
- domresmon->instance = virResctrlMonitorNew();
- if (!domresmon->instance) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Could not create monitor"));
- goto cleanup;
+ if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
+ return -1;
+ for (i = 0; i < n; i++) {
+ if (!nodes[i]->children ||
+ !nodes[i]->children->content) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("No data supplied for <initarg> element"));
+ return -1;
+ }
+ def->os.initargv[i] = g_strdup((const char *)nodes[i]->children->content);
}
+ def->os.initargv[n] = NULL;
+ VIR_FREE(nodes);
- if (tag == VIR_RESCTRL_MONITOR_TYPE_CACHE) {
- tmp = virXMLPropString(nodes[i], "level");
- if (!tmp) {
+ if ((n = virXPathNodeSet("./os/initenv", ctxt, &nodes)) < 0)
+ return -1;
+
+ if (VIR_ALLOC_N(def->os.initenv, n+1) < 0)
+ return -1;
+ for (i = 0; i < n; i++) {
+ if (!(name = virXMLPropString(nodes[i], "name"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing monitor attribute 'level'"));
- goto cleanup;
+ _("No name supplied for <initenv> element"));
+ return -1;
}
- if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
+ if (!nodes[i]->children ||
+ !nodes[i]->children->content) {
virReportError(VIR_ERR_XML_ERROR,
- _("Invalid monitor attribute 'level' value '%s'"),
- tmp);
- goto cleanup;
+ _("No value supplied for <initenv name='%s'> element"),
+ name);
+ return -1;
}
- if (level != VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL) {
+ if (VIR_ALLOC(def->os.initenv[i]) < 0)
+ return -1;
+
+ def->os.initenv[i]->name = name;
+ def->os.initenv[i]->value = g_strdup((const char *)nodes[i]->children->content);
+ }
+ def->os.initenv[n] = NULL;
+ VIR_FREE(nodes);
+ }
+
+ if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
+ def->os.type == VIR_DOMAIN_OSTYPE_XENPVH ||
+ def->os.type == VIR_DOMAIN_OSTYPE_HVM ||
+ def->os.type == VIR_DOMAIN_OSTYPE_UML) {
+ g_autofree char *firmware = NULL;
+ xmlNodePtr loader_node;
+
+ def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt);
+ def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt);
+ def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
+ def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
+ def->os.root = virXPathString("string(./os/root[1])", ctxt);
+
+ if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
+ (firmware = virXPathString("string(./os/@firmware)", ctxt))) {
+ int fw = virDomainOsDefFirmwareTypeFromString(firmware);
+
+ if (fw <= 0) {
virReportError(VIR_ERR_XML_ERROR,
- _("Invalid monitor cache level '%d'"),
- level);
- goto cleanup;
+ _("unknown firmware value %s"),
+ firmware);
+ return -1;
}
- VIR_FREE(tmp);
+ def->os.firmware = fw;
}
- if (virDomainResctrlParseVcpus(def, nodes[i], &domresmon->vcpus) < 0)
- goto cleanup;
+ if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) {
+ const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
- rv = virDomainResctrlValidateMonitor(resctrl, domresmon);
- if (rv < 0)
- goto cleanup;
+ if (VIR_ALLOC(def->os.loader) < 0)
+ return -1;
- /* If monitor's vcpu list is identical to the vcpu list of the
- * associated allocation, set monitor's id to the same value
- * as the allocation. */
- if (rv == 1) {
- const char *alloc_id = virResctrlAllocGetID(resctrl->alloc);
+ if (virDomainLoaderDefParseXML(loader_node,
+ def->os.loader,
+ fwAutoSelect) < 0)
+ return -1;
- id = g_strdup(alloc_id);
- } else {
- if (!(tmp = virBitmapFormat(domresmon->vcpus)))
- goto cleanup;
+ def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
+ if (!fwAutoSelect)
+ def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
+ }
+ }
- id = g_strdup_printf("vcpus_%s", tmp);
+ if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
+ if ((n = virXPathNodeSet("./os/acpi/table", ctxt, &nodes)) < 0)
+ return -1;
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Only one acpi table is supported"));
+ return -1;
}
- virResctrlMonitorSetAlloc(domresmon->instance, resctrl->alloc);
+ if (n == 1) {
+ tmp = virXMLPropString(nodes[0], "type");
- if (virResctrlMonitorSetID(domresmon->instance, id) < 0)
- goto cleanup;
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing acpi table type"));
+ return -1;
+ }
- if (VIR_APPEND_ELEMENT(resctrl->monitors,
- resctrl->nmonitors,
- domresmon) < 0)
- goto cleanup;
+ if (STREQ_NULLABLE(tmp, "slic")) {
+ VIR_FREE(tmp);
+ tmp = virXMLNodeContentString(nodes[0]);
+ def->os.slic_table = virFileSanitizePath(tmp);
+ } else {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unknown acpi table type: %s"),
+ tmp);
+ return -1;
+ }
+ }
- VIR_FREE(id);
- VIR_FREE(tmp);
+ if (virDomainDefParseBootXML(ctxt, def) < 0)
+ return -1;
}
- ret = 0;
- cleanup:
- virDomainResctrlMonDefFree(domresmon);
- return ret;
+ return 0;
}
-static virDomainResctrlDefPtr
-virDomainResctrlNew(xmlNodePtr node,
- virResctrlAllocPtr alloc,
- virBitmapPtr vcpus,
- unsigned int flags)
+static int
+virDomainResctrlParseVcpus(virDomainDefPtr def,
+ xmlNodePtr node,
+ virBitmapPtr *vcpus)
{
- virDomainResctrlDefPtr resctrl = NULL;
- virDomainResctrlDefPtr ret = NULL;
g_autofree char *vcpus_str = NULL;
- g_autofree char *alloc_id = NULL;
- /* We need to format it back because we need to be consistent in the naming
- * even when users specify some "sub-optimal" string there. */
- vcpus_str = virBitmapFormat(vcpus);
- if (!vcpus_str)
- return NULL;
+ vcpus_str = virXMLPropString(node, "vcpus");
+ if (!vcpus_str) {
+ virReportError(VIR_ERR_XML_ERROR, _("Missing %s attribute 'vcpus'"),
+ node->name);
+ return -1;
+ }
+ if (virBitmapParse(vcpus_str, vcpus, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s attribute 'vcpus' value '%s'"),
+ node->name, vcpus_str);
+ return -1;
+ }
- if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
- alloc_id = virXMLPropString(node, "id");
+ /* We need to limit the bitmap to number of vCPUs. If there's nothing left,
+ * then we can just clean up and return 0 immediately */
+ virBitmapShrink(*vcpus, def->maxvcpus);
- if (!alloc_id) {
- /* The number of allocations is limited and the directory structure is flat,
- * not hierarchical, so we need to have all same allocations in one
- * directory, so it's nice to have it named appropriately. For now it's
- * 'vcpus_...' but it's designed in order for it to be changeable in the
- * future (it's part of the status XML). */
- alloc_id = g_strdup_printf("vcpus_%s", vcpus_str);
- }
+ return 0;
+}
- if (virResctrlAllocSetID(alloc, alloc_id) < 0)
- goto cleanup;
- if (VIR_ALLOC(resctrl) < 0)
- goto cleanup;
+static int
+virDomainResctrlVcpuMatch(virDomainDefPtr def,
+ virBitmapPtr vcpus,
+ virDomainResctrlDefPtr *resctrl)
+{
+ ssize_t i = 0;
- if (!(resctrl->vcpus = virBitmapNewCopy(vcpus))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to copy 'vcpus'"));
- goto cleanup;
+ for (i = 0; i < def->nresctrls; i++) {
+ /* vcpus group has been created, directly use the existing one.
+ * Just updating memory allocation information of that group
+ */
+ if (virBitmapEqual(def->resctrls[i]->vcpus, vcpus)) {
+ *resctrl = def->resctrls[i];
+ break;
+ }
+ if (virBitmapOverlaps(def->resctrls[i]->vcpus, vcpus)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Overlapping vcpus in resctrls"));
+ return -1;
+ }
}
-
- resctrl->alloc = virObjectRef(alloc);
-
- ret = g_steal_pointer(&resctrl);
- cleanup:
- virDomainResctrlDefFree(resctrl);
- return ret;
+ return 0;
}
static int
-virDomainCachetuneDefParse(virDomainDefPtr def,
- xmlXPathContextPtr ctxt,
- xmlNodePtr node,
- unsigned int flags)
+virDomainCachetuneDefParseCache(xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ virResctrlAllocPtr alloc)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt);
- virDomainResctrlDefPtr resctrl = NULL;
- ssize_t i = 0;
- int n;
- int ret = -1;
- g_autoptr(virBitmap) vcpus = NULL;
- g_autofree xmlNodePtr *nodes = NULL;
- g_autoptr(virResctrlAlloc) alloc = NULL;
+ unsigned int level;
+ unsigned int cache;
+ int type;
+ unsigned long long size;
+ g_autofree char *tmp = NULL;
ctxt->node = node;
- if (virDomainResctrlParseVcpus(def, node, &vcpus) < 0)
+ tmp = virXMLPropString(node, "id");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing cachetune attribute 'id'"));
return -1;
-
- if (virBitmapIsAllClear(vcpus))
- return 0;
-
- if ((n = virXPathNodeSet("./cache", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot extract cache nodes under cachetune"));
+ }
+ if (virStrToLong_uip(tmp, NULL, 10, &cache) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid cachetune attribute 'id' value '%s'"),
+ tmp);
return -1;
}
+ VIR_FREE(tmp);
- if (virDomainResctrlVcpuMatch(def, vcpus, &resctrl) < 0)
+ tmp = virXMLPropString(node, "level");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing cachetune attribute 'level'"));
+ return -1;
+ }
+ if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid cachetune attribute 'level' value '%s'"),
+ tmp);
return -1;
+ }
+ VIR_FREE(tmp);
- if (resctrl) {
+ tmp = virXMLPropString(node, "type");
+ if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Identical vcpus in cachetunes found"));
+ _("Missing cachetune attribute 'type'"));
return -1;
}
-
- if (!(alloc = virResctrlAllocNew()))
+ type = virCacheTypeFromString(tmp);
+ if (type < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid cachetune attribute 'type' value '%s'"),
+ tmp);
return -1;
-
- for (i = 0; i < n; i++) {
- if (virDomainCachetuneDefParseCache(ctxt, nodes[i], alloc) < 0)
- return -1;
}
- if (!(resctrl = virDomainResctrlNew(node, alloc, vcpus, flags)))
+ if (virDomainParseScaledValue("./@size", "./@unit",
+ ctxt, &size, 1024,
+ ULLONG_MAX, true) < 0)
return -1;
- if (virDomainResctrlMonDefParse(def, ctxt, node,
- VIR_RESCTRL_MONITOR_TYPE_CACHE,
- resctrl) < 0)
- goto cleanup;
-
- /* If no <cache> element or <monitor> element in <cachetune>, do not
- * append any resctrl element */
- if (!resctrl->nmonitors && n == 0) {
- ret = 0;
- goto cleanup;
- }
-
- if (VIR_APPEND_ELEMENT(def->resctrls, def->nresctrls, resctrl) < 0)
- goto cleanup;
+ if (virResctrlAllocSetCacheSize(alloc, level, type, cache, size) < 0)
+ return -1;
- ret = 0;
- cleanup:
- virDomainResctrlDefFree(resctrl);
- return ret;
+ return 0;
}
+/* Checking if the monitor's vcpus and tag is conflicted with existing
+ * allocation and monitors.
+ *
+ * Returns 1 if @monitor->vcpus equals to @resctrl->vcpus, then the monitor
+ * will share the underlying resctrl group with @resctrl->alloc. Returns -1
+ * if any conflict found. Returns 0 if no conflict and @monitor->vcpus is
+ * not equal to @resctrl->vcpus.
+ */
static int
-virDomainDefParseCaps(virDomainDefPtr def,
- xmlXPathContextPtr ctxt,
- virDomainXMLOptionPtr xmlopt)
+virDomainResctrlValidateMonitor(virDomainResctrlDefPtr resctrl,
+ virDomainResctrlMonDefPtr monitor)
{
- g_autofree char *virttype = NULL;
- g_autofree char *arch = NULL;
- g_autofree char *ostype = NULL;
-
- virttype = virXPathString("string(./@type)", ctxt);
- ostype = virXPathString("string(./os/type[1])", ctxt);
- arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
-
- def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
- def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
- def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
- def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
+ size_t i = 0;
+ int vcpu = -1;
+ bool vcpus_overlap_any = false;
+ bool vcpus_equal_to_resctrl = false;
+ bool vcpus_overlap_no_resctrl = false;
+ bool default_alloc_monitor = virResctrlAllocIsEmpty(resctrl->alloc);
- if (!virttype) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing domain type attribute"));
- return -1;
- }
- if ((def->virtType = virDomainVirtTypeFromString(virttype)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("invalid domain type %s"), virttype);
+ if (virBitmapIsAllClear(monitor->vcpus)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("vcpus is empty"));
return -1;
}
- if (!ostype) {
- if (def->os.bootloader) {
- def->os.type = VIR_DOMAIN_OSTYPE_XEN;
- } else {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("an os <type> must be specified"));
- return -1;
- }
- } else {
- if ((def->os.type = virDomainOSTypeFromString(ostype)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown OS type '%s'"), ostype);
+ while ((vcpu = virBitmapNextSetBit(monitor->vcpus, vcpu)) >= 0) {
+ if (!virBitmapIsBitSet(resctrl->vcpus, vcpu)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Monitor vcpus conflicts with allocation"));
return -1;
}
}
- /*
- * HACK: For xen driver we previously used bogus 'linux' as the
- * os type for paravirt, whereas capabilities declare it to
- * be 'xen'. So we accept the former and convert
- */
- if (def->os.type == VIR_DOMAIN_OSTYPE_LINUX &&
- def->virtType == VIR_DOMAIN_VIRT_XEN) {
- def->os.type = VIR_DOMAIN_OSTYPE_XEN;
+ vcpus_equal_to_resctrl = virBitmapEqual(monitor->vcpus, resctrl->vcpus);
+
+ for (i = 0; i < resctrl->nmonitors; i++) {
+ if (virBitmapEqual(monitor->vcpus, resctrl->monitors[i]->vcpus)) {
+ if (monitor->tag != resctrl->monitors[i]->tag) {
+ continue;
+ } else {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Identical vcpus found in same type monitors"));
+ return -1;
+ }
+ }
+
+ if (virBitmapOverlaps(monitor->vcpus, resctrl->monitors[i]->vcpus))
+ vcpus_overlap_any = true;
+
+ if (vcpus_equal_to_resctrl ||
+ virBitmapEqual(resctrl->monitors[i]->vcpus, resctrl->vcpus))
+ continue;
+
+ if (virBitmapOverlaps(monitor->vcpus, resctrl->monitors[i]->vcpus))
+ vcpus_overlap_no_resctrl = true;
}
- if (arch && !(def->os.arch = virArchFromString(arch))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unknown architecture %s"), arch);
+ if (vcpus_overlap_no_resctrl ||
+ (default_alloc_monitor && vcpus_overlap_any)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("vcpus overlaps in resctrl groups"));
return -1;
}
- if (def->os.arch == VIR_ARCH_NONE) {
- if (xmlopt && xmlopt->config.defArch != VIR_ARCH_NONE)
- def->os.arch = xmlopt->config.defArch;
- else
- def->os.arch = virArchFromHost();
- }
+ if (vcpus_equal_to_resctrl && !default_alloc_monitor)
+ return 1;
return 0;
}
+#define VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL 3
+
static int
-virDomainMemorytuneDefParseMemory(xmlXPathContextPtr ctxt,
- xmlNodePtr node,
- virResctrlAllocPtr alloc)
+virDomainResctrlMonDefParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ virResctrlMonitorType tag,
+ virDomainResctrlDefPtr resctrl)
{
+ virDomainResctrlMonDefPtr domresmon = NULL;
VIR_XPATH_NODE_AUTORESTORE(ctxt);
- unsigned int id;
- unsigned int bandwidth;
+ unsigned int level = 0;
+ size_t i = 0;
+ int n = 0;
+ int rv = -1;
+ int ret = -1;
+ g_autofree xmlNodePtr *nodes = NULL;
g_autofree char *tmp = NULL;
+ g_autofree char *id = NULL;
ctxt->node = node;
- tmp = virXMLPropString(node, "id");
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing memorytune attribute 'id'"));
- return -1;
- }
- if (virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid memorytune attribute 'id' value '%s'"),
- tmp);
- return -1;
- }
- VIR_FREE(tmp);
-
- tmp = virXMLPropString(node, "bandwidth");
- if (!tmp) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing memorytune attribute 'bandwidth'"));
- return -1;
- }
- if (virStrToLong_uip(tmp, NULL, 10, &bandwidth) < 0) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid memorytune attribute 'bandwidth' value '%s'"),
- tmp);
- return -1;
- }
- if (virResctrlAllocSetMemoryBandwidth(alloc, id, bandwidth) < 0)
- return -1;
+ if ((n = virXPathNodeSet("./monitor", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot extract monitor nodes"));
+ goto cleanup;
+ }
- return 0;
-}
+ for (i = 0; i < n; i++) {
+ if (VIR_ALLOC(domresmon) < 0)
+ goto cleanup;
+ domresmon->tag = tag;
-static int
-virDomainMemorytuneDefParse(virDomainDefPtr def,
- xmlXPathContextPtr ctxt,
- xmlNodePtr node,
- unsigned int flags)
-{
- VIR_XPATH_NODE_AUTORESTORE(ctxt);
- virDomainResctrlDefPtr resctrl = NULL;
- virDomainResctrlDefPtr newresctrl = NULL;
- g_autoptr(virBitmap) vcpus = NULL;
- g_autofree xmlNodePtr *nodes = NULL;
- g_autoptr(virResctrlAlloc) alloc = NULL;
- ssize_t i = 0;
- size_t nmons = 0;
- size_t ret = -1;
+ domresmon->instance = virResctrlMonitorNew();
+ if (!domresmon->instance) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not create monitor"));
+ goto cleanup;
+ }
- int n;
+ if (tag == VIR_RESCTRL_MONITOR_TYPE_CACHE) {
+ tmp = virXMLPropString(nodes[i], "level");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing monitor attribute 'level'"));
+ goto cleanup;
+ }
- ctxt->node = node;
+ if (virStrToLong_uip(tmp, NULL, 10, &level) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid monitor attribute 'level' value '%s'"),
+ tmp);
+ goto cleanup;
+ }
- if (virDomainResctrlParseVcpus(def, node, &vcpus) < 0)
- return -1;
+ if (level != VIR_DOMAIN_RESCTRL_MONITOR_CACHELEVEL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid monitor cache level '%d'"),
+ level);
+ goto cleanup;
+ }
- if (virBitmapIsAllClear(vcpus))
- return 0;
+ VIR_FREE(tmp);
+ }
- if ((n = virXPathNodeSet("./node", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot extract memory nodes under memorytune"));
- return -1;
- }
+ if (virDomainResctrlParseVcpus(def, nodes[i], &domresmon->vcpus) < 0)
+ goto cleanup;
- if (virDomainResctrlVcpuMatch(def, vcpus, &resctrl) < 0)
- return -1;
+ rv = virDomainResctrlValidateMonitor(resctrl, domresmon);
+ if (rv < 0)
+ goto cleanup;
- if (resctrl) {
- alloc = virObjectRef(resctrl->alloc);
- } else {
- if (!(alloc = virResctrlAllocNew()))
- return -1;
- }
+ /* If monitor's vcpu list is identical to the vcpu list of the
+ * associated allocation, set monitor's id to the same value
+ * as the allocation. */
+ if (rv == 1) {
+ const char *alloc_id = virResctrlAllocGetID(resctrl->alloc);
- /* First, parse <memorytune/node> element if any <node> element exists */
- for (i = 0; i < n; i++) {
- if (virDomainMemorytuneDefParseMemory(ctxt, nodes[i], alloc) < 0)
- return -1;
- }
+ id = g_strdup(alloc_id);
+ } else {
+ if (!(tmp = virBitmapFormat(domresmon->vcpus)))
+ goto cleanup;
- /*
- * If this is a new allocation, format ID and append to resctrl, otherwise
- * just update the existing alloc information, which is done in above
- * virDomainMemorytuneDefParseMemory */
- if (!resctrl) {
- if (!(newresctrl = virDomainResctrlNew(node, alloc, vcpus, flags)))
- return -1;
+ id = g_strdup_printf("vcpus_%s", tmp);
+ }
- resctrl = newresctrl;
- }
+ virResctrlMonitorSetAlloc(domresmon->instance, resctrl->alloc);
- /* Next, parse <memorytune/monitor> element */
- nmons = resctrl->nmonitors;
- if (virDomainResctrlMonDefParse(def, ctxt, node,
- VIR_RESCTRL_MONITOR_TYPE_MEMBW,
- resctrl) < 0)
- goto cleanup;
+ if (virResctrlMonitorSetID(domresmon->instance, id) < 0)
+ goto cleanup;
- nmons = resctrl->nmonitors - nmons;
- /* Now @nmons contains the new <monitor> element number found in current
- * <memorytune> element, and @n holds the number of new <node> element,
- * only append the new @newresctrl object to domain if any of them is
- * not zero. */
- if (newresctrl && (nmons || n)) {
- if (VIR_APPEND_ELEMENT(def->resctrls, def->nresctrls, newresctrl) < 0)
+ if (VIR_APPEND_ELEMENT(resctrl->monitors,
+ resctrl->nmonitors,
+ domresmon) < 0)
goto cleanup;
+
+ VIR_FREE(id);
+ VIR_FREE(tmp);
}
ret = 0;
cleanup:
- virDomainResctrlDefFree(newresctrl);
+ virDomainResctrlMonDefFree(domresmon);
return ret;
}
-static virDomainDefPtr
-virDomainDefParseXML(xmlDocPtr xml,
- xmlXPathContextPtr ctxt,
- virDomainXMLOptionPtr xmlopt,
- unsigned int flags)
+static virDomainResctrlDefPtr
+virDomainResctrlNew(xmlNodePtr node,
+ virResctrlAllocPtr alloc,
+ virBitmapPtr vcpus,
+ unsigned int flags)
{
- xmlNodePtr node = NULL;
- size_t i, j;
- int n, gic_version;
- long id = -1;
- virDomainDefPtr def;
- bool uuid_generated = false;
- bool usb_none = false;
- bool usb_other = false;
- bool usb_master = false;
- g_autofree xmlNodePtr *nodes = NULL;
- g_autofree char *tmp = NULL;
-
- if (flags & VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA) {
- g_autofree char *schema = NULL;
-
- schema = virFileFindResource("domain.rng",
- abs_top_srcdir "/docs/schemas",
- PKGDATADIR "/schemas");
- if (!schema)
- return NULL;
- if (virXMLValidateAgainstSchema(schema, xml) < 0)
- return NULL;
- }
+ virDomainResctrlDefPtr resctrl = NULL;
+ virDomainResctrlDefPtr ret = NULL;
+ g_autofree char *vcpus_str = NULL;
+ g_autofree char *alloc_id = NULL;
- if (!(def = virDomainDefNew()))
+ /* We need to format it back because we need to be consistent in the naming
+ * even when users specify some "sub-optimal" string there. */
+ vcpus_str = virBitmapFormat(vcpus);
+ if (!vcpus_str)
return NULL;
if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
- if (virXPathLong("string(./@id)", ctxt, &id) < 0)
- id = -1;
- def->id = (int)id;
-
- if (virDomainDefParseCaps(def, ctxt, xmlopt) < 0)
- goto error;
+ alloc_id = virXMLPropString(node, "id");
- /* Extract domain name */
- if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
- virReportError(VIR_ERR_NO_NAME, NULL);
- goto error;
+ if (!alloc_id) {
+ /* The number of allocations is limited and the directory structure is flat,
+ * not hierarchical, so we need to have all same allocations in one
+ * directory, so it's nice to have it named appropriately. For now it's
+ * 'vcpus_...' but it's designed in order for it to be changeable in the
+ * future (it's part of the status XML). */
+ alloc_id = g_strdup_printf("vcpus_%s", vcpus_str);
}
- /* Extract domain uuid. If both uuid and sysinfo/system/entry/uuid
- * exist, they must match; and if only the latter exists, it can
- * also serve as the uuid. */
- tmp = virXPathString("string(./uuid[1])", ctxt);
- if (!tmp) {
- if (virUUIDGenerate(def->uuid) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Failed to generate UUID"));
- goto error;
- }
- uuid_generated = true;
- } else {
- if (virUUIDParse(tmp, def->uuid) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed uuid element"));
- goto error;
- }
- VIR_FREE(tmp);
+ if (virResctrlAllocSetID(alloc, alloc_id) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(resctrl) < 0)
+ goto cleanup;
+
+ if (!(resctrl->vcpus = virBitmapNewCopy(vcpus))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to copy 'vcpus'"));
+ goto cleanup;
}
- /* Extract domain genid - a genid can either be provided or generated */
- if ((n = virXPathNodeSet("./genid", ctxt, &nodes)) < 0)
- goto error;
+ resctrl->alloc = virObjectRef(alloc);
- if (n > 0) {
- if (n != 1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("element 'genid' can only appear once"));
- goto error;
- }
- def->genidRequested = true;
- if (!(tmp = virXPathString("string(./genid)", ctxt))) {
- if (virUUIDGenerate(def->genid) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Failed to generate genid"));
- goto error;
- }
- def->genidGenerated = true;
- } else {
- if (virUUIDParse(tmp, def->genid) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed genid element"));
- goto error;
- }
- VIR_FREE(tmp);
- }
+ ret = g_steal_pointer(&resctrl);
+ cleanup:
+ virDomainResctrlDefFree(resctrl);
+ return ret;
+}
+
+
+static int
+virDomainCachetuneDefParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ unsigned int flags)
+{
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+ virDomainResctrlDefPtr resctrl = NULL;
+ ssize_t i = 0;
+ int n;
+ int ret = -1;
+ g_autoptr(virBitmap) vcpus = NULL;
+ g_autofree xmlNodePtr *nodes = NULL;
+ g_autoptr(virResctrlAlloc) alloc = NULL;
+
+ ctxt->node = node;
+
+ if (virDomainResctrlParseVcpus(def, node, &vcpus) < 0)
+ return -1;
+
+ if (virBitmapIsAllClear(vcpus))
+ return 0;
+
+ if ((n = virXPathNodeSet("./cache", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot extract cache nodes under cachetune"));
+ return -1;
}
- VIR_FREE(nodes);
- /* Extract short description of domain (title) */
- def->title = virXPathString("string(./title[1])", ctxt);
- if (def->title && strchr(def->title, '\n')) {
+ if (virDomainResctrlVcpuMatch(def, vcpus, &resctrl) < 0)
+ return -1;
+
+ if (resctrl) {
virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Domain title can't contain newlines"));
- goto error;
+ _("Identical vcpus in cachetunes found"));
+ return -1;
}
- /* Extract documentation if present */
- def->description = virXPathString("string(./description[1])", ctxt);
+ if (!(alloc = virResctrlAllocNew()))
+ return -1;
- /* analysis of security label, done early even though we format it
- * late, so devices can refer to this for defaults */
- if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_SECLABEL)) {
- if (virSecurityLabelDefsParseXML(def, ctxt, xmlopt, flags) == -1)
- goto error;
+ for (i = 0; i < n; i++) {
+ if (virDomainCachetuneDefParseCache(ctxt, nodes[i], alloc) < 0)
+ return -1;
}
- /* Extract domain memory */
- if (virDomainParseMemory("./memory[1]", NULL, ctxt,
- &def->mem.total_memory, false, true) < 0)
- goto error;
-
- if (virDomainParseMemory("./currentMemory[1]", NULL, ctxt,
- &def->mem.cur_balloon, false, true) < 0)
- goto error;
+ if (!(resctrl = virDomainResctrlNew(node, alloc, vcpus, flags)))
+ return -1;
- if (virDomainParseMemory("./maxMemory[1]", NULL, ctxt,
- &def->mem.max_memory, false, false) < 0)
- goto error;
+ if (virDomainResctrlMonDefParse(def, ctxt, node,
+ VIR_RESCTRL_MONITOR_TYPE_CACHE,
+ resctrl) < 0)
+ goto cleanup;
- if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Failed to parse memory slot count"));
- goto error;
+ /* If no <cache> element or <monitor> element in <cachetune>, do not
+ * append any resctrl element */
+ if (!resctrl->nmonitors && n == 0) {
+ ret = 0;
+ goto cleanup;
}
- /* and info about it */
- if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
- (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
+ if (VIR_APPEND_ELEMENT(def->resctrls, def->nresctrls, resctrl) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virDomainResctrlDefFree(resctrl);
+ return ret;
+}
+
+
+static int
+virDomainDefParseCaps(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOptionPtr xmlopt)
+{
+ g_autofree char *virttype = NULL;
+ g_autofree char *arch = NULL;
+ g_autofree char *ostype = NULL;
+
+ virttype = virXPathString("string(./@type)", ctxt);
+ ostype = virXPathString("string(./os/type[1])", ctxt);
+ arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
+
+ def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
+ def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
+ def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
+ def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
+
+ if (!virttype) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing domain type attribute"));
+ return -1;
+ }
+ if ((def->virtType = virDomainVirtTypeFromString(virttype)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Invalid memory core dump attribute value '%s'"), tmp);
- goto error;
+ _("invalid domain type %s"), virttype);
+ return -1;
}
- VIR_FREE(tmp);
- tmp = virXPathString("string(./memoryBacking/source/@type)", ctxt);
- if (tmp) {
- if ((def->mem.source = virDomainMemorySourceTypeFromString(tmp)) <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown memoryBacking/source/type '%s'"), tmp);
- goto error;
+ if (!ostype) {
+ if (def->os.bootloader) {
+ def->os.type = VIR_DOMAIN_OSTYPE_XEN;
+ } else {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("an os <type> must be specified"));
+ return -1;
}
- VIR_FREE(tmp);
- }
-
- tmp = virXPathString("string(./memoryBacking/access/@mode)", ctxt);
- if (tmp) {
- if ((def->mem.access = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
+ } else {
+ if ((def->os.type = virDomainOSTypeFromString(ostype)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown memoryBacking/access/mode '%s'"), tmp);
- goto error;
+ _("unknown OS type '%s'"), ostype);
+ return -1;
}
- VIR_FREE(tmp);
}
- tmp = virXPathString("string(./memoryBacking/allocation/@mode)", ctxt);
- if (tmp) {
- if ((def->mem.allocation = virDomainMemoryAllocationTypeFromString(tmp)) <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown memoryBacking/allocation/mode '%s'"), tmp);
- goto error;
- }
- VIR_FREE(tmp);
+ /*
+ * HACK: For xen driver we previously used bogus 'linux' as the
+ * os type for paravirt, whereas capabilities declare it to
+ * be 'xen'. So we accept the former and convert
+ */
+ if (def->os.type == VIR_DOMAIN_OSTYPE_LINUX &&
+ def->virtType == VIR_DOMAIN_VIRT_XEN) {
+ def->os.type = VIR_DOMAIN_OSTYPE_XEN;
}
- if (virXPathNode("./memoryBacking/hugepages", ctxt)) {
- /* hugepages will be used */
- if ((n = virXPathNodeSet("./memoryBacking/hugepages/page", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract hugepages nodes"));
- goto error;
- }
-
- if (n) {
- if (VIR_ALLOC_N(def->mem.hugepages, n) < 0)
- goto error;
-
- for (i = 0; i < n; i++) {
- if (virDomainHugepagesParseXML(nodes[i], ctxt,
- &def->mem.hugepages[i]) < 0)
- goto error;
- def->mem.nhugepages++;
- }
-
- VIR_FREE(nodes);
- } else {
- /* no hugepage pages */
- if (VIR_ALLOC(def->mem.hugepages) < 0)
- goto error;
+ if (arch && !(def->os.arch = virArchFromString(arch))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unknown architecture %s"), arch);
+ return -1;
+ }
- def->mem.nhugepages = 1;
- }
+ if (def->os.arch == VIR_ARCH_NONE) {
+ if (xmlopt && xmlopt->config.defArch != VIR_ARCH_NONE)
+ def->os.arch = xmlopt->config.defArch;
+ else
+ def->os.arch = virArchFromHost();
}
- if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
- def->mem.nosharepages = true;
+ return 0;
+}
- if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
- def->mem.locked = true;
- if (virXPathBoolean("boolean(./memoryBacking/discard)", ctxt))
- def->mem.discard = VIR_TRISTATE_BOOL_YES;
+static int
+virDomainMemorytuneDefParseMemory(xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ virResctrlAllocPtr alloc)
+{
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+ unsigned int id;
+ unsigned int bandwidth;
+ g_autofree char *tmp = NULL;
- /* Extract blkio cgroup tunables */
- if (virXPathUInt("string(./blkiotune/weight)", ctxt,
- &def->blkio.weight) < 0)
- def->blkio.weight = 0;
+ ctxt->node = node;
- if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot extract blkiotune nodes"));
- goto error;
+ tmp = virXMLPropString(node, "id");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing memorytune attribute 'id'"));
+ return -1;
}
- if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
- goto error;
-
- for (i = 0; i < n; i++) {
- if (virDomainBlkioDeviceParseXML(nodes[i],
- &def->blkio.devices[i]) < 0)
- goto error;
- def->blkio.ndevices++;
- for (j = 0; j < i; j++) {
- if (STREQ(def->blkio.devices[j].path,
- def->blkio.devices[i].path)) {
- virReportError(VIR_ERR_XML_ERROR,
- _("duplicate blkio device path '%s'"),
- def->blkio.devices[i].path);
- goto error;
- }
- }
+ if (virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid memorytune attribute 'id' value '%s'"),
+ tmp);
+ return -1;
}
- VIR_FREE(nodes);
-
- /* Extract other memory tunables */
- if (virDomainParseMemoryLimit("./memtune/hard_limit[1]", NULL, ctxt,
- &def->mem.hard_limit) < 0)
- goto error;
+ VIR_FREE(tmp);
- if (virDomainParseMemoryLimit("./memtune/soft_limit[1]", NULL, ctxt,
- &def->mem.soft_limit) < 0)
- goto error;
+ tmp = virXMLPropString(node, "bandwidth");
+ if (!tmp) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing memorytune attribute 'bandwidth'"));
+ return -1;
+ }
+ if (virStrToLong_uip(tmp, NULL, 10, &bandwidth) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid memorytune attribute 'bandwidth' value '%s'"),
+ tmp);
+ return -1;
+ }
+ if (virResctrlAllocSetMemoryBandwidth(alloc, id, bandwidth) < 0)
+ return -1;
- if (virDomainParseMemory("./memtune/min_guarantee[1]", NULL, ctxt,
- &def->mem.min_guarantee, false, false) < 0)
- goto error;
+ return 0;
+}
- if (virDomainParseMemoryLimit("./memtune/swap_hard_limit[1]", NULL, ctxt,
- &def->mem.swap_hard_limit) < 0)
- goto error;
- if (virDomainVcpuParse(def, ctxt, xmlopt) < 0)
- goto error;
+static int
+virDomainMemorytuneDefParse(virDomainDefPtr def,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ unsigned int flags)
+{
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+ virDomainResctrlDefPtr resctrl = NULL;
+ virDomainResctrlDefPtr newresctrl = NULL;
+ g_autoptr(virBitmap) vcpus = NULL;
+ g_autofree xmlNodePtr *nodes = NULL;
+ g_autoptr(virResctrlAlloc) alloc = NULL;
+ ssize_t i = 0;
+ size_t nmons = 0;
+ size_t ret = -1;
- if (virDomainDefParseIOThreads(def, ctxt) < 0)
- goto error;
+ int n;
- /* Extract cpu tunables. */
- if ((n = virXPathULongLong("string(./cputune/shares[1])", ctxt,
- &def->cputune.shares)) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune shares value"));
- goto error;
- } else if (n == 0) {
- def->cputune.sharesSpecified = true;
- }
+ ctxt->node = node;
- if (virXPathULongLong("string(./cputune/period[1])", ctxt,
- &def->cputune.period) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune period value"));
- goto error;
- }
+ if (virDomainResctrlParseVcpus(def, node, &vcpus) < 0)
+ return -1;
- if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
- &def->cputune.quota) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune quota value"));
- goto error;
- }
+ if (virBitmapIsAllClear(vcpus))
+ return 0;
- if (virXPathULongLong("string(./cputune/global_period[1])", ctxt,
- &def->cputune.global_period) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune global period value"));
- goto error;
+ if ((n = virXPathNodeSet("./node", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot extract memory nodes under memorytune"));
+ return -1;
}
- if (virXPathLongLong("string(./cputune/global_quota[1])", ctxt,
- &def->cputune.global_quota) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune global quota value"));
- goto error;
- }
+ if (virDomainResctrlVcpuMatch(def, vcpus, &resctrl) < 0)
+ return -1;
- if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
- &def->cputune.emulator_period) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune emulator period value"));
- goto error;
+ if (resctrl) {
+ alloc = virObjectRef(resctrl->alloc);
+ } else {
+ if (!(alloc = virResctrlAllocNew()))
+ return -1;
}
- if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
- &def->cputune.emulator_quota) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune emulator quota value"));
- goto error;
+ /* First, parse <memorytune/node> element if any <node> element exists */
+ for (i = 0; i < n; i++) {
+ if (virDomainMemorytuneDefParseMemory(ctxt, nodes[i], alloc) < 0)
+ return -1;
}
+ /*
+ * If this is a new allocation, format ID and append to resctrl, otherwise
+ * just update the existing alloc information, which is done in above
+ * virDomainMemorytuneDefParseMemory */
+ if (!resctrl) {
+ if (!(newresctrl = virDomainResctrlNew(node, alloc, vcpus, flags)))
+ return -1;
- if (virXPathULongLong("string(./cputune/iothread_period[1])", ctxt,
- &def->cputune.iothread_period) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune iothread period value"));
- goto error;
- }
-
- if (virXPathLongLong("string(./cputune/iothread_quota[1])", ctxt,
- &def->cputune.iothread_quota) < -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("can't parse cputune iothread quota value"));
- goto error;
+ resctrl = newresctrl;
}
- if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0)
- goto error;
+ /* Next, parse <memorytune/monitor> element */
+ nmons = resctrl->nmonitors;
+ if (virDomainResctrlMonDefParse(def, ctxt, node,
+ VIR_RESCTRL_MONITOR_TYPE_MEMBW,
+ resctrl) < 0)
+ goto cleanup;
- for (i = 0; i < n; i++) {
- if (virDomainVcpuPinDefParseXML(def, nodes[i]))
- goto error;
+ nmons = resctrl->nmonitors - nmons;
+ /* Now @nmons contains the new <monitor> element number found in current
+ * <memorytune> element, and @n holds the number of new <node> element,
+ * only append the new @newresctrl object to domain if any of them is
+ * not zero. */
+ if (newresctrl && (nmons || n)) {
+ if (VIR_APPEND_ELEMENT(def->resctrls, def->nresctrls, newresctrl) < 0)
+ goto cleanup;
}
- VIR_FREE(nodes);
- if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract emulatorpin nodes"));
- goto error;
- }
+ ret = 0;
+ cleanup:
+ virDomainResctrlDefFree(newresctrl);
+ return ret;
+}
- if (n) {
- if (n > 1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("only one emulatorpin is supported"));
- VIR_FREE(nodes);
- goto error;
- }
- if (!(def->cputune.emulatorpin = virDomainEmulatorPinDefParseXML(nodes[0])))
- goto error;
- }
- VIR_FREE(nodes);
+static virDomainDefPtr
+virDomainDefParseXML(xmlDocPtr xml,
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags)
+{
+ xmlNodePtr node = NULL;
+ size_t i, j;
+ int n;
+ long id = -1;
+ virDomainDefPtr def;
+ bool uuid_generated = false;
+ bool usb_none = false;
+ bool usb_other = false;
+ bool usb_master = false;
+ g_autofree xmlNodePtr *nodes = NULL;
+ g_autofree char *tmp = NULL;
+ if (flags & VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA) {
+ g_autofree char *schema = NULL;
- if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract iothreadpin nodes"));
- goto error;
+ schema = virFileFindResource("domain.rng",
+ abs_top_srcdir "/docs/schemas",
+ PKGDATADIR "/schemas");
+ if (!schema)
+ return NULL;
+ if (virXMLValidateAgainstSchema(schema, xml) < 0)
+ return NULL;
}
- for (i = 0; i < n; i++) {
- if (virDomainIOThreadPinDefParseXML(nodes[i], def) < 0)
- goto error;
- }
- VIR_FREE(nodes);
+ if (!(def = virDomainDefNew()))
+ return NULL;
- if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract vcpusched nodes"));
- goto error;
- }
+ if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
+ if (virXPathLong("string(./@id)", ctxt, &id) < 0)
+ id = -1;
+ def->id = (int)id;
- for (i = 0; i < n; i++) {
- if (virDomainVcpuThreadSchedParse(nodes[i], def) < 0)
- goto error;
- }
- VIR_FREE(nodes);
+ if (virDomainDefParseCaps(def, ctxt, xmlopt) < 0)
+ goto error;
- if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract iothreadsched nodes"));
+ /* Extract domain name */
+ if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
+ virReportError(VIR_ERR_NO_NAME, NULL);
goto error;
}
- for (i = 0; i < n; i++) {
- if (virDomainIOThreadSchedParse(nodes[i], def) < 0)
+ /* Extract domain uuid. If both uuid and sysinfo/system/entry/uuid
+ * exist, they must match; and if only the latter exists, it can
+ * also serve as the uuid. */
+ tmp = virXPathString("string(./uuid[1])", ctxt);
+ if (!tmp) {
+ if (virUUIDGenerate(def->uuid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Failed to generate UUID"));
goto error;
+ }
+ uuid_generated = true;
+ } else {
+ if (virUUIDParse(tmp, def->uuid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed uuid element"));
+ goto error;
+ }
+ VIR_FREE(tmp);
}
- VIR_FREE(nodes);
- if ((n = virXPathNodeSet("./cputune/emulatorsched", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract emulatorsched nodes"));
+ /* Extract domain genid - a genid can either be provided or generated */
+ if ((n = virXPathNodeSet("./genid", ctxt, &nodes)) < 0)
goto error;
- }
- if (n) {
- if (n > 1) {
+ if (n > 0) {
+ if (n != 1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
- _("only one emulatorsched is supported"));
- VIR_FREE(nodes);
+ _("element 'genid' can only appear once"));
goto error;
}
-
- if (virDomainEmulatorSchedParse(nodes[0], def) < 0)
- goto error;
+ def->genidRequested = true;
+ if (!(tmp = virXPathString("string(./genid)", ctxt))) {
+ if (virUUIDGenerate(def->genid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Failed to generate genid"));
+ goto error;
+ }
+ def->genidGenerated = true;
+ } else {
+ if (virUUIDParse(tmp, def->genid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed genid element"));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ }
}
VIR_FREE(nodes);
- if ((n = virXPathNodeSet("./cputune/cachetune", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract cachetune nodes"));
+ /* Extract short description of domain (title) */
+ def->title = virXPathString("string(./title[1])", ctxt);
+ if (def->title && strchr(def->title, '\n')) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Domain title can't contain newlines"));
goto error;
}
- for (i = 0; i < n; i++) {
- if (virDomainCachetuneDefParse(def, ctxt, nodes[i], flags) < 0)
- goto error;
- }
- VIR_FREE(nodes);
-
- if ((n = virXPathNodeSet("./cputune/memorytune", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot extract memorytune nodes"));
- goto error;
- }
+ /* Extract documentation if present */
+ def->description = virXPathString("string(./description[1])", ctxt);
- for (i = 0; i < n; i++) {
- if (virDomainMemorytuneDefParse(def, ctxt, nodes[i], flags) < 0)
+ /* analysis of security label, done early even though we format it
+ * late, so devices can refer to this for defaults */
+ if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_SECLABEL)) {
+ if (virSecurityLabelDefsParseXML(def, ctxt, xmlopt, flags) == -1)
goto error;
}
- VIR_FREE(nodes);
- if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
+ /* Extract domain memory */
+ if (virDomainParseMemory("./memory[1]", NULL, ctxt,
+ &def->mem.total_memory, false, true) < 0)
goto error;
- if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
+ if (virDomainParseMemory("./currentMemory[1]", NULL, ctxt,
+ &def->mem.cur_balloon, false, true) < 0)
goto error;
- if (virDomainNumaGetCPUCountTotal(def->numa) > virDomainDefGetVcpusMax(def)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Number of CPUs in <numa> exceeds the"
- " <vcpu> count"));
+ if (virDomainParseMemory("./maxMemory[1]", NULL, ctxt,
+ &def->mem.max_memory, false, false) < 0)
goto error;
- }
- if (virDomainNumaGetMaxCPUID(def->numa) >= virDomainDefGetVcpusMax(def)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("CPU IDs in <numa> exceed the <vcpu> count"));
+ if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Failed to parse memory slot count"));
goto error;
}
- if (virDomainNumatuneParseXML(def->numa,
- def->placement_mode ==
- VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
- ctxt) < 0)
- goto error;
-
- if (virDomainNumatuneHasPlacementAuto(def->numa) &&
- !def->cpumask && !virDomainDefHasVcpuPin(def) &&
- !def->cputune.emulatorpin &&
- !virDomainIOThreadIDArrayHasPin(def))
- def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;
-
- if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot extract resource nodes"));
+ /* and info about it */
+ if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
+ (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid memory core dump attribute value '%s'"), tmp);
goto error;
}
+ VIR_FREE(tmp);
- if (n > 1) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("only one resource element is supported"));
- goto error;
+ tmp = virXPathString("string(./memoryBacking/source/@type)", ctxt);
+ if (tmp) {
+ if ((def->mem.source = virDomainMemorySourceTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown memoryBacking/source/type '%s'"), tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
}
- if (n &&
- !(def->resource = virDomainResourceDefParse(nodes[0], ctxt)))
- goto error;
- VIR_FREE(nodes);
-
- if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
- goto error;
-
- for (i = 0; i < n; i++) {
- int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
- if (val < 0) {
+ tmp = virXPathString("string(./memoryBacking/access/@mode)", ctxt);
+ if (tmp) {
+ if ((def->mem.access = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unexpected feature '%s'"), nodes[i]->name);
+ _("unknown memoryBacking/access/mode '%s'"), tmp);
goto error;
}
+ VIR_FREE(tmp);
+ }
- switch ((virDomainFeature) val) {
- case VIR_DOMAIN_FEATURE_APIC:
- if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
- int eoi;
- if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown value for attribute eoi: '%s'"),
- tmp);
- goto error;
- }
- def->apic_eoi = eoi;
- VIR_FREE(tmp);
- }
- G_GNUC_FALLTHROUGH;
- case VIR_DOMAIN_FEATURE_ACPI:
- case VIR_DOMAIN_FEATURE_PAE:
- case VIR_DOMAIN_FEATURE_VIRIDIAN:
- case VIR_DOMAIN_FEATURE_PRIVNET:
- case VIR_DOMAIN_FEATURE_HYPERV:
- case VIR_DOMAIN_FEATURE_KVM:
- case VIR_DOMAIN_FEATURE_MSRS:
- case VIR_DOMAIN_FEATURE_XEN:
- def->features[val] = VIR_TRISTATE_SWITCH_ON;
- break;
-
- case VIR_DOMAIN_FEATURE_CAPABILITIES:
- if ((tmp = virXMLPropString(nodes[i], "policy"))) {
- if ((def->features[val] = virDomainCapabilitiesPolicyTypeFromString(tmp)) == -1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown policy attribute '%s' of feature '%s'"),
- tmp, virDomainFeatureTypeToString(val));
- goto error;
- }
- VIR_FREE(tmp);
- } else {
- def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
- }
- break;
-
- case VIR_DOMAIN_FEATURE_VMCOREINFO:
- case VIR_DOMAIN_FEATURE_HAP:
- case VIR_DOMAIN_FEATURE_PMU:
- case VIR_DOMAIN_FEATURE_PVSPINLOCK:
- case VIR_DOMAIN_FEATURE_VMPORT:
- case VIR_DOMAIN_FEATURE_SMM:
- if ((tmp = virXMLPropString(nodes[i], "state"))) {
- if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown state attribute '%s' of feature '%s'"),
- tmp, virDomainFeatureTypeToString(val));
- goto error;
- }
- VIR_FREE(tmp);
- } else {
- def->features[val] = VIR_TRISTATE_SWITCH_ON;
- }
- break;
-
- case VIR_DOMAIN_FEATURE_GIC:
- if ((tmp = virXMLPropString(nodes[i], "version"))) {
- gic_version = virGICVersionTypeFromString(tmp);
- if (gic_version < 0 || gic_version == VIR_GIC_VERSION_NONE) {
- virReportError(VIR_ERR_XML_ERROR,
- _("malformed gic version: %s"), tmp);
- goto error;
- }
- def->gic_version = gic_version;
- VIR_FREE(tmp);
- }
- def->features[val] = VIR_TRISTATE_SWITCH_ON;
- break;
-
- case VIR_DOMAIN_FEATURE_IOAPIC:
- tmp = virXMLPropString(nodes[i], "driver");
- if (tmp) {
- int value = virDomainIOAPICTypeFromString(tmp);
- if (value < 0 || value == VIR_DOMAIN_IOAPIC_NONE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unknown driver mode: %s"),
- tmp);
- goto error;
- }
- def->features[val] = value;
- VIR_FREE(tmp);
- }
- break;
-
- case VIR_DOMAIN_FEATURE_HPT:
- tmp = virXMLPropString(nodes[i], "resizing");
- if (tmp) {
- int value = virDomainHPTResizingTypeFromString(tmp);
- if (value < 0 || value == VIR_DOMAIN_HPT_RESIZING_NONE) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unknown HPT resizing setting: %s"),
- tmp);
- goto error;
- }
- def->hpt_resizing = (virDomainHPTResizing) value;
- VIR_FREE(tmp);
- }
-
- if (virDomainParseScaledValue("./features/hpt/maxpagesize",
- NULL,
- ctxt,
- &def->hpt_maxpagesize,
- 1024,
- ULLONG_MAX,
- false) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s",
- _("Unable to parse HPT maxpagesize setting"));
- goto error;
- }
- def->hpt_maxpagesize = VIR_DIV_UP(def->hpt_maxpagesize, 1024);
-
- if (def->hpt_resizing != VIR_DOMAIN_HPT_RESIZING_NONE ||
- def->hpt_maxpagesize > 0) {
- def->features[val] = VIR_TRISTATE_SWITCH_ON;
- }
- break;
-
- case VIR_DOMAIN_FEATURE_HTM:
- case VIR_DOMAIN_FEATURE_NESTED_HV:
- case VIR_DOMAIN_FEATURE_CCF_ASSIST:
- if (!(tmp = virXMLPropString(nodes[i], "state"))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("missing state attribute '%s' of feature '%s'"),
- tmp, virDomainFeatureTypeToString(val));
- goto error;
- }
- if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown state attribute '%s' of feature '%s'"),
- tmp, virDomainFeatureTypeToString(val));
- goto error;
- }
- VIR_FREE(tmp);
- break;
-
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_FEATURE_LAST:
- break;
+ tmp = virXPathString("string(./memoryBacking/allocation/@mode)", ctxt);
+ if (tmp) {
+ if ((def->mem.allocation = virDomainMemoryAllocationTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown memoryBacking/allocation/mode '%s'"), tmp);
+ goto error;
}
+ VIR_FREE(tmp);
}
- VIR_FREE(nodes);
- if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
- int feature;
- int value;
- node = ctxt->node;
- if ((n = virXPathNodeSet("./features/hyperv/*", ctxt, &nodes)) < 0)
+ if (virXPathNode("./memoryBacking/hugepages", ctxt)) {
+ /* hugepages will be used */
+ if ((n = virXPathNodeSet("./memoryBacking/hugepages/page", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract hugepages nodes"));
goto error;
+ }
- for (i = 0; i < n; i++) {
- feature = virDomainHypervTypeFromString((const char *)nodes[i]->name);
- if (feature < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported HyperV Enlightenment feature: %s"),
- nodes[i]->name);
+ if (n) {
+ if (VIR_ALLOC_N(def->mem.hugepages, n) < 0)
goto error;
- }
-
- ctxt->node = nodes[i];
- if (!(tmp = virXMLPropString(nodes[i], "state"))) {
- virReportError(VIR_ERR_XML_ERROR,
- _("missing 'state' attribute for "
- "HyperV Enlightenment feature '%s'"),
- nodes[i]->name);
- goto error;
+ for (i = 0; i < n; i++) {
+ if (virDomainHugepagesParseXML(nodes[i], ctxt,
+ &def->mem.hugepages[i]) < 0)
+ goto error;
+ def->mem.nhugepages++;
}
- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("invalid value of state argument "
- "for HyperV Enlightenment feature '%s'"),
- nodes[i]->name);
+ VIR_FREE(nodes);
+ } else {
+ /* no hugepage pages */
+ if (VIR_ALLOC(def->mem.hugepages) < 0)
goto error;
- }
-
- VIR_FREE(tmp);
- def->hyperv_features[feature] = value;
-
- switch ((virDomainHyperv) feature) {
- case VIR_DOMAIN_HYPERV_RELAXED:
- case VIR_DOMAIN_HYPERV_VAPIC:
- case VIR_DOMAIN_HYPERV_VPINDEX:
- case VIR_DOMAIN_HYPERV_RUNTIME:
- case VIR_DOMAIN_HYPERV_SYNIC:
- case VIR_DOMAIN_HYPERV_STIMER:
- case VIR_DOMAIN_HYPERV_RESET:
- case VIR_DOMAIN_HYPERV_FREQUENCIES:
- case VIR_DOMAIN_HYPERV_REENLIGHTENMENT:
- case VIR_DOMAIN_HYPERV_TLBFLUSH:
- case VIR_DOMAIN_HYPERV_IPI:
- case VIR_DOMAIN_HYPERV_EVMCS:
- break;
- case VIR_DOMAIN_HYPERV_SPINLOCKS:
- if (value != VIR_TRISTATE_SWITCH_ON)
- break;
-
- if (virXPathUInt("string(./@retries)", ctxt,
- &def->hyperv_spinlocks) < 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid HyperV spinlock retry count"));
- goto error;
- }
+ def->mem.nhugepages = 1;
+ }
+ }
- if (def->hyperv_spinlocks < 0xFFF) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("HyperV spinlock retry count must be "
- "at least 4095"));
- goto error;
- }
- break;
+ if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
+ def->mem.nosharepages = true;
- case VIR_DOMAIN_HYPERV_VENDOR_ID:
- if (value != VIR_TRISTATE_SWITCH_ON)
- break;
+ if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
+ def->mem.locked = true;
- if (!(def->hyperv_vendor_id = virXMLPropString(nodes[i],
- "value"))) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing 'value' attribute for "
- "HyperV feature 'vendor_id'"));
- goto error;
- }
+ if (virXPathBoolean("boolean(./memoryBacking/discard)", ctxt))
+ def->mem.discard = VIR_TRISTATE_BOOL_YES;
- if (strlen(def->hyperv_vendor_id) > VIR_DOMAIN_HYPERV_VENDOR_ID_MAX) {
- virReportError(VIR_ERR_XML_ERROR,
- _("HyperV vendor_id value must not be more "
- "than %d characters."),
- VIR_DOMAIN_HYPERV_VENDOR_ID_MAX);
- goto error;
- }
+ /* Extract blkio cgroup tunables */
+ if (virXPathUInt("string(./blkiotune/weight)", ctxt,
+ &def->blkio.weight) < 0)
+ def->blkio.weight = 0;
- /* ensure that the string can be passed to qemu */
- if (strchr(def->hyperv_vendor_id, ',')) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("HyperV vendor_id value is invalid"));
- goto error;
- }
+ if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract blkiotune nodes"));
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
+ goto error;
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_HYPERV_LAST:
- break;
+ for (i = 0; i < n; i++) {
+ if (virDomainBlkioDeviceParseXML(nodes[i],
+ &def->blkio.devices[i]) < 0)
+ goto error;
+ def->blkio.ndevices++;
+ for (j = 0; j < i; j++) {
+ if (STREQ(def->blkio.devices[j].path,
+ def->blkio.devices[i].path)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("duplicate blkio device path '%s'"),
+ def->blkio.devices[i].path);
+ goto error;
}
}
- VIR_FREE(nodes);
- ctxt->node = node;
}
+ VIR_FREE(nodes);
- if (def->features[VIR_DOMAIN_HYPERV_STIMER] == VIR_TRISTATE_SWITCH_ON) {
- int value;
- if ((n = virXPathNodeSet("./features/hyperv/stimer/*", ctxt, &nodes)) < 0)
- goto error;
+ /* Extract other memory tunables */
+ if (virDomainParseMemoryLimit("./memtune/hard_limit[1]", NULL, ctxt,
+ &def->mem.hard_limit) < 0)
+ goto error;
- for (i = 0; i < n; i++) {
- if (STRNEQ((const char *)nodes[i]->name, "direct")) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported Hyper-V stimer feature: %s"),
- nodes[i]->name);
- goto error;
- }
+ if (virDomainParseMemoryLimit("./memtune/soft_limit[1]", NULL, ctxt,
+ &def->mem.soft_limit) < 0)
+ goto error;
- if (!(tmp = virXMLPropString(nodes[i], "state"))) {
- virReportError(VIR_ERR_XML_ERROR,
- _("missing 'state' attribute for "
- "Hyper-V stimer '%s' feature"), "direct");
- goto error;
- }
+ if (virDomainParseMemory("./memtune/min_guarantee[1]", NULL, ctxt,
+ &def->mem.min_guarantee, false, false) < 0)
+ goto error;
- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("invalid value of state argument "
- "for Hyper-V stimer '%s' feature"), "direct");
- goto error;
- }
+ if (virDomainParseMemoryLimit("./memtune/swap_hard_limit[1]", NULL, ctxt,
+ &def->mem.swap_hard_limit) < 0)
+ goto error;
- VIR_FREE(tmp);
- def->hyperv_stimer_direct = value;
- }
- VIR_FREE(nodes);
+ if (virDomainVcpuParse(def, ctxt, xmlopt) < 0)
+ goto error;
+
+ if (virDomainDefParseIOThreads(def, ctxt) < 0)
+ goto error;
+
+ /* Extract cpu tunables. */
+ if ((n = virXPathULongLong("string(./cputune/shares[1])", ctxt,
+ &def->cputune.shares)) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune shares value"));
+ goto error;
+ } else if (n == 0) {
+ def->cputune.sharesSpecified = true;
}
- if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
- int feature;
- int value;
- if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0)
- goto error;
+ if (virXPathULongLong("string(./cputune/period[1])", ctxt,
+ &def->cputune.period) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune period value"));
+ goto error;
+ }
- for (i = 0; i < n; i++) {
- feature = virDomainKVMTypeFromString((const char *)nodes[i]->name);
- if (feature < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported KVM feature: %s"),
- nodes[i]->name);
- goto error;
- }
+ if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
+ &def->cputune.quota) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune quota value"));
+ goto error;
+ }
- switch ((virDomainKVM) feature) {
- case VIR_DOMAIN_KVM_HIDDEN:
- case VIR_DOMAIN_KVM_DEDICATED:
- if (!(tmp = virXMLPropString(nodes[i], "state"))) {
- virReportError(VIR_ERR_XML_ERROR,
- _("missing 'state' attribute for "
- "KVM feature '%s'"),
- nodes[i]->name);
- goto error;
- }
+ if (virXPathULongLong("string(./cputune/global_period[1])", ctxt,
+ &def->cputune.global_period) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune global period value"));
+ goto error;
+ }
+
+ if (virXPathLongLong("string(./cputune/global_quota[1])", ctxt,
+ &def->cputune.global_quota) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune global quota value"));
+ goto error;
+ }
+
+ if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
+ &def->cputune.emulator_period) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune emulator period value"));
+ goto error;
+ }
+
+ if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
+ &def->cputune.emulator_quota) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune emulator quota value"));
+ goto error;
+ }
- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("invalid value of state argument "
- "for KVM feature '%s'"),
- nodes[i]->name);
- goto error;
- }
- VIR_FREE(tmp);
- def->kvm_features[feature] = value;
- break;
+ if (virXPathULongLong("string(./cputune/iothread_period[1])", ctxt,
+ &def->cputune.iothread_period) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune iothread period value"));
+ goto error;
+ }
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_KVM_LAST:
- break;
- }
- }
- VIR_FREE(nodes);
+ if (virXPathLongLong("string(./cputune/iothread_quota[1])", ctxt,
+ &def->cputune.iothread_quota) < -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("can't parse cputune iothread quota value"));
+ goto error;
}
- if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
- int feature;
- int value;
- g_autofree char *ptval = NULL;
+ if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0)
+ goto error;
- if ((n = virXPathNodeSet("./features/xen/*", ctxt, &nodes)) < 0)
+ for (i = 0; i < n; i++) {
+ if (virDomainVcpuPinDefParseXML(def, nodes[i]))
goto error;
+ }
+ VIR_FREE(nodes);
- for (i = 0; i < n; i++) {
- feature = virDomainXenTypeFromString((const char *)nodes[i]->name);
- if (feature < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported Xen feature: %s"),
- nodes[i]->name);
- goto error;
- }
-
- if (!(tmp = virXMLPropString(nodes[i], "state"))) {
- virReportError(VIR_ERR_XML_ERROR,
- _("missing 'state' attribute for "
- "Xen feature '%s'"),
- nodes[i]->name);
- goto error;
- }
+ if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract emulatorpin nodes"));
+ goto error;
+ }
- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("invalid value of state argument "
- "for Xen feature '%s'"),
- nodes[i]->name);
- goto error;
- }
+ if (n) {
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only one emulatorpin is supported"));
+ VIR_FREE(nodes);
+ goto error;
+ }
- VIR_FREE(tmp);
- def->xen_features[feature] = value;
+ if (!(def->cputune.emulatorpin = virDomainEmulatorPinDefParseXML(nodes[0])))
+ goto error;
+ }
+ VIR_FREE(nodes);
- switch ((virDomainXen) feature) {
- case VIR_DOMAIN_XEN_E820_HOST:
- break;
- case VIR_DOMAIN_XEN_PASSTHROUGH:
- if (value != VIR_TRISTATE_SWITCH_ON)
- break;
+ if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract iothreadpin nodes"));
+ goto error;
+ }
- if ((ptval = virXMLPropString(nodes[i], "mode"))) {
- int mode = virDomainXenPassthroughModeTypeFromString(ptval);
+ for (i = 0; i < n; i++) {
+ if (virDomainIOThreadPinDefParseXML(nodes[i], def) < 0)
+ goto error;
+ }
+ VIR_FREE(nodes);
- if (mode < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unsupported mode '%s' for Xen passthrough feature"),
- ptval);
- goto error;
- }
+ if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract vcpusched nodes"));
+ goto error;
+ }
- if (mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT &&
- mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("'mode' attribute for Xen feature "
- "'passthrough' must be 'sync_pt' or 'share_pt'"));
- goto error;
- }
- def->xen_passthrough_mode = mode;
- }
- break;
+ for (i = 0; i < n; i++) {
+ if (virDomainVcpuThreadSchedParse(nodes[i], def) < 0)
+ goto error;
+ }
+ VIR_FREE(nodes);
- /* coverity[dead_error_begin] */
- case VIR_DOMAIN_XEN_LAST:
- break;
- }
- }
- VIR_FREE(nodes);
+ if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract iothreadsched nodes"));
+ goto error;
}
- if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
- int rv = virDomainParseScaledValue("string(./features/smm/tseg)",
- "string(./features/smm/tseg/@unit)",
- ctxt,
- &def->tseg_size,
- 1024 * 1024, /* Defaults to mebibytes */
- ULLONG_MAX,
- false);
- if (rv < 0)
+ for (i = 0; i < n; i++) {
+ if (virDomainIOThreadSchedParse(nodes[i], def) < 0)
goto error;
- def->tseg_specified = rv;
}
+ VIR_FREE(nodes);
- if (def->features[VIR_DOMAIN_FEATURE_MSRS] == VIR_TRISTATE_SWITCH_ON) {
- if ((node = virXPathNode("./features/msrs", ctxt)) == NULL)
- goto error;
+ if ((n = virXPathNodeSet("./cputune/emulatorsched", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract emulatorsched nodes"));
+ goto error;
+ }
- if (!(tmp = virXMLPropString(node, "unknown"))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("missing 'unknown' attribute for feature '%s'"),
- virDomainFeatureTypeToString(VIR_DOMAIN_FEATURE_MSRS));
+ if (n) {
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only one emulatorsched is supported"));
+ VIR_FREE(nodes);
goto error;
}
- if ((def->msrs_features[VIR_DOMAIN_MSRS_UNKNOWN] = virDomainMsrsUnknownTypeFromString(tmp)) < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown 'unknown' value '%s'"),
- tmp);
+ if (virDomainEmulatorSchedParse(nodes[0], def) < 0)
goto error;
- }
- VIR_FREE(tmp);
}
+ VIR_FREE(nodes);
- if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
+ if ((n = virXPathNodeSet("./cputune/cachetune", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract cachetune nodes"));
goto error;
+ }
for (i = 0; i < n; i++) {
- int val = virDomainProcessCapsFeatureTypeFromString((const char *)nodes[i]->name);
- if (val < 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unexpected capability feature '%s'"), nodes[i]->name);
+ if (virDomainCachetuneDefParse(def, ctxt, nodes[i], flags) < 0)
goto error;
- }
+ }
+ VIR_FREE(nodes);
- if ((tmp = virXMLPropString(nodes[i], "state"))) {
- if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown state attribute '%s' of feature capability '%s'"),
- tmp, virDomainProcessCapsFeatureTypeToString(val));
- goto error;
- }
- VIR_FREE(tmp);
- } else {
- def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
- }
+ if ((n = virXPathNodeSet("./cputune/memorytune", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract memorytune nodes"));
+ goto error;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (virDomainMemorytuneDefParse(def, ctxt, nodes[i], flags) < 0)
+ goto error;
+ }
+ VIR_FREE(nodes);
+
+ if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
+ goto error;
+
+ if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
+ goto error;
+
+ if (virDomainNumaGetCPUCountTotal(def->numa) > virDomainDefGetVcpusMax(def)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Number of CPUs in <numa> exceeds the"
+ " <vcpu> count"));
+ goto error;
+ }
+
+ if (virDomainNumaGetMaxCPUID(def->numa) >= virDomainDefGetVcpusMax(def)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("CPU IDs in <numa> exceed the <vcpu> count"));
+ goto error;
+ }
+
+ if (virDomainNumatuneParseXML(def->numa,
+ def->placement_mode ==
+ VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
+ ctxt) < 0)
+ goto error;
+
+ if (virDomainNumatuneHasPlacementAuto(def->numa) &&
+ !def->cpumask && !virDomainDefHasVcpuPin(def) &&
+ !def->cputune.emulatorpin &&
+ !virDomainIOThreadIDArrayHasPin(def))
+ def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;
+
+ if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract resource nodes"));
+ goto error;
+ }
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only one resource element is supported"));
+ goto error;
}
+
+ if (n &&
+ !(def->resource = virDomainResourceDefParse(nodes[0], ctxt)))
+ goto error;
VIR_FREE(nodes);
+ if (virDomainFeaturesDefParse(def, ctxt) < 0)
+ goto error;
+
if (virDomainEventActionParseXML(ctxt, "on_reboot",
"string(./on_reboot[1])",
&def->onReboot,