[PATCH 5/5] cpu: Introduce getHost supoort for ARM

Daniel P. Berrangé berrange at redhat.com
Mon Mar 30 11:26:58 UTC 2020


On Fri, Mar 27, 2020 at 04:52:25PM +0800, Zhenyu Zheng wrote:
> Introduce getHost support for ARM, use data from 'lscpu' cmd
> result. 'util-linux/lscpu' provided a very good translation of
> ARM cpu data start from release v2.32, use it directly to avoid
> re-implement the translation.

I'm a bit wary of this approach, because parsing the output of
command line tools is generally fragile  / liable to break in
future releases, since few tools guarantee that their output
format is stable for machine parsing.

How hard would it be to probe this directly in libvirt, as we
do on x86 arch.

> 
> Signed-of-by: Zhenyu Zheng <zhengzhenyulixi at gmail.com>
> ---
>  src/cpu/cpu_arm.c | 198 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 197 insertions(+), 1 deletion(-)
> 
> diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
> index 969025b5cf..30d9c0ae2e 100644
> --- a/src/cpu/cpu_arm.c
> +++ b/src/cpu/cpu_arm.c
> @@ -22,8 +22,11 @@
>  #include <config.h>
>  
>  #include "viralloc.h"
> +#include "virlog.h"
>  #include "cpu.h"
>  #include "cpu_map.h"
> +#include "vircommand.h"
> +#include "virfile.h"
>  #include "virstring.h"
>  #include "virxml.h"
>  #include "cpu_map.h"
> @@ -31,6 +34,14 @@
>  
>  #define VIR_FROM_THIS VIR_FROM_CPU
>  
> +VIR_LOG_INIT("cpu.cpu_arm");
> +
> +static const char *lsCpuPath = "/usr/bin/lscpu";
> +
> +#define LSCPU lsCpuPath
> +#define MAX_LSCPU_SIZE = (1024*1024)   /* 1MB limit for lscpu output */
> +
> +
>  static const virArch archs[] = {
>      VIR_ARCH_ARMV6L,
>      VIR_ARCH_ARMV7B,
> @@ -464,13 +475,198 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu)
>      return 0;
>  }
>  
> +static int
> +armCpuDataFromLsCpu(virCPUarmData *data)
> +{
> +    int ret = -1;
> +    char *outbuf = NULL;
> +    char *eol = NULL;
> +    const char *cur;
> +    virCommandPtr cmd = NULL;
> +    g_autofree char *lscpu = NULL;
> +
> +    if (!data)
> +        return ret;
> +
> +    lscpu = virFindFileInPath("lscpu");
> +    cmd = virCommandNew(lscpu);
> +    virCommandSetOutputBuffer(cmd, &outbuf);
> +
> +    if (virCommandRun(cmd, NULL) < 0) 
> +        goto cleanup;
> +
> +    if ((cur = strstr(outbuf, "Vendor ID")) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("there is no \"Vendor ID\" info in %s command result"), LSCPU);
> +        goto cleanup;
> +    }
> +    cur = strchr(cur, ':') + 1;
> +    eol = strchr(cur, '\n');
> +    virSkipSpaces(&cur);
> +    if (!eol)
> +        goto cleanup;
> +
> +    data->vendor_id = g_strndup(cur, eol - cur);
> +
> +    if ((cur = strstr(outbuf, "Model name")) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("there is no \"Model name\" info in %s command result"), LSCPU);
> +        goto cleanup;
> +    }
> +    cur = strchr(cur, ':') + 1;
> +    eol = strchr(cur, '\n');
> +    virSkipSpaces(&cur);
> +    if (!eol)
> +        goto cleanup;
> +
> +    data->model_name = g_strndup(cur, eol - cur);
> +
> +    if ((cur = strstr(outbuf, "Flags")) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("there is no \"Flags\" info in %s command result"), LSCPU);
> +        goto cleanup;
> +    }
> +    cur = strchr(cur, ':') + 1;
> +    eol = strchr(cur, '\n');
> +    virSkipSpaces(&cur);
> +    if (!eol)
> +        goto cleanup;
> +
> +    data->features = g_strndup(cur, eol - cur);
> +
> +    ret = 0;
> +
> + cleanup:
> +    virCommandFree(cmd);
> +    VIR_FREE(outbuf);
> +    return ret;
> +}
> +
> +static int
> +armCpuDataParseFeatures(virCPUDefPtr cpu,
> +                        const virCPUarmData *cpuData)
> +{
> +    int ret = -1;
> +    size_t i;
> +    char **features;
> +
> +    if (!cpu || !cpuData)
> +        return ret;
> +
> +    if (!(features = virStringSplitCount(cpuData->features, " ",
> +                                         0, &cpu->nfeatures)))
> +        return ret;
> +    if (cpu->nfeatures) {
> +        if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0)
> +            goto error;
> +
> +        for (i = 0; i < cpu->nfeatures; i++) {
> +            cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
> +            cpu->features[i].name = g_strdup(features[i]);
> +        }
> +    }
> +
> +    ret = 0;
> +
> + cleanup:
> +    virStringListFree(features);
> +    return ret;
> +
> + error:
> +    for (i = 0; i < cpu->nfeatures; i++)
> +        VIR_FREE(cpu->features[i].name);
> +    VIR_FREE(cpu->features);
> +    cpu->nfeatures = 0;
> +    goto cleanup;
> +}
> +
> +static int
> +armDecode(virCPUDefPtr cpu,
> +          const virCPUarmData *cpuData,
> +          virDomainCapsCPUModelsPtr models)
> +{
> +    virCPUarmMapPtr map;
> +    virCPUarmModelPtr model;
> +    virCPUarmVendorPtr vendor = NULL;
> +
> +    if (!cpuData || !(map = virCPUarmGetMap()))
> +        return -1;
> +
> +    if (!(model = armModelFind(map, cpuData->model_name))) {
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       _("Cannot find CPU model with name %s"),
> +                       cpuData->model_name);
> +        return -1;
> +    }
> +
> +    if (!virCPUModelIsAllowed(model->name, models)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("CPU model %s is not supported by hypervisor"),
> +                       model->name);
> +        return -1;
> +    }
> +
> +    cpu->model = g_strdup(model->name);
> +
> +    if (cpuData->vendor_id &&
> +        !(vendor = armVendorFindByName(map, cpuData->vendor_id))) {
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       _("Cannot find CPU vendor with vendor id %s"),
> +                       cpuData->vendor_id);
> +        return -1;
> +    }
> +
> +
> +    if (vendor)
> +        cpu->vendor = g_strdup(vendor->name);
> +
> +    if (cpuData->features &&
> +        armCpuDataParseFeatures(cpu, cpuData) < 0)
> +        return -1;
> +
> +    return 0;
> +}
> +
> +static int
> +armDecodeCPUData(virCPUDefPtr cpu,
> +                 const virCPUData *data,
> +                 virDomainCapsCPUModelsPtr models)
> +{
> +    return armDecode(cpu, &data->data.arm, models);
> +}
> +
> +static int
> +virCPUarmGetHost(virCPUDefPtr cpu,
> +                 virDomainCapsCPUModelsPtr models)
> +{
> +    virCPUDataPtr cpuData = NULL;
> +    int ret = -1;
> +
> +    if (virCPUarmDriverInitialize() < 0)
> +        goto cleanup;
> +
> +    if (!(cpuData = virCPUDataNew(archs[0])))
> +        goto cleanup;
> +
> +    if (armCpuDataFromLsCpu(&cpuData->data.arm) < 0)
> +        goto cleanup;
> +
> +    ret = armDecodeCPUData(cpu, cpuData, models);
> +
> + cleanup:
> +    virCPUarmDataFree(cpuData);
> +    return ret;
> +}
> +
>  struct cpuArchDriver cpuDriverArm = {
>      .name = "arm",
>      .arch = archs,
>      .narch = G_N_ELEMENTS(archs),
>      .compare = virCPUarmCompare,
> -    .decode = NULL,
> +    .decode = armDecodeCPUData,
>      .encode = NULL,
> +    .dataFree = virCPUarmDataFree,
> +    .getHost = virCPUarmGetHost,
>      .baseline = virCPUarmBaseline,
>      .update = virCPUarmUpdate,
>      .validateFeatures = virCPUarmValidateFeatures,
> -- 
> 2.26.0.windows.1
> 
> 

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the libvir-list mailing list