libvirt/libvirt-qemu_agent-Introduce-guest-get-devices.patch
Jiri Denemark c6a4088d90 libvirt-12.5.0-3.el10
- qemu: Always assume support for 'QEMU_CAPS_SET_ACTION' (RHEL-242545)
- qemu: Remove unused 'qemuProcessRebootAllowed' (RHEL-242545)
- qemu: monitor: Remove support for 'watchdog-set-action' (RHEL-242545)
- qemu: Remove 'allowReboot' field (RHEL-242545)
- qemu: capabilities: Retire QEMU_CAPS_SET_ACTION (RHEL-242545)
- qemuProcessSetupLifecycleActions: Prepare to handle other actions (RHEL-242545)
- qemuDomainModifyLifecycleActionLive: Prepare to handle other actions (RHEL-242545)
- processGuestPanicEvent: Don't pass panic action via parameter (RHEL-242545)
- conf: Use proper enum types for 'onReboot', 'onPoweroff', 'onCrash', and 'onLockFailure' (RHEL-242545)
- qemuMonitorGuestPanicEventInfoFormatMsg: Directly return message (RHEL-242545)
- qemuProcessGuestPanicEventInfo: Fold into only caller (RHEL-242545)
- qemu: processGuestPanicEvent: Split individual steps under separate conditions (RHEL-242545)
- Add support for keeping VM running when panic notifier is used (RHEL-242545)
- qemu: Fix proper ordering of 'virtlockd' shutdown (RHEL-185108)
- qemu: move qemuAgent*InfoFormatParams to hypervisor/qemu_agent.c (RHEL-235731)
- Add guest device info to virDomainGetGuestInfo (RHEL-235731)
- qemu_agent: Introduce guest-get-devices (RHEL-235731)
- qemuagenttest: Introduce GetGuestDeviceInfo test case (RHEL-235731)
- qemu: Implement device info for virDomainGetGuestInfo() API (RHEL-235731)
- virsh: Add support for VIR_DOMAIN_GUEST_INFO_DEVICES (RHEL-235731)

Resolves: RHEL-185108, RHEL-235731, RHEL-242545
2026-08-19 14:56:37 +02:00

212 lines
7.3 KiB
Diff

