From 809926db8f836eeb9f4482fd9f2b2a1838cb9a0f Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Sat, 6 Nov 2010 18:53:39 +0100 Subject: [PATCH] esx: Add support for memtune/min_guarantee Also add a test case for the VMX handling of it. --- src/esx/esx_driver.c | 133 +++++++++++++++++- src/esx/esx_vi.c | 31 ++++ src/esx/esx_vi.h | 3 + src/esx/esx_vi_types.c | 5 + src/esx/esx_vi_types.h | 1 + src/esx/esx_vmx.c | 49 +++++-- .../vmx2xmldata/vmx2xml-esx-in-the-wild-5.vmx | 2 +- .../vmx2xmldata/vmx2xml-esx-in-the-wild-5.xml | 3 + .../xml2vmxdata/xml2vmx-esx-in-the-wild-5.vmx | 26 ++++ .../xml2vmxdata/xml2vmx-esx-in-the-wild-5.xml | 37 +++++ tests/xml2vmxtest.c | 1 + 11 files changed, 280 insertions(+), 11 deletions(-) create mode 100644 tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.vmx create mode 100644 tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.xml diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index b3e1284119..059111531b 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4149,6 +4149,135 @@ esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags) +static int +esxDomainSetMemoryParameters(virDomainPtr domain, virMemoryParameterPtr params, + int nparams, unsigned int flags) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachineConfigSpec *spec = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + int i; + + virCheckFlags(0, -1); + + if (esxVI_EnsureSession(priv->primary) < 0) { + return -1; + } + + if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask + (priv->primary, domain->uuid, NULL, &virtualMachine, + priv->autoAnswer) < 0 || + esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 || + esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) { + goto cleanup; + } + + for (i = 0; i < nparams; ++i) { + if (STREQ (params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE) && + params[i].type == VIR_DOMAIN_SCHED_FIELD_ULLONG) { + if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) { + goto cleanup; + } + + spec->memoryAllocation->reservation->value = + params[i].value.ul / 1024; /* Scale from kilobytes to megabytes */ + } else { + ESX_ERROR(VIR_ERR_INVALID_ARG, _("Unknown field '%s'"), + params[i].field); + goto cleanup; + } + } + + if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec, + &task) < 0 || + esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid, + esxVI_Occurrence_RequiredItem, + priv->autoAnswer, &taskInfoState) < 0) { + goto cleanup; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not change memory parameters")); + goto cleanup; + } + + result = 0; + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_VirtualMachineConfigSpec_Free(&spec); + esxVI_ManagedObjectReference_Free(&task); + + return result; +} + + + +static int +esxDomainGetMemoryParameters(virDomainPtr domain, virMemoryParameterPtr params, + int *nparams, unsigned int flags) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_Long *reservation = NULL; + + virCheckFlags(0, -1); + + if (*nparams == 0) { + *nparams = 1; /* min_guarantee */ + return 0; + } + + if (*nparams < 1) { + ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", + _("Parameter array must have space for 1 item")); + return -1; + } + + if (esxVI_EnsureSession(priv->primary) < 0) { + return -1; + } + + if (esxVI_String_AppendValueToList + (&propertyNameList, "config.memoryAllocation.reservation") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_RequiredItem) < 0 || + esxVI_GetLong(virtualMachine, "config.memoryAllocation.reservation", + &reservation, esxVI_Occurrence_RequiredItem) < 0) { + goto cleanup; + } + + if (virStrcpyStatic(params[0].field, + VIR_DOMAIN_MEMORY_MIN_GUARANTEE) == NULL) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Field %s too big for destination"), + VIR_DOMAIN_MEMORY_MIN_GUARANTEE); + goto cleanup; + } + + params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG; + params[0].value.ul = reservation->value * 1024; /* Scale from megabytes to kilobytes */ + + *nparams = 1; + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_Long_Free(&reservation); + + return result; +} + + + static virDriver esxDriver = { VIR_DRV_ESX, "ESX", @@ -4251,8 +4380,8 @@ static virDriver esxDriver = { esxDomainRevertToSnapshot, /* domainRevertToSnapshot */ esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ - NULL, /* domainSetMemoryParameters */ - NULL, /* domainGetMemoryParameters */ + esxDomainSetMemoryParameters, /* domainSetMemoryParameters */ + esxDomainGetMemoryParameters, /* domainGetMemoryParameters */ }; diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index c450730219..9c966504b7 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -1840,6 +1840,37 @@ esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName, return 0; } +int +esxVI_GetLong(esxVI_ObjectContent *objectContent, const char *propertyName, + esxVI_Long **value, esxVI_Occurrence occurence) +{ + esxVI_DynamicProperty *dynamicProperty; + + if (value == NULL || *value != NULL) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, propertyName)) { + if (esxVI_Long_CastFromAnyType(dynamicProperty->val, value) < 0) { + return -1; + } + + break; + } + } + + if (*value == NULL && occurence == esxVI_Occurrence_RequiredItem) { + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Missing '%s' property"), propertyName); + return -1; + } + + return 0; +} + int diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index aa47e871f4..26779ad074 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -302,6 +302,9 @@ int esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName, esxVI_Boolean *value, esxVI_Occurrence occurence); +int esxVI_GetLong(esxVI_ObjectContent *objectContent, const char *propertyName, + esxVI_Long **value, esxVI_Occurrence occurence); + int esxVI_GetStringValue(esxVI_ObjectContent *objectContent, const char *propertyName, char **value, esxVI_Occurrence occurence); diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index bb791af128..ad45483b45 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -1235,6 +1235,11 @@ ESX_VI__TEMPLATE__VALIDATE(Long, /* esxVI_Long_AppendToList */ ESX_VI__TEMPLATE__LIST__APPEND(Long) +/* esxVI_Long_CastFromAnyType */ +ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(Long, +{ +}) + /* esxVI_Long_Serialize */ ESX_VI__TEMPLATE__SERIALIZE(Long, { diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h index f659361d9c..901eda0357 100644 --- a/src/esx/esx_vi_types.h +++ b/src/esx/esx_vi_types.h @@ -227,6 +227,7 @@ int esxVI_Long_Alloc(esxVI_Long **number); void esxVI_Long_Free(esxVI_Long **numberList); int esxVI_Long_Validate(esxVI_Long *number); int esxVI_Long_AppendToList(esxVI_Long **numberList, esxVI_Long *number); +int esxVI_Long_CastFromAnyType(esxVI_AnyType *anyType, esxVI_Long **number); int esxVI_Long_Serialize(esxVI_Long *number, const char *element, virBufferPtr output); int esxVI_Long_SerializeList(esxVI_Long *numberList, const char *element, diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c index b6b3954010..b853bdf913 100644 --- a/src/esx/esx_vmx.c +++ b/src/esx/esx_vmx.c @@ -50,6 +50,7 @@ def->uuid = <=> uuid.bios = "" def->name = <=> displayName = "" def->mem.max_balloon = <=> memsize = "" # must be a multiple of 4, defaults to 32 def->mem.cur_balloon = <=> sched.mem.max = "" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon +def->mem.min_guarantee = <=> sched.mem.minsize = "" # defaults to 0 def->maxvcpus = <=> numvcpus = "" # must be 1 or a multiple of 2, defaults to 1 def->cpumask = <=> sched.cpu.affinity = "" @@ -874,7 +875,8 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, long long config_version = 0; long long virtualHW_version = 0; long long memsize = 0; - long long memory = 0; + long long sched_mem_max = 0; + long long sched_mem_minsize = 0; long long numvcpus = 0; char *sched_cpu_affinity = NULL; char *guestOS = NULL; @@ -1047,22 +1049,38 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */ - /* vmx:sched.mem.max -> def:memory */ - if (esxUtil_GetConfigLong(conf, "sched.mem.max", &memory, memsize, + /* vmx:sched.mem.max -> def:mem.cur_balloon */ + if (esxUtil_GetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize, true) < 0) { goto cleanup; } - if (memory < 0) { - memory = memsize; + if (sched_mem_max < 0) { + sched_mem_max = memsize; } - def->mem.cur_balloon = memory * 1024; /* Scale from megabytes to kilobytes */ + def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */ if (def->mem.cur_balloon > def->mem.max_balloon) { def->mem.cur_balloon = def->mem.max_balloon; } + /* vmx:sched.mem.minsize -> def:mem.min_guarantee */ + if (esxUtil_GetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0, + true) < 0) { + goto cleanup; + } + + if (sched_mem_minsize < 0) { + sched_mem_minsize = 0; + } + + def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */ + + if (def->mem.min_guarantee > def->mem.max_balloon) { + def->mem.min_guarantee = def->mem.max_balloon; + } + /* vmx:numvcpus -> def:vcpus */ if (esxUtil_GetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) { goto cleanup; @@ -2594,12 +2612,12 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def, virBufferVSprintf(&buffer, "memsize = \"%d\"\n", (int)(def->mem.max_balloon / 1024)); - /* def:memory -> vmx:sched.mem.max */ + /* def:mem.cur_balloon -> vmx:sched.mem.max */ if (def->mem.cur_balloon < def->mem.max_balloon) { if (def->mem.cur_balloon <= 0 || def->mem.cur_balloon % 1024 != 0) { ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Expecting domain XML entry 'currentMemory' to be an " - "unsigned integer (multiple of 1024) but found %lld"), + "unsigned integer (multiple of 1024) but found %llu"), (unsigned long long)def->mem.cur_balloon); goto cleanup; } @@ -2609,6 +2627,21 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def, (int)(def->mem.cur_balloon / 1024)); } + /* def:mem.min_guarantee -> vmx:sched.mem.minsize */ + if (def->mem.min_guarantee > 0) { + if (def->mem.min_guarantee % 1024 != 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Expecting domain XML entry 'memtune/min_guarantee' to " + "be an unsigned integer (multiple of 1024) but found %llu"), + (unsigned long long)def->mem.min_guarantee); + goto cleanup; + } + + /* Scale from kilobytes to megabytes */ + virBufferVSprintf(&buffer, "sched.mem.minsize = \"%d\"\n", + (int)(def->mem.min_guarantee / 1024)); + } + /* def:maxvcpus -> vmx:numvcpus */ if (def->vcpus != def->maxvcpus) { ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.vmx b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.vmx index 6b11cc27e4..650f8fda5d 100644 --- a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.vmx +++ b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.vmx @@ -52,7 +52,7 @@ snapshot.action = "keep" sched.cpu.min = "0" sched.cpu.units = "mhz" sched.cpu.shares = "normal" -sched.mem.minsize = "0" +sched.mem.minsize = "256" sched.mem.shares = "normal" tools.upgrade.policy = "manual" cpuid.80000001.eax = "--------------------------------" diff --git a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.xml b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.xml index c3246735e9..d55bf6be7e 100644 --- a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.xml +++ b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-5.xml @@ -4,6 +4,9 @@ Centos 5.5 64bit Server 2097152 2097152 + + 262144 + 2 hvm diff --git a/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.vmx b/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.vmx new file mode 100644 index 0000000000..cc2485f7c7 --- /dev/null +++ b/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.vmx @@ -0,0 +1,26 @@ +.encoding = "UTF-8" +config.version = "8" +virtualHW.version = "4" +guestOS = "other-64" +uuid.bios = "42 3e 94 a9 a1 c7 b3 1d-71 61 76 c7 58 6c 83 0e" +displayName = "vmtest.local" +annotation = "Centos 5.5 64bit Server" +memsize = "2048" +sched.mem.minsize = "256" +numvcpus = "2" +scsi0.present = "true" +scsi0.virtualDev = "lsilogic" +scsi0:0.present = "true" +scsi0:0.deviceType = "scsi-hardDisk" +scsi0:0.fileName = "/vmfs/volumes/datastore/directory/vmtest-000001.vmdk" +ide0:0.present = "true" +ide0:0.deviceType = "cdrom-image" +ide0:0.fileName = "/vmfs/volumes/4af0231d-1eff559a-6369-0024e84773b6/isos/CentOS-5.5-x86_64-bin-DVD-1of2.iso" +floppy0.present = "false" +floppy1.present = "false" +ethernet0.present = "true" +ethernet0.virtualDev = "e1000" +ethernet0.networkName = "VM-LAN" +ethernet0.connectionType = "bridged" +ethernet0.addressType = "vpx" +ethernet0.generatedAddress = "00:50:56:BE:00:15" diff --git a/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.xml b/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.xml new file mode 100644 index 0000000000..d55bf6be7e --- /dev/null +++ b/tests/xml2vmxdata/xml2vmx-esx-in-the-wild-5.xml @@ -0,0 +1,37 @@ + + vmtest.local + 423e94a9-a1c7-b31d-7161-76c7586c830e + Centos 5.5 64bit Server + 2097152 + 2097152 + + 262144 + + 2 + + hvm + + + destroy + restart + destroy + + + + +
+ + + + +
+ + + + + + + + + + diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 0881ae9904..db7eb53e5b 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -269,6 +269,7 @@ mymain(int argc, char **argv) DO_TEST("esx-in-the-wild-2", "esx-in-the-wild-2", esxVI_ProductVersion_ESX35); DO_TEST("esx-in-the-wild-3", "esx-in-the-wild-3", esxVI_ProductVersion_ESX35); DO_TEST("esx-in-the-wild-4", "esx-in-the-wild-4", esxVI_ProductVersion_ESX35); + DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5", esxVI_ProductVersion_ESX35); DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1", esxVI_ProductVersion_ESX35); DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2", esxVI_ProductVersion_ESX35);