[libvirt PATCH v2 05/16] nodedev: add ability to list and parse defined mdevs
Ján Tomko
jtomko at redhat.com
Tue Aug 25 12:48:48 UTC 2020
On a Tuesday in 2020, Jonathon Jongsma wrote:
>This adds some internal API to query for persistent mediated devices
>that are defined by mdevctl. Following commits will make use of this
>information. This just provides the infrastructure and tests for this
>feature. One test verifies that we are executing mdevctl with the proper
>arguments, and other tests verify that we can parse the returned JSON
>and convert it to our own internal node device representations.
>
>Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
>---
> src/node_device/node_device_driver.c | 156 ++++++++++++++++++
> src/node_device/node_device_driver.h | 13 ++
> src/node_device/node_device_udev.c | 19 +--
> .../mdevctl-list-defined.argv | 1 +
> .../mdevctl-list-multiple-parents.json | 59 +++++++
> .../mdevctl-list-multiple-parents.out.xml | 39 +++++
> .../mdevctl-list-multiple.json | 59 +++++++
> .../mdevctl-list-multiple.out.xml | 39 +++++
> .../mdevctl-list-single-noattr.json | 11 ++
> .../mdevctl-list-single-noattr.out.xml | 8 +
> .../mdevctl-list-single.json | 31 ++++
> .../mdevctl-list-single.out.xml | 14 ++
> tests/nodedevmdevctltest.c | 98 +++++++++++
> 13 files changed, 531 insertions(+), 16 deletions(-)
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-defined.argv
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple-parents.json
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple-parents.out.xml
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.json
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single-noattr.json
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single-noattr.out.xml
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single.json
> create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single.out.xml
>
>diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
>index f766fd9f32..3b042e9a45 100644
>--- a/src/node_device/node_device_driver.c
>+++ b/src/node_device/node_device_driver.c
>@@ -812,6 +812,137 @@ virMdevctlStop(virNodeDeviceDefPtr def)
> }
>
>
>+virCommandPtr
>+nodeDeviceGetMdevctlListCommand(bool defined,
>+ char **output)
>+{
>+ virCommandPtr cmd = virCommandNewArgList(MDEVCTL,
>+ "list",
>+ "--dumpjson",
>+ NULL);
>+
>+ if (defined)
>+ virCommandAddArg(cmd, "--defined");
>+
>+ virCommandSetOutputBuffer(cmd, output);
>+
>+ return cmd;
>+}
>+
>+
>+static void mdevGenerateDeviceName(virNodeDeviceDefPtr dev)
>+{
>+ nodeDeviceGenerateName(dev, "mdev", dev->caps->data.mdev.uuid, NULL);
>+}
>+
>+int
>+nodeDeviceParseMdevctlJSON(const char *jsonstring,
>+ virNodeDeviceDefPtr **devs)
>+{
>+ int n;
>+ g_autoptr(virJSONValue) json_devicelist = NULL;
>+ virNodeDeviceDefPtr *outdevs = NULL;
>+ size_t noutdevs = 0;
>+ size_t i, j, k, m;
>+
>+ json_devicelist = virJSONValueFromString(jsonstring);
>+
>+ if (!json_devicelist)
>+ goto parsefailure;
>+
>+ if (!virJSONValueIsArray(json_devicelist))
>+ goto parsefailure;
>+
>+ n = virJSONValueArraySize(json_devicelist);
>+
>+ for (i = 0; i < n; i++) {
>+ virJSONValuePtr obj = virJSONValueArrayGet(json_devicelist, i);
>+ int nparents;
>+
>+ if (!virJSONValueIsObject(obj))
>+ goto parsefailure;
>+
>+ nparents = virJSONValueObjectKeysNumber(obj);
>+
>+ for (j = 0; j < nparents; j++) {
>+ const char *parent = virJSONValueObjectGetKey(obj, j);
>+ virJSONValuePtr child_array = virJSONValueObjectGetValue(obj, j);
>+ int nchildren;
>+
>+ if (!virJSONValueIsArray(child_array))
>+ goto parsefailure;
>+
>+ nchildren = virJSONValueArraySize(child_array);
>+
>+ for (k = 0; k < nchildren; k++) {
This is nested quite deep. Maybe a helper function like 'nodeDeviceParseMdevctlSingleDevJSON'
would help get rid of it.
>+ virNodeDevCapMdevPtr mdev;
>+ const char *uuid;
>+ virJSONValuePtr props;
>+ g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1);
>+ virJSONValuePtr child_obj = virJSONValueArrayGet(child_array, k);
>+
>+ /* 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(child_obj) != 1)
>+ goto parsefailure;
>+
>+ uuid = virJSONValueObjectGetKey(child_obj, 0);
>+ props = virJSONValueObjectGetValue(child_obj, 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"));
>+
>+ virJSONValuePtr attrs = virJSONValueObjectGet(props, "attrs");
>+
>+ if (attrs && virJSONValueIsArray(attrs)) {
>+ int nattrs = virJSONValueArraySize(attrs);
>+
>+ mdev->attributes = g_new0(virMediatedDeviceAttrPtr, nattrs);
>+ mdev->nattributes = nattrs;
>+
>+ for (m = 0; m < nattrs; m++) {
>+ virJSONValuePtr attr = virJSONValueArrayGet(attrs, m);
>+ virMediatedDeviceAttrPtr attribute;
>+
>+ if (!virJSONValueIsObject(attr) ||
>+ virJSONValueObjectKeysNumber(attr) != 1)
>+ goto parsefailure;
>+
>+ attribute = g_new0(virMediatedDeviceAttr, 1);
>+ attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0));
>+ virJSONValuePtr value = virJSONValueObjectGetValue(attr, 0);
>+ attribute->value = g_strdup(virJSONValueGetString(value));
>+ mdev->attributes[m] = attribute;
>+ }
>+ }
>+ mdevGenerateDeviceName(child);
>+
>+ if (VIR_APPEND_ELEMENT(outdevs, noutdevs, child) < 0)
>+ child = NULL;
The indentation is off here. Note that VIR_APPEND_ELEMENT aborts on
failure and NULL's the element on success, so the assignment here is
pointless.
>+ }
>+ }
>+ }
>+
>+ *devs = outdevs;
>+ return noutdevs;
>+
>+ parsefailure:
s/parsefailure/error/
>+ for (i = 0; i < noutdevs; i++)
>+ virNodeDeviceDefFree(outdevs[i]);
>+ VIR_FREE(outdevs);
>+
>+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>+ _("unable to parse JSON response"));
>+ return -1;
>+}
>+
>+
> int
> nodeDeviceDestroy(virNodeDevicePtr device)
> {
>@@ -931,3 +1062,28 @@ nodedevRegister(void)
> # endif
> #endif
> }
>+
>+
>+void
>+nodeDeviceGenerateName(virNodeDeviceDefPtr def,
>+ const char *subsystem,
>+ const char *sysname,
>+ const char *s)
>+{
>+ size_t i;
>+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
>+
>+ virBufferAsprintf(&buf, "%s_%s",
>+ subsystem,
>+ sysname);
>+
>+ if (s != NULL)
>+ virBufferAsprintf(&buf, "_%s", s);
>+
>+ def->name = virBufferContentAndReset(&buf);
>+
>+ for (i = 0; i < strlen(def->name); i++) {
>+ if (!(g_ascii_isalnum(*(def->name + i))))
>+ *(def->name + i) = '_';
>+ }
>+}
>+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);
>+ g_autofree char *actualxml = NULL;
Fails to compile with clang:
../tests/nodedevmdevctltest.c:190:22: error: unused variable 'actualxml' [-Werror,-Wunused-variable]
g_autofree char *actualxml = NULL;
^
1 error generated.
Jano
>+ int ret = -1;
>+ int nmdevs = 0;
>+ virNodeDeviceDefPtr *mdevs = NULL;
>+ virBuffer xmloutbuf = VIR_BUFFER_INITIALIZER;
>+ size_t i;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20200825/c147d682/attachment-0001.sig>
More information about the libvir-list
mailing list