From 97cc433df8d7eebda4985b76e4b38b0597c6ddc6 Mon Sep 17 00:00:00 2001
Message-ID: <97cc433df8d7eebda4985b76e4b38b0597c6ddc6.1787144197.git.jdenemar@redhat.com>
From: Michal Privoznik <mprivozn@redhat.com>
Date: Tue, 11 Aug 2026 17:08:05 +0200
Subject: [PATCH] qemu_agent: Introduce guest-get-devices
QEMU agent has 'guest-get-devices` command. Even though it's
currently implemented only for Windows, it shows some interesting
information from inside the guest, like device drivers, their
versions, and so on.
Looking at the command definition in qga/qapi-schema.json the
only non-optional field in returned data is 'driver-name'. The
rest is optional. Although looking at the current implementation
either all fields are set or device is ignored completely.
Nevertheless, our code should follow QMP schema.
New qemuAgentGuestDeviceInfo structure is introduced among with
qemuAgentGetGuestDeviceInfo() function which parses reply from
agent and fills the structure. Optional fields are either set to
NULL or -1, if missing.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
(cherry picked from commit 7dea038439aa025d18c716e3343d3f0e9ccd672a)
Resolves: https://redhat.atlassian.net/browse/RHEL-235731
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
src/hypervisor/qemu_agent.c | 119 ++++++++++++++++++++++++++++++++++++
src/hypervisor/qemu_agent.h | 21 +++++++
src/libvirt_private.syms | 2 +
3 files changed, 142 insertions(+)
diff --git a/src/hypervisor/qemu_agent.c b/src/hypervisor/qemu_agent.c
index 418386317d..fbfaafc1bb 100644
--- a/src/hypervisor/qemu_agent.c
+++ b/src/hypervisor/qemu_agent.c
@@ -2843,3 +2843,122 @@ qemuAgentInterfaceFormatParams(virDomainInterfacePtr *ifaces,
}
}
}
+
+
+void
+qemuAgentGuestDeviceInfoFree(qemuAgentGuestDeviceInfo *info)
+{
+ if (!info)
+ return;
+
+ g_free(info->driverName);
+ g_free(info->driverVersion);
+ g_free(info->pci);
+ g_free(info);
+}
+
+
+int
+qemuAgentGetGuestDeviceInfo(qemuAgent *agent,
+ qemuAgentGuestDeviceInfo ***info,
+ bool report_unsupported)
+{
+ g_autoptr(virJSONValue) cmd = NULL;
+ g_autoptr(virJSONValue) reply = NULL;
+ virJSONValue *data = NULL;
+ size_t ndata;
+ size_t i;
+ int rc;
+
+ if (!(cmd = qemuAgentMakeCommand("guest-get-devices", NULL)))
+ return -1;
+
+ if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
+ report_unsupported)) < 0)
+ return rc;
+
+ if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("qemu agent didn't return an array of devices"));
+ return -1;
+ }
+
+ ndata = virJSONValueArraySize(data);
+
+ *info = g_new0(qemuAgentGuestDeviceInfo *, ndata);
+
+ for (i = 0; i < ndata; i++) {
+ g_autoptr(qemuAgentGuestDeviceInfo) oneInfo = NULL;
+ virJSONValue *entry = virJSONValueArrayGet(data, i);
+ virJSONValue *dDate = NULL;
+ virJSONValue *idObj = NULL;
+
+ if (!entry) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("array element missing in guest-get-devices return value"));
+ goto error;
+ }
+
+ oneInfo = g_new0(qemuAgentGuestDeviceInfo, 1);
+
+ oneInfo->driverName = g_strdup(virJSONValueObjectGetString(entry, "driver-name"));
+ if (!oneInfo->driverName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'driver-name' missing in reply of guest-get-devices"));
+ goto error;
+ }
+
+ if ((dDate = virJSONValueObjectGet(entry, "driver-date"))) {
+ if (virJSONValueGetNumberLong(dDate, &oneInfo->driverDate) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed 'driver-date' in reply of guest-get-devices"));
+ goto error;
+ }
+ } else {
+ oneInfo->driverDate = -1;
+ }
+
+ oneInfo->driverVersion = g_strdup(virJSONValueObjectGetString(entry, "driver-version"));
+
+ if ((idObj = virJSONValueObjectGet(entry, "id"))) {
+ const char *type = NULL;
+
+ if (!(type = virJSONValueObjectGetString(idObj, "type"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing 'type' in reply of guest-get-devices"));
+ goto error;
+ }
+
+ if (STREQ("pci", type)) {
+ g_autofree qemuAgentGuestDeviceInfoPCI *pci = NULL;
+
+ pci = g_new0(qemuAgentGuestDeviceInfoPCI, 1);
+
+ if (virJSONValueObjectGetNumberUint(idObj, "vendor-id", &pci->vendorID) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing or malformed 'vendor-id' in reply of guest-get-devices"));
+ goto error;
+ }
+
+ if (virJSONValueObjectGetNumberUint(idObj, "device-id", &pci->deviceID) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing or malformed 'device-id' in reply of guest-get-devices"));
+ goto error;
+ }
+
+ oneInfo->pci = g_steal_pointer(&pci);
+ }
+ }
+
+ (*info)[i] = g_steal_pointer(&oneInfo);
+ }
+
+ return ndata;
+
+ error:
+ for (i = 0; i < ndata; i++) {
+ qemuAgentGuestDeviceInfoFree((*info)[i]);
+ }
+ g_clear_pointer(info, g_free);
+ return -1;
+}
diff --git a/src/hypervisor/qemu_agent.h b/src/hypervisor/qemu_agent.h
index def6f983d4..def4194ab7 100644
--- a/src/hypervisor/qemu_agent.h
+++ b/src/hypervisor/qemu_agent.h
@@ -218,3 +218,24 @@ void
qemuAgentInterfaceFormatParams(virDomainInterfacePtr *ifaces,
int nifaces,
virTypedParamList *list);
+
+typedef struct _qemuAgentGuestDeviceInfoPCI qemuAgentGuestDeviceInfoPCI;
+struct _qemuAgentGuestDeviceInfoPCI {
+ unsigned int vendorID;
+ unsigned int deviceID;
+};
+
+typedef struct _qemuAgentGuestDeviceInfo qemuAgentGuestDeviceInfo;
+struct _qemuAgentGuestDeviceInfo {
+ char *driverName;
+ long long driverDate; /* In nanoseconds since the epoch */
+ char *driverVersion;
+ qemuAgentGuestDeviceInfoPCI *pci;
+};
+
+void qemuAgentGuestDeviceInfoFree(qemuAgentGuestDeviceInfo *info);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuAgentGuestDeviceInfo, qemuAgentGuestDeviceInfoFree);
+
+int qemuAgentGetGuestDeviceInfo(qemuAgent *agent,
+ qemuAgentGuestDeviceInfo ***info,
+ bool report_unsupported);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 02bd505749..0bd8c6f781 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1726,6 +1726,7 @@ qemuAgentFSThaw;
qemuAgentFSTrim;
qemuAgentGetDisks;
qemuAgentGetFSInfo;
+qemuAgentGetGuestDeviceInfo;
qemuAgentGetHostname;
qemuAgentGetInterfaces;
qemuAgentGetLoadAvg;
@@ -1734,6 +1735,7 @@ qemuAgentGetTime;
qemuAgentGetTimezone;
qemuAgentGetUsers;
qemuAgentGetVCPUs;
+qemuAgentGuestDeviceInfoFree;
qemuAgentInterfaceFormatParams;
qemuAgentNotifyClose;
qemuAgentNotifyEvent;
--
2.55.0