- 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
212 lines
7.3 KiB
Diff
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
|