Ejemplo n.º 1
0
static void virQEMUDriverConfigDispose(void *obj)
{
    virQEMUDriverConfigPtr cfg = obj;


    virStringFreeList(cfg->cgroupDeviceACL);

    VIR_FREE(cfg->configBaseDir);
    VIR_FREE(cfg->configDir);
    VIR_FREE(cfg->autostartDir);
    VIR_FREE(cfg->logDir);
    VIR_FREE(cfg->stateDir);

    VIR_FREE(cfg->libDir);
    VIR_FREE(cfg->cacheDir);
    VIR_FREE(cfg->saveDir);
    VIR_FREE(cfg->snapshotDir);
    VIR_FREE(cfg->channelTargetDir);
    VIR_FREE(cfg->nvramDir);

    VIR_FREE(cfg->vncTLSx509certdir);
    VIR_FREE(cfg->vncListen);
    VIR_FREE(cfg->vncPassword);
    VIR_FREE(cfg->vncSASLdir);

    VIR_FREE(cfg->spiceTLSx509certdir);
    VIR_FREE(cfg->spiceListen);
    VIR_FREE(cfg->spicePassword);
    VIR_FREE(cfg->spiceSASLdir);

    while (cfg->nhugetlbfs) {
        cfg->nhugetlbfs--;
        VIR_FREE(cfg->hugetlbfs[cfg->nhugetlbfs].mnt_dir);
    }
    VIR_FREE(cfg->hugetlbfs);
    VIR_FREE(cfg->bridgeHelperName);

    VIR_FREE(cfg->saveImageFormat);
    VIR_FREE(cfg->dumpImageFormat);
    VIR_FREE(cfg->autoDumpPath);

    virStringFreeList(cfg->securityDriverNames);

    VIR_FREE(cfg->lockManagerName);

    virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares);
}
Ejemplo n.º 2
0
static int
fillXenCaps(virDomainCapsPtr domCaps)
{
    virFirmwarePtr *firmwares;
    int ret = -1;

    if (VIR_ALLOC_N(firmwares, 2) < 0)
        return ret;

    if (VIR_ALLOC(firmwares[0]) < 0 || VIR_ALLOC(firmwares[1]) < 0)
        goto cleanup;
    if (VIR_STRDUP(firmwares[0]->name, "/usr/lib/xen/boot/hvmloader") < 0 ||
        VIR_STRDUP(firmwares[1]->name, "/usr/lib/xen/boot/ovmf.bin") < 0)
        goto cleanup;

    if (libxlMakeDomainCapabilities(domCaps, firmwares, 2) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virFirmwareFreeList(firmwares, 2);
    return ret;
}
Ejemplo n.º 3
0
static int
fillAllCaps(virDomainCapsPtr domCaps)
{
    virDomainCapsOSPtr os = &domCaps->os;
    virDomainCapsLoaderPtr loader = &os->loader;
    virDomainCapsCPUPtr cpu = &domCaps->cpu;
    virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
    virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics;
    virDomainCapsDeviceVideoPtr video = &domCaps->video;
    virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev;
    virCPUDef host = {
        .type = VIR_CPU_TYPE_HOST,
        .arch = VIR_ARCH_X86_64,
        .model = (char *) "host",
        .vendor = (char *) "CPU Vendorrr",
    };

    domCaps->maxvcpus = 255;
    os->supported = true;

    loader->supported = true;
    SET_ALL_BITS(loader->type);
    SET_ALL_BITS(loader->readonly);
    if (fillStringValues(&loader->values,
                         "/foo/bar",
                         "/tmp/my_path",
                         NULL) < 0)
        return -1;

    cpu->hostPassthrough = true;
    cpu->hostModel = virCPUDefCopy(&host);
    if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) ||
        virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1,
                                  VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 ||
        virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1,
                                  VIR_DOMCAPS_CPU_USABLE_NO) < 0 ||
        virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1,
                                  VIR_DOMCAPS_CPU_USABLE_YES) < 0)
        return -1;

    disk->supported = true;
    SET_ALL_BITS(disk->diskDevice);
    SET_ALL_BITS(disk->bus);

    graphics->supported = true;
    SET_ALL_BITS(graphics->type);

    video->supported = true;
    SET_ALL_BITS(video->modelType);

    hostdev->supported = true;
    SET_ALL_BITS(hostdev->mode);
    SET_ALL_BITS(hostdev->startupPolicy);
    SET_ALL_BITS(hostdev->subsysType);
    SET_ALL_BITS(hostdev->capsType);
    SET_ALL_BITS(hostdev->pciBackend);
    return 0;
}


