mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
nodedev: add ability to parse mdevs from mdevctl
This function will parse the list of mediated devices that are returned by mdevctl and convert it into our internal node device representation. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> Reviewed-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
parent
eb27a233f2
commit
58d093a55f
@ -861,6 +861,149 @@ virMdevctlStop(virNodeDeviceDefPtr def, char **errmsg)
|
||||
}
|
||||
|
||||
|
||||
static void mdevGenerateDeviceName(virNodeDeviceDef *dev)
|
||||
{
|
||||
nodeDeviceGenerateName(dev, "mdev", dev->caps->data.mdev.uuid, NULL);
|
||||
}
|
||||
|
||||
|
||||
static virNodeDeviceDef*
|
||||
nodeDeviceParseMdevctlChildDevice(const char *parent,
|
||||
virJSONValue *json)
|
||||
{
|
||||
virNodeDevCapMdev *mdev;
|
||||
const char *uuid;
|
||||
virJSONValue *props;
|
||||
virJSONValue *attrs;
|
||||
g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1);
|
||||
|
||||
/* the child object should have a single key equal to its uuid.
|
||||
* The value is an object describing the properties of the mdev */
|
||||
if (virJSONValueObjectKeysNumber(json) != 1)
|
||||
return NULL;
|
||||
|
||||
uuid = virJSONValueObjectGetKey(json, 0);
|
||||
props = virJSONValueObjectGetValue(json, 0);
|
||||
|
||||
child->parent = g_strdup(parent);
|
||||
child->caps = g_new0(virNodeDevCapsDef, 1);
|
||||
child->caps->data.type = VIR_NODE_DEV_CAP_MDEV;
|
||||
|
||||
mdev = &child->caps->data.mdev;
|
||||
mdev->uuid = g_strdup(uuid);
|
||||
mdev->type =
|
||||
g_strdup(virJSONValueObjectGetString(props, "mdev_type"));
|
||||
|
||||
attrs = virJSONValueObjectGet(props, "attrs");
|
||||
|
||||
if (attrs && virJSONValueIsArray(attrs)) {
|
||||
size_t i;
|
||||
int nattrs = virJSONValueArraySize(attrs);
|
||||
|
||||
mdev->attributes = g_new0(virMediatedDeviceAttr*, nattrs);
|
||||
mdev->nattributes = nattrs;
|
||||
|
||||
for (i = 0; i < nattrs; i++) {
|
||||
virJSONValue *attr = virJSONValueArrayGet(attrs, i);
|
||||
virMediatedDeviceAttr *attribute;
|
||||
virJSONValue *value;
|
||||
|
||||
if (!virJSONValueIsObject(attr) ||
|
||||
virJSONValueObjectKeysNumber(attr) != 1)
|
||||
return NULL;
|
||||
|
||||
attribute = g_new0(virMediatedDeviceAttr, 1);
|
||||
attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0));
|
||||
value = virJSONValueObjectGetValue(attr, 0);
|
||||
attribute->value = g_strdup(virJSONValueGetString(value));
|
||||
mdev->attributes[i] = attribute;
|
||||
}
|
||||
}
|
||||
mdevGenerateDeviceName(child);
|
||||
|
||||
return g_steal_pointer(&child);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
nodeDeviceParseMdevctlJSON(const char *jsonstring,
|
||||
virNodeDeviceDef ***devs)
|
||||
{
|
||||
int n;
|
||||
g_autoptr(virJSONValue) json_devicelist = NULL;
|
||||
virNodeDeviceDef **outdevs = NULL;
|
||||
size_t noutdevs = 0;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
json_devicelist = virJSONValueFromString(jsonstring);
|
||||
|
||||
if (!json_devicelist || !virJSONValueIsArray(json_devicelist)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("mdevctl JSON response contains no devices"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
n = virJSONValueArraySize(json_devicelist);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
virJSONValue *obj = virJSONValueArrayGet(json_devicelist, i);
|
||||
const char *parent;
|
||||
virJSONValue *child_array;
|
||||
int nchildren;
|
||||
|
||||
if (!virJSONValueIsObject(obj)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Parent device is not an object"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mdevctl returns an array of objects. Each object is a parent device
|
||||
* object containing a single key-value pair which maps from the name
|
||||
* of the parent device to an array of child devices */
|
||||
if (virJSONValueObjectKeysNumber(obj) != 1) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Unexpected format for parent device object"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
parent = virJSONValueObjectGetKey(obj, 0);
|
||||
child_array = virJSONValueObjectGetValue(obj, 0);
|
||||
|
||||
if (!virJSONValueIsArray(child_array)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Parent device's JSON object data is not an array"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
nchildren = virJSONValueArraySize(child_array);
|
||||
|
||||
for (j = 0; j < nchildren; j++) {
|
||||
g_autoptr(virNodeDeviceDef) child = NULL;
|
||||
virJSONValue *child_obj = virJSONValueArrayGet(child_array, j);
|
||||
|
||||
if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Unable to parse child device"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (VIR_APPEND_ELEMENT(outdevs, noutdevs, child) < 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*devs = outdevs;
|
||||
return noutdevs;
|
||||
|
||||
error:
|
||||
for (i = 0; i < noutdevs; i++)
|
||||
virNodeDeviceDefFree(outdevs[i]);
|
||||
VIR_FREE(outdevs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
nodeDeviceDestroy(virNodeDevicePtr device)
|
||||
{
|
||||
|
@ -121,6 +121,10 @@ virCommandPtr
|
||||
nodeDeviceGetMdevctlStopCommand(const char *uuid,
|
||||
char **errmsg);
|
||||
|
||||
int
|
||||
nodeDeviceParseMdevctlJSON(const char *jsonstring,
|
||||
virNodeDeviceDef ***devs);
|
||||
|
||||
void
|
||||
nodeDeviceGenerateName(virNodeDeviceDef *def,
|
||||
const char *subsystem,
|
||||
|
59
tests/nodedevmdevctldata/mdevctl-list-multiple.json
Normal file
59
tests/nodedevmdevctldata/mdevctl-list-multiple.json
Normal file
@ -0,0 +1,59 @@
|
||||
[
|
||||
{
|
||||
"0000:00:02.0": [
|
||||
{
|
||||
"200f228a-c80a-4d50-bfb7-f5a0e4e34045": {
|
||||
"mdev_type": "i915-GVTg_V5_4",
|
||||
"start": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"de807ffc-1923-4d5f-b6c9-b20ecebc6d4b": {
|
||||
"mdev_type": "i915-GVTg_V5_4",
|
||||
"start": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"435722ea-5f43-468a-874f-da34f1217f13": {
|
||||
"mdev_type": "i915-GVTg_V5_8",
|
||||
"start": "manual",
|
||||
"attrs": [
|
||||
{
|
||||
"testattr": "42"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matrix": [
|
||||
{ "783e6dbb-ea0e-411f-94e2-717eaad438bf": {
|
||||
"mdev_type": "vfio_ap-passthrough",
|
||||
"start": "manual",
|
||||
"attrs": [
|
||||
{
|
||||
"assign_adapter": "5"
|
||||
},
|
||||
{
|
||||
"assign_adapter": "6"
|
||||
},
|
||||
{
|
||||
"assign_domain": "0xab"
|
||||
},
|
||||
{
|
||||
"assign_control_domain": "0xab"
|
||||
},
|
||||
{
|
||||
"assign_domain": "4"
|
||||
},
|
||||
{
|
||||
"assign_control_domain": "4"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
39
tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml
Normal file
39
tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<device>
|
||||
<name>mdev_200f228a_c80a_4d50_bfb7_f5a0e4e34045</name>
|
||||
<parent>0000:00:02.0</parent>
|
||||
<capability type='mdev'>
|
||||
<type id='i915-GVTg_V5_4'/>
|
||||
<iommuGroup number='0'/>
|
||||
</capability>
|
||||
</device>
|
||||
<device>
|
||||
<name>mdev_de807ffc_1923_4d5f_b6c9_b20ecebc6d4b</name>
|
||||
<parent>0000:00:02.0</parent>
|
||||
<capability type='mdev'>
|
||||
<type id='i915-GVTg_V5_4'/>
|
||||
<iommuGroup number='0'/>
|
||||
</capability>
|
||||
</device>
|
||||
<device>
|
||||
<name>mdev_435722ea_5f43_468a_874f_da34f1217f13</name>
|
||||
<parent>0000:00:02.0</parent>
|
||||
<capability type='mdev'>
|
||||
<type id='i915-GVTg_V5_8'/>
|
||||
<iommuGroup number='0'/>
|
||||
<attr name='testattr' value='42'/>
|
||||
</capability>
|
||||
</device>
|
||||
<device>
|
||||
<name>mdev_783e6dbb_ea0e_411f_94e2_717eaad438bf</name>
|
||||
<parent>matrix</parent>
|
||||
<capability type='mdev'>
|
||||
<type id='vfio_ap-passthrough'/>
|
||||
<iommuGroup number='0'/>
|
||||
<attr name='assign_adapter' value='5'/>
|
||||
<attr name='assign_adapter' value='6'/>
|
||||
<attr name='assign_domain' value='0xab'/>
|
||||
<attr name='assign_control_domain' value='0xab'/>
|
||||
<attr name='assign_domain' value='4'/>
|
||||
<attr name='assign_control_domain' value='4'/>
|
||||
</capability>
|
||||
</device>
|
@ -145,6 +145,53 @@ testMdevctlStop(const void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
testMdevctlParse(const void *data)
|
||||
{
|
||||
g_autofree char *buf = NULL;
|
||||
const char *filename = data;
|
||||
g_autofree char *jsonfile = g_strdup_printf("%s/nodedevmdevctldata/%s.json",
|
||||
abs_srcdir, filename);
|
||||
g_autofree char *xmloutfile = g_strdup_printf("%s/nodedevmdevctldata/%s.out.xml",
|
||||
abs_srcdir, filename);
|
||||
int ret = -1;
|
||||
int nmdevs = 0;
|
||||
virNodeDeviceDef **mdevs = NULL;
|
||||
virBuffer xmloutbuf = VIR_BUFFER_INITIALIZER;
|
||||
size_t i;
|
||||
|
||||
if (virFileReadAll(jsonfile, 1024*1024, &buf) < 0) {
|
||||
VIR_TEST_DEBUG("Unable to read file %s", jsonfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((nmdevs = nodeDeviceParseMdevctlJSON(buf, &mdevs)) < 0) {
|
||||
VIR_TEST_DEBUG("Unable to parse json for %s", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nmdevs; i++) {
|
||||
g_autofree char *devxml = virNodeDeviceDefFormat(mdevs[i]);
|
||||
if (!devxml)
|
||||
goto cleanup;
|
||||
virBufferAddStr(&xmloutbuf, devxml);
|
||||
}
|
||||
|
||||
if (nodedevCompareToFile(virBufferCurrentContent(&xmloutbuf), xmloutfile) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virBufferFreeAndReset(&xmloutbuf);
|
||||
for (i = 0; i < nmdevs; i++)
|
||||
virNodeDeviceDefFree(mdevs[i]);
|
||||
g_free(mdevs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nodedevTestDriverFree(virNodeDeviceDriverStatePtr drv)
|
||||
{
|
||||
@ -281,6 +328,9 @@ mymain(void)
|
||||
#define DO_TEST_STOP(uuid) \
|
||||
DO_TEST_FULL("mdevctl stop " uuid, testMdevctlStop, uuid)
|
||||
|
||||
#define DO_TEST_PARSE_JSON(filename) \
|
||||
DO_TEST_FULL("parse mdevctl json " filename, testMdevctlParse, filename)
|
||||
|
||||
/* Test mdevctl start commands */
|
||||
DO_TEST_START("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366");
|
||||
DO_TEST_START("mdev_fedc4916_1ca8_49ac_b176_871d16c13076");
|
||||
@ -289,6 +339,8 @@ mymain(void)
|
||||
/* Test mdevctl stop command, pass an arbitrary uuid */
|
||||
DO_TEST_STOP("e2451f73-c95b-4124-b900-e008af37c576");
|
||||
|
||||
DO_TEST_PARSE_JSON("mdevctl-list-multiple");
|
||||
|
||||
done:
|
||||
nodedevTestDriverFree(driver);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user