[libvirt] [PATCH v3 5/5] qemu: Connect to guest agent iff needed

Michal Privoznik mprivozn at redhat.com
Mon Jan 11 10:31:12 UTC 2016


https://bugzilla.redhat.com/show_bug.cgi?id=1293351

Since we already have virtio channel events, we know when guest
agent within guest has (dis-)connected. Instead of us blindly
connecting to a socket that no one is listening to, we can just
follow what qemu-ga does. This has a nice benefit that we don't
need to 'guest-ping' the agent just to timeout and find out
nobody is listening.

The way that this commit is implemented:
- don't connect in qemuProcessStart directly, defer that to event
  callback (which already follows the agent).
- after migration is settled, before we resume vCPUs, ask qemu
  whether somebody is listening on the socket and if so, connect
  to it.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/qemu/qemu_driver.c    | 21 ++++++++++++++++++++-
 src/qemu/qemu_migration.c | 20 ++++++++++++++++++++
 src/qemu/qemu_process.c   |  9 +++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8ccf68b..43ef18a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6650,12 +6650,13 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
                            bool start_paused,
                            qemuDomainAsyncJob asyncJob)
 {
-    int ret = -1;
+    int rc, ret = -1;
     virObjectEventPtr event;
     int intermediatefd = -1;
     virCommandPtr cmd = NULL;
     char *errbuf = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    qemuDomainObjPrivatePtr priv = vm->privateData;
 
     if ((header->version == 2) &&
         (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
@@ -6710,6 +6711,24 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
         goto cleanup;
     }
 
+    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VSERPORT_CHANGE)) {
+        /* If QEMU is capable of vserport_change events, we ought to
+         * refresh channel states here and possibly connect to the guest
+         * agent too. */
+        if (qemuProcessRefreshChannelState(driver, vm) < 0)
+            goto cleanup;
+
+        if ((rc = qemuConnectAgent(driver, vm)) < 0) {
+            if (rc == -2)
+                goto cleanup;
+
+            VIR_WARN("Cannot connect to QEMU guest agent for %s",
+                     vm->def->name);
+            virResetLastError();
+            priv->agentError = true;
+        }
+    }
+
     event = virDomainEventLifecycleNewFromObj(vm,
                                      VIR_DOMAIN_EVENT_STARTED,
                                      VIR_DOMAIN_EVENT_STARTED_RESTORED);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 51e7125..33ed738 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5795,6 +5795,7 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
     unsigned short port;
     unsigned long long timeReceived = 0;
     virObjectEventPtr event;
+    int rc;
 
     VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
               "cookieout=%p, cookieoutlen=%p, flags=%lx, retcode=%d",
@@ -5863,6 +5864,25 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
     if (qemuMigrationStopNBDServer(driver, vm, mig) < 0)
         goto endjob;
 
+    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VSERPORT_CHANGE)) {
+        /* If QEMU is capable of vserport_change events, we ought to
+         * refresh channel states here and possibly connect to the guest
+         * agent too. */
+        if (qemuProcessRefreshChannelState(driver, vm) < 0)
+            goto endjob;
+
+        if ((rc = qemuConnectAgent(driver, vm)) < 0) {
+            if (rc == -2)
+                goto endjob;
+
+            VIR_WARN("Cannot connect to QEMU guest agent for %s",
+                     vm->def->name);
+            virResetLastError();
+            priv->agentError = true;
+        }
+    }
+
+
     if (flags & VIR_MIGRATE_PERSIST_DEST) {
         if (qemuMigrationPersist(driver, vm, mig, !v3proto) < 0) {
             /* Hmpf.  Migration was successful, but making it persistent
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 43092d4..03b8d16 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -208,6 +208,15 @@ qemuConnectAgent(virQEMUDriverPtr driver, virDomainObjPtr vm)
     if (!config)
         return 0;
 
+    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VSERPORT_CHANGE) &&
+        config->state != VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED) {
+        /* So, qemu is capable of sending us event whenever guest agent
+         * (dis-)connects. And we reflect its state in config->state. So when
+         * we are called without proper state set, just defer connecting. */
+        VIR_DEBUG("Deferring connecting to guest agent");
+        return 0;
+    }
+
     if (virSecurityManagerSetDaemonSocketLabel(driver->securityManager,
                                                vm->def) < 0) {
         VIR_ERROR(_("Failed to set security context for agent for %s"),
-- 
2.4.10




More information about the libvir-list mailing list