#if WITH_QEMU
# include "testutilsqemu.h"

static virCPUDef aarch64Cpu = {
    .sockets = 1,
    .cores = 1,
    .threads = 1,
};

static virCPUDef ppc64leCpu = {
    .type = VIR_CPU_TYPE_HOST,
    .arch = VIR_ARCH_PPC64LE,
    .model = (char *) "POWER8",
    .sockets = 1,
    .cores = 1,
    .threads = 1,
};

static virCPUDef x86Cpu = {
    .type = VIR_CPU_TYPE_HOST,
    .arch = VIR_ARCH_X86_64,
    .model = (char *) "Broadwell",
    .sockets = 1,
    .cores = 1,
    .threads = 1,
};

static virCPUDef s390Cpu = {
    .type = VIR_CPU_TYPE_HOST,
    .arch = VIR_ARCH_S390X,
    .sockets = 1,
    .cores = 1,
    .threads = 1,
};

static int
fakeHostCPU(virCapsPtr caps,
            virArch arch)
{
    virCPUDefPtr cpu;

    switch (arch) {
    case VIR_ARCH_AARCH64:
        cpu = &aarch64Cpu;
        break;

    case VIR_ARCH_PPC64LE:
        cpu = &ppc64leCpu;
        break;

    case VIR_ARCH_X86_64:
        cpu = &x86Cpu;
        break;

    case VIR_ARCH_S390X:
        cpu = &s390Cpu;
        break;

    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "cannot fake host CPU for arch %s",
                       virArchToString(arch));
        return -1;
    }

    if (!(caps->host.cpu = virCPUDefCopy(cpu)))
        return -1;

    return 0;
}

static int
fillQemuCaps(virDomainCapsPtr domCaps,
             const char *name,
             const char *arch,
             const char *machine,
             virQEMUDriverConfigPtr cfg)
{
    int ret = -1;
    char *path = NULL;
    virCapsPtr caps = NULL;
    virQEMUCapsPtr qemuCaps = NULL;
    virDomainCapsLoaderPtr loader = &domCaps->os.loader;

    if (!(caps = virCapabilitiesNew(domCaps->arch, false, false)) ||
        fakeHostCPU(caps, domCaps->arch) < 0)
        goto cleanup;

    if (virAsprintf(&path, "%s/qemucapabilitiesdata/%s.%s.xml",
                    abs_srcdir, name, arch) < 0 ||
        !(qemuCaps = qemuTestParseCapabilities(caps, path)))
        goto cleanup;

    if (machine &&
        VIR_STRDUP(domCaps->machine,
                   virQEMUCapsGetCanonicalMachine(qemuCaps, machine)) < 0)
        goto cleanup;

    if (!domCaps->machine &&
        VIR_STRDUP(domCaps->machine,
                   virQEMUCapsGetDefaultMachine(qemuCaps)) < 0)
        goto cleanup;

    if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps,
                                  cfg->firmwares,
                                  cfg->nfirmwares) < 0)
        goto cleanup;

    /* The function above tries to query host's KVM & VFIO capabilities by
     * calling qemuHostdevHostSupportsPassthroughLegacy() and
     * qemuHostdevHostSupportsPassthroughVFIO() which, however, can't be
     * successfully mocked as they are not exposed as internal APIs. Therefore,
     * instead of mocking set the expected values here by hand. */
    VIR_DOMAIN_CAPS_ENUM_SET(domCaps->hostdev.pciBackend,
                             VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
                             VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,
                             VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);

    /* As of f05b6a918e28 we are expecting to see OVMF_CODE.fd file which
     * may not exists everywhere. */
    while (loader->values.nvalues)
        VIR_FREE(loader->values.values[--loader->values.nvalues]);

    if (fillStringValues(&loader->values,
                         "/usr/share/AAVMF/AAVMF_CODE.fd",
                         "/usr/share/OVMF/OVMF_CODE.fd",
                         NULL) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virObjectUnref(caps);
    virObjectUnref(qemuCaps);
    VIR_FREE(path);
    return ret;
}
#endif /* WITH_QEMU */


#ifdef WITH_LIBXL
# include "testutilsxen.h"

