[PATCH v2 0/6] hyperv: implement vCPU APIs

Changes since v1: * use an enum for the real CPU constants * remove the forward declaration Here's a GitLab merge request, if you'd prefer to review it there: https://gitlab.com/iammattcoleman/libvirt/-/merge_requests/11 Matt Coleman (6): domain: introduce constants for virVcpuInfo->cpu state values hyperv: implement domainGetVcpus hyperv: implement domainGetVcpusFlags hyperv: implement domainGetMaxVcpus hyperv: implement domainSetVcpus and domainSetVcpusFlags news: implement vCPU APIs in the Hyper-V driver NEWS.rst | 8 +- include/libvirt/libvirt-domain.h | 7 +- src/hyperv/hyperv_driver.c | 175 +++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 4 deletions(-) -- 2.27.0

Signed-off-by: Matt Coleman <matt@datto.com> --- include/libvirt/libvirt-domain.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index b3310729bf..e1095a193d 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1910,12 +1910,17 @@ typedef enum { # endif } virVcpuState; +typedef enum { + VIR_VCPU_INFO_CPU_OFFLINE = -1, /* the vCPU is offline */ + VIR_VCPU_INFO_CPU_UNAVAILABLE = -2, /* the hypervisor does not expose real CPU information */ +} virVcpuHostCpuState; + typedef struct _virVcpuInfo virVcpuInfo; struct _virVcpuInfo { unsigned int number; /* virtual CPU number */ int state; /* value from virVcpuState */ unsigned long long cpuTime; /* CPU time used, in nanoseconds */ - int cpu; /* real CPU number, or -1 if offline */ + int cpu; /* real CPU number, or one of the values from virVcpuHostCpuState */ }; typedef virVcpuInfo *virVcpuInfoPtr; -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 9fda0d6047..56d6da80e0 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1078,6 +1078,61 @@ hypervDomainGetState(virDomainPtr domain, int *state, int *reason, } +static int +hypervDomainGetVcpus(virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen) +{ + int count = 0; + int vcpu_number; + hypervPrivate *priv = domain->conn->privateData; + Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor *vproc = NULL; + + /* Hyper-V does not allow setting CPU affinity: all cores will be used */ + if (cpumaps && maplen > 0) + memset(cpumaps, 0xFF, maxinfo * maplen); + + for (vcpu_number = 0; vcpu_number < maxinfo; vcpu_number++) { + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + + /* Name format: <domain_name>:Hv VP <vCPU_number> */ + g_autofree char *vcpu_name = g_strdup_printf("%s:Hv VP %d", domain->name, vcpu_number); + + /* try to free objects from previous iteration */ + hypervFreeObject(priv, (hypervObject *)vproc); + vproc = NULL; + + /* get the info */ + virBufferEscapeSQL(&query, + WIN32_PERFRAWDATA_HVSTATS_HYPERVHYPERVISORVIRTUALPROCESSOR_WQL_SELECT + "WHERE Name = '%s'", + vcpu_name); + + if (hypervGetWmiClass(Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor, &vproc) < 0) + continue; + + /* fill structure info */ + info[vcpu_number].number = vcpu_number; + if (vproc) { + info[vcpu_number].state = VIR_VCPU_RUNNING; + info[vcpu_number].cpuTime = vproc->data->PercentTotalRunTime * 100; + info[vcpu_number].cpu = VIR_VCPU_INFO_CPU_UNAVAILABLE; + } else { + info[vcpu_number].state = VIR_VCPU_OFFLINE; + info[vcpu_number].cpuTime = 0LLU; + info[vcpu_number].cpu = VIR_VCPU_INFO_CPU_OFFLINE; + } + count++; + } + + hypervFreeObject(priv, (hypervObject *)vproc); + + return count; +} + + static char * hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) { @@ -1875,6 +1930,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* 3.6.0 */ .domainGetInfo = hypervDomainGetInfo, /* 0.9.5 */ .domainGetState = hypervDomainGetState, /* 0.9.5 */ + .domainGetVcpus = hypervDomainGetVcpus, /* 6.10.0 */ .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.5 */ .connectListDefinedDomains = hypervConnectListDefinedDomains, /* 0.9.5 */ .connectNumOfDefinedDomains = hypervConnectNumOfDefinedDomains, /* 0.9.5 */ -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 56d6da80e0..3c436d9465 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1078,6 +1078,57 @@ hypervDomainGetState(virDomainPtr domain, int *state, int *reason, } +static int +hypervDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_ProcessorSettingData *proc_sd = NULL; + Msvm_VirtualSystemSettingData *vssd = NULL; + + virCheckFlags(VIR_DOMAIN_VCPU_LIVE | + VIR_DOMAIN_VCPU_CONFIG | + VIR_DOMAIN_VCPU_MAXIMUM, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + /* Start by getting the Msvm_ComputerSystem */ + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + /* Check @flags to see if we are to query a running domain, and fail + * if that domain is not running */ + if (flags & VIR_DOMAIN_VCPU_LIVE && + computerSystem->data->EnabledState != MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not active")); + goto cleanup; + } + + /* Check @flags to see if we are to return the maximum vCPU limit */ + if (flags & VIR_DOMAIN_VCPU_MAXIMUM) { + result = hypervConnectGetMaxVcpus(domain->conn, NULL); + goto cleanup; + } + + if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) < 0) + goto cleanup; + + if (hypervGetProcessorSD(priv, vssd->data->InstanceID, &proc_sd) < 0) + goto cleanup; + + result = proc_sd->data->VirtualQuantity; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + hypervFreeObject(priv, (hypervObject *)vssd); + hypervFreeObject(priv, (hypervObject *)proc_sd); + + return result; +} + + static int hypervDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, @@ -1930,6 +1981,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* 3.6.0 */ .domainGetInfo = hypervDomainGetInfo, /* 0.9.5 */ .domainGetState = hypervDomainGetState, /* 0.9.5 */ + .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 6.10.0 */ .domainGetVcpus = hypervDomainGetVcpus, /* 6.10.0 */ .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.5 */ .connectListDefinedDomains = hypervConnectListDefinedDomains, /* 0.9.5 */ -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 3c436d9465..44ef4c53e0 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1627,6 +1627,16 @@ hypervDomainIsActive(virDomainPtr domain) } +static int +hypervDomainGetMaxVcpus(virDomainPtr dom) +{ + if (hypervDomainIsActive(dom)) + return hypervDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)); + else + return hypervConnectGetMaxVcpus(dom->conn, NULL); +} + + static int hypervDomainIsPersistent(virDomainPtr domain G_GNUC_UNUSED) { @@ -1983,6 +1993,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainGetState = hypervDomainGetState, /* 0.9.5 */ .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 6.10.0 */ .domainGetVcpus = hypervDomainGetVcpus, /* 6.10.0 */ + .domainGetMaxVcpus = hypervDomainGetMaxVcpus, /* 6.10.0 */ .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.5 */ .connectListDefinedDomains = hypervConnectListDefinedDomains, /* 0.9.5 */ .connectNumOfDefinedDomains = hypervConnectNumOfDefinedDomains, /* 0.9.5 */ -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 44ef4c53e0..40739595ac 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1078,6 +1078,60 @@ hypervDomainGetState(virDomainPtr domain, int *state, int *reason, } +static int +hypervDomainSetVcpusFlags(virDomainPtr domain, + unsigned int nvcpus, + unsigned int flags) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_VirtualSystemSettingData *vssd = NULL; + Msvm_ProcessorSettingData *proc_sd = NULL; + g_autoptr(GHashTable) vcpuResource = NULL; + g_autofree char *nvcpus_str = g_strdup_printf("%u", nvcpus); + + virCheckFlags(0, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) < 0) + goto cleanup; + + if (hypervGetProcessorSD(priv, vssd->data->InstanceID, &proc_sd) < 0) + goto cleanup; + + vcpuResource = hypervCreateEmbeddedParam(Msvm_ProcessorSettingData_WmiInfo); + if (!vcpuResource) + goto cleanup; + + if (hypervSetEmbeddedProperty(vcpuResource, "VirtualQuantity", nvcpus_str) < 0) + goto cleanup; + + if (hypervSetEmbeddedProperty(vcpuResource, "InstanceID", proc_sd->data->InstanceID) < 0) + goto cleanup; + + if (hypervMsvmVSMSModifyResourceSettings(priv, &vcpuResource, + Msvm_ProcessorSettingData_WmiInfo) < 0) + goto cleanup; + + result = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)vssd); + hypervFreeObject(priv, (hypervObject *)proc_sd); + + return result; +} + + +static int +hypervDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) +{ + return hypervDomainSetVcpusFlags(domain, nvcpus, 0); +} + + static int hypervDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) { @@ -1991,6 +2045,8 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* 3.6.0 */ .domainGetInfo = hypervDomainGetInfo, /* 0.9.5 */ .domainGetState = hypervDomainGetState, /* 0.9.5 */ + .domainSetVcpus = hypervDomainSetVcpus, /* 6.10.0 */ + .domainSetVcpusFlags = hypervDomainSetVcpusFlags, /* 6.10.0 */ .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 6.10.0 */ .domainGetVcpus = hypervDomainGetVcpus, /* 6.10.0 */ .domainGetMaxVcpus = hypervDomainGetMaxVcpus, /* 6.10.0 */ -- 2.27.0

Signed-off-by: Matt Coleman <matt@datto.com> --- NEWS.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 8b60a5da11..3fd3ce4cb9 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -16,9 +16,11 @@ v6.10.0 (unreleased) * hyperv: implement new APIs The `virDomainGetMaxMemory()``, ``virDomainSetMaxMemory()``, - ``virDomainGetSchedulerType()``, ``virDomainGetSchedulerParameters()``, and - ``virDomainGetSchedulerParametersFlags()`` APIs have been implemented in - the Hyper-V driver. + ``virDomainGetSchedulerType()``, ``virDomainGetSchedulerParameters()``, + ``virDomainGetSchedulerParametersFlags()``, ``virDomainGetVcpus()``, + ``virDomainGetVcpusFlags()``, ``virDomainGetMaxVcpus()``, + ``virDomainSetVcpus()``, and ``virDomainSetVcpusFlags()`` APIs have been + implemented in the Hyper-V driver. * **Improvements** -- 2.27.0

On 11/12/20 6:10 PM, Matt Coleman wrote:
Changes since v1: * use an enum for the real CPU constants * remove the forward declaration
Here's a GitLab merge request, if you'd prefer to review it there: https://gitlab.com/iammattcoleman/libvirt/-/merge_requests/11
Matt Coleman (6): domain: introduce constants for virVcpuInfo->cpu state values hyperv: implement domainGetVcpus hyperv: implement domainGetVcpusFlags hyperv: implement domainGetMaxVcpus hyperv: implement domainSetVcpus and domainSetVcpusFlags news: implement vCPU APIs in the Hyper-V driver
NEWS.rst | 8 +- include/libvirt/libvirt-domain.h | 7 +- src/hyperv/hyperv_driver.c | 175 +++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 4 deletions(-)
Thanks for addressing my review. Reviewed-by: Michal Privoznik <mprivozn@redhat.com> and pushed. Michal
participants (2)
-
Matt Coleman
-
Michal Privoznik