- qemu: Always assume support for 'QEMU_CAPS_SET_ACTION' (RHEL-242546) - qemu: Remove unused 'qemuProcessRebootAllowed' (RHEL-242546) - qemu: monitor: Remove support for 'watchdog-set-action' (RHEL-242546) - qemu: Remove 'allowReboot' field (RHEL-242546) - qemu: capabilities: Retire QEMU_CAPS_SET_ACTION (RHEL-242546) - qemuProcessSetupLifecycleActions: Prepare to handle other actions (RHEL-242546) - qemuDomainModifyLifecycleActionLive: Prepare to handle other actions (RHEL-242546) - processGuestPanicEvent: Don't pass panic action via parameter (RHEL-242546) - conf: Use proper enum types for 'onReboot', 'onPoweroff', 'onCrash', and 'onLockFailure' (RHEL-242546) - qemuMonitorGuestPanicEventInfoFormatMsg: Directly return message (RHEL-242546) - qemuProcessGuestPanicEventInfo: Fold into only caller (RHEL-242546) - qemu: processGuestPanicEvent: Split individual steps under separate conditions (RHEL-242546) - Add support for keeping VM running when panic notifier is used (RHEL-242546) - qemu: Fix proper ordering of 'virtlockd' shutdown (RHEL-180876) - Add guest device info to virDomainGetGuestInfo (RHEL-243300) - qemu_agent: Introduce guest-get-devices (RHEL-243300) - qemuagenttest: Introduce GetGuestDeviceInfo test case (RHEL-243300) - qemu: Implement device info for virDomainGetGuestInfo() API (RHEL-243300) - virsh: Add support for VIR_DOMAIN_GUEST_INFO_DEVICES (RHEL-243300) Resolves: RHEL-180876, RHEL-242546, RHEL-243300
199 lines
6.9 KiB
Diff
199 lines
6.9 KiB
Diff
From 2eed5180fb11ed18a6cb35e77b7904e5af2eaacd Mon Sep 17 00:00:00 2001
|
|
Message-ID: <2eed5180fb11ed18a6cb35e77b7904e5af2eaacd.1787144643.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)
|
|
|
|
Conflicts:
|
|
src/libvirt_private.syms:
|
|
src/qemu/qemu_agent.c:
|
|
src/qemu/qemu_agent.h: All three conflicts are due to v12.4.0-rc1~76
|
|
not being backported (it moved parts of the
|
|
agent code under src/hypervisor for wider use).
|
|
|
|
Resolves: https://redhat.atlassian.net/browse/RHEL-243300
|
|
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
---
|
|
src/qemu/qemu_agent.c | 119 ++++++++++++++++++++++++++++++++++++++++++
|
|
src/qemu/qemu_agent.h | 21 ++++++++
|
|
2 files changed, 140 insertions(+)
|
|
|
|
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
|
|
index ee0921eca6..67faa5aa97 100644
|
|
--- a/src/qemu/qemu_agent.c
|
|
+++ b/src/qemu/qemu_agent.c
|
|
@@ -2599,3 +2599,122 @@ qemuAgentGetLoadAvg(qemuAgent *agent,
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+
|
|
+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/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
|
|
index 860f19b6bd..a6be2ff387 100644
|
|
--- a/src/qemu/qemu_agent.h
|
|
+++ b/src/qemu/qemu_agent.h
|
|
@@ -195,3 +195,24 @@ int qemuAgentGetLoadAvg(qemuAgent *agent,
|
|
double *load5m,
|
|
double *load15m,
|
|
bool report_unsupported);
|
|
+
|
|
+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);
|
|
--
|
|
2.55.0
|