Exemple #1
0
/**
 * virArchFromHost:
 *
 * Return the host architecture. Prefer this to the
 * uname 'machine' field, since this will canonicalize
 * architecture names like 'amd64' into 'x86_64'.
 */
virArch virArchFromHost(void)
{
    struct utsname ut;
    virArch arch;

    uname(&ut);

    /* Some special cases we need to handle first
     * for non-canonical names */
    if (strlen(ut.machine) == 4 &&
        ut.machine[0] == 'i' &&
        ut.machine[2] == '8' &&
        ut.machine[3] == '6' &&
        ut.machine[4] == '\0') {
        arch = VIR_ARCH_I686;
    } else if (STREQ(ut.machine, "amd64")) {
        arch = VIR_ARCH_X86_64;
    } else {
        /* Otherwise assume the canonical name */
        if ((arch = virArchFromString(ut.machine)) == VIR_ARCH_NONE) {
            VIR_WARN("Unknown host arch %s, report to [email protected]",
                     ut.machine);
        }
    }

    VIR_DEBUG("Mapped %s to %d (%s)",
              ut.machine, arch, virArchToString(arch));

    return arch;
}
Exemple #2
0
/**
 * cpuGetModels:
 *
 * @archName: CPU architecture string
 * @models: where to store the list of supported models
 *
 * Fetches all CPU models supported by libvirt on @archName.
 *
 * Returns number of supported CPU models or -1 on error.
 */
int
cpuGetModels(const char *archName, char ***models)
{
    struct cpuArchDriver *driver;
    virArch arch;

    VIR_DEBUG("arch=%s", archName);

    arch = virArchFromString(archName);
    if (arch == VIR_ARCH_NONE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("cannot find architecture %s"),
                       archName);
        return -1;
    }

    driver = cpuGetSubDriver(arch);
    if (driver == NULL) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("cannot find a driver for the architecture %s"),
                       archName);
        return -1;
    }

    if (!driver->getModels) {
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("CPU driver for %s has no CPU model support"),
                       virArchToString(arch));
        return -1;
    }

    return driver->getModels(models);
}
Exemple #3
0
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;
    }

    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
