From nobody Mon Feb 9 20:10:42 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1612374012; cv=none; d=zohomail.com; s=zohoarc; b=A8tq7WkiW+s76UtJq2WquURoN3BUz6tB27QIbRGliAm8ZeGhhGbGflXkVdzhxpfngJ9OB4oWV7W1m3vSeG3aOgOzVkC9jfaMYlGEzIAy9zdmZCPSrUKl03TLIXfKeAUk6epCvqQRYsJh9WXjumdRi0Y4OLISAkthZT8fS1k6MAk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1612374012; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=h95ZW0sRZLCNraaXhEVrRDCWgy5YMgGL10hckOA9XOI=; b=hBgyJRqleD/w2ChJKqdgw3ysgbwbtF3tpibfJ4Dm6x4DLwo0fhkSHs9to/USmobZxyxvDx5gX8BAZcWdqeQEM3/YitgZihDgbPg49s7FwZsjXKIUDhk23lT2epTFoqVDJzufdSyzWY2k3ZfeYbCyD27d7XgMCNVq8k37oYFVEz4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.zohomail.com with SMTPS id 1612374012960612.3931391532619; Wed, 3 Feb 2021 09:40:12 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-473-veKaVINbOGeW8Y4C1ng5hA-1; Wed, 03 Feb 2021 12:39:31 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4AEFA85B689; Wed, 3 Feb 2021 17:39:20 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 24A395D723; Wed, 3 Feb 2021 17:39:20 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id E117857DF9; Wed, 3 Feb 2021 17:39:19 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 113HdFRH024276 for ; Wed, 3 Feb 2021 12:39:15 -0500 Received: by smtp.corp.redhat.com (Postfix) id BA6D6722C6; Wed, 3 Feb 2021 17:39:15 +0000 (UTC) Received: from himantopus.redhat.com (ovpn-113-7.phx2.redhat.com [10.3.113.7]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 695075B4AE; Wed, 3 Feb 2021 17:39:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1612374011; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=h95ZW0sRZLCNraaXhEVrRDCWgy5YMgGL10hckOA9XOI=; b=AKxTNK10iSp4+OFv0MM+ldC7mrbhZMi9kPSK3MPkOWQpYxquiarAckGZfmrGqCb0hVRpiO sFoMQhPePgXNTYQQ6PTqcHCtZTLCNAEsIpT8ORjN1/X9j29dX6zYRDScFUr4cB42hBIC8g nQfE3Hf1vyTwlVeSp6TmPG1YZs6tImk= X-MC-Unique: veKaVINbOGeW8Y4C1ng5hA-1 From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v4 05/25] nodedev: add ability to parse mdevs from mdevctl Date: Wed, 3 Feb 2021 11:38:49 -0600 Message-Id: <20210203173909.1273000-6-jjongsma@redhat.com> In-Reply-To: <20210203173909.1273000-1-jjongsma@redhat.com> References: <20210203173909.1273000-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-loop: libvir-list@redhat.com Cc: eskultet@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" 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 --- src/node_device/node_device_driver.c | 145 ++++++++++++++++++ src/node_device/node_device_driver.h | 4 + .../mdevctl-list-multiple.json | 59 +++++++ .../mdevctl-list-multiple.out.xml | 39 +++++ tests/nodedevmdevctltest.c | 56 ++++++- 5 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.json create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_de= vice_driver.c index 6143459618..fc5ac1d27e 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -853,6 +853,151 @@ virMdevctlStop(virNodeDeviceDefPtr def) } =20 =20 +static void mdevGenerateDeviceName(virNodeDeviceDefPtr dev) +{ + nodeDeviceGenerateName(dev, "mdev", dev->caps->data.mdev.uuid, NULL); +} + + +static virNodeDeviceDefPtr +nodeDeviceParseMdevctlChildDevice(const char *parent, + virJSONValuePtr json) +{ + virNodeDevCapMdevPtr mdev; + const char *uuid; + virJSONValuePtr props, attrs; + g_autoptr(virNodeDeviceDef) child =3D 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) !=3D 1) + return NULL; + + uuid =3D virJSONValueObjectGetKey(json, 0); + props =3D virJSONValueObjectGetValue(json, 0); + + child->parent =3D g_strdup(parent); + child->caps =3D g_new0(virNodeDevCapsDef, 1); + child->caps->data.type =3D VIR_NODE_DEV_CAP_MDEV; + + mdev =3D &child->caps->data.mdev; + mdev->uuid =3D g_strdup(uuid); + mdev->type =3D + g_strdup(virJSONValueObjectGetString(props, "mdev_type")); + + attrs =3D virJSONValueObjectGet(props, "attrs"); + + if (attrs && virJSONValueIsArray(attrs)) { + size_t i; + int nattrs =3D virJSONValueArraySize(attrs); + + mdev->attributes =3D g_new0(virMediatedDeviceAttrPtr, nattrs); + mdev->nattributes =3D nattrs; + + for (i =3D 0; i < nattrs; i++) { + virJSONValuePtr attr =3D virJSONValueArrayGet(attrs, i); + virMediatedDeviceAttrPtr attribute; + virJSONValuePtr value; + + if (!virJSONValueIsObject(attr) || + virJSONValueObjectKeysNumber(attr) !=3D 1) + return NULL; + + attribute =3D g_new0(virMediatedDeviceAttr, 1); + attribute->name =3D g_strdup(virJSONValueObjectGetKey(attr, 0)= ); + value =3D virJSONValueObjectGetValue(attr, 0); + attribute->value =3D g_strdup(virJSONValueGetString(value)); + mdev->attributes[i] =3D attribute; + } + } + mdevGenerateDeviceName(child); + + return g_steal_pointer(&child); +} + + +int +nodeDeviceParseMdevctlJSON(const char *jsonstring, + virNodeDeviceDefPtr **devs) +{ + int n; + g_autoptr(virJSONValue) json_devicelist =3D NULL; + virNodeDeviceDefPtr *outdevs =3D NULL; + size_t noutdevs =3D 0; + size_t i; + size_t j; + + json_devicelist =3D virJSONValueFromString(jsonstring); + + if (!json_devicelist || !virJSONValueIsArray(json_devicelist)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("JSON response contains no devices")); + goto error; + } + + n =3D virJSONValueArraySize(json_devicelist); + + for (i =3D 0; i < n; i++) { + virJSONValuePtr obj =3D virJSONValueArrayGet(json_devicelist, i); + const char *parent; + virJSONValuePtr 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 d= evice + * object containing a single key-value pair which maps from the n= ame + * of the parent device to an array of child devices */ + if (virJSONValueObjectKeysNumber(obj) !=3D 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unexpected format for parent device object")= ); + goto error; + } + + parent =3D virJSONValueObjectGetKey(obj, 0); + child_array =3D virJSONValueObjectGetValue(obj, 0); + + if (!virJSONValueIsArray(child_array)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Child list is not an array")); + goto error; + } + + nchildren =3D virJSONValueArraySize(child_array); + + for (j =3D 0; j < nchildren; j++) { + g_autoptr(virNodeDeviceDef) child =3D NULL; + virJSONValuePtr child_obj =3D virJSONValueArrayGet(child_array= , j); + + if (!(child =3D nodeDeviceParseMdevctlChildDevice(parent, chil= d_obj))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to parse child device")); + goto error; + } + + if (VIR_APPEND_ELEMENT(outdevs, noutdevs, child) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to append child device to list")); + goto error; + } + } + } + + *devs =3D outdevs; + return noutdevs; + + error: + for (i =3D 0; i < noutdevs; i++) + virNodeDeviceDefFree(outdevs[i]); + VIR_FREE(outdevs); + return -1; +} + + int nodeDeviceDestroy(virNodeDevicePtr device) { diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_de= vice_driver.h index 02baf56dab..2a162513c0 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -119,6 +119,10 @@ nodeDeviceGetMdevctlStartCommand(virNodeDeviceDefPtr d= ef, virCommandPtr nodeDeviceGetMdevctlStopCommand(const char *uuid); =20 +int +nodeDeviceParseMdevctlJSON(const char *jsonstring, + virNodeDeviceDefPtr **devs); + void nodeDeviceGenerateName(virNodeDeviceDefPtr def, const char *subsystem, diff --git a/tests/nodedevmdevctldata/mdevctl-list-multiple.json b/tests/no= dedevmdevctldata/mdevctl-list-multiple.json new file mode 100644 index 0000000000..eefcd90c62 --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-list-multiple.json @@ -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" + } + ] + } + } + ] + } +] + diff --git a/tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml b/tests= /nodedevmdevctldata/mdevctl-list-multiple.out.xml new file mode 100644 index 0000000000..543ad916b7 --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml @@ -0,0 +1,39 @@ + + mdev_200f228a_c80a_4d50_bfb7_f5a0e4e34045 + 0000:00:02.0 + + + + + + + mdev_de807ffc_1923_4d5f_b6c9_b20ecebc6d4b + 0000:00:02.0 + + + + + + + mdev_435722ea_5f43_468a_874f_da34f1217f13 + 0000:00:02.0 + + + + + + + + mdev_783e6dbb_ea0e_411f_94e2_717eaad438bf + matrix + + + + + + + + + + + diff --git a/tests/nodedevmdevctltest.c b/tests/nodedevmdevctltest.c index 1d3cb00400..93f4e3252c 100644 --- a/tests/nodedevmdevctltest.c +++ b/tests/nodedevmdevctltest.c @@ -143,6 +143,53 @@ testMdevctlStop(const void *data) return ret; } =20 + +static int +testMdevctlParse(const void *data) +{ + g_autofree char *buf =3D NULL; + const char *filename =3D data; + g_autofree char *jsonfile =3D g_strdup_printf("%s/nodedevmdevctldata/%= s.json", + abs_srcdir, filename); + g_autofree char *xmloutfile =3D g_strdup_printf("%s/nodedevmdevctldata= /%s.out.xml", + abs_srcdir, filename); + int ret =3D -1; + int nmdevs =3D 0; + virNodeDeviceDefPtr *mdevs =3D NULL; + virBuffer xmloutbuf =3D 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 =3D nodeDeviceParseMdevctlJSON(buf, &mdevs)) < 0) { + VIR_TEST_DEBUG("Unable to parse json for %s", filename); + return -1; + } + + for (i =3D 0; i < nmdevs; i++) { + g_autofree char *devxml =3D virNodeDeviceDefFormat(mdevs[i]); + if (!devxml) + goto cleanup; + virBufferAddStr(&xmloutbuf, devxml); + } + + if (nodedevCompareToFile(virBufferCurrentContent(&xmloutbuf), xmloutfi= le) < 0) + goto cleanup; + + ret =3D 0; + + cleanup: + virBufferFreeAndReset(&xmloutbuf); + for (i =3D 0; i < nmdevs; i++) + virNodeDeviceDefFree(mdevs[i]); + g_free(mdevs); + + return ret; +} + static void nodedevTestDriverFree(virNodeDeviceDriverStatePtr drv) { @@ -263,13 +310,13 @@ mymain(void) } =20 #define DO_TEST_FULL(desc, func, info) \ - if (virTestRun(desc, func, &info) < 0) \ + if (virTestRun(desc, func, info) < 0) \ ret =3D -1; =20 #define DO_TEST_START_FULL(virt_type, create, filename) \ do { \ struct startTestInfo info =3D { virt_type, create, filename }; \ - DO_TEST_FULL("mdevctl start " filename, testMdevctlStartHelper, in= fo); \ + DO_TEST_FULL("mdevctl start " filename, testMdevctlStartHelper, &i= nfo); \ } \ while (0) =20 @@ -279,6 +326,9 @@ mymain(void) #define DO_TEST_STOP(uuid) \ DO_TEST_FULL("mdevctl stop " uuid, testMdevctlStop, uuid) =20 +#define DO_TEST_PARSE_JSON(filename) \ + DO_TEST_FULL("parse mdevctl json " filename, testMdevctlParse, filenam= e) + /* Test mdevctl start commands */ DO_TEST_START("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366"); DO_TEST_START("mdev_fedc4916_1ca8_49ac_b176_871d16c13076"); @@ -287,6 +337,8 @@ mymain(void) /* Test mdevctl stop command, pass an arbitrary uuid */ DO_TEST_STOP("e2451f73-c95b-4124-b900-e008af37c576"); =20 + DO_TEST_PARSE_JSON("mdevctl-list-multiple"); + done: nodedevTestDriverFree(driver); =20 --=20 2.26.2