[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