mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
qemu: add vhost-user helpers
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers. qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
d27abda98d
commit
13248e1688
@ -2844,6 +2844,8 @@ virDomainVideoDefClear(virDomainVideoDefPtr def)
|
||||
VIR_FREE(def->accel->rendernode);
|
||||
VIR_FREE(def->accel);
|
||||
VIR_FREE(def->virtio);
|
||||
if (def->driver)
|
||||
VIR_FREE(def->driver->vhost_user_binary);
|
||||
VIR_FREE(def->driver);
|
||||
|
||||
memset(def, 0, sizeof(*def));
|
||||
|
@ -1423,6 +1423,7 @@ struct _virDomainVideoAccelDef {
|
||||
|
||||
struct _virDomainVideoDriverDef {
|
||||
virDomainVideoVGAConf vgaconf;
|
||||
char *vhost_user_binary;
|
||||
};
|
||||
|
||||
struct _virDomainVideoDef {
|
||||
|
@ -64,6 +64,8 @@ QEMU_DRIVER_SOURCES = \
|
||||
qemu/qemu_slirp.h \
|
||||
qemu/qemu_tpm.c \
|
||||
qemu/qemu_tpm.h \
|
||||
qemu/qemu_vhost_user.c \
|
||||
qemu/qemu_vhost_user.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
422
src/qemu/qemu_vhost_user.c
Normal file
422
src/qemu/qemu_vhost_user.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* qemu_vhost_user.c: QEMU vhost-user
|
||||
*
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "qemu_vhost_user.h"
|
||||
#include "qemu_interop_config.h"
|
||||
#include "virjson.h"
|
||||
#include "virlog.h"
|
||||
#include "virstring.h"
|
||||
#include "viralloc.h"
|
||||
#include "virenum.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
VIR_LOG_INIT("qemu.qemu_vhost_user");
|
||||
|
||||
typedef enum {
|
||||
QEMU_VHOST_USER_TYPE_NONE = 0,
|
||||
QEMU_VHOST_USER_TYPE_9P,
|
||||
QEMU_VHOST_USER_TYPE_BALLOON,
|
||||
QEMU_VHOST_USER_TYPE_BLOCK,
|
||||
QEMU_VHOST_USER_TYPE_CAIF,
|
||||
QEMU_VHOST_USER_TYPE_CONSOLE,
|
||||
QEMU_VHOST_USER_TYPE_CRYPTO,
|
||||
QEMU_VHOST_USER_TYPE_GPU,
|
||||
QEMU_VHOST_USER_TYPE_INPUT,
|
||||
QEMU_VHOST_USER_TYPE_NET,
|
||||
QEMU_VHOST_USER_TYPE_RNG,
|
||||
QEMU_VHOST_USER_TYPE_RPMSG,
|
||||
QEMU_VHOST_USER_TYPE_RPROC_SERIAL,
|
||||
QEMU_VHOST_USER_TYPE_SCSI,
|
||||
QEMU_VHOST_USER_TYPE_VSOCK,
|
||||
QEMU_VHOST_USER_TYPE_FS,
|
||||
|
||||
QEMU_VHOST_USER_TYPE_LAST
|
||||
} qemuVhostUserType;
|
||||
|
||||
VIR_ENUM_DECL(qemuVhostUserType);
|
||||
VIR_ENUM_IMPL(qemuVhostUserType,
|
||||
QEMU_VHOST_USER_TYPE_LAST,
|
||||
"",
|
||||
"9p",
|
||||
"balloon",
|
||||
"block",
|
||||
"caif",
|
||||
"console",
|
||||
"crypto",
|
||||
"gpu",
|
||||
"input",
|
||||
"net",
|
||||
"rng",
|
||||
"rpmsg",
|
||||
"rproc-serial",
|
||||
"scsi",
|
||||
"vsock",
|
||||
"fs",
|
||||
);
|
||||
|
||||
typedef enum {
|
||||
QEMU_VHOST_USER_GPU_FEATURE_NONE = 0,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_VIRGL,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE,
|
||||
|
||||
QEMU_VHOST_USER_GPU_FEATURE_LAST
|
||||
} qemuVhostUserGPUFeature;
|
||||
|
||||
VIR_ENUM_DECL(qemuVhostUserGPUFeature);
|
||||
VIR_ENUM_IMPL(qemuVhostUserGPUFeature,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_LAST,
|
||||
"",
|
||||
"virgl",
|
||||
"render-node",
|
||||
);
|
||||
|
||||
typedef struct _qemuVhostUserGPU qemuVhostUserGPU;
|
||||
typedef qemuVhostUserGPU *qemuVhostUserGPUPtr;
|
||||
struct _qemuVhostUserGPU {
|
||||
size_t nfeatures;
|
||||
qemuVhostUserGPUFeature *features;
|
||||
};
|
||||
|
||||
struct _qemuVhostUser {
|
||||
/* Description intentionally not parsed. */
|
||||
qemuVhostUserType type;
|
||||
char *binary;
|
||||
/* Tags intentionally not parsed. */
|
||||
|
||||
union {
|
||||
qemuVhostUserGPU gpu;
|
||||
} capabilities;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
qemuVhostUserGPUFeatureFree(qemuVhostUserGPUFeature *features)
|
||||
{
|
||||
VIR_FREE(features);
|
||||
}
|
||||
|
||||
|
||||
VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUserGPUFeature, qemuVhostUserGPUFeatureFree);
|
||||
|
||||
|
||||
void
|
||||
qemuVhostUserFree(qemuVhostUserPtr vu)
|
||||
{
|
||||
if (!vu)
|
||||
return;
|
||||
|
||||
if (vu->type == QEMU_VHOST_USER_TYPE_GPU)
|
||||
VIR_FREE(vu->capabilities.gpu.features);
|
||||
|
||||
VIR_FREE(vu->binary);
|
||||
|
||||
VIR_FREE(vu);
|
||||
}
|
||||
|
||||
|
||||
/* 1MiB should be enough for everybody (TM) */
|
||||
#define DOCUMENT_SIZE (1024 * 1024)
|
||||
|
||||
|
||||
static int
|
||||
qemuVhostUserTypeParse(const char *path,
|
||||
virJSONValuePtr doc,
|
||||
qemuVhostUserPtr vu)
|
||||
{
|
||||
const char *type = virJSONValueObjectGetString(doc, "type");
|
||||
int tmp;
|
||||
|
||||
VIR_DEBUG("vhost-user description path '%s' type : %s",
|
||||
path, type);
|
||||
|
||||
if ((tmp = qemuVhostUserTypeTypeFromString(type)) <= 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown vhost-user type: '%s'"),
|
||||
type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vu->type = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuVhostUserBinaryParse(const char *path,
|
||||
virJSONValuePtr doc,
|
||||
qemuVhostUserPtr vu)
|
||||
{
|
||||
const char *binary = virJSONValueObjectGetString(doc, "binary");
|
||||
|
||||
VIR_DEBUG("vhost-user description path '%s' binary : %s",
|
||||
path, binary);
|
||||
|
||||
if (VIR_STRDUP(vu->binary, binary) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
qemuVhostUserPtr
|
||||
qemuVhostUserParse(const char *path)
|
||||
{
|
||||
VIR_AUTOFREE(char *) cont = NULL;
|
||||
VIR_AUTOPTR(virJSONValue) doc = NULL;
|
||||
VIR_AUTOPTR(qemuVhostUser) vu = NULL;
|
||||
qemuVhostUserPtr ret = NULL;
|
||||
|
||||
if (virFileReadAll(path, DOCUMENT_SIZE, &cont) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!(doc = virJSONValueFromString(cont))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to parse json file '%s'"),
|
||||
path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(vu) < 0)
|
||||
return NULL;
|
||||
|
||||
if (qemuVhostUserTypeParse(path, doc, vu) < 0)
|
||||
return NULL;
|
||||
|
||||
if (qemuVhostUserBinaryParse(path, doc, vu) < 0)
|
||||
return NULL;
|
||||
|
||||
VIR_STEAL_PTR(ret, vu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
qemuVhostUserFormat(qemuVhostUserPtr vu)
|
||||
{
|
||||
VIR_AUTOPTR(virJSONValue) doc = NULL;
|
||||
|
||||
if (!vu)
|
||||
return NULL;
|
||||
|
||||
if (!(doc = virJSONValueNewObject()))
|
||||
return NULL;
|
||||
|
||||
if (virJSONValueObjectAppendString(doc, "type",
|
||||
qemuVhostUserTypeTypeToString(vu->type)) < 0)
|
||||
return NULL;
|
||||
|
||||
if (virJSONValueObjectAppendString(doc, "binary", vu->binary) < 0)
|
||||
return NULL;
|
||||
|
||||
return virJSONValueToString(doc, true);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuVhostUserFetchConfigs(char ***configs,
|
||||
bool privileged)
|
||||
{
|
||||
return qemuInteropFetchConfigs("vhost-user", configs, privileged);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
qemuVhostUserFetchParsedConfigs(bool privileged,
|
||||
qemuVhostUserPtr **vhostuserRet,
|
||||
char ***pathsRet)
|
||||
{
|
||||
VIR_AUTOSTRINGLIST paths = NULL;
|
||||
size_t npaths;
|
||||
qemuVhostUserPtr *vus = NULL;
|
||||
size_t i;
|
||||
|
||||
if (qemuVhostUserFetchConfigs(&paths, privileged) < 0)
|
||||
return -1;
|
||||
|
||||
npaths = virStringListLength((const char **)paths);
|
||||
|
||||
if (VIR_ALLOC_N(vus, npaths) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < npaths; i++) {
|
||||
if (!(vus[i] = qemuVhostUserParse(paths[i])))
|
||||
goto error;
|
||||
}
|
||||
|
||||
VIR_STEAL_PTR(*vhostuserRet, vus);
|
||||
if (pathsRet)
|
||||
VIR_STEAL_PTR(*pathsRet, paths);
|
||||
return npaths;
|
||||
|
||||
error:
|
||||
while (i > 0)
|
||||
qemuVhostUserFree(vus[--i]);
|
||||
VIR_FREE(vus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuVhostUserGPUFillCapabilities(qemuVhostUserPtr vu,
|
||||
virJSONValuePtr doc)
|
||||
{
|
||||
qemuVhostUserGPUPtr gpu = &vu->capabilities.gpu;
|
||||
virJSONValuePtr featuresJSON;
|
||||
size_t nfeatures;
|
||||
size_t i;
|
||||
VIR_AUTOPTR(qemuVhostUserGPUFeature) features = NULL;
|
||||
|
||||
if (!(featuresJSON = virJSONValueObjectGetArray(doc, "features"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("failed to get features from '%s'"),
|
||||
vu->binary);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nfeatures = virJSONValueArraySize(featuresJSON);
|
||||
if (VIR_ALLOC_N(features, nfeatures) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < nfeatures; i++) {
|
||||
virJSONValuePtr item = virJSONValueArrayGet(featuresJSON, i);
|
||||
const char *tmpStr = virJSONValueGetString(item);
|
||||
int tmp;
|
||||
|
||||
if ((tmp = qemuVhostUserGPUFeatureTypeFromString(tmpStr)) <= 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown feature %s"),
|
||||
tmpStr);
|
||||
continue;
|
||||
}
|
||||
|
||||
features[i] = tmp;
|
||||
}
|
||||
|
||||
VIR_STEAL_PTR(gpu->features, features);
|
||||
gpu->nfeatures = nfeatures;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
qemuVhostUserGPUHasFeature(qemuVhostUserGPUPtr gpu,
|
||||
qemuVhostUserGPUFeature feature)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < gpu->nfeatures; i++) {
|
||||
if (gpu->features[i] == feature)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuVhostUserFillDomainGPU(virQEMUDriverPtr driver,
|
||||
virDomainVideoDefPtr video)
|
||||
{
|
||||
qemuVhostUserPtr *vus = NULL;
|
||||
qemuVhostUserPtr vu = NULL;
|
||||
ssize_t nvus = 0;
|
||||
ssize_t i;
|
||||
int ret = -1;
|
||||
|
||||
if ((nvus = qemuVhostUserFetchParsedConfigs(driver->privileged,
|
||||
&vus, NULL)) < 0)
|
||||
goto end;
|
||||
|
||||
for (i = 0; i < nvus; i++) {
|
||||
VIR_AUTOPTR(virJSONValue) doc = NULL;
|
||||
VIR_AUTOFREE(char *) output = NULL;
|
||||
VIR_AUTOPTR(virCommand) cmd = NULL;
|
||||
|
||||
vu = vus[i];
|
||||
if (vu->type != QEMU_VHOST_USER_TYPE_GPU)
|
||||
continue;
|
||||
|
||||
cmd = virCommandNewArgList(vu->binary, "--print-capabilities", NULL);
|
||||
virCommandSetOutputBuffer(cmd, &output);
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
continue;
|
||||
|
||||
if (!(doc = virJSONValueFromString(output))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to parse json capabilities '%s'"),
|
||||
vu->binary);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (qemuVhostUserGPUFillCapabilities(vu, doc) < 0)
|
||||
continue;
|
||||
|
||||
if (video->accel) {
|
||||
if (video->accel->accel3d &&
|
||||
!qemuVhostUserGPUHasFeature(&vu->capabilities.gpu,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_VIRGL))
|
||||
continue;
|
||||
|
||||
if (video->accel->rendernode &&
|
||||
!qemuVhostUserGPUHasFeature(&vu->capabilities.gpu,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!video->driver && VIR_ALLOC(video->driver) < 0)
|
||||
goto end;
|
||||
|
||||
VIR_FREE(video->driver->vhost_user_binary);
|
||||
if (VIR_STRDUP(video->driver->vhost_user_binary, vu->binary) < 0)
|
||||
goto end;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == nvus) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("Unable to find a satisfying vhost-user-gpu"));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!video->accel && VIR_ALLOC(video->accel) < 0)
|
||||
goto end;
|
||||
|
||||
if (!video->accel->rendernode &&
|
||||
qemuVhostUserGPUHasFeature(&vu->capabilities.gpu,
|
||||
QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE)) {
|
||||
video->accel->rendernode = virHostGetDRMRenderNode();
|
||||
if (!video->accel->rendernode)
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
for (i = 0; i < nvus; i++)
|
||||
qemuVhostUserFree(vus[i]);
|
||||
VIR_FREE(vus);
|
||||
return ret;
|
||||
}
|
48
src/qemu/qemu_vhost_user.h
Normal file
48
src/qemu/qemu_vhost_user.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* qemu_vhost_user.h: QEMU vhost-user
|
||||
*
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "domain_conf.h"
|
||||
#include "qemu_conf.h"
|
||||
#include "virautoclean.h"
|
||||
#include "virarch.h"
|
||||
|
||||
typedef struct _qemuVhostUser qemuVhostUser;
|
||||
typedef qemuVhostUser *qemuVhostUserPtr;
|
||||
|
||||
void
|
||||
qemuVhostUserFree(qemuVhostUserPtr fw);
|
||||
|
||||
VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUser, qemuVhostUserFree);
|
||||
|
||||
qemuVhostUserPtr
|
||||
qemuVhostUserParse(const char *path);
|
||||
|
||||
char *
|
||||
qemuVhostUserFormat(qemuVhostUserPtr fw);
|
||||
|
||||
int
|
||||
qemuVhostUserFetchConfigs(char ***configs,
|
||||
bool privileged);
|
||||
|
||||
int
|
||||
qemuVhostUserFillDomainGPU(virQEMUDriverPtr driver,
|
||||
virDomainVideoDefPtr video);
|
@ -127,6 +127,7 @@ EXTRA_DIST = \
|
||||
qemustatusxml2xmldata \
|
||||
qemumemlockdata \
|
||||
qemufirmwaredata \
|
||||
qemuvhostuserdata \
|
||||
secretxml2xmlin \
|
||||
securityselinuxhelperdata \
|
||||
securityselinuxlabeldata \
|
||||
@ -290,6 +291,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest \
|
||||
qemumigparamstest \
|
||||
qemusecuritytest \
|
||||
qemufirmwaretest \
|
||||
qemuvhostusertest \
|
||||
$(NULL)
|
||||
test_helpers += qemucapsprobe
|
||||
test_libraries += libqemumonitortestutils.la \
|
||||
@ -692,6 +694,13 @@ qemufirmwaretest_SOURCES = \
|
||||
$(NULL)
|
||||
qemufirmwaretest_LDADD = $(qemu_LDADDS)
|
||||
|
||||
qemuvhostusertest_SOURCES = \
|
||||
qemuvhostusertest.c \
|
||||
testutils.h testutils.c \
|
||||
virfilewrapper.c virfilewrapper.h \
|
||||
$(NULL)
|
||||
qemuvhostusertest_LDADD = $(qemu_LDADDS)
|
||||
|
||||
else ! WITH_QEMU
|
||||
EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c \
|
||||
qemudomaincheckpointxml2xmltest.c qemudomainsnapshotxml2xmltest.c \
|
||||
@ -706,6 +715,7 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c \
|
||||
qemusecuritytest.c qemusecuritytest.h \
|
||||
qemusecuritymock.c \
|
||||
qemufirmwaretest.c \
|
||||
qemuvhostusertest.c \
|
||||
$(QEMUMONITORTESTUTILS_SOURCES)
|
||||
endif ! WITH_QEMU
|
||||
|
||||
|
1
tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json
Symbolic link
1
tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json
Symbolic link
@ -0,0 +1 @@
|
||||
../../../usr/share/qemu/vhost-user/50-gpu.json
|
11
tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu
Executable file
11
tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"type": "gpu",
|
||||
"features": [
|
||||
"render-node",
|
||||
"virgl"
|
||||
]
|
||||
}
|
||||
EOF
|
1
tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json
Symbolic link
1
tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json
Symbolic link
@ -0,0 +1 @@
|
||||
50-gpu.json
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"description": "QEMU vhost-user-gpu",
|
||||
"type": "gpu",
|
||||
"binary": "/usr/libexec/qemu/vhost-user/test-vhost-user-gpu",
|
||||
"tags": [
|
||||
"CONFIG_OPENGL_DMABUF=y"
|
||||
]
|
||||
}
|
1
tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json
Symbolic link
1
tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json
Symbolic link
@ -0,0 +1 @@
|
||||
50-gpu.json
|
132
tests/qemuvhostusertest.c
Normal file
132
tests/qemuvhostusertest.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "testutils.h"
|
||||
#include "virfilewrapper.h"
|
||||
#include "qemu/qemu_vhost_user.h"
|
||||
#include "configmake.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
/* A very basic test. Parse given JSON vhostuser description into
|
||||
* an internal structure, format it back and compare with the
|
||||
* contents of the file (minus some keys that are not parsed).
|
||||
*/
|
||||
static int
|
||||
testParseFormatVU(const void *opaque)
|
||||
{
|
||||
const char *filename = opaque;
|
||||
VIR_AUTOFREE(char *) path = NULL;
|
||||
VIR_AUTOPTR(qemuVhostUser) vu = NULL;
|
||||
VIR_AUTOFREE(char *) buf = NULL;
|
||||
VIR_AUTOPTR(virJSONValue) json = NULL;
|
||||
VIR_AUTOFREE(char *) expected = NULL;
|
||||
VIR_AUTOFREE(char *) actual = NULL;
|
||||
|
||||
if (virAsprintf(&path, "%s/qemuvhostuserdata/%s",
|
||||
abs_srcdir, filename) < 0)
|
||||
return -1;
|
||||
|
||||
if (!(vu = qemuVhostUserParse(path)))
|
||||
return -1;
|
||||
|
||||
if (virFileReadAll(path,
|
||||
1024 * 1024, /* 1MiB */
|
||||
&buf) < 0)
|
||||
return -1;
|
||||
|
||||
if (!(json = virJSONValueFromString(buf)))
|
||||
return -1;
|
||||
|
||||
/* Description and tags are not parsed. */
|
||||
if (virJSONValueObjectRemoveKey(json, "description", NULL) < 0 ||
|
||||
virJSONValueObjectRemoveKey(json, "tags", NULL) < 0)
|
||||
return -1;
|
||||
|
||||
if (!(expected = virJSONValueToString(json, true)))
|
||||
return -1;
|
||||
|
||||
if (!(actual = qemuVhostUserFormat(vu)))
|
||||
return -1;
|
||||
|
||||
return virTestCompareToString(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
testVUPrecedence(const void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
VIR_AUTOFREE(char *) fakehome = NULL;
|
||||
VIR_AUTOSTRINGLIST vuList = NULL;
|
||||
size_t nvuList;
|
||||
size_t i;
|
||||
const char *expected[] = {
|
||||
PREFIX "/share/qemu/vhost-user/30-gpu.json",
|
||||
SYSCONFDIR "/qemu/vhost-user/40-gpu.json",
|
||||
PREFIX "/share/qemu/vhost-user/60-gpu.json",
|
||||
};
|
||||
const size_t nexpected = ARRAY_CARDINALITY(expected);
|
||||
|
||||
if (VIR_STRDUP(fakehome, abs_srcdir "/qemuvhostuserdata/home/user/.config") < 0)
|
||||
return -1;
|
||||
|
||||
setenv("XDG_CONFIG_HOME", fakehome, 1);
|
||||
|
||||
if (qemuVhostUserFetchConfigs(&vuList, false) < 0)
|
||||
return -1;
|
||||
|
||||
if (!vuList) {
|
||||
fprintf(stderr, "Expected a non-NULL result, but got a NULL result\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nvuList = virStringListLength((const char **)vuList);
|
||||
|
||||
for (i = 0; i < MAX(nvuList, nexpected); i++) {
|
||||
const char *e = i < nexpected ? expected[i] : NULL;
|
||||
const char *f = i < nvuList ? vuList[i] : NULL;
|
||||
|
||||
if (STRNEQ_NULLABLE(e, f)) {
|
||||
fprintf(stderr,
|
||||
"Unexpected path (i=%zu). Expected %s got %s \n",
|
||||
i, NULLSTR(e), NULLSTR(f));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mymain(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
virFileWrapperAddPrefix(SYSCONFDIR "/qemu/vhost-user",
|
||||
abs_srcdir "/qemuvhostuserdata/etc/qemu/vhost-user");
|
||||
virFileWrapperAddPrefix(PREFIX "/share/qemu/vhost-user",
|
||||
abs_srcdir "/qemuvhostuserdata/usr/share/qemu/vhost-user");
|
||||
virFileWrapperAddPrefix("/home/user/.config/qemu/vhost-user",
|
||||
abs_srcdir "/qemuvhostuserdata/home/user/.config/qemu/vhost-user");
|
||||
|
||||
#define DO_PARSE_TEST(filename) \
|
||||
do { \
|
||||
if (virTestRun("QEMU vhost-user " filename, \
|
||||
testParseFormatVU, filename) < 0) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
DO_PARSE_TEST("usr/share/qemu/vhost-user/50-gpu.json");
|
||||
|
||||
if (virTestRun("QEMU vhost-user precedence test", testVUPrecedence, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
virFileWrapperClearPrefixes();
|
||||
|
||||
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
VIR_TEST_MAIN(mymain)
|
Loading…
Reference in New Issue
Block a user