From nobody Mon Feb 9 17:57:29 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; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=canonical.com 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 1632320662731185.70102982511537; Wed, 22 Sep 2021 07:24:22 -0700 (PDT) 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-445-BLAKc0ZwOLOukBrOmY5H3Q-1; Wed, 22 Sep 2021 10:24:19 -0400 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 364F01006AA2; Wed, 22 Sep 2021 14:24:14 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 943D26B54E; Wed, 22 Sep 2021 14:24:13 +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 5C10B1800B9C; Wed, 22 Sep 2021 14:24:10 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 18MEO8Nd028607 for ; Wed, 22 Sep 2021 10:24:08 -0400 Received: by smtp.corp.redhat.com (Postfix) id E4C4C203B865; Wed, 22 Sep 2021 14:24:07 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DB7C72026E03 for ; Wed, 22 Sep 2021 14:24:02 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C4C9618A01C3 for ; Wed, 22 Sep 2021 14:24:02 +0000 (UTC) Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-350-tv74qKSKOwaUMyUMotpz4Q-1; Wed, 22 Sep 2021 10:23:59 -0400 Received: from mail-lf1-f71.google.com (mail-lf1-f71.google.com [209.85.167.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id B8ECA3F325 for ; Wed, 22 Sep 2021 14:23:58 +0000 (UTC) Received: by mail-lf1-f71.google.com with SMTP id s28-20020a056512203c00b003f42015e912so2991868lfs.4 for ; Wed, 22 Sep 2021 07:23:58 -0700 (PDT) Received: from ws.. ([5.8.16.162]) by smtp.gmail.com with ESMTPSA id e3sm273868ljo.2.2021.09.22.07.23.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Sep 2021 07:23:57 -0700 (PDT) X-MC-Unique: BLAKc0ZwOLOukBrOmY5H3Q-1 X-MC-Unique: tv74qKSKOwaUMyUMotpz4Q-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fA+wsYS0rD2wUYq/dQugFcNCuUL+ZGz3vhVEygdXEZ8=; b=AdhdbnmzrkaxxAo5f2bSGTrIOGoKIZmYwzwqD1Cuu8Z1MgpqrP1UOxOc0pa8tSJ+Rb 5TePlVBP2K84cy/S9m8t0LaGeOnzaVcQx7wuTqX3Z8QZhV3+Cgk1uxbI1EwY9gzmi+hB 5W2SqmeJHyrbiJA3BrA7/xztuPXl6vnPZJF6PtADiwmBjzqXT8PiChOwzpNeHn4gn9Gr LMpxbZYZVR633bwn1NKYg0zbeaf+Aj8j5Jfrl1/uHrMn4Pd4uR6upDmCJvgGTfFMFRCa mN9Y6RCAFE3BIJmmXtEHCQM3NfWsHeFntNU2nDxp+bCz4K1Ck+ccwb4TsFn6BCXNBuEy bvMQ== X-Gm-Message-State: AOAM531PhPYLsJZFzCMx22D7pKwcVi5IcETULIp9O4Bixb0DbCl1zH2o Eq2Y5f1iGrano/p/vOEmDc7N25l8JzB4ymwo/PIF3TKbIfyBVoGEGfkdiWYcvMLA8cPsTRQEBDB 73YlUCtoEJZ2Z26uw5x+xa6v3xsRWM8NSTQ== X-Received: by 2002:a05:6512:3f89:: with SMTP id x9mr27384387lfa.392.1632320638107; Wed, 22 Sep 2021 07:23:58 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxcLNte5/+3CDptuWHeEwg/zm1jLACFEDxQByoGhCgplo06s11NxeKo5VcI+4ZJkZiYlGuSEQ== X-Received: by 2002:a05:6512:3f89:: with SMTP id x9mr27384354lfa.392.1632320637618; Wed, 22 Sep 2021 07:23:57 -0700 (PDT) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v4 2/4] Add PCI VPD-related helper functions to virpci Date: Wed, 22 Sep 2021 17:23:51 +0300 Message-Id: <20210922142353.957080-3-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20210922142353.957080-1-dmitrii.shcherbakov@canonical.com> References: <20210922142353.957080-1-dmitrii.shcherbakov@canonical.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 18MEO8Nd028607 X-loop: libvir-list@redhat.com Cc: pkrempa@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-ZM-MESSAGEID: 1632320663628100001 Content-Type: text/plain; charset="utf-8" Add helper functions to virpci to provide means of checking for a VPD file presence and for VPD resource retrieval using the PCI VPD parser. The added test assesses the basic functionality of VPD retrieval while the full parser is tested by virpcivpdtest. --- src/libvirt_private.syms | 2 ++ src/util/virpci.c | 62 ++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 3 ++ tests/virpcimock.c | 30 +++++++++++++++++++ tests/virpcitest.c | 64 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1a16d97e02..3035adebe1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2985,7 +2985,9 @@ virPCIDeviceGetReprobe; virPCIDeviceGetStubDriver; virPCIDeviceGetUnbindFromStub; virPCIDeviceGetUsedBy; +virPCIDeviceGetVPDResources; virPCIDeviceHasPCIExpressLink; +virPCIDeviceHasVPD; virPCIDeviceIsAssignable; virPCIDeviceIsPCIExpress; virPCIDeviceListAdd; diff --git a/src/util/virpci.c b/src/util/virpci.c index f307580a53..480d91c17f 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -37,6 +37,7 @@ #include "virkmod.h" #include "virstring.h" #include "viralloc.h" +#include "virpcivpd.h" =20 VIR_LOG_INIT("util.pci"); =20 @@ -2640,6 +2641,53 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_de= vice_path, return 0; } =20 + +gboolean +virPCIDeviceHasVPD(virPCIDevice *dev) +{ + g_autofree char *vpdPath =3D NULL; + vpdPath =3D virPCIFile(dev->name, "vpd"); + if (!virFileExists(vpdPath)) { + VIR_INFO("Device VPD file does not exist %s", vpdPath); + return false; + } else if (!virFileIsRegular(vpdPath)) { + VIR_WARN("VPD path does not point to a regular file %s", vpdPath); + return false; + } + return true; +} + +/** + * virPCIDeviceGetVPDResources: + * @dev: a PCI device to get a list of VPD resources for. + * + * Obtain resources stored in the PCI device's Vital Product Data (VPD). + * VPD is optional in both PCI Local Bus and PCIe specifications so there = is + * no guarantee it will be there for a particular device. + * + * Returns: a pointer to a list of VPDResource types which needs to be fre= ed by the caller or + * NULL if getting it failed for some reason. + */ +GList * +virPCIDeviceGetVPDResources(virPCIDevice *dev) +{ + g_autofree char *vpdPath =3D NULL; + int fd; + + vpdPath =3D virPCIFile(dev->name, "vpd"); + if (!virPCIDeviceHasVPD(dev)) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Device %s does not have = a VPD"), + virPCIDeviceGetName(dev)); + return NULL; + } + if ((fd =3D open(vpdPath, O_RDONLY)) < 0) { + virReportSystemError(-fd, + _("Failed to open a VPD file '%s'"), vpdPath); + return NULL; + } + return virPCIVPDParse(fd); +} + #else static const char *unsupported =3D N_("not supported on non-linux platform= s"); =20 @@ -2713,6 +2761,20 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_de= vice_path G_GNUC_UNUSED, virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; } + +gboolean +virPCIDeviceHasVPD(virPCIDevice *dev) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return NULL; +} + +GList * +virPCIDeviceGetVPDResources(virPCIDevice *dev) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return NULL; +} #endif /* __linux__ */ =20 int diff --git a/src/util/virpci.h b/src/util/virpci.h index 9a3db6c6d8..a89561496b 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -269,6 +269,9 @@ int virPCIGetVirtualFunctionInfo(const char *vf_sysfs_d= evice_path, char **pfname, int *vf_index); =20 +gboolean virPCIDeviceHasVPD(virPCIDevice *dev); +GList * virPCIDeviceGetVPDResources(virPCIDevice *dev); + int virPCIDeviceUnbind(virPCIDevice *dev); int virPCIDeviceRebind(virPCIDevice *dev); int virPCIDeviceGetDriverPathAndName(virPCIDevice *dev, diff --git a/tests/virpcimock.c b/tests/virpcimock.c index d4d43aac51..e10ebce76f 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -18,6 +18,8 @@ =20 #include =20 +#include "virpcivpd.h" + #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) # define VIR_MOCK_LOOKUP_MAIN # include "virmock.h" @@ -123,6 +125,13 @@ struct pciDeviceAddress { }; # define ADDR_STR_FMT "%04x:%02x:%02x.%u" =20 +struct pciVPD { + /* PCI VPD contents (binary, may contain NULLs), NULL if not present. = */ + const char *data; + /* VPD length in bytes. */ + size_t vpd_len; +}; + struct pciDevice { struct pciDeviceAddress addr; int vendor; @@ -131,6 +140,7 @@ struct pciDevice { int iommuGroup; const char *physfn; struct pciDriver *driver; /* Driver attached. NULL if attached to no= driver */ + struct pciVPD vpd; }; =20 struct fdCallback { @@ -537,6 +547,10 @@ pci_device_new_from_stub(const struct pciDevice *data) make_symlink(devpath, "physfn", tmp); } =20 + if (dev->vpd.data && dev->vpd.vpd_len) { + make_file(devpath, "vpd", dev->vpd.data, dev->vpd.vpd_len); + } + if (pci_device_autobind(dev) < 0) ABORT("Unable to bind: %s", devid); =20 @@ -942,6 +956,20 @@ static void init_env(void) { g_autofree char *tmp =3D NULL; + const char fullVPDExampleData[] =3D { + PCI_VPD_LARGE_RESOURCE_FLAG | PCI_VPD_STRING_RESOURCE_FLAG, 0x08, = 0x00, + 't', 'e', 's', 't', 'n', 'a', 'm', 'e', + PCI_VPD_LARGE_RESOURCE_FLAG | PCI_VPD_READ_ONLY_LARGE_RESOURCE_FLA= G, 0x16, 0x00, + 'P', 'N', 0x02, '4', '2', + 'E', 'C', 0x04, '4', '2', '4', '2', + 'V', 'A', 0x02, 'E', 'X', + 'R', 'V', 0x02, 0x31, 0x00, + PCI_VPD_RESOURCE_END_VAL + }; + struct pciVPD exampleVPD =3D { + .data =3D fullVPDExampleData, + .vpd_len =3D sizeof(fullVPDExampleData) / sizeof(fullVPDExampleDat= a[0]), + }; =20 if (!(fakerootdir =3D getenv("LIBVIRT_FAKE_ROOT_DIR"))) ABORT("Missing LIBVIRT_FAKE_ROOT_DIR env variable\n"); @@ -1008,6 +1036,8 @@ init_env(void) =20 MAKE_PCI_DEVICE("0000:01:00.0", 0x1cc1, 0x8201, 14, .klass =3D 0x01080= 2); MAKE_PCI_DEVICE("0000:02:00.0", 0x1cc1, 0x8201, 15, .klass =3D 0x01080= 2); + + MAKE_PCI_DEVICE("0000:03:00.0", 0x15b3, 0xa2d6, 16, .vpd =3D exampleVP= D); } =20 =20 diff --git a/tests/virpcitest.c b/tests/virpcitest.c index 6fe9b7d13a..c6bf12ba0b 100644 --- a/tests/virpcitest.c +++ b/tests/virpcitest.c @@ -17,6 +17,7 @@ */ =20 #include +#include "internal.h" =20 #include "testutils.h" =20 @@ -26,6 +27,7 @@ # include # include # include +# include =20 # define VIR_FROM_THIS VIR_FROM_NONE =20 @@ -328,6 +330,66 @@ testVirPCIDeviceUnbind(const void *opaque) return ret; } =20 + +static gboolean +testVirPCIGetOneResourceField(gpointer *key, gpointer *val, gpointer userD= ata) +{ + const char **fieldValue =3D (const char **)userData; + if (STREQ((const char*)key, "PN")) { + *fieldValue =3D (const char*)val; + return true; + } + return false; +} + +static int +testVirPCIDeviceGetVPDResources(const void *opaque) +{ + const struct testPCIDevData *data =3D opaque; + int ret =3D -1; + g_autofree virPCIDevice *dev =3D NULL; + virPCIDeviceAddress devAddr =3D {.domain =3D data->domain, .bus =3D da= ta->bus, + .slot =3D data->slot, .function =3D dat= a->function}; + g_autofree GList *resources =3D NULL; + const char* resValue =3D NULL; + const char* fieldValue =3D NULL; + virPCIVPDStringResource *strRes; + virPCIVPDKeywordResource *kwRes; + + dev =3D virPCIDeviceNew(&devAddr); + if (!dev) { + return ret; + } + + resources =3D virPCIDeviceGetVPDResources(dev); + + /* Here we simply check that 2 resources are present and their basic u= se. + * Full parser validation is done elsewhere. + */ + if (g_list_length(resources) !=3D 2) { + return ret; + } + + strRes =3D g_list_nth_data(resources, 0); + resValue =3D virPCIVPDStringResourceGetValue(strRes); + if (STRNEQ(resValue, "testname")) { + VIR_TEST_DEBUG("Unexpected string resource value: %s", resValue); + return ret; + } + kwRes =3D g_list_nth_data(resources, 1); + virPCIVPDKeywordResourceForEach(kwRes, + (GTraverseFunc)testVirPCIGetOneResourceField, &fieldValue); + + if (!fieldValue || STRNEQ(fieldValue, "42")) { + VIR_TEST_DEBUG("Could not retrieve an expected value from the Keyw= ord resource: %s", + resValue); + return ret; + } + + ret =3D 0; + return ret; +} + # define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" =20 static int @@ -409,6 +471,8 @@ mymain(void) DO_TEST_PCI(testVirPCIDeviceReattachSingle, 0, 0x0a, 3, 0); DO_TEST_PCI_DRIVER(0, 0x0a, 3, 0, NULL); =20 + DO_TEST_PCI(testVirPCIDeviceGetVPDResources, 0, 0x03, 0, 0); + if (getenv("LIBVIRT_SKIP_CLEANUP") =3D=3D NULL) virFileDeleteTree(fakerootdir); =20 --=20 2.30.2