static int
fillXenCaps(virDomainCapsPtr domCaps)
{
    virFirmwarePtr *firmwares;
    int ret = -1;

    if (VIR_ALLOC_N(firmwares, 2) < 0)
        return ret;

    if (VIR_ALLOC(firmwares[0]) < 0 || VIR_ALLOC(firmwares[1]) < 0)
        goto cleanup;
    if (VIR_STRDUP(firmwares[0]->name, "/usr/lib/xen/boot/hvmloader") < 0 ||
        VIR_STRDUP(firmwares[1]->name, "/usr/lib/xen/boot/ovmf.bin") < 0)
        goto cleanup;

    if (libxlMakeDomainCapabilities(domCaps, firmwares, 2) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virFirmwareFreeList(firmwares, 2);
    return ret;
}
#endif /* WITH_LIBXL */

#ifdef WITH_BHYVE
# include "bhyve/bhyve_capabilities.h"

static int
fillBhyveCaps(virDomainCapsPtr domCaps, unsigned int *bhyve_caps)
{
    virDomainCapsStringValuesPtr firmwares = NULL;
    int ret = -1;

    if (VIR_ALLOC(firmwares) < 0)
        return -1;

    if (fillStringValues(firmwares, "/foo/bar", "/foo/baz", NULL) < 0)
        goto cleanup;

    if (virBhyveDomainCapsFill(domCaps, *bhyve_caps, firmwares) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(firmwares);
    return ret;
}
#endif /* WITH_BHYVE */

enum testCapsType {
    CAPS_NONE,
    CAPS_ALL,
    CAPS_QEMU,
    CAPS_LIBXL,
    CAPS_BHYVE,
};

struct testData {
    const char *name;
    const char *emulator;
    const char *machine;
    const char *arch;
    virDomainVirtType type;
    enum testCapsType capsType;
    const char *capsName;
    void *capsOpaque;
};

static int
test_virDomainCapsFormat(const void *opaque)
{
    const struct testData *data = opaque;
    virDomainCapsPtr domCaps = NULL;
    char *path = NULL;
    char *domCapsXML = NULL;
    int ret = -1;

    if (virAsprintf(&path, "%s/domaincapsschemadata/%s.xml",
                    abs_srcdir, data->name) < 0)
        goto cleanup;

    if (!(domCaps = virDomainCapsNew(data->emulator, data->machine,
                                     virArchFromString(data->arch),
                                     data->type)))
        goto cleanup;

    switch (data->capsType) {
    case CAPS_NONE:
        break;

    case CAPS_ALL:
        if (fillAllCaps(domCaps) < 0)
            goto cleanup;
        break;

    case CAPS_QEMU:
#if WITH_QEMU
        if (fillQemuCaps(domCaps, data->capsName, data->arch, data->machine,
                         data->capsOpaque) < 0)
            goto cleanup;
#endif
        break;

    case CAPS_LIBXL:
#if WITH_LIBXL
        if (fillXenCaps(domCaps) < 0)
            goto cleanup;
#endif
        break;
    case CAPS_BHYVE:
#if WITH_BHYVE
        if (fillBhyveCaps(domCaps, data->capsOpaque) < 0)
            goto cleanup;
#endif
        break;
    }

    if (!(domCapsXML = virDomainCapsFormat(domCaps)))
        goto cleanup;

    if (virTestCompareToFile(domCapsXML, path) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(domCapsXML);
    VIR_FREE(path);
    virObjectUnref(domCaps);
    return ret;
}

static int
mymain(void)
{
    int ret = 0;

#if WITH_BHYVE
    unsigned int bhyve_caps = 0;
#endif

#if WITH_QEMU
    virQEMUDriverConfigPtr cfg = virQEMUDriverConfigNew(false);

    if (!cfg)
        return EXIT_FAILURE;
#endif

#define DO_TEST(Name, Emulator, Machine, Arch, Type, CapsType)          \
    do {                                                                \
        struct testData data = {                                        \
            .name = Name,                                               \
            .emulator = Emulator,                                       \
            .machine = Machine,                                         \
            .arch = Arch,                                               \
            .type = Type,                                               \
            .capsType = CapsType,                                       \
        };                                                              \
        if (virTestRun(Name, test_virDomainCapsFormat, &data) < 0)      \
            ret = -1;                                                   \
    } while (0)

#define DO_TEST_QEMU(Name, CapsName, Emulator, Machine, Arch, Type)     \
    do {                                                                \
        char *name = NULL;                                              \
        if (virAsprintf(&name, "qemu_%s%s%s.%s",                        \
                        Name,                                           \
                        Machine ? "-" : "", Machine ? Machine : "",     \
                        Arch) < 0) {                                    \
            ret = -1;                                                   \
            break;                                                      \
        }                                                               \
        struct testData data = {                                        \
            .name = name,                                               \
            .emulator = Emulator,                                       \
            .machine = Machine,                                         \
            .arch = Arch,                                               \
            .type = Type,                                               \
            .capsType = CAPS_QEMU,                                      \
            .capsName = CapsName,                                       \
            .capsOpaque = cfg,                                          \
        };                                                              \
        if (virTestRun(name, test_virDomainCapsFormat, &data) < 0)      \
            ret = -1;                                                   \
        VIR_FREE(name);                                                 \
    } while (0)

#define DO_TEST_LIBXL(Name, Emulator, Machine, Arch, Type)              \
    do {                                                                \
        struct testData data = {                                        \
            .name = Name,                                               \
            .emulator = Emulator,                                       \
            .machine = Machine,                                         \
            .arch = Arch,                                               \
            .type = Type,                                               \
            .capsType = CAPS_LIBXL,                                     \
        };                                                              \
        if (virTestRun(Name, test_virDomainCapsFormat, &data) < 0)     \
            ret = -1;                                                   \
    } while (0)

    DO_TEST("basic", "/bin/emulatorbin", "my-machine-type",
            "x86_64", VIR_DOMAIN_VIRT_UML, CAPS_NONE);
    DO_TEST("full", "/bin/emulatorbin", "my-machine-type",
            "x86_64", VIR_DOMAIN_VIRT_KVM, CAPS_ALL);

#define DO_TEST_BHYVE(Name, Emulator, BhyveCaps, Type) \
    do {                                                                \
        char *name = NULL;                                              \
        if (virAsprintf(&name, "bhyve_%s.x86_64", Name) < 0) {          \
             ret = -1;                                                  \
             break;                                                     \
        }                                                               \
        struct testData data = {                                        \
            .name = name,                                               \
            .emulator = Emulator,                                       \
            .arch = "x86_64",                                           \
            .type = Type,                                               \
            .capsType = CAPS_BHYVE,                                     \
            .capsOpaque = BhyveCaps,                                    \
        };                                                              \
        if (virTestRun(name, test_virDomainCapsFormat, &data) < 0)      \
            ret = -1;                                                   \
        VIR_FREE(name);                                                 \
    } while (0)

#if WITH_QEMU

    DO_TEST_QEMU("1.7.0", "caps_1.7.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.6.0", "caps_2.6.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.6.0", "caps_2.6.0-gicv2",
                 "/usr/bin/qemu-system-aarch64", NULL,
                 "aarch64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.6.0-gicv2", "caps_2.6.0-gicv2",
                 "/usr/bin/qemu-system-aarch64", "virt",
                 "aarch64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.6.0-gicv3", "caps_2.6.0-gicv3",
                 "/usr/bin/qemu-system-aarch64", "virt",
                 "aarch64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.6.0", "caps_2.6.0",
                 "/usr/bin/qemu-system-ppc64", NULL,
                 "ppc64le", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.8.0", "caps_2.8.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.8.0-tcg", "caps_2.8.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_QEMU);

    DO_TEST_QEMU("2.9.0", "caps_2.9.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.9.0", "caps_2.9.0",
                 "/usr/bin/qemu-system-x86_64", "q35",
                 "x86_64", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.9.0-tcg", "caps_2.9.0",
                 "/usr/bin/qemu-system-x86_64", NULL,
                 "x86_64", VIR_DOMAIN_VIRT_QEMU);

    DO_TEST_QEMU("2.7.0", "caps_2.7.0",
                 "/usr/bin/qemu-system-s390x", NULL,
                 "s390x", VIR_DOMAIN_VIRT_KVM);

    DO_TEST_QEMU("2.8.0", "caps_2.8.0",
                 "/usr/bin/qemu-system-s390x", NULL,
                 "s390x", VIR_DOMAIN_VIRT_KVM);

    virObjectUnref(cfg);

#endif /* WITH_QEMU */

#if WITH_LIBXL

# ifdef LIBXL_HAVE_PVUSB
#  define LIBXL_XENPV_CAPS "libxl-xenpv-usb"
#  define LIBXL_XENFV_CAPS "libxl-xenfv-usb"
# else
#  define LIBXL_XENPV_CAPS "libxl-xenpv"
#  define LIBXL_XENFV_CAPS "libxl-xenfv"
# endif

    DO_TEST_LIBXL(LIBXL_XENPV_CAPS, "/usr/bin/qemu-system-x86_64",
                  "xenpv", "x86_64", VIR_DOMAIN_VIRT_XEN);
    DO_TEST_LIBXL(LIBXL_XENFV_CAPS, "/usr/bin/qemu-system-x86_64",
                  "xenfv", "x86_64", VIR_DOMAIN_VIRT_XEN);

#endif /* WITH_LIBXL */

#if WITH_BHYVE
    DO_TEST_BHYVE("basic", "/usr/sbin/bhyve", &bhyve_caps, VIR_DOMAIN_VIRT_BHYVE);

    bhyve_caps |= BHYVE_CAP_LPC_BOOTROM;
    DO_TEST_BHYVE("uefi", "/usr/sbin/bhyve", &bhyve_caps, VIR_DOMAIN_VIRT_BHYVE);

    bhyve_caps |= BHYVE_CAP_FBUF;
    DO_TEST_BHYVE("fbuf", "/usr/sbin/bhyve", &bhyve_caps, VIR_DOMAIN_VIRT_BHYVE);
#endif /* WITH_BHYVE */

    return ret;
}
Ejemplo n.º 4
0
int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
                                const char *filename)
{
    virConfPtr conf = NULL;
    virConfValuePtr p;
    int ret = -1;
    size_t i;
    char *stdioHandler = NULL;

    /* Just check the file is readable before opening it, otherwise
     * libvirt emits an error.
     */
    if (access(filename, R_OK) == -1) {
        VIR_INFO("Could not read qemu config file %s", filename);
        return 0;
    }

    if (!(conf = virConfReadFile(filename, 0)))
        goto cleanup;

#define CHECK_TYPE(name, typ)                         \
    if (p && p->type != (typ)) {                      \
        virReportError(VIR_ERR_INTERNAL_ERROR,        \
                       "%s: %s: expected type " #typ, \
                       filename, (name));             \
        goto cleanup;                                 \
    }

#define CHECK_TYPE_ALT(name, type1, type2)                      \
    if (p && (p->type != (type1) && p->type != (type2))) {      \
        virReportError(VIR_ERR_INTERNAL_ERROR,                  \
                       "%s: %s: expected type " #type1,         \
                       filename, (name));                       \
        goto cleanup;                                           \
    }

#define GET_VALUE_LONG(NAME, VAR)                               \
    p = virConfGetValue(conf, NAME);                            \
    CHECK_TYPE_ALT(NAME, VIR_CONF_LONG, VIR_CONF_ULONG);        \
    if (p)                                                      \
        VAR = p->l;

#define GET_VALUE_ULONG(NAME, VAR)    \
    p = virConfGetValue(conf, NAME);  \
    CHECK_TYPE(NAME, VIR_CONF_ULONG); \
    if (p)                            \
        VAR = p->l;

#define GET_VALUE_BOOL(NAME, VAR)     \
    p = virConfGetValue(conf, NAME);  \
    CHECK_TYPE(NAME, VIR_CONF_ULONG); \
    if (p)                            \
        VAR = p->l != 0;

#define GET_VALUE_STR(NAME, VAR)           \
    p = virConfGetValue(conf, NAME);       \
    CHECK_TYPE(NAME, VIR_CONF_STRING);     \
    if (p && p->str) {                     \
        VIR_FREE(VAR);                     \
        if (VIR_STRDUP(VAR, p->str) < 0)   \
            goto cleanup;                  \
    }

    GET_VALUE_BOOL("vnc_auto_unix_socket", cfg->vncAutoUnixSocket);
    GET_VALUE_BOOL("vnc_tls", cfg->vncTLS);
    GET_VALUE_BOOL("vnc_tls_x509_verify", cfg->vncTLSx509verify);
    GET_VALUE_STR("vnc_tls_x509_cert_dir", cfg->vncTLSx509certdir);
    GET_VALUE_STR("vnc_listen", cfg->vncListen);
    GET_VALUE_STR("vnc_password", cfg->vncPassword);
    GET_VALUE_BOOL("vnc_sasl", cfg->vncSASL);
    GET_VALUE_STR("vnc_sasl_dir", cfg->vncSASLdir);
    GET_VALUE_BOOL("vnc_allow_host_audio", cfg->vncAllowHostAudio);
    GET_VALUE_BOOL("nographics_allow_host_audio", cfg->nogfxAllowHostAudio);

    p = virConfGetValue(conf, "security_driver");
    if (p && p->type == VIR_CONF_LIST) {
        size_t len, j;
        virConfValuePtr pp;

        /* Calc length and check items */
        for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
            if (pp->type != VIR_CONF_STRING) {
                virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                               _("security_driver must be a list of strings"));
                goto cleanup;
            }
        }

        if (VIR_ALLOC_N(cfg->securityDriverNames, len + 1) < 0)
            goto cleanup;

        for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
            for (j = 0; j < i; j++) {
                if (STREQ(pp->str, cfg->securityDriverNames[j])) {
                    virReportError(VIR_ERR_CONF_SYNTAX,
                                   _("Duplicate security driver %s"), pp->str);
                    goto cleanup;
                }
            }
            if (VIR_STRDUP(cfg->securityDriverNames[i], pp->str) < 0)
                goto cleanup;
        }
        cfg->securityDriverNames[len] = NULL;
    } else {
        CHECK_TYPE("security_driver", VIR_CONF_STRING);
        if (p && p->str) {
            if (VIR_ALLOC_N(cfg->securityDriverNames, 2) < 0)
                goto cleanup;
            if (VIR_STRDUP(cfg->securityDriverNames[0], p->str) < 0)
                goto cleanup;

            cfg->securityDriverNames[1] = NULL;
        }
    }

    GET_VALUE_BOOL("security_default_confined", cfg->securityDefaultConfined);
    GET_VALUE_BOOL("security_require_confined", cfg->securityRequireConfined);

    GET_VALUE_BOOL("spice_tls", cfg->spiceTLS);
    GET_VALUE_STR("spice_tls_x509_cert_dir", cfg->spiceTLSx509certdir);
    GET_VALUE_BOOL("spice_sasl", cfg->spiceSASL);
    GET_VALUE_STR("spice_sasl_dir", cfg->spiceSASLdir);
    GET_VALUE_STR("spice_listen", cfg->spiceListen);
    GET_VALUE_STR("spice_password", cfg->spicePassword);
    GET_VALUE_BOOL("spice_auto_unix_socket", cfg->spiceAutoUnixSocket);


    GET_VALUE_ULONG("remote_websocket_port_min", cfg->webSocketPortMin);
    if (cfg->webSocketPortMin < QEMU_WEBSOCKET_PORT_MIN) {
        /* if the port is too low, we can't get the display name
         * to tell to vnc (usually subtract 5700, e.g. localhost:1
         * for port 5701) */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: remote_websocket_port_min: port must be greater "
                         "than or equal to %d"),
                        filename, QEMU_WEBSOCKET_PORT_MIN);
        goto cleanup;
    }

    GET_VALUE_ULONG("remote_websocket_port_max", cfg->webSocketPortMax);
    if (cfg->webSocketPortMax > QEMU_WEBSOCKET_PORT_MAX ||
        cfg->webSocketPortMax < cfg->webSocketPortMin) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("%s: remote_websocket_port_max: port must be between "
                          "the minimal port and %d"),
                       filename, QEMU_WEBSOCKET_PORT_MAX);
        goto cleanup;
    }

    if (cfg->webSocketPortMin > cfg->webSocketPortMax) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("%s: remote_websocket_port_min: min port must not be "
                          "greater than max port"), filename);
        goto cleanup;
    }

    GET_VALUE_ULONG("remote_display_port_min", cfg->remotePortMin);
    if (cfg->remotePortMin < QEMU_REMOTE_PORT_MIN) {
        /* if the port is too low, we can't get the display name
         * to tell to vnc (usually subtract 5900, e.g. localhost:1
         * for port 5901) */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: remote_display_port_min: port must be greater "
                         "than or equal to %d"),
                        filename, QEMU_REMOTE_PORT_MIN);
        goto cleanup;
    }

    GET_VALUE_ULONG("remote_display_port_max", cfg->remotePortMax);
    if (cfg->remotePortMax > QEMU_REMOTE_PORT_MAX ||
        cfg->remotePortMax < cfg->remotePortMin) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("%s: remote_display_port_max: port must be between "
                          "the minimal port and %d"),
                       filename, QEMU_REMOTE_PORT_MAX);
        goto cleanup;
    }

    if (cfg->remotePortMin > cfg->remotePortMax) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("%s: remote_display_port_min: min port must not be "
                          "greater than max port"), filename);
        goto cleanup;
    }

    GET_VALUE_ULONG("migration_port_min", cfg->migrationPortMin);
    if (cfg->migrationPortMin <= 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: migration_port_min: port must be greater than 0"),
                        filename);
        goto cleanup;
    }

    GET_VALUE_ULONG("migration_port_max", cfg->migrationPortMax);
    if (cfg->migrationPortMax > 65535 ||
        cfg->migrationPortMax < cfg->migrationPortMin) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("%s: migration_port_max: port must be between "
                          "the minimal port %d and 65535"),
                       filename, cfg->migrationPortMin);
        goto cleanup;
    }

    p = virConfGetValue(conf, "user");
    CHECK_TYPE("user", VIR_CONF_STRING);
    if (p && p->str &&
        virGetUserID(p->str, &cfg->user) < 0)
        goto cleanup;

    p = virConfGetValue(conf, "group");
    CHECK_TYPE("group", VIR_CONF_STRING);
    if (p && p->str &&
        virGetGroupID(p->str, &cfg->group) < 0)
        goto cleanup;

    GET_VALUE_BOOL("dynamic_ownership", cfg->dynamicOwnership);

    p = virConfGetValue(conf, "cgroup_controllers");
    CHECK_TYPE("cgroup_controllers", VIR_CONF_LIST);
    if (p) {
        cfg->cgroupControllers = 0;
        virConfValuePtr pp;
        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
            int ctl;
            if (pp->type != VIR_CONF_STRING) {
                virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                               _("cgroup_controllers must be a "
                                 "list of strings"));
                goto cleanup;
            }

            if ((ctl = virCgroupControllerTypeFromString(pp->str)) < 0) {
                virReportError(VIR_ERR_CONF_SYNTAX,
                               _("Unknown cgroup controller '%s'"), pp->str);
                goto cleanup;
            }
            cfg->cgroupControllers |= (1 << ctl);
        }
    }

    p = virConfGetValue(conf, "cgroup_device_acl");
    CHECK_TYPE("cgroup_device_acl", VIR_CONF_LIST);
    if (p) {
        int len = 0;
        virConfValuePtr pp;
        for (pp = p->list; pp; pp = pp->next)
            len++;
        if (VIR_ALLOC_N(cfg->cgroupDeviceACL, 1+len) < 0)
            goto cleanup;

        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
            if (pp->type != VIR_CONF_STRING) {
                virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                               _("cgroup_device_acl must be a "
                                 "list of strings"));
                goto cleanup;
            }
            if (VIR_STRDUP(cfg->cgroupDeviceACL[i], pp->str) < 0)
                goto cleanup;
        }
        cfg->cgroupDeviceACL[i] = NULL;
    }

    GET_VALUE_STR("save_image_format", cfg->saveImageFormat);
    GET_VALUE_STR("dump_image_format", cfg->dumpImageFormat);
    GET_VALUE_STR("snapshot_image_format", cfg->snapshotImageFormat);

    GET_VALUE_STR("auto_dump_path", cfg->autoDumpPath);
    GET_VALUE_BOOL("auto_dump_bypass_cache", cfg->autoDumpBypassCache);
    GET_VALUE_BOOL("auto_start_bypass_cache", cfg->autoStartBypassCache);

    /* Some crazy backcompat. Back in the old days, this was just a pure
     * string. We must continue supporting it. These days however, this may be
     * an array of strings. */
    p = virConfGetValue(conf, "hugetlbfs_mount");
    if (p) {
        /* There already might be something autodetected. Avoid leaking it. */
        while (cfg->nhugetlbfs) {
            cfg->nhugetlbfs--;
            VIR_FREE(cfg->hugetlbfs[cfg->nhugetlbfs].mnt_dir);
        }
        VIR_FREE(cfg->hugetlbfs);

        if (p->type == VIR_CONF_LIST) {
            size_t len = 0;
            virConfValuePtr pp = p->list;

            /* Calc length and check items */
            while (pp) {
                if (pp->type != VIR_CONF_STRING) {
                    virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                                   _("hugetlbfs_mount must be a list of strings"));
                    goto cleanup;
                }
                len++;
                pp = pp->next;
            }

            if (len && VIR_ALLOC_N(cfg->hugetlbfs, len) < 0)
                goto cleanup;
            cfg->nhugetlbfs = len;

            pp = p->list;
            len = 0;
            while (pp) {
                if (virQEMUDriverConfigHugeTLBFSInit(&cfg->hugetlbfs[len],
                                                     pp->str, !len) < 0)
                    goto cleanup;
                len++;
                pp = pp->next;
            }
        } else {
            CHECK_TYPE("hugetlbfs_mount", VIR_CONF_STRING);
            if (STRNEQ(p->str, "")) {
                if (VIR_ALLOC_N(cfg->hugetlbfs, 1) < 0)
                    goto cleanup;
                cfg->nhugetlbfs = 1;
                if (virQEMUDriverConfigHugeTLBFSInit(&cfg->hugetlbfs[0],
                                                     p->str, true) < 0)
                    goto cleanup;
            }
        }
    }

    GET_VALUE_STR("bridge_helper", cfg->bridgeHelperName);

    GET_VALUE_BOOL("mac_filter", cfg->macFilter);

    GET_VALUE_BOOL("relaxed_acs_check", cfg->relaxedACS);
    GET_VALUE_BOOL("clear_emulator_capabilities", cfg->clearEmulatorCapabilities);
    GET_VALUE_BOOL("allow_disk_format_probing", cfg->allowDiskFormatProbing);
    GET_VALUE_BOOL("set_process_name", cfg->setProcessName);
    GET_VALUE_ULONG("max_processes", cfg->maxProcesses);
    GET_VALUE_ULONG("max_files", cfg->maxFiles);

    GET_VALUE_STR("lock_manager", cfg->lockManagerName);
    GET_VALUE_STR("stdio_handler", stdioHandler);
    if (stdioHandler) {
        if (STREQ(stdioHandler, "logd")) {
            cfg->stdioLogD = true;
        } else if (STREQ(stdioHandler, "file")) {
            cfg->stdioLogD = false;
        } else {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown stdio handler %s"),
                           stdioHandler);
            VIR_FREE(stdioHandler);
            goto cleanup;
        }
        VIR_FREE(stdioHandler);
    }

    GET_VALUE_ULONG("max_queued", cfg->maxQueuedJobs);

    GET_VALUE_LONG("keepalive_interval", cfg->keepAliveInterval);
    GET_VALUE_ULONG("keepalive_count", cfg->keepAliveCount);

    GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox);

    GET_VALUE_STR("migration_host", cfg->migrateHost);
    virStringStripIPv6Brackets(cfg->migrateHost);
    if (cfg->migrateHost &&
        (STRPREFIX(cfg->migrateHost, "localhost") ||
         virSocketAddrIsNumericLocalhost(cfg->migrateHost))) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("migration_host must not be the address of"
                         " the local machine: %s"),
                       cfg->migrateHost);
        goto cleanup;
    }

    GET_VALUE_STR("migration_address", cfg->migrationAddress);
    virStringStripIPv6Brackets(cfg->migrationAddress);
    if (cfg->migrationAddress &&
        (STRPREFIX(cfg->migrationAddress, "localhost") ||
         virSocketAddrIsNumericLocalhost(cfg->migrationAddress))) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("migration_address must not be the address of"
                         " the local machine: %s"),
                       cfg->migrationAddress);
        goto cleanup;
    }

    GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp);

    if ((p = virConfGetValue(conf, "nvram"))) {
        size_t len;
        virConfValuePtr pp;

        CHECK_TYPE("nvram", VIR_CONF_LIST);

        virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares);
        /* Calc length and check items */
        for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
            if (pp->type != VIR_CONF_STRING) {
                virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                               _("nvram must be a list of strings"));
                goto cleanup;
            }
        }

        if (len && VIR_ALLOC_N(cfg->firmwares, len) < 0)
            goto cleanup;
        cfg->nfirmwares = len;

        for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
            if (VIR_ALLOC(cfg->firmwares[i]) < 0)
                goto cleanup;
            if (virFirmwareParse(pp->str, cfg->firmwares[i]) < 0)
                goto cleanup;
        }
    }

    ret = 0;

 cleanup:
    virConfFree(conf);
    return ret;
}