testQemuCapsCopy(const void *opaque)
{
    int ret = -1;
    const testQemuData *data = opaque;
    char *capsFile = NULL;
    virCapsPtr caps = NULL;
    virQEMUCapsPtr orig = NULL;
    virQEMUCapsPtr copy = NULL;
    char *actual = NULL;

    if (virAsprintf(&capsFile, "%s/qemucapabilitiesdata/%s.%s.xml",
                    abs_srcdir, data->base, data->archName) < 0)
        goto cleanup;

    if (!(caps = virCapabilitiesNew(virArchFromString(data->archName),
                                    false, false)))
        goto cleanup;

    if (!(orig = qemuTestParseCapabilities(caps, capsFile)))
        goto cleanup;

    if (!(copy = virQEMUCapsNewCopy(orig)))
        goto cleanup;

    if (!(actual = virQEMUCapsFormatCache(copy)))
        goto cleanup;

    if (virTestCompareToFile(actual, capsFile) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    VIR_FREE(capsFile);
    virObjectUnref(caps);
    virObjectUnref(orig);
    virObjectUnref(copy);
    VIR_FREE(actual);
    return ret;
}
Exemple #5
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;
}
Exemple #6
0
virDomainDefPtr
lxcParseConfigString(const char *config,
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt)
{
    virDomainDefPtr vmdef = NULL;
    virConfPtr properties = NULL;
    virConfValuePtr value;

    if (!(properties = virConfReadMem(config, 0, VIR_CONF_FLAG_LXC_FORMAT)))
        return NULL;

    if (!(vmdef = virDomainDefNew()))
        goto error;

    if (virUUIDGenerate(vmdef->uuid) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to generate uuid"));
        goto error;
    }

    vmdef->id = -1;
    virDomainDefSetMemoryTotal(vmdef, 64 * 1024);

    vmdef->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
    vmdef->onCrash = VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY;
    vmdef->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
    vmdef->virtType = VIR_DOMAIN_VIRT_LXC;

    /* Value not handled by the LXC driver, setting to
     * minimum required to make XML parsing pass */
    if (virDomainDefSetVcpusMax(vmdef, 1) < 0)
        goto error;

    if (virDomainDefSetVcpus(vmdef, 1) < 0)
        goto error;

    vmdef->nfss = 0;
    vmdef->os.type = VIR_DOMAIN_OSTYPE_EXE;

    if ((value = virConfGetValue(properties, "lxc.arch")) && value->str) {
        virArch arch = virArchFromString(value->str);
        if (arch == VIR_ARCH_NONE && STREQ(value->str, "x86"))
            arch = VIR_ARCH_I686;
        else if (arch == VIR_ARCH_NONE && STREQ(value->str, "amd64"))
            arch = VIR_ARCH_X86_64;
        vmdef->os.arch = arch;
    }

    if (VIR_STRDUP(vmdef->os.init, "/sbin/init") < 0)
        goto error;

    if (!(value = virConfGetValue(properties, "lxc.utsname")) ||
            !value->str || (VIR_STRDUP(vmdef->name, value->str) < 0))
        goto error;
    if (!vmdef->name && (VIR_STRDUP(vmdef->name, "unnamed") < 0))
        goto error;

    if (lxcSetRootfs(vmdef, properties) < 0)
        goto error;

    /* Look for fstab: we shouldn't have it */
    if (virConfGetValue(properties, "lxc.mount")) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("lxc.mount found, use lxc.mount.entry lines instead"));
        goto error;
    }

    /* Loop over lxc.mount.entry to add filesystem devices for them */
    if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0)
        goto error;

    /* Network configuration */
    if (lxcConvertNetworkSettings(vmdef, properties) < 0)
        goto error;

    /* Consoles */
    if (lxcCreateConsoles(vmdef, properties) < 0)
        goto error;

    /* lxc.id_map */
    if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 0)
        goto error;

    /* lxc.cgroup.memory.* */
    if (lxcSetMemTune(vmdef, properties) < 0)
        goto error;

    /* lxc.cgroup.cpu.* */
    if (lxcSetCpuTune(vmdef, properties) < 0)
        goto error;

    /* lxc.cgroup.cpuset.* */
    if (lxcSetCpusetTune(vmdef, properties) < 0)
        goto error;

    /* lxc.cgroup.blkio.* */
    if (lxcSetBlkioTune(vmdef, properties) < 0)
        goto error;

    /* lxc.cap.drop */
    lxcSetCapDrop(vmdef, properties);

    if (virDomainDefPostParse(vmdef, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
                              xmlopt) < 0)
        goto cleanup;

    goto cleanup;

 error:
    virDomainDefFree(vmdef);
    vmdef = NULL;

 cleanup:
    virConfFree(properties);

    return vmdef;
}
Exemple #7
0
virCPUDefPtr
virCPUDefParseXML(xmlNodePtr node,
                  xmlXPathContextPtr ctxt,
                  enum virCPUType mode)
{
    virCPUDefPtr def;
    xmlNodePtr *nodes = NULL;
    int n;
    size_t i;
    char *cpuMode;
    char *fallback = NULL;
    char *vendor_id = NULL;

