}
+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)
{
--- /dev/null
+<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>
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)
{
#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");
/* 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);