    if (!xmlStrEqual(node->name, BAD_CAST "cpu")) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("XML does not contain expected 'cpu' element"));
        return NULL;
    }

    if (VIR_ALLOC(def) < 0)
        return NULL;

    if (mode == VIR_CPU_TYPE_AUTO) {
        if (virXPathBoolean("boolean(./arch)", ctxt)) {
            if (virXPathBoolean("boolean(./@match)", ctxt)) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("'arch' element element cannot be used inside 'cpu'"
                                 " element with 'match' attribute'"));
                goto error;
            }
            def->type = VIR_CPU_TYPE_HOST;
        } else {
            def->type = VIR_CPU_TYPE_GUEST;
        }
    } else {
        def->type = mode;
    }

    if ((cpuMode = virXMLPropString(node, "mode"))) {
        if (def->type == VIR_CPU_TYPE_HOST) {
            VIR_FREE(cpuMode);
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Attribute mode is only allowed for guest CPU"));
            goto error;
        } else {
            def->mode = virCPUModeTypeFromString(cpuMode);

            if (def->mode < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Invalid mode attribute '%s'"),
                               cpuMode);
                VIR_FREE(cpuMode);
                goto error;
            }
            VIR_FREE(cpuMode);
        }
    } else {
        if (def->type == VIR_CPU_TYPE_HOST)
            def->mode = -1;
        else
            def->mode = VIR_CPU_MODE_CUSTOM;
    }

    if (def->type == VIR_CPU_TYPE_GUEST) {
        char *match = virXMLPropString(node, "match");

        if (!match) {
            if (virXPathBoolean("boolean(./model)", ctxt))
                def->match = VIR_CPU_MATCH_EXACT;
            else
                def->match = -1;
        } else {
            def->match = virCPUMatchTypeFromString(match);
            VIR_FREE(match);

            if (def->match < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid match attribute for CPU "
                                 "specification"));
                goto error;
            }
        }
    }

    if (def->type == VIR_CPU_TYPE_HOST) {
        char *arch = virXPathString("string(./arch[1])", ctxt);
        if (!arch) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing CPU architecture"));
            goto error;
        }
        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown architecture %s"), arch);
            VIR_FREE(arch);
            goto error;
        }
        VIR_FREE(arch);
    }

    if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
        def->type == VIR_CPU_TYPE_HOST) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Missing CPU model name"));
        goto error;
    }

    if (def->type == VIR_CPU_TYPE_GUEST &&
        def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {

        if ((fallback = virXPathString("string(./model[1]/@fallback)", ctxt))) {
            if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid fallback attribute"));
                goto error;
            }
        }

        if ((vendor_id = virXPathString("string(./model[1]/@vendor_id)",
                                        ctxt))) {
            if (strlen(vendor_id) != VIR_CPU_VENDOR_ID_LENGTH) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("vendor_id must be exactly %d characters long"),
                               VIR_CPU_VENDOR_ID_LENGTH);
                goto error;
            }

            /* ensure that the string can be passed to qemu*/
            if (strchr(vendor_id, ',')) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("vendor id is invalid"));
                    goto error;
            }

            def->vendor_id = vendor_id;
            vendor_id = NULL;
        }
    }

    def->vendor = virXPathString("string(./vendor[1])", ctxt);
    if (def->vendor && !def->model) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("CPU vendor specified without CPU model"));
        goto error;
    }

    if (virXPathNode("./topology[1]", ctxt)) {
        int ret;
        unsigned long ul;

        ret = virXPathULong("string(./topology[1]/@sockets)",
                            ctxt, &ul);
        if (ret < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'sockets' attribute in CPU topology"));
            goto error;
        }
        def->sockets = (unsigned int) ul;

        ret = virXPathULong("string(./topology[1]/@cores)",
                            ctxt, &ul);
        if (ret < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'cores' attribute in CPU topology"));
            goto error;
        }
        def->cores = (unsigned int) ul;

        ret = virXPathULong("string(./topology[1]/@threads)",
                            ctxt, &ul);
        if (ret < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'threads' attribute in CPU topology"));
            goto error;
        }
        def->threads = (unsigned int) ul;

        if (!def->sockets || !def->cores || !def->threads) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU topology"));
            goto error;
        }
    }

    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
        goto error;

    if (n > 0) {
        if (!def->model && def->mode != VIR_CPU_MODE_HOST_MODEL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Non-empty feature list specified without "
                             "CPU model"));
            goto error;
        }

        if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                         def->nfeatures, n) < 0)
            goto error;

        def->nfeatures = n;
    }

    for (i = 0; i < n; i++) {
        char *name;
        int policy; /* enum virDomainCPUFeaturePolicy */
        size_t j;

        if (def->type == VIR_CPU_TYPE_GUEST) {
            char *strpolicy;

            strpolicy = virXMLPropString(nodes[i], "policy");
            if (strpolicy == NULL)
                policy = VIR_CPU_FEATURE_REQUIRE;
            else
                policy = virCPUFeaturePolicyTypeFromString(strpolicy);
            VIR_FREE(strpolicy);

            if (policy < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid CPU feature policy"));
                goto error;
            }
        } else {
            policy = -1;
        }

        if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) {
            VIR_FREE(name);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU feature name"));
            goto error;
        }

        for (j = 0; j < i; j++) {
            if (STREQ(name, def->features[j].name)) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("CPU feature `%s' specified more than once"),
                               name);
                VIR_FREE(name);
                goto error;
            }
        }

        def->features[i].name = name;
        def->features[i].policy = policy;
    }

    if (virXPathNode("./numa[1]", ctxt)) {
        VIR_FREE(nodes);
        n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes);
        if (n <= 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("NUMA topology defined without NUMA cells"));
            goto error;
        }

        if (VIR_RESIZE_N(def->cells, def->ncells_max,
                         def->ncells, n) < 0)
            goto error;

        def->ncells = n;

        for (i = 0; i < n; i++) {
            char *cpus, *memory;
            int ret, ncpus = 0;

            def->cells[i].cellid = i;
            cpus = virXMLPropString(nodes[i], "cpus");
            if (!cpus) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Missing 'cpus' attribute in NUMA cell"));
                goto error;
            }
            def->cells[i].cpustr = cpus;

            ncpus = virBitmapParse(cpus, 0, &def->cells[i].cpumask,
                                   VIR_DOMAIN_CPUMASK_LEN);
            if (ncpus <= 0)
                goto error;
            def->cells_cpus += ncpus;

            memory = virXMLPropString(nodes[i], "memory");
            if (!memory) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Missing 'memory' attribute in NUMA cell"));
                goto error;
            }

            ret  = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem);
            if (ret == -1) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Invalid 'memory' attribute in NUMA cell"));
                VIR_FREE(memory);
                goto error;
            }
            VIR_FREE(memory);
        }
    }

cleanup:
    VIR_FREE(fallback);
    VIR_FREE(vendor_id);
    VIR_FREE(nodes);
    return def;

error:
    virCPUDefFree(def);
    def = NULL;
    goto cleanup;
}
Exemple #8
0
/*
 * Parses CPU definition XML from a node pointed to by @xpath. If @xpath is
 * NULL, the current node of @ctxt is used (i.e., it is a shortcut to ".").
 *
 * Missing <cpu> element in the XML document is not considered an error unless
 * @xpath is NULL in which case the function expects it was provided with a
 * valid <cpu> element already. In other words, the function returns success
 * and sets @cpu to NULL if @xpath is not NULL and the node pointed to by
 * @xpath is not found.
 *
 * Returns 0 on success, -1 on error.
 */
int
virCPUDefParseXML(xmlXPathContextPtr ctxt,
                  const char *xpath,
                  virCPUType type,
                  virCPUDefPtr *cpu)
{
    virCPUDefPtr def = NULL;
    xmlNodePtr *nodes = NULL;
    xmlNodePtr oldnode = ctxt->node;
    int n;
    size_t i;
    char *cpuMode;
    char *fallback = NULL;
    char *vendor_id = NULL;
    int ret = -1;

    *cpu = NULL;

    if (xpath && !(ctxt->node = virXPathNode(xpath, ctxt))) {
        ret = 0;
        goto cleanup;
    }

    if (!virXMLNodeNameEqual(ctxt->node, "cpu")) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("XML does not contain expected 'cpu' element"));
        goto cleanup;
    }

    if (VIR_ALLOC(def) < 0)
        goto cleanup;

    if (type == VIR_CPU_TYPE_AUTO) {
        if (virXPathBoolean("boolean(./arch)", ctxt)) {
            if (virXPathBoolean("boolean(./@match)", ctxt)) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("'arch' element cannot be used inside 'cpu'"
                                 " element with 'match' attribute'"));
                goto cleanup;
            }
            def->type = VIR_CPU_TYPE_HOST;
        } else {
            def->type = VIR_CPU_TYPE_GUEST;
        }
    } else {
        def->type = type;
    }

    if ((cpuMode = virXMLPropString(ctxt->node, "mode"))) {
        if (def->type == VIR_CPU_TYPE_HOST) {
            VIR_FREE(cpuMode);
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Attribute mode is only allowed for guest CPU"));
            goto cleanup;
        } else {
            def->mode = virCPUModeTypeFromString(cpuMode);

            if (def->mode < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Invalid mode attribute '%s'"),
                               cpuMode);
                VIR_FREE(cpuMode);
                goto cleanup;
            }
            VIR_FREE(cpuMode);
        }
    } else {
        if (def->type == VIR_CPU_TYPE_HOST)
            def->mode = -1;
        else
            def->mode = VIR_CPU_MODE_CUSTOM;
    }

    if (def->type == VIR_CPU_TYPE_GUEST) {
        char *match = virXMLPropString(ctxt->node, "match");
        char *check;

        if (!match) {
            if (virXPathBoolean("boolean(./model)", ctxt))
                def->match = VIR_CPU_MATCH_EXACT;
            else
                def->match = -1;
        } else {
            def->match = virCPUMatchTypeFromString(match);
            VIR_FREE(match);

            if (def->match < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid match attribute for CPU "
                                 "specification"));
                goto cleanup;
            }
        }

        if ((check = virXMLPropString(ctxt->node, "check"))) {
            int value = virCPUCheckTypeFromString(check);
            VIR_FREE(check);

            if (value < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid check attribute for CPU "
                                 "specification"));
                goto cleanup;
            }
            def->check = value;
        }
    }

    if (def->type == VIR_CPU_TYPE_HOST) {
        char *arch = virXPathString("string(./arch[1])", ctxt);
        if (!arch) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing CPU architecture"));
            goto cleanup;
        }
        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown architecture %s"), arch);
            VIR_FREE(arch);
            goto cleanup;
        }
        VIR_FREE(arch);

        if (virXPathBoolean("boolean(./microcode[1]/@version)", ctxt) > 0 &&
            virXPathUInt("string(./microcode[1]/@version)", ctxt,
                         &def->microcodeVersion) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("invalid microcode version"));
            goto cleanup;
        }
    }

    if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
        def->type == VIR_CPU_TYPE_HOST) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Missing CPU model name"));
        goto cleanup;
    }

    if (def->type == VIR_CPU_TYPE_GUEST &&
        def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {

        if ((fallback = virXPathString("string(./model[1]/@fallback)", ctxt))) {
            if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid fallback attribute"));
                goto cleanup;
            }
        }

        if ((vendor_id = virXPathString("string(./model[1]/@vendor_id)",
                                        ctxt))) {
            if (strlen(vendor_id) != VIR_CPU_VENDOR_ID_LENGTH) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("vendor_id must be exactly %d characters long"),
                               VIR_CPU_VENDOR_ID_LENGTH);
                goto cleanup;
            }

            /* ensure that the string can be passed to qemu*/
            if (strchr(vendor_id, ',')) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("vendor id is invalid"));
                    goto cleanup;
            }

            def->vendor_id = vendor_id;
            vendor_id = NULL;
        }
    }

    def->vendor = virXPathString("string(./vendor[1])", ctxt);
    if (def->vendor && !def->model) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("CPU vendor specified without CPU model"));
        goto cleanup;
    }

    if (virXPathNode("./topology[1]", ctxt)) {
        unsigned long ul;

        if (virXPathULong("string(./topology[1]/@sockets)", ctxt, &ul) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'sockets' attribute in CPU topology"));
            goto cleanup;
        }
        def->sockets = (unsigned int) ul;

        if (virXPathULong("string(./topology[1]/@cores)", ctxt, &ul) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'cores' attribute in CPU topology"));
            goto cleanup;
        }
        def->cores = (unsigned int) ul;

        if (virXPathULong("string(./topology[1]/@threads)", ctxt, &ul) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing 'threads' attribute in CPU topology"));
            goto cleanup;
        }
        def->threads = (unsigned int) ul;

        if (!def->sockets || !def->cores || !def->threads) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU topology"));
            goto cleanup;
        }
    }

    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
        goto cleanup;

    if (n > 0) {
        if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Non-empty feature list specified without "
                             "CPU model"));
            goto cleanup;
        }

        if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                         def->nfeatures, n) < 0)
            goto cleanup;

        def->nfeatures = n;
    }

    for (i = 0; i < n; i++) {
        char *name;
        int policy; /* enum virDomainCPUFeaturePolicy */
        size_t j;

        if (def->type == VIR_CPU_TYPE_GUEST) {
            char *strpolicy;

            strpolicy = virXMLPropString(nodes[i], "policy");
            if (strpolicy == NULL)
                policy = VIR_CPU_FEATURE_REQUIRE;
            else
                policy = virCPUFeaturePolicyTypeFromString(strpolicy);
            VIR_FREE(strpolicy);

            if (policy < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid CPU feature policy"));
                goto cleanup;
            }
        } else {
            policy = -1;
        }

        if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) {
            VIR_FREE(name);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU feature name"));
            goto cleanup;
        }

        for (j = 0; j < i; j++) {
            if (STREQ(name, def->features[j].name)) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("CPU feature '%s' specified more than once"),
                               name);
                VIR_FREE(name);
                goto cleanup;
            }
        }

        def->features[i].name = name;
        def->features[i].policy = policy;
    }

    if (virXPathInt("count(./cache)", ctxt, &n) < 0) {
        goto cleanup;
    } else if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("at most one CPU cache element may be specified"));
        goto cleanup;
    } else if (n == 1) {
        int level = -1;
        char *strmode;
        int mode;

        if (virXPathBoolean("boolean(./cache[1]/@level)", ctxt) == 1 &&
            (virXPathInt("string(./cache[1]/@level)", ctxt, &level) < 0 ||
             level < 1 || level > 3)) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid CPU cache level, must be in range [1,3]"));
            goto cleanup;
        }

        if (!(strmode = virXPathString("string(./cache[1]/@mode)", ctxt)) ||
            (mode = virCPUCacheModeTypeFromString(strmode)) < 0) {
            VIR_FREE(strmode);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing or invalid CPU cache mode"));
            goto cleanup;
        }
        VIR_FREE(strmode);

        if (VIR_ALLOC(def->cache) < 0)
            goto cleanup;

        def->cache->level = level;
        def->cache->mode = mode;
    }

    VIR_STEAL_PTR(*cpu, def);
    ret = 0;

 cleanup:
    ctxt->node = oldnode;
    VIR_FREE(fallback);
    VIR_FREE(vendor_id);
    VIR_FREE(nodes);
    virCPUDefFree(def);
    return ret;
}
Exemple #9
0
static int
mymain(void)
{
    int ret = 0;
    virQEMUDriver driver;
    struct testBackingXMLjsonXMLdata xmljsonxmldata;
    struct testQemuDiskXMLToJSONData diskxmljsondata;
    char *capslatest_x86_64 = NULL;
    virQEMUCapsPtr caps_x86_64 = NULL;

    if (qemuTestDriverInit(&driver) < 0)
        return EXIT_FAILURE;

    diskxmljsondata.driver = &driver;

    if (!(capslatest_x86_64 = testQemuGetLatestCapsForArch("x86_64", "xml")))
        return EXIT_FAILURE;

    VIR_TEST_VERBOSE("\nlatest caps x86_64: %s\n", capslatest_x86_64);

    if (!(caps_x86_64 = qemuTestParseCapabilitiesArch(virArchFromString("x86_64"),
                                                      capslatest_x86_64)))
        return EXIT_FAILURE;

    diskxmljsondata.qemuCaps = caps_x86_64;

    virTestCounterReset("qemu storage source xml->json->xml ");

# define TEST_JSON_FORMAT(tpe, xmlstr) \
    do { \
        xmljsonxmldata.type = tpe; \
        xmljsonxmldata.xml = xmlstr; \
        if (virTestRun(virTestCounterNext(), testBackingXMLjsonXML, \
                       &xmljsonxmldata) < 0) \
            ret = -1; \
    } while (0)

# define TEST_JSON_FORMAT_NET(xmlstr) \
    TEST_JSON_FORMAT(VIR_STORAGE_TYPE_NETWORK, xmlstr)

    TEST_JSON_FORMAT(VIR_STORAGE_TYPE_FILE, "<source file='/path/to/file'/>\n");

    /* type VIR_STORAGE_TYPE_BLOCK is not tested since it parses back to 'file' */
    /* type VIR_STORAGE_TYPE_DIR it is a 'format' driver in qemu */

    TEST_JSON_FORMAT_NET("<source protocol='http' name=''>\n"
                         "  <host name='example.com' port='80'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='http' name='file'>\n"
                         "  <host name='example.com' port='80'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='https' name='file'>\n"
                         "  <host name='example.com' port='432'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='gluster' name='vol/file'>\n"
                         "  <host name='example.com' port='24007'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='gluster' name='testvol/img.qcow2'>\n"
                         "  <host name='example.com' port='1234'/>\n"
                         "  <host transport='unix' socket='/path/socket'/>\n"
                         "  <host name='example.com' port='24007'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='nbd'>\n"
                         "  <host transport='unix' socket='/path/to/socket'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='nbd' name='blah'>\n"
                         "  <host name='example.org' port='6000'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='nbd'>\n"
                         "  <host name='example.org' port='6000'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='ssh' name='blah'>\n"
                         "  <host name='example.org' port='6000'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='rbd' name='libvirt/test'>\n"
                         "  <host name='example.com' port='1234'/>\n"
                         "  <host name='example2.com'/>\n"
                         "  <snapshot name='snapshotname'/>\n"
                         "  <config file='/path/to/conf'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='iscsi' name='iqn.2016-12.com.virttest:emulated-iscsi-noauth.target/0'>\n"
                         "  <host name='test.org' port='3260'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='iscsi' name='iqn.2016-12.com.virttest:emulated-iscsi-noauth.target/6'>\n"
                         "  <host name='test.org' port='1234'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='sheepdog' name='test'>\n"
                         "  <host name='example.com' port='321'/>\n"
                         "</source>\n");
    TEST_JSON_FORMAT_NET("<source protocol='vxhs' name='c6718f6b-0401-441d-a8c3-1f0064d75ee0'>\n"
                         "  <host name='example.com' port='9999'/>\n"
                         "</source>\n");

# define TEST_DISK_TO_JSON_FULL(nme, fl) \
    do { \
        diskxmljsondata.name = nme; \
        diskxmljsondata.props = NULL; \
        diskxmljsondata.nprops = 0; \
        diskxmljsondata.fail = fl; \
        if (virTestRun("disk xml to props " nme, testQemuDiskXMLToProps, \
                       &diskxmljsondata) < 0) \
            ret = -1; \
        if (virTestRun("disk xml to props validate schema " nme, \
                       testQemuDiskXMLToPropsValidateSchema, &diskxmljsondata) < 0) \
            ret = -1; \
        if (virTestRun("disk xml to props validate file " nme, \
                       testQemuDiskXMLToPropsValidateFile,  &diskxmljsondata) < 0) \
            ret = -1; \
        testQemuDiskXMLToPropsClear(&diskxmljsondata); \
    } while (0)

# define TEST_DISK_TO_JSON(nme) TEST_DISK_TO_JSON_FULL(nme, false)

    if (!(diskxmljsondata.schema = testQEMUSchemaLoad())) {
        ret = -1;
        goto cleanup;
    }

    if (virQEMUQAPISchemaPathGet("blockdev-add/arg-type",
                                 diskxmljsondata.schema,
                                 &diskxmljsondata.schemaroot) < 0 ||
        !diskxmljsondata.schemaroot) {
        VIR_TEST_VERBOSE("failed to find schema entry for blockdev-add\n");
        ret = -1;
        goto cleanup;
    }

    TEST_DISK_TO_JSON_FULL("nodename-long-format", true);
    TEST_DISK_TO_JSON_FULL("nodename-long-protocol", true);

    TEST_DISK_TO_JSON("file-raw-noopts");
    TEST_DISK_TO_JSON("file-bochs-noopts");
    TEST_DISK_TO_JSON("file-cloop-noopts");
    TEST_DISK_TO_JSON("file-dmg-noopts");
    TEST_DISK_TO_JSON("file-ploop-noopts");
    TEST_DISK_TO_JSON("file-vdi-noopts");
    TEST_DISK_TO_JSON("file-vhd-noopts");
    TEST_DISK_TO_JSON("file-vpc-noopts");

    TEST_DISK_TO_JSON("file-backing_basic-noopts");
    TEST_DISK_TO_JSON("dir-fat-readonly");
    TEST_DISK_TO_JSON("dir-fat-floppy");
    TEST_DISK_TO_JSON("file-raw-aio_native");
    TEST_DISK_TO_JSON("file-backing_basic-aio_threads");
    TEST_DISK_TO_JSON("file-raw-luks");
    TEST_DISK_TO_JSON("file-qcow2-backing-chain-noopts");
    TEST_DISK_TO_JSON("file-qcow2-backing-chain-unterminated");
    TEST_DISK_TO_JSON("file-qcow2-backing-chain-encryption");
    TEST_DISK_TO_JSON("network-qcow2-backing-chain-encryption_auth");

    TEST_DISK_TO_JSON("file-backing_basic-unmap");
    TEST_DISK_TO_JSON("file-backing_basic-unmap-detect");
    TEST_DISK_TO_JSON("file-backing_basic-unmap-ignore");
    TEST_DISK_TO_JSON("file-backing_basic-detect");

    TEST_DISK_TO_JSON("file-backing_basic-cache-none");
    TEST_DISK_TO_JSON("file-backing_basic-cache-writethrough");
    TEST_DISK_TO_JSON("file-backing_basic-cache-writeback");
    TEST_DISK_TO_JSON("file-backing_basic-cache-directsync");
    TEST_DISK_TO_JSON("file-backing_basic-cache-unsafe");
    TEST_DISK_TO_JSON("network-qcow2-backing-chain-cache-unsafe");
    TEST_DISK_TO_JSON("dir-fat-cache");
    TEST_DISK_TO_JSON("network-nbd-tls");

    TEST_DISK_TO_JSON("block-raw-noopts");
    TEST_DISK_TO_JSON("block-raw-reservations");

 cleanup:
    virHashFree(diskxmljsondata.schema);
    qemuTestDriverFree(&driver);
    VIR_FREE(capslatest_x86_64);
    virObjectUnref(caps_x86_64);

    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}