From nobody Mon May 6 02:09:52 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1490370025427612.8123431641613; Fri, 24 Mar 2017 08:40:25 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B4F4180516; Fri, 24 Mar 2017 15:40:24 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8AF4E82FB1; Fri, 24 Mar 2017 15:40:24 +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 436985ED6C; Fri, 24 Mar 2017 15:40:24 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v2OFeFfa023353 for ; Fri, 24 Mar 2017 11:40:15 -0400 Received: by smtp.corp.redhat.com (Postfix) id 5B11282FA2; Fri, 24 Mar 2017 15:40:15 +0000 (UTC) Received: from virval.usersys.redhat.com (dhcp129-92.brq.redhat.com [10.34.129.92]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8896482FB0 for ; Fri, 24 Mar 2017 15:40:10 +0000 (UTC) Received: by virval.usersys.redhat.com (Postfix, from userid 500) id B24171003C5; Fri, 24 Mar 2017 16:40:09 +0100 (CET) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B4F4180516 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com B4F4180516 From: Jiri Denemark To: libvir-list@redhat.com Date: Fri, 24 Mar 2017 16:40:05 +0100 Message-Id: <1af97087740a0c69468ec5ab7bb63378264caee7.1490369794.git.jdenemar@redhat.com> In-Reply-To: References: In-Reply-To: References: Mail-Followup-To: libvir-list@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 1/4] qemu: Move migration cookies to a separate file 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Fri, 24 Mar 2017 15:40:25 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Jiri Denemark --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/qemu/qemu_migration.c | 1407 +---------------------------------= ---- src/qemu/qemu_migration_cookie.c | 1340 ++++++++++++++++++++++++++++++++++= ++ src/qemu/qemu_migration_cookie.h | 153 +++++ 5 files changed, 1496 insertions(+), 1406 deletions(-) create mode 100644 src/qemu/qemu_migration_cookie.c create mode 100644 src/qemu/qemu_migration_cookie.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 64cb88cfa..d9e9d0591 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -141,6 +141,7 @@ src/qemu/qemu_hostdev.c src/qemu/qemu_hotplug.c src/qemu/qemu_interface.c src/qemu/qemu_migration.c +src/qemu/qemu_migration_cookie.c src/qemu/qemu_monitor.c src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_text.c diff --git a/src/Makefile.am b/src/Makefile.am index 3b1bb1da3..3295bc2c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -839,6 +839,7 @@ QEMU_DRIVER_SOURCES =3D \ qemu/qemu_process.c qemu/qemu_process.h \ qemu/qemu_processpriv.h \ qemu/qemu_migration.c qemu/qemu_migration.h \ + qemu/qemu_migration_cookie.c qemu/qemu_migration_cookie.h \ qemu/qemu_monitor.c qemu/qemu_monitor.h \ qemu/qemu_monitor_text.c \ qemu/qemu_monitor_text.h \ diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f5711bcf7..b1d141755 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -24,14 +24,11 @@ #include #include #include -#ifdef WITH_GNUTLS -# include -# include -#endif #include #include =20 #include "qemu_migration.h" +#include "qemu_migration_cookie.h" #include "qemu_monitor.h" #include "qemu_domain.h" #include "qemu_process.h" @@ -85,1408 +82,6 @@ VIR_ENUM_IMPL(qemuMigrationCompressMethod, QEMU_MIGRAT= ION_COMPRESS_LAST, "mt", ); =20 -enum qemuMigrationCookieFlags { - QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, - QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, - QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT, - QEMU_MIGRATION_COOKIE_FLAG_NETWORK, - QEMU_MIGRATION_COOKIE_FLAG_NBD, - QEMU_MIGRATION_COOKIE_FLAG_STATS, - QEMU_MIGRATION_COOKIE_FLAG_MEMORY_HOTPLUG, - QEMU_MIGRATION_COOKIE_FLAG_CPU_HOTPLUG, - - QEMU_MIGRATION_COOKIE_FLAG_LAST -}; - -VIR_ENUM_DECL(qemuMigrationCookieFlag); -VIR_ENUM_IMPL(qemuMigrationCookieFlag, - QEMU_MIGRATION_COOKIE_FLAG_LAST, - "graphics", - "lockstate", - "persistent", - "network", - "nbd", - "statistics", - "memory-hotplug", - "cpu-hotplug"); - -enum qemuMigrationCookieFeatures { - QEMU_MIGRATION_COOKIE_GRAPHICS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_G= RAPHICS), - QEMU_MIGRATION_COOKIE_LOCKSTATE =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_L= OCKSTATE), - QEMU_MIGRATION_COOKIE_PERSISTENT =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_= PERSISTENT), - QEMU_MIGRATION_COOKIE_NETWORK =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_NET= WORK), - QEMU_MIGRATION_COOKIE_NBD =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_NBD), - QEMU_MIGRATION_COOKIE_STATS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS= ), - QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_F= LAG_MEMORY_HOTPLUG), - QEMU_MIGRATION_COOKIE_CPU_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_FLAG= _CPU_HOTPLUG), -}; - -typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; -typedef qemuMigrationCookieGraphics *qemuMigrationCookieGraphicsPtr; -struct _qemuMigrationCookieGraphics { - int type; - int port; - int tlsPort; - char *listen; - char *tlsSubject; -}; - -typedef struct _qemuMigrationCookieNetData qemuMigrationCookieNetData; -typedef qemuMigrationCookieNetData *qemuMigrationCookieNetDataPtr; -struct _qemuMigrationCookieNetData { - int vporttype; /* enum virNetDevVPortProfile */ - - /* - * Array of pointers to saved data. Each VIF will have its own - * data to transfer. - */ - char *portdata; -}; - -typedef struct _qemuMigrationCookieNetwork qemuMigrationCookieNetwork; -typedef qemuMigrationCookieNetwork *qemuMigrationCookieNetworkPtr; -struct _qemuMigrationCookieNetwork { - /* How many virtual NICs are we saving data for? */ - int nnets; - - qemuMigrationCookieNetDataPtr net; -}; - -typedef struct _qemuMigrationCookieNBD qemuMigrationCookieNBD; -typedef qemuMigrationCookieNBD *qemuMigrationCookieNBDPtr; -struct _qemuMigrationCookieNBD { - int port; /* on which port does NBD server listen for incoming data */ - - size_t ndisks; /* Number of items in @disk array */ - struct { - char *target; /* Disk target */ - unsigned long long capacity; /* And its capacity */ - } *disks; -}; - -typedef struct _qemuMigrationCookie qemuMigrationCookie; -typedef qemuMigrationCookie *qemuMigrationCookiePtr; -struct _qemuMigrationCookie { - unsigned int flags; - unsigned int flagsMandatory; - - /* Host properties */ - unsigned char localHostuuid[VIR_UUID_BUFLEN]; - unsigned char remoteHostuuid[VIR_UUID_BUFLEN]; - char *localHostname; - char *remoteHostname; - - /* Guest properties */ - unsigned char uuid[VIR_UUID_BUFLEN]; - char *name; - - /* If (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) */ - char *lockState; - char *lockDriver; - - /* If (flags & QEMU_MIGRATION_COOKIE_GRAPHICS) */ - qemuMigrationCookieGraphicsPtr graphics; - - /* If (flags & QEMU_MIGRATION_COOKIE_PERSISTENT) */ - virDomainDefPtr persistent; - - /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */ - qemuMigrationCookieNetworkPtr network; - - /* If (flags & QEMU_MIGRATION_COOKIE_NBD) */ - qemuMigrationCookieNBDPtr nbd; - - /* If (flags & QEMU_MIGRATION_COOKIE_STATS) */ - qemuDomainJobInfoPtr jobInfo; -}; - -static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr= grap) -{ - if (!grap) - return; - VIR_FREE(grap->listen); - VIR_FREE(grap->tlsSubject); - VIR_FREE(grap); -} - - -static void -qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network) -{ - size_t i; - - if (!network) - return; - - if (network->net) { - for (i =3D 0; i < network->nnets; i++) - VIR_FREE(network->net[i].portdata); - } - VIR_FREE(network->net); - VIR_FREE(network); -} - - -static void qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd) -{ - if (!nbd) - return; - - while (nbd->ndisks) - VIR_FREE(nbd->disks[--nbd->ndisks].target); - VIR_FREE(nbd->disks); - VIR_FREE(nbd); -} - - -static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) -{ - if (!mig) - return; - - qemuMigrationCookieGraphicsFree(mig->graphics); - qemuMigrationCookieNetworkFree(mig->network); - qemuMigrationCookieNBDFree(mig->nbd); - - VIR_FREE(mig->localHostname); - VIR_FREE(mig->remoteHostname); - VIR_FREE(mig->name); - VIR_FREE(mig->lockState); - VIR_FREE(mig->lockDriver); - VIR_FREE(mig->jobInfo); - VIR_FREE(mig); -} - - -#ifdef WITH_GNUTLS -static char * -qemuDomainExtractTLSSubject(const char *certdir) -{ - char *certfile =3D NULL; - char *subject =3D NULL; - char *pemdata =3D NULL; - gnutls_datum_t pemdatum; - gnutls_x509_crt_t cert; - int ret; - size_t subjectlen; - - if (virAsprintf(&certfile, "%s/server-cert.pem", certdir) < 0) - goto error; - - if (virFileReadAll(certfile, 8192, &pemdata) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unable to read server cert %s"), certfile); - goto error; - } - - ret =3D gnutls_x509_crt_init(&cert); - if (ret < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot initialize cert object: %s"), - gnutls_strerror(ret)); - goto error; - } - - pemdatum.data =3D (unsigned char *)pemdata; - pemdatum.size =3D strlen(pemdata); - - ret =3D gnutls_x509_crt_import(cert, &pemdatum, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot load cert data from %s: %s"), - certfile, gnutls_strerror(ret)); - goto error; - } - - subjectlen =3D 1024; - if (VIR_ALLOC_N(subject, subjectlen+1) < 0) - goto error; - - gnutls_x509_crt_get_dn(cert, subject, &subjectlen); - subject[subjectlen] =3D '\0'; - - VIR_FREE(certfile); - VIR_FREE(pemdata); - - return subject; - - error: - VIR_FREE(certfile); - VIR_FREE(pemdata); - return NULL; -} -#endif - -static qemuMigrationCookieGraphicsPtr -qemuMigrationCookieGraphicsSpiceAlloc(virQEMUDriverPtr driver, - virDomainGraphicsDefPtr def, - virDomainGraphicsListenDefPtr gliste= n) -{ - qemuMigrationCookieGraphicsPtr mig =3D NULL; - const char *listenAddr; - virQEMUDriverConfigPtr cfg =3D virQEMUDriverGetConfig(driver); - - if (VIR_ALLOC(mig) < 0) - goto error; - - mig->type =3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE; - mig->port =3D def->data.spice.port; - if (cfg->spiceTLS) - mig->tlsPort =3D def->data.spice.tlsPort; - else - mig->tlsPort =3D -1; - - if (!glisten || !(listenAddr =3D glisten->address)) - listenAddr =3D cfg->spiceListen; - -#ifdef WITH_GNUTLS - if (cfg->spiceTLS && - !(mig->tlsSubject =3D qemuDomainExtractTLSSubject(cfg->spiceTLSx50= 9certdir))) - goto error; -#endif - if (VIR_STRDUP(mig->listen, listenAddr) < 0) - goto error; - - virObjectUnref(cfg); - return mig; - - error: - qemuMigrationCookieGraphicsFree(mig); - virObjectUnref(cfg); - return NULL; -} - - -static qemuMigrationCookieNetworkPtr -qemuMigrationCookieNetworkAlloc(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - virDomainDefPtr def) -{ - qemuMigrationCookieNetworkPtr mig; - size_t i; - - if (VIR_ALLOC(mig) < 0) - goto error; - - mig->nnets =3D def->nnets; - - if (VIR_ALLOC_N(mig->net, def->nnets) <0) - goto error; - - for (i =3D 0; i < def->nnets; i++) { - virDomainNetDefPtr netptr; - virNetDevVPortProfilePtr vport; - - netptr =3D def->nets[i]; - vport =3D virDomainNetGetActualVirtPortProfile(netptr); - - if (vport) { - mig->net[i].vporttype =3D vport->virtPortType; - - switch (vport->virtPortType) { - case VIR_NETDEV_VPORT_PROFILE_NONE: - case VIR_NETDEV_VPORT_PROFILE_8021QBG: - case VIR_NETDEV_VPORT_PROFILE_8021QBH: - break; - case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: - if (virNetDevOpenvswitchGetMigrateData(&mig->net[i].portda= ta, - netptr->ifname) != =3D 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to run command to get OVS= port data for " - "interface %s"), netptr->ifname); - goto error; - } - break; - default: - break; - } - } - } - return mig; - - error: - qemuMigrationCookieNetworkFree(mig); - return NULL; -} - -static qemuMigrationCookiePtr -qemuMigrationCookieNew(virDomainObjPtr dom) -{ - qemuDomainObjPrivatePtr priv =3D dom->privateData; - qemuMigrationCookiePtr mig =3D NULL; - const char *name; - - if (VIR_ALLOC(mig) < 0) - goto error; - - if (priv->origname) - name =3D priv->origname; - else - name =3D dom->def->name; - if (VIR_STRDUP(mig->name, name) < 0) - goto error; - memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); - - if (!(mig->localHostname =3D virGetHostname())) - goto error; - if (virGetHostUUID(mig->localHostuuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to obtain host UUID")); - goto error; - } - - return mig; - - error: - qemuMigrationCookieFree(mig); - return NULL; -} - - -static int -qemuMigrationCookieAddGraphics(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - virDomainObjPtr dom) -{ - size_t i =3D 0; - - if (mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Migration graphics data already present")); - return -1; - } - - for (i =3D 0; i < dom->def->ngraphics; i++) { - if (dom->def->graphics[i]->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SP= ICE) { - virDomainGraphicsListenDefPtr glisten =3D - virDomainGraphicsGetListen(dom->def->graphics[i], 0); - - if (!glisten) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("missing listen element")); - return -1; - } - - switch (glisten->type) { - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: - /* Seamless migration is supported only for listen types - * 'address and 'network'. */ - if (!(mig->graphics =3D - qemuMigrationCookieGraphicsSpiceAlloc(driver, - dom->def->grap= hics[i], - glisten))) - return -1; - mig->flags |=3D QEMU_MIGRATION_COOKIE_GRAPHICS; - break; - - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET: - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE: - case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST: - break; - } - - /* Seamless migration is supported only for one graphics. */ - if (mig->graphics) - break; - } - } - - return 0; -} - - -static int -qemuMigrationCookieAddLockstate(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - virDomainObjPtr dom) -{ - qemuDomainObjPrivatePtr priv =3D dom->privateData; - - if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Migration lockstate data already present")); - return -1; - } - - if (virDomainObjGetState(dom, NULL) =3D=3D VIR_DOMAIN_PAUSED) { - if (VIR_STRDUP(mig->lockState, priv->lockState) < 0) - return -1; - } else { - if (virDomainLockProcessInquire(driver->lockManager, dom, &mig->lo= ckState) < 0) - return -1; - } - - if (VIR_STRDUP(mig->lockDriver, virLockManagerPluginGetName(driver->lo= ckManager)) < 0) { - VIR_FREE(mig->lockState); - return -1; - } - - mig->flags |=3D QEMU_MIGRATION_COOKIE_LOCKSTATE; - mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_LOCKSTATE; - - return 0; -} - - -static int -qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, - virDomainDefPtr def) -{ - if (mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Migration persistent data already present")); - return -1; - } - - if (!def) - return 0; - - mig->persistent =3D def; - mig->flags |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; - mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; - return 0; -} - - -static virDomainDefPtr -qemuMigrationCookieGetPersistent(qemuMigrationCookiePtr mig) -{ - virDomainDefPtr def =3D mig->persistent; - - mig->persistent =3D NULL; - mig->flags &=3D ~QEMU_MIGRATION_COOKIE_PERSISTENT; - mig->flagsMandatory &=3D ~QEMU_MIGRATION_COOKIE_PERSISTENT; - - return def; -} - - -static int -qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - virDomainObjPtr dom) -{ - if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Network migration data already present")); - return -1; - } - - if (dom->def->nnets > 0) { - mig->network =3D qemuMigrationCookieNetworkAlloc(driver, dom->def); - if (!mig->network) - return -1; - mig->flags |=3D QEMU_MIGRATION_COOKIE_NETWORK; - } - - return 0; -} - - -static int -qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - virDomainObjPtr vm) -{ - qemuDomainObjPrivatePtr priv =3D vm->privateData; - virHashTablePtr stats =3D NULL; - size_t i; - int ret =3D -1, rc; - - /* It is not a bug if there already is a NBD data */ - qemuMigrationCookieNBDFree(mig->nbd); - - if (VIR_ALLOC(mig->nbd) < 0) - return -1; - - if (vm->def->ndisks && - VIR_ALLOC_N(mig->nbd->disks, vm->def->ndisks) < 0) - return -1; - mig->nbd->ndisks =3D 0; - - for (i =3D 0; i < vm->def->ndisks; i++) { - virDomainDiskDefPtr disk =3D vm->def->disks[i]; - qemuBlockStats *entry; - - if (!stats) { - if (!(stats =3D virHashCreate(10, virHashValueFree))) - goto cleanup; - - if (qemuDomainObjEnterMonitorAsync(driver, vm, - priv->job.asyncJob) < 0) - goto cleanup; - rc =3D qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats, f= alse); - if (qemuDomainObjExitMonitor(driver, vm) < 0) - goto cleanup; - if (rc < 0) - goto cleanup; - } - - if (!disk->info.alias || - !(entry =3D virHashLookup(stats, disk->info.alias))) - continue; - - if (VIR_STRDUP(mig->nbd->disks[mig->nbd->ndisks].target, - disk->dst) < 0) - goto cleanup; - mig->nbd->disks[mig->nbd->ndisks].capacity =3D entry->capacity; - mig->nbd->ndisks++; - } - - mig->nbd->port =3D priv->nbdPort; - mig->flags |=3D QEMU_MIGRATION_COOKIE_NBD; - - ret =3D 0; - cleanup: - virHashFree(stats); - return ret; -} - - -static int -qemuMigrationCookieAddStatistics(qemuMigrationCookiePtr mig, - virDomainObjPtr vm) -{ - qemuDomainObjPrivatePtr priv =3D vm->privateData; - - if (!priv->job.completed) - return 0; - - if (!mig->jobInfo && VIR_ALLOC(mig->jobInfo) < 0) - return -1; - - *mig->jobInfo =3D *priv->job.completed; - mig->flags |=3D QEMU_MIGRATION_COOKIE_STATS; - - return 0; -} - - -static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, - qemuMigrationCookieGraphi= csPtr grap) -{ - virBufferAsprintf(buf, "type), - grap->port, grap->listen); - if (grap->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) - virBufferAsprintf(buf, " tlsPort=3D'%d'", grap->tlsPort); - if (grap->tlsSubject) { - virBufferAddLit(buf, ">\n"); - virBufferAdjustIndent(buf, 2); - virBufferEscapeString(buf, "\= n", grap->tlsSubject); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - } else { - virBufferAddLit(buf, "/>\n"); - } -} - - -static void -qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf, - qemuMigrationCookieNetworkPtr optr) -{ - size_t i; - bool empty =3D true; - - for (i =3D 0; i < optr->nnets; i++) { - /* If optr->net[i].vporttype is not set, there is nothing to trans= fer */ - if (optr->net[i].vporttype !=3D VIR_NETDEV_VPORT_PROFILE_NONE) { - if (empty) { - virBufferAddLit(buf, "\n"); - virBufferAdjustIndent(buf, 2); - empty =3D false; - } - virBufferAsprintf(buf, "net[i].v= porttype)); - if (optr->net[i].portdata) { - virBufferAddLit(buf, ">\n"); - virBufferAdjustIndent(buf, 2); - virBufferEscapeString(buf, "%s\n", - optr->net[i].portdata); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - } else { - virBufferAddLit(buf, "/>\n"); - } - } - } - if (!empty) { - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - } -} - - -static void -qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, - qemuDomainJobInfoPtr jobInfo) -{ - qemuMonitorMigrationStats *stats =3D &jobInfo->stats; - - virBufferAddLit(buf, "\n"); - virBufferAdjustIndent(buf, 2); - - virBufferAsprintf(buf, "%llu\n", jobInfo->started); - virBufferAsprintf(buf, "%llu\n", jobInfo->stopped); - virBufferAsprintf(buf, "%llu\n", jobInfo->sent); - if (jobInfo->timeDeltaSet) - virBufferAsprintf(buf, "%lld\n", jobInfo->timeDelta= ); - - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_TIME_ELAPSED, - jobInfo->timeElapsed); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_TIME_REMAINING, - jobInfo->timeRemaining); - if (stats->downtime_set) - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_DOWNTIME, - stats->downtime); - if (stats->setup_time_set) - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_SETUP_TIME, - stats->setup_time); - - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_TOTAL, - stats->ram_total); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_PROCESSED, - stats->ram_transferred); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_REMAINING, - stats->ram_remaining); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_BPS, - stats->ram_bps); - - if (stats->ram_duplicate_set) { - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_CONSTANT, - stats->ram_duplicate); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_NORMAL, - stats->ram_normal); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES, - stats->ram_normal_bytes); - } - - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE, - stats->ram_dirty_rate); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_MEMORY_ITERATION, - stats->ram_iteration); - - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_DISK_TOTAL, - stats->disk_total); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_DISK_PROCESSED, - stats->disk_transferred); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_DISK_REMAINING, - stats->disk_remaining); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_DISK_BPS, - stats->disk_bps); - - if (stats->xbzrle_set) { - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_COMPRESSION_CACHE, - stats->xbzrle_cache_size); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_COMPRESSION_BYTES, - stats->xbzrle_bytes); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_COMPRESSION_PAGES, - stats->xbzrle_pages); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES, - stats->xbzrle_cache_miss); - virBufferAsprintf(buf, "<%1$s>%2$llu\n", - VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW, - stats->xbzrle_overflow); - } - - virBufferAsprintf(buf, "<%1$s>%2$d\n", - VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE, - stats->cpu_throttle_percentage); - - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); -} - - -static int -qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, - virBufferPtr buf, - qemuMigrationCookiePtr mig) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - char hostuuidstr[VIR_UUID_STRING_BUFLEN]; - size_t i; - - virUUIDFormat(mig->uuid, uuidstr); - virUUIDFormat(mig->localHostuuid, hostuuidstr); - - virBufferAddLit(buf, "\n"); - virBufferAdjustIndent(buf, 2); - virBufferEscapeString(buf, "%s\n", mig->name); - virBufferAsprintf(buf, "%s\n", uuidstr); - virBufferEscapeString(buf, "%s\n", mig->localHost= name); - virBufferAsprintf(buf, "%s\n", hostuuidstr); - - for (i =3D 0; i < QEMU_MIGRATION_COOKIE_FLAG_LAST; i++) { - if (mig->flagsMandatory & (1 << i)) - virBufferAsprintf(buf, "\n", - qemuMigrationCookieFlagTypeToString(i)); - } - - if ((mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) && - mig->graphics) - qemuMigrationCookieGraphicsXMLFormat(buf, mig->graphics); - - if ((mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) && - mig->lockState) { - virBufferAsprintf(buf, "\n", - mig->lockDriver); - virBufferAdjustIndent(buf, 2); - virBufferAsprintf(buf, "%s\n", - mig->lockState); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - } - - if ((mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) && - mig->persistent) { - if (qemuDomainDefFormatBuf(driver, - mig->persistent, - VIR_DOMAIN_XML_INACTIVE | - VIR_DOMAIN_XML_SECURE | - VIR_DOMAIN_XML_MIGRATABLE, - buf) < 0) - return -1; - } - - if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network) - qemuMigrationCookieNetworkXMLFormat(buf, mig->network); - - if ((mig->flags & QEMU_MIGRATION_COOKIE_NBD) && mig->nbd) { - virBufferAddLit(buf, "nbd->port) - virBufferAsprintf(buf, " port=3D'%d'", mig->nbd->port); - if (mig->nbd->ndisks) { - virBufferAddLit(buf, ">\n"); - virBufferAdjustIndent(buf, 2); - for (i =3D 0; i < mig->nbd->ndisks; i++) { - virBufferEscapeString(buf, "nbd->disks[i].target); - virBufferAsprintf(buf, " capacity=3D'%llu'/>\n", - mig->nbd->disks[i].capacity); - } - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - } else { - virBufferAddLit(buf, "/>\n"); - } - } - - if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo) - qemuMigrationCookieStatisticsXMLFormat(buf, mig->jobInfo); - - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - return 0; -} - - -static char *qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver, - qemuMigrationCookiePtr mig) -{ - virBuffer buf =3D VIR_BUFFER_INITIALIZER; - - if (qemuMigrationCookieXMLFormat(driver, &buf, mig) < 0) { - virBufferFreeAndReset(&buf); - return NULL; - } - - if (virBufferCheckError(&buf) < 0) - return NULL; - - return virBufferContentAndReset(&buf); -} - - -static qemuMigrationCookieGraphicsPtr -qemuMigrationCookieGraphicsXMLParse(xmlXPathContextPtr ctxt) -{ - qemuMigrationCookieGraphicsPtr grap; - char *tmp; - - if (VIR_ALLOC(grap) < 0) - goto error; - - if (!(tmp =3D virXPathString("string(./graphics/@type)", ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing type attribute in migration data")= ); - goto error; - } - if ((grap->type =3D virDomainGraphicsTypeFromString(tmp)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown graphics type %s"), tmp); - VIR_FREE(tmp); - goto error; - } - VIR_FREE(tmp); - if (virXPathInt("string(./graphics/@port)", ctxt, &grap->port) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing port attribute in migration data")= ); - goto error; - } - if (grap->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { - if (virXPathInt("string(./graphics/@tlsPort)", ctxt, &grap->tlsPor= t) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing tlsPort attribute in migration= data")); - goto error; - } - } - if (!(grap->listen =3D virXPathString("string(./graphics/@listen)", ct= xt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing listen attribute in migration data= ")); - goto error; - } - /* Optional */ - grap->tlsSubject =3D virXPathString("string(./graphics/cert[@info=3D's= ubject']/@value)", ctxt); - - return grap; - - error: - qemuMigrationCookieGraphicsFree(grap); - return NULL; -} - - -static qemuMigrationCookieNetworkPtr -qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt) -{ - qemuMigrationCookieNetworkPtr optr; - size_t i; - int n; - xmlNodePtr *interfaces =3D NULL; - char *vporttype; - xmlNodePtr save_ctxt =3D ctxt->node; - - if (VIR_ALLOC(optr) < 0) - goto error; - - if ((n =3D virXPathNodeSet("./network/interface", ctxt, &interfaces)) = < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing interface information")); - goto error; - } - - optr->nnets =3D n; - if (VIR_ALLOC_N(optr->net, optr->nnets) < 0) - goto error; - - for (i =3D 0; i < n; i++) { - /* portdata is optional, and may not exist */ - ctxt->node =3D interfaces[i]; - optr->net[i].portdata =3D virXPathString("string(./portdata[1])", = ctxt); - - if (!(vporttype =3D virXMLPropString(interfaces[i], "vporttype")))= { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing vporttype attribute in migrati= on data")); - goto error; - } - optr->net[i].vporttype =3D virNetDevVPortTypeFromString(vporttype); - } - - VIR_FREE(interfaces); - - cleanup: - ctxt->node =3D save_ctxt; - return optr; - - error: - VIR_FREE(interfaces); - qemuMigrationCookieNetworkFree(optr); - optr =3D NULL; - goto cleanup; -} - - -static qemuMigrationCookieNBDPtr -qemuMigrationCookieNBDXMLParse(xmlXPathContextPtr ctxt) -{ - qemuMigrationCookieNBDPtr ret =3D NULL; - char *port =3D NULL, *capacity =3D NULL; - size_t i; - int n; - xmlNodePtr *disks =3D NULL; - xmlNodePtr save_ctxt =3D ctxt->node; - - if (VIR_ALLOC(ret) < 0) - goto error; - - port =3D virXPathString("string(./nbd/@port)", ctxt); - if (port && virStrToLong_i(port, NULL, 10, &ret->port) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Malformed nbd port '%s'"), - port); - goto error; - } - - /* Now check if source sent a list of disks to prealloc. We might be - * talking to an older server, so it's not an error if the list is - * missing. */ - if ((n =3D virXPathNodeSet("./nbd/disk", ctxt, &disks)) > 0) { - if (VIR_ALLOC_N(ret->disks, n) < 0) - goto error; - ret->ndisks =3D n; - - for (i =3D 0; i < n; i++) { - ctxt->node =3D disks[i]; - VIR_FREE(capacity); - - if (!(ret->disks[i].target =3D virXPathString("string(./@targe= t)", ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Malformed disk target")); - goto error; - } - - capacity =3D virXPathString("string(./@capacity)", ctxt); - if (!capacity || - virStrToLong_ull(capacity, NULL, 10, - &ret->disks[i].capacity) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Malformed disk capacity: '%s'"), - NULLSTR(capacity)); - goto error; - } - } - } - - cleanup: - VIR_FREE(port); - VIR_FREE(capacity); - VIR_FREE(disks); - ctxt->node =3D save_ctxt; - return ret; - error: - qemuMigrationCookieNBDFree(ret); - ret =3D NULL; - goto cleanup; -} - - -static qemuDomainJobInfoPtr -qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) -{ - qemuDomainJobInfoPtr jobInfo =3D NULL; - qemuMonitorMigrationStats *stats; - xmlNodePtr save_ctxt =3D ctxt->node; - - if (!(ctxt->node =3D virXPathNode("./statistics", ctxt))) - goto cleanup; - - if (VIR_ALLOC(jobInfo) < 0) - goto cleanup; - - stats =3D &jobInfo->stats; - jobInfo->type =3D VIR_DOMAIN_JOB_COMPLETED; - - virXPathULongLong("string(./started[1])", ctxt, &jobInfo->started); - virXPathULongLong("string(./stopped[1])", ctxt, &jobInfo->stopped); - virXPathULongLong("string(./sent[1])", ctxt, &jobInfo->sent); - if (virXPathLongLong("string(./delta[1])", ctxt, &jobInfo->timeDelta) = =3D=3D 0) - jobInfo->timeDeltaSet =3D true; - - virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_ELAPSED "[1])", - ctxt, &jobInfo->timeElapsed); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_REMAINING "[1])", - ctxt, &jobInfo->timeRemaining); - - if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])", - ctxt, &stats->downtime) =3D=3D 0) - stats->downtime_set =3D true; - if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_SETUP_TIME "[1])", - ctxt, &stats->setup_time) =3D=3D 0) - stats->setup_time_set =3D true; - - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])", - ctxt, &stats->ram_total); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_PROCESSED "[1])", - ctxt, &stats->ram_transferred); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])", - ctxt, &stats->ram_remaining); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_BPS "[1])", - ctxt, &stats->ram_bps); - - if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])= ", - ctxt, &stats->ram_duplicate) =3D=3D 0) - stats->ram_duplicate_set =3D true; - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL "[1])", - ctxt, &stats->ram_normal); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "[1])= ", - ctxt, &stats->ram_normal_bytes); - - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE "[1])", - ctxt, &stats->ram_dirty_rate); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_ITERATION "[1])", - ctxt, &stats->ram_iteration); - - virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_TOTAL "[1])", - ctxt, &stats->disk_total); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_PROCESSED "[1])", - ctxt, &stats->disk_transferred); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])", - ctxt, &stats->disk_remaining); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_BPS "[1])", - ctxt, &stats->disk_bps); - - if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1= ])", - ctxt, &stats->xbzrle_cache_size) =3D=3D 0) - stats->xbzrle_set =3D true; - virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_BYTES "[1])", - ctxt, &stats->xbzrle_bytes); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_PAGES "[1])", - ctxt, &stats->xbzrle_pages); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES = "[1])", - ctxt, &stats->xbzrle_cache_miss); - virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW "[1]= )", - ctxt, &stats->xbzrle_overflow); - - virXPathInt("string(./" VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE "[1])", - ctxt, &stats->cpu_throttle_percentage); - cleanup: - ctxt->node =3D save_ctxt; - return jobInfo; -} - - -static int -qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - xmlDocPtr doc, - xmlXPathContextPtr ctxt, - unsigned int flags) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - char *tmp =3D NULL; - xmlNodePtr *nodes =3D NULL; - size_t i; - int n; - virCapsPtr caps =3D NULL; - - if (!(caps =3D virQEMUDriverGetCapabilities(driver, false))) - goto error; - - /* We don't store the uuid, name, hostname, or hostuuid - * values. We just compare them to local data to do some - * sanity checking on migration operation - */ - - /* Extract domain name */ - if (!(tmp =3D virXPathString("string(./name[1])", ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing name element in migration data")); - goto error; - } - if (STRNEQ(tmp, mig->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Incoming cookie data had unexpected name %s vs %= s"), - tmp, mig->name); - goto error; - } - VIR_FREE(tmp); - - /* Extract domain uuid */ - tmp =3D virXPathString("string(./uuid[1])", ctxt); - if (!tmp) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing uuid element in migration data")); - goto error; - } - virUUIDFormat(mig->uuid, uuidstr); - if (STRNEQ(tmp, uuidstr)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Incoming cookie data had unexpected UUID %s vs %= s"), - tmp, uuidstr); - goto error; - } - VIR_FREE(tmp); - - /* Check & forbid "localhost" migration */ - if (!(mig->remoteHostname =3D virXPathString("string(./hostname[1])", = ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing hostname element in migration data= ")); - goto error; - } - if (STREQ(mig->remoteHostname, mig->localHostname)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Attempt to migrate guest to the same host %s"), - mig->remoteHostname); - goto error; - } - - if (!(tmp =3D virXPathString("string(./hostuuid[1])", ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing hostuuid element in migration data= ")); - goto error; - } - if (virUUIDParse(tmp, mig->remoteHostuuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed hostuuid element in migration da= ta")); - goto error; - } - if (memcmp(mig->remoteHostuuid, mig->localHostuuid, VIR_UUID_BUFLEN) = =3D=3D 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Attempt to migrate guest to the same host %s"), - tmp); - goto error; - } - VIR_FREE(tmp); - - /* Check to ensure all mandatory features from XML are also - * present in 'flags' */ - if ((n =3D virXPathNodeSet("./feature", ctxt, &nodes)) < 0) - goto error; - - for (i =3D 0; i < n; i++) { - int val; - char *str =3D virXMLPropString(nodes[i], "name"); - if (!str) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing feature name")); - goto error; - } - - if ((val =3D qemuMigrationCookieFlagTypeFromString(str)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown migration cookie feature %s"), - str); - VIR_FREE(str); - goto error; - } - - if ((flags & (1 << val)) =3D=3D 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unsupported migration cookie feature %s"), - str); - VIR_FREE(str); - goto error; - } - VIR_FREE(str); - } - VIR_FREE(nodes); - - if ((flags & QEMU_MIGRATION_COOKIE_GRAPHICS) && - virXPathBoolean("count(./graphics) > 0", ctxt) && - (!(mig->graphics =3D qemuMigrationCookieGraphicsXMLParse(ctxt)))) - goto error; - - if ((flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) && - virXPathBoolean("count(./lockstate) > 0", ctxt)) { - mig->lockDriver =3D virXPathString("string(./lockstate[1]/@driver)= ", ctxt); - if (!mig->lockDriver) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Missing lock driver name in migration cookie= ")); - goto error; - } - mig->lockState =3D virXPathString("string(./lockstate[1]/leases[1]= )", ctxt); - if (mig->lockState && STREQ(mig->lockState, "")) - VIR_FREE(mig->lockState); - } - - if ((flags & QEMU_MIGRATION_COOKIE_PERSISTENT) && - virXPathBoolean("count(./domain) > 0", ctxt)) { - if ((n =3D virXPathNodeSet("./domain", ctxt, &nodes)) > 1) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Too many domain elements in " - "migration cookie: %d"), - n); - goto error; - } - mig->persistent =3D virDomainDefParseNode(doc, nodes[0], - caps, driver->xmlopt, NULL, - VIR_DOMAIN_DEF_PARSE_INACT= IVE | - VIR_DOMAIN_DEF_PARSE_ABI_U= PDATE | - VIR_DOMAIN_DEF_PARSE_SKIP_= VALIDATE); - if (!mig->persistent) { - /* virDomainDefParseNode already reported - * an error for us */ - goto error; - } - VIR_FREE(nodes); - } - - if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) && - virXPathBoolean("count(./network) > 0", ctxt) && - (!(mig->network =3D qemuMigrationCookieNetworkXMLParse(ctxt)))) - goto error; - - if (flags & QEMU_MIGRATION_COOKIE_NBD && - virXPathBoolean("boolean(./nbd)", ctxt) && - (!(mig->nbd =3D qemuMigrationCookieNBDXMLParse(ctxt)))) - goto error; - - if (flags & QEMU_MIGRATION_COOKIE_STATS && - virXPathBoolean("boolean(./statistics)", ctxt) && - (!(mig->jobInfo =3D qemuMigrationCookieStatisticsXMLParse(ctxt)))) - goto error; - - virObjectUnref(caps); - return 0; - - error: - VIR_FREE(tmp); - VIR_FREE(nodes); - virObjectUnref(caps); - return -1; -} - - -static int -qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - const char *xml, - unsigned int flags) -{ - xmlDocPtr doc =3D NULL; - xmlXPathContextPtr ctxt =3D NULL; - int ret =3D -1; - - VIR_DEBUG("xml=3D%s", NULLSTR(xml)); - - if (!(doc =3D virXMLParseStringCtxt(xml, _("(qemu_migration_cookie)"),= &ctxt))) - goto cleanup; - - ret =3D qemuMigrationCookieXMLParse(mig, driver, doc, ctxt, flags); - - cleanup: - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); - - return ret; -} - - -static int -qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, - virQEMUDriverPtr driver, - virDomainObjPtr dom, - char **cookieout, - int *cookieoutlen, - unsigned int flags) -{ - if (!cookieout || !cookieoutlen) - return 0; - - *cookieoutlen =3D 0; - - if (flags & QEMU_MIGRATION_COOKIE_GRAPHICS && - qemuMigrationCookieAddGraphics(mig, driver, dom) < 0) - return -1; - - if (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE && - qemuMigrationCookieAddLockstate(mig, driver, dom) < 0) - return -1; - - if (flags & QEMU_MIGRATION_COOKIE_NETWORK && - qemuMigrationCookieAddNetwork(mig, driver, dom) < 0) { - return -1; - } - - if ((flags & QEMU_MIGRATION_COOKIE_NBD) && - qemuMigrationCookieAddNBD(mig, driver, dom) < 0) - return -1; - - if (flags & QEMU_MIGRATION_COOKIE_STATS && - qemuMigrationCookieAddStatistics(mig, dom) < 0) - return -1; - - if (flags & QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG) - mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG; - - if (flags & QEMU_MIGRATION_COOKIE_CPU_HOTPLUG) - mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_CPU_HOTPLUG; - - if (!(*cookieout =3D qemuMigrationCookieXMLFormatStr(driver, mig))) - return -1; - - *cookieoutlen =3D strlen(*cookieout) + 1; - - VIR_DEBUG("cookielen=3D%d cookie=3D%s", *cookieoutlen, *cookieout); - - return 0; -} - - -static qemuMigrationCookiePtr -qemuMigrationEatCookie(virQEMUDriverPtr driver, - virDomainObjPtr dom, - const char *cookiein, - int cookieinlen, - unsigned int flags) -{ - qemuMigrationCookiePtr mig =3D NULL; - - /* Parse & validate incoming cookie (if any) */ - if (cookiein && cookieinlen && - cookiein[cookieinlen-1] !=3D '\0') { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Migration cookie was not NULL terminated")); - goto error; - } - - VIR_DEBUG("cookielen=3D%d cookie=3D'%s'", cookieinlen, NULLSTR(cookiei= n)); - - if (!(mig =3D qemuMigrationCookieNew(dom))) - return NULL; - - if (cookiein && cookieinlen && - qemuMigrationCookieXMLParseStr(mig, - driver, - cookiein, - flags) < 0) - goto error; - - if (flags & QEMU_MIGRATION_COOKIE_PERSISTENT && - mig->persistent && - STRNEQ(dom->def->name, mig->persistent->name)) { - VIR_FREE(mig->persistent->name); - if (VIR_STRDUP(mig->persistent->name, dom->def->name) < 0) - goto error; - } - - if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) { - if (!mig->lockDriver) { - if (virLockManagerPluginUsesState(driver->lockManager)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Missing %s lock state for migration cook= ie"), - virLockManagerPluginGetName(driver->lockMan= ager)); - goto error; - } - } else if (STRNEQ(mig->lockDriver, - virLockManagerPluginGetName(driver->lockManager)= )) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Source host lock driver %s different from ta= rget %s"), - mig->lockDriver, - virLockManagerPluginGetName(driver->lockManager= )); - goto error; - } - } - - return mig; - - error: - qemuMigrationCookieFree(mig); - return NULL; -} =20 static void qemuMigrationStoreDomainState(virDomainObjPtr vm) diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_coo= kie.c new file mode 100644 index 000000000..7b237c546 --- /dev/null +++ b/src/qemu/qemu_migration_cookie.c @@ -0,0 +1,1340 @@ +/* + * qemu_migration_cookie.c: QEMU migration cookie handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#ifdef WITH_GNUTLS +# include +# include +#endif + +#include "locking/domain_lock.h" +#include "viralloc.h" +#include "virerror.h" +#include "virlog.h" +#include "virnetdevopenvswitch.h" +#include "virstring.h" +#include "virutil.h" + +#include "qemu_domain.h" +#include "qemu_migration_cookie.h" + + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_migration_cookie"); + +VIR_ENUM_IMPL(qemuMigrationCookieFlag, + QEMU_MIGRATION_COOKIE_FLAG_LAST, + "graphics", + "lockstate", + "persistent", + "network", + "nbd", + "statistics", + "memory-hotplug", + "cpu-hotplug"); + + +static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr= grap) +{ + if (!grap) + return; + VIR_FREE(grap->listen); + VIR_FREE(grap->tlsSubject); + VIR_FREE(grap); +} + + +static void +qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network) +{ + size_t i; + + if (!network) + return; + + if (network->net) { + for (i =3D 0; i < network->nnets; i++) + VIR_FREE(network->net[i].portdata); + } + VIR_FREE(network->net); + VIR_FREE(network); +} + + +static void qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd) +{ + if (!nbd) + return; + + while (nbd->ndisks) + VIR_FREE(nbd->disks[--nbd->ndisks].target); + VIR_FREE(nbd->disks); + VIR_FREE(nbd); +} + + +void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) +{ + if (!mig) + return; + + qemuMigrationCookieGraphicsFree(mig->graphics); + qemuMigrationCookieNetworkFree(mig->network); + qemuMigrationCookieNBDFree(mig->nbd); + + VIR_FREE(mig->localHostname); + VIR_FREE(mig->remoteHostname); + VIR_FREE(mig->name); + VIR_FREE(mig->lockState); + VIR_FREE(mig->lockDriver); + VIR_FREE(mig->jobInfo); + VIR_FREE(mig); +} + + +#ifdef WITH_GNUTLS +static char * +qemuDomainExtractTLSSubject(const char *certdir) +{ + char *certfile =3D NULL; + char *subject =3D NULL; + char *pemdata =3D NULL; + gnutls_datum_t pemdatum; + gnutls_x509_crt_t cert; + int ret; + size_t subjectlen; + + if (virAsprintf(&certfile, "%s/server-cert.pem", certdir) < 0) + goto error; + + if (virFileReadAll(certfile, 8192, &pemdata) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to read server cert %s"), certfile); + goto error; + } + + ret =3D gnutls_x509_crt_init(&cert); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot initialize cert object: %s"), + gnutls_strerror(ret)); + goto error; + } + + pemdatum.data =3D (unsigned char *)pemdata; + pemdatum.size =3D strlen(pemdata); + + ret =3D gnutls_x509_crt_import(cert, &pemdatum, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot load cert data from %s: %s"), + certfile, gnutls_strerror(ret)); + goto error; + } + + subjectlen =3D 1024; + if (VIR_ALLOC_N(subject, subjectlen+1) < 0) + goto error; + + gnutls_x509_crt_get_dn(cert, subject, &subjectlen); + subject[subjectlen] =3D '\0'; + + VIR_FREE(certfile); + VIR_FREE(pemdata); + + return subject; + + error: + VIR_FREE(certfile); + VIR_FREE(pemdata); + return NULL; +} +#endif + +static qemuMigrationCookieGraphicsPtr +qemuMigrationCookieGraphicsSpiceAlloc(virQEMUDriverPtr driver, + virDomainGraphicsDefPtr def, + virDomainGraphicsListenDefPtr gliste= n) +{ + qemuMigrationCookieGraphicsPtr mig =3D NULL; + const char *listenAddr; + virQEMUDriverConfigPtr cfg =3D virQEMUDriverGetConfig(driver); + + if (VIR_ALLOC(mig) < 0) + goto error; + + mig->type =3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE; + mig->port =3D def->data.spice.port; + if (cfg->spiceTLS) + mig->tlsPort =3D def->data.spice.tlsPort; + else + mig->tlsPort =3D -1; + + if (!glisten || !(listenAddr =3D glisten->address)) + listenAddr =3D cfg->spiceListen; + +#ifdef WITH_GNUTLS + if (cfg->spiceTLS && + !(mig->tlsSubject =3D qemuDomainExtractTLSSubject(cfg->spiceTLSx50= 9certdir))) + goto error; +#endif + if (VIR_STRDUP(mig->listen, listenAddr) < 0) + goto error; + + virObjectUnref(cfg); + return mig; + + error: + qemuMigrationCookieGraphicsFree(mig); + virObjectUnref(cfg); + return NULL; +} + + +static qemuMigrationCookieNetworkPtr +qemuMigrationCookieNetworkAlloc(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + qemuMigrationCookieNetworkPtr mig; + size_t i; + + if (VIR_ALLOC(mig) < 0) + goto error; + + mig->nnets =3D def->nnets; + + if (VIR_ALLOC_N(mig->net, def->nnets) <0) + goto error; + + for (i =3D 0; i < def->nnets; i++) { + virDomainNetDefPtr netptr; + virNetDevVPortProfilePtr vport; + + netptr =3D def->nets[i]; + vport =3D virDomainNetGetActualVirtPortProfile(netptr); + + if (vport) { + mig->net[i].vporttype =3D vport->virtPortType; + + switch (vport->virtPortType) { + case VIR_NETDEV_VPORT_PROFILE_NONE: + case VIR_NETDEV_VPORT_PROFILE_8021QBG: + case VIR_NETDEV_VPORT_PROFILE_8021QBH: + break; + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + if (virNetDevOpenvswitchGetMigrateData(&mig->net[i].portda= ta, + netptr->ifname) != =3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to run command to get OVS= port data for " + "interface %s"), netptr->ifname); + goto error; + } + break; + default: + break; + } + } + } + return mig; + + error: + qemuMigrationCookieNetworkFree(mig); + return NULL; +} + +static qemuMigrationCookiePtr +qemuMigrationCookieNew(virDomainObjPtr dom) +{ + qemuDomainObjPrivatePtr priv =3D dom->privateData; + qemuMigrationCookiePtr mig =3D NULL; + const char *name; + + if (VIR_ALLOC(mig) < 0) + goto error; + + if (priv->origname) + name =3D priv->origname; + else + name =3D dom->def->name; + if (VIR_STRDUP(mig->name, name) < 0) + goto error; + memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); + + if (!(mig->localHostname =3D virGetHostname())) + goto error; + if (virGetHostUUID(mig->localHostuuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to obtain host UUID")); + goto error; + } + + return mig; + + error: + qemuMigrationCookieFree(mig); + return NULL; +} + + +static int +qemuMigrationCookieAddGraphics(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr dom) +{ + size_t i =3D 0; + + if (mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration graphics data already present")); + return -1; + } + + for (i =3D 0; i < dom->def->ngraphics; i++) { + if (dom->def->graphics[i]->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SP= ICE) { + virDomainGraphicsListenDefPtr glisten =3D + virDomainGraphicsGetListen(dom->def->graphics[i], 0); + + if (!glisten) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing listen element")); + return -1; + } + + switch (glisten->type) { + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: + /* Seamless migration is supported only for listen types + * 'address and 'network'. */ + if (!(mig->graphics =3D + qemuMigrationCookieGraphicsSpiceAlloc(driver, + dom->def->grap= hics[i], + glisten))) + return -1; + mig->flags |=3D QEMU_MIGRATION_COOKIE_GRAPHICS; + break; + + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET: + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE: + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST: + break; + } + + /* Seamless migration is supported only for one graphics. */ + if (mig->graphics) + break; + } + } + + return 0; +} + + +static int +qemuMigrationCookieAddLockstate(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr dom) +{ + qemuDomainObjPrivatePtr priv =3D dom->privateData; + + if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration lockstate data already present")); + return -1; + } + + if (virDomainObjGetState(dom, NULL) =3D=3D VIR_DOMAIN_PAUSED) { + if (VIR_STRDUP(mig->lockState, priv->lockState) < 0) + return -1; + } else { + if (virDomainLockProcessInquire(driver->lockManager, dom, &mig->lo= ckState) < 0) + return -1; + } + + if (VIR_STRDUP(mig->lockDriver, virLockManagerPluginGetName(driver->lo= ckManager)) < 0) { + VIR_FREE(mig->lockState); + return -1; + } + + mig->flags |=3D QEMU_MIGRATION_COOKIE_LOCKSTATE; + mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_LOCKSTATE; + + return 0; +} + + +int +qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, + virDomainDefPtr def) +{ + if (mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration persistent data already present")); + return -1; + } + + if (!def) + return 0; + + mig->persistent =3D def; + mig->flags |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; + mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; + return 0; +} + + +virDomainDefPtr +qemuMigrationCookieGetPersistent(qemuMigrationCookiePtr mig) +{ + virDomainDefPtr def =3D mig->persistent; + + mig->persistent =3D NULL; + mig->flags &=3D ~QEMU_MIGRATION_COOKIE_PERSISTENT; + mig->flagsMandatory &=3D ~QEMU_MIGRATION_COOKIE_PERSISTENT; + + return def; +} + + +static int +qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr dom) +{ + if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Network migration data already present")); + return -1; + } + + if (dom->def->nnets > 0) { + mig->network =3D qemuMigrationCookieNetworkAlloc(driver, dom->def); + if (!mig->network) + return -1; + mig->flags |=3D QEMU_MIGRATION_COOKIE_NETWORK; + } + + return 0; +} + + +static int +qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virHashTablePtr stats =3D NULL; + size_t i; + int ret =3D -1, rc; + + /* It is not a bug if there already is a NBD data */ + qemuMigrationCookieNBDFree(mig->nbd); + + if (VIR_ALLOC(mig->nbd) < 0) + return -1; + + if (vm->def->ndisks && + VIR_ALLOC_N(mig->nbd->disks, vm->def->ndisks) < 0) + return -1; + mig->nbd->ndisks =3D 0; + + for (i =3D 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk =3D vm->def->disks[i]; + qemuBlockStats *entry; + + if (!stats) { + if (!(stats =3D virHashCreate(10, virHashValueFree))) + goto cleanup; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, + priv->job.asyncJob) < 0) + goto cleanup; + rc =3D qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats, f= alse); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + goto cleanup; + if (rc < 0) + goto cleanup; + } + + if (!disk->info.alias || + !(entry =3D virHashLookup(stats, disk->info.alias))) + continue; + + if (VIR_STRDUP(mig->nbd->disks[mig->nbd->ndisks].target, + disk->dst) < 0) + goto cleanup; + mig->nbd->disks[mig->nbd->ndisks].capacity =3D entry->capacity; + mig->nbd->ndisks++; + } + + mig->nbd->port =3D priv->nbdPort; + mig->flags |=3D QEMU_MIGRATION_COOKIE_NBD; + + ret =3D 0; + cleanup: + virHashFree(stats); + return ret; +} + + +static int +qemuMigrationCookieAddStatistics(qemuMigrationCookiePtr mig, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + + if (!priv->job.completed) + return 0; + + if (!mig->jobInfo && VIR_ALLOC(mig->jobInfo) < 0) + return -1; + + *mig->jobInfo =3D *priv->job.completed; + mig->flags |=3D QEMU_MIGRATION_COOKIE_STATS; + + return 0; +} + + +static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, + qemuMigrationCookieGraphi= csPtr grap) +{ + virBufferAsprintf(buf, "type), + grap->port, grap->listen); + if (grap->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) + virBufferAsprintf(buf, " tlsPort=3D'%d'", grap->tlsPort); + if (grap->tlsSubject) { + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "\= n", grap->tlsSubject); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } +} + + +static void +qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf, + qemuMigrationCookieNetworkPtr optr) +{ + size_t i; + bool empty =3D true; + + for (i =3D 0; i < optr->nnets; i++) { + /* If optr->net[i].vporttype is not set, there is nothing to trans= fer */ + if (optr->net[i].vporttype !=3D VIR_NETDEV_VPORT_PROFILE_NONE) { + if (empty) { + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + empty =3D false; + } + virBufferAsprintf(buf, "net[i].v= porttype)); + if (optr->net[i].portdata) { + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "%s\n", + optr->net[i].portdata); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + } + } + if (!empty) { + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } +} + + +static void +qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, + qemuDomainJobInfoPtr jobInfo) +{ + qemuMonitorMigrationStats *stats =3D &jobInfo->stats; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "%llu\n", jobInfo->started); + virBufferAsprintf(buf, "%llu\n", jobInfo->stopped); + virBufferAsprintf(buf, "%llu\n", jobInfo->sent); + if (jobInfo->timeDeltaSet) + virBufferAsprintf(buf, "%lld\n", jobInfo->timeDelta= ); + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_TIME_ELAPSED, + jobInfo->timeElapsed); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_TIME_REMAINING, + jobInfo->timeRemaining); + if (stats->downtime_set) + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DOWNTIME, + stats->downtime); + if (stats->setup_time_set) + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_SETUP_TIME, + stats->setup_time); + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_TOTAL, + stats->ram_total); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_PROCESSED, + stats->ram_transferred); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_REMAINING, + stats->ram_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_BPS, + stats->ram_bps); + + if (stats->ram_duplicate_set) { + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_CONSTANT, + stats->ram_duplicate); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_NORMAL, + stats->ram_normal); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES, + stats->ram_normal_bytes); + } + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE, + stats->ram_dirty_rate); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_ITERATION, + stats->ram_iteration); + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_TOTAL, + stats->disk_total); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_PROCESSED, + stats->disk_transferred); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_REMAINING, + stats->disk_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_BPS, + stats->disk_bps); + + if (stats->xbzrle_set) { + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_CACHE, + stats->xbzrle_cache_size); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_BYTES, + stats->xbzrle_bytes); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_PAGES, + stats->xbzrle_pages); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES, + stats->xbzrle_cache_miss); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW, + stats->xbzrle_overflow); + } + + virBufferAsprintf(buf, "<%1$s>%2$d\n", + VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE, + stats->cpu_throttle_percentage); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} + + +static int +qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, + virBufferPtr buf, + qemuMigrationCookiePtr mig) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char hostuuidstr[VIR_UUID_STRING_BUFLEN]; + size_t i; + + virUUIDFormat(mig->uuid, uuidstr); + virUUIDFormat(mig->localHostuuid, hostuuidstr); + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "%s\n", mig->name); + virBufferAsprintf(buf, "%s\n", uuidstr); + virBufferEscapeString(buf, "%s\n", mig->localHost= name); + virBufferAsprintf(buf, "%s\n", hostuuidstr); + + for (i =3D 0; i < QEMU_MIGRATION_COOKIE_FLAG_LAST; i++) { + if (mig->flagsMandatory & (1 << i)) + virBufferAsprintf(buf, "\n", + qemuMigrationCookieFlagTypeToString(i)); + } + + if ((mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) && + mig->graphics) + qemuMigrationCookieGraphicsXMLFormat(buf, mig->graphics); + + if ((mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) && + mig->lockState) { + virBufferAsprintf(buf, "\n", + mig->lockDriver); + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "%s\n", + mig->lockState); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } + + if ((mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) && + mig->persistent) { + if (qemuDomainDefFormatBuf(driver, + mig->persistent, + VIR_DOMAIN_XML_INACTIVE | + VIR_DOMAIN_XML_SECURE | + VIR_DOMAIN_XML_MIGRATABLE, + buf) < 0) + return -1; + } + + if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network) + qemuMigrationCookieNetworkXMLFormat(buf, mig->network); + + if ((mig->flags & QEMU_MIGRATION_COOKIE_NBD) && mig->nbd) { + virBufferAddLit(buf, "nbd->port) + virBufferAsprintf(buf, " port=3D'%d'", mig->nbd->port); + if (mig->nbd->ndisks) { + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + for (i =3D 0; i < mig->nbd->ndisks; i++) { + virBufferEscapeString(buf, "nbd->disks[i].target); + virBufferAsprintf(buf, " capacity=3D'%llu'/>\n", + mig->nbd->disks[i].capacity); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + } + + if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo) + qemuMigrationCookieStatisticsXMLFormat(buf, mig->jobInfo); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + return 0; +} + + +static char *qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver, + qemuMigrationCookiePtr mig) +{ + virBuffer buf =3D VIR_BUFFER_INITIALIZER; + + if (qemuMigrationCookieXMLFormat(driver, &buf, mig) < 0) { + virBufferFreeAndReset(&buf); + return NULL; + } + + if (virBufferCheckError(&buf) < 0) + return NULL; + + return virBufferContentAndReset(&buf); +} + + +static qemuMigrationCookieGraphicsPtr +qemuMigrationCookieGraphicsXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieGraphicsPtr grap; + char *tmp; + + if (VIR_ALLOC(grap) < 0) + goto error; + + if (!(tmp =3D virXPathString("string(./graphics/@type)", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing type attribute in migration data")= ); + goto error; + } + if ((grap->type =3D virDomainGraphicsTypeFromString(tmp)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown graphics type %s"), tmp); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + if (virXPathInt("string(./graphics/@port)", ctxt, &grap->port) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing port attribute in migration data")= ); + goto error; + } + if (grap->type =3D=3D VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { + if (virXPathInt("string(./graphics/@tlsPort)", ctxt, &grap->tlsPor= t) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing tlsPort attribute in migration= data")); + goto error; + } + } + if (!(grap->listen =3D virXPathString("string(./graphics/@listen)", ct= xt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing listen attribute in migration data= ")); + goto error; + } + /* Optional */ + grap->tlsSubject =3D virXPathString("string(./graphics/cert[@info=3D's= ubject']/@value)", ctxt); + + return grap; + + error: + qemuMigrationCookieGraphicsFree(grap); + return NULL; +} + + +static qemuMigrationCookieNetworkPtr +qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieNetworkPtr optr; + size_t i; + int n; + xmlNodePtr *interfaces =3D NULL; + char *vporttype; + xmlNodePtr save_ctxt =3D ctxt->node; + + if (VIR_ALLOC(optr) < 0) + goto error; + + if ((n =3D virXPathNodeSet("./network/interface", ctxt, &interfaces)) = < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing interface information")); + goto error; + } + + optr->nnets =3D n; + if (VIR_ALLOC_N(optr->net, optr->nnets) < 0) + goto error; + + for (i =3D 0; i < n; i++) { + /* portdata is optional, and may not exist */ + ctxt->node =3D interfaces[i]; + optr->net[i].portdata =3D virXPathString("string(./portdata[1])", = ctxt); + + if (!(vporttype =3D virXMLPropString(interfaces[i], "vporttype")))= { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing vporttype attribute in migrati= on data")); + goto error; + } + optr->net[i].vporttype =3D virNetDevVPortTypeFromString(vporttype); + } + + VIR_FREE(interfaces); + + cleanup: + ctxt->node =3D save_ctxt; + return optr; + + error: + VIR_FREE(interfaces); + qemuMigrationCookieNetworkFree(optr); + optr =3D NULL; + goto cleanup; +} + + +static qemuMigrationCookieNBDPtr +qemuMigrationCookieNBDXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieNBDPtr ret =3D NULL; + char *port =3D NULL, *capacity =3D NULL; + size_t i; + int n; + xmlNodePtr *disks =3D NULL; + xmlNodePtr save_ctxt =3D ctxt->node; + + if (VIR_ALLOC(ret) < 0) + goto error; + + port =3D virXPathString("string(./nbd/@port)", ctxt); + if (port && virStrToLong_i(port, NULL, 10, &ret->port) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Malformed nbd port '%s'"), + port); + goto error; + } + + /* Now check if source sent a list of disks to prealloc. We might be + * talking to an older server, so it's not an error if the list is + * missing. */ + if ((n =3D virXPathNodeSet("./nbd/disk", ctxt, &disks)) > 0) { + if (VIR_ALLOC_N(ret->disks, n) < 0) + goto error; + ret->ndisks =3D n; + + for (i =3D 0; i < n; i++) { + ctxt->node =3D disks[i]; + VIR_FREE(capacity); + + if (!(ret->disks[i].target =3D virXPathString("string(./@targe= t)", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed disk target")); + goto error; + } + + capacity =3D virXPathString("string(./@capacity)", ctxt); + if (!capacity || + virStrToLong_ull(capacity, NULL, 10, + &ret->disks[i].capacity) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Malformed disk capacity: '%s'"), + NULLSTR(capacity)); + goto error; + } + } + } + + cleanup: + VIR_FREE(port); + VIR_FREE(capacity); + VIR_FREE(disks); + ctxt->node =3D save_ctxt; + return ret; + error: + qemuMigrationCookieNBDFree(ret); + ret =3D NULL; + goto cleanup; +} + + +static qemuDomainJobInfoPtr +qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) +{ + qemuDomainJobInfoPtr jobInfo =3D NULL; + qemuMonitorMigrationStats *stats; + xmlNodePtr save_ctxt =3D ctxt->node; + + if (!(ctxt->node =3D virXPathNode("./statistics", ctxt))) + goto cleanup; + + if (VIR_ALLOC(jobInfo) < 0) + goto cleanup; + + stats =3D &jobInfo->stats; + jobInfo->type =3D VIR_DOMAIN_JOB_COMPLETED; + + virXPathULongLong("string(./started[1])", ctxt, &jobInfo->started); + virXPathULongLong("string(./stopped[1])", ctxt, &jobInfo->stopped); + virXPathULongLong("string(./sent[1])", ctxt, &jobInfo->sent); + if (virXPathLongLong("string(./delta[1])", ctxt, &jobInfo->timeDelta) = =3D=3D 0) + jobInfo->timeDeltaSet =3D true; + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_ELAPSED "[1])", + ctxt, &jobInfo->timeElapsed); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_REMAINING "[1])", + ctxt, &jobInfo->timeRemaining); + + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])", + ctxt, &stats->downtime) =3D=3D 0) + stats->downtime_set =3D true; + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_SETUP_TIME "[1])", + ctxt, &stats->setup_time) =3D=3D 0) + stats->setup_time_set =3D true; + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])", + ctxt, &stats->ram_total); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_PROCESSED "[1])", + ctxt, &stats->ram_transferred); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])", + ctxt, &stats->ram_remaining); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_BPS "[1])", + ctxt, &stats->ram_bps); + + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])= ", + ctxt, &stats->ram_duplicate) =3D=3D 0) + stats->ram_duplicate_set =3D true; + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL "[1])", + ctxt, &stats->ram_normal); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "[1])= ", + ctxt, &stats->ram_normal_bytes); + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE "[1])", + ctxt, &stats->ram_dirty_rate); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_ITERATION "[1])", + ctxt, &stats->ram_iteration); + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_TOTAL "[1])", + ctxt, &stats->disk_total); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_PROCESSED "[1])", + ctxt, &stats->disk_transferred); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])", + ctxt, &stats->disk_remaining); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_BPS "[1])", + ctxt, &stats->disk_bps); + + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1= ])", + ctxt, &stats->xbzrle_cache_size) =3D=3D 0) + stats->xbzrle_set =3D true; + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_BYTES "[1])", + ctxt, &stats->xbzrle_bytes); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_PAGES "[1])", + ctxt, &stats->xbzrle_pages); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES = "[1])", + ctxt, &stats->xbzrle_cache_miss); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW "[1]= )", + ctxt, &stats->xbzrle_overflow); + + virXPathInt("string(./" VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE "[1])", + ctxt, &stats->cpu_throttle_percentage); + cleanup: + ctxt->node =3D save_ctxt; + return jobInfo; +} + + +static int +qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + xmlDocPtr doc, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char *tmp =3D NULL; + xmlNodePtr *nodes =3D NULL; + size_t i; + int n; + virCapsPtr caps =3D NULL; + + if (!(caps =3D virQEMUDriverGetCapabilities(driver, false))) + goto error; + + /* We don't store the uuid, name, hostname, or hostuuid + * values. We just compare them to local data to do some + * sanity checking on migration operation + */ + + /* Extract domain name */ + if (!(tmp =3D virXPathString("string(./name[1])", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing name element in migration data")); + goto error; + } + if (STRNEQ(tmp, mig->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Incoming cookie data had unexpected name %s vs %= s"), + tmp, mig->name); + goto error; + } + VIR_FREE(tmp); + + /* Extract domain uuid */ + tmp =3D virXPathString("string(./uuid[1])", ctxt); + if (!tmp) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing uuid element in migration data")); + goto error; + } + virUUIDFormat(mig->uuid, uuidstr); + if (STRNEQ(tmp, uuidstr)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Incoming cookie data had unexpected UUID %s vs %= s"), + tmp, uuidstr); + goto error; + } + VIR_FREE(tmp); + + /* Check & forbid "localhost" migration */ + if (!(mig->remoteHostname =3D virXPathString("string(./hostname[1])", = ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing hostname element in migration data= ")); + goto error; + } + if (STREQ(mig->remoteHostname, mig->localHostname)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Attempt to migrate guest to the same host %s"), + mig->remoteHostname); + goto error; + } + + if (!(tmp =3D virXPathString("string(./hostuuid[1])", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing hostuuid element in migration data= ")); + goto error; + } + if (virUUIDParse(tmp, mig->remoteHostuuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("malformed hostuuid element in migration da= ta")); + goto error; + } + if (memcmp(mig->remoteHostuuid, mig->localHostuuid, VIR_UUID_BUFLEN) = =3D=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Attempt to migrate guest to the same host %s"), + tmp); + goto error; + } + VIR_FREE(tmp); + + /* Check to ensure all mandatory features from XML are also + * present in 'flags' */ + if ((n =3D virXPathNodeSet("./feature", ctxt, &nodes)) < 0) + goto error; + + for (i =3D 0; i < n; i++) { + int val; + char *str =3D virXMLPropString(nodes[i], "name"); + if (!str) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing feature name")); + goto error; + } + + if ((val =3D qemuMigrationCookieFlagTypeFromString(str)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown migration cookie feature %s"), + str); + VIR_FREE(str); + goto error; + } + + if ((flags & (1 << val)) =3D=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unsupported migration cookie feature %s"), + str); + VIR_FREE(str); + goto error; + } + VIR_FREE(str); + } + VIR_FREE(nodes); + + if ((flags & QEMU_MIGRATION_COOKIE_GRAPHICS) && + virXPathBoolean("count(./graphics) > 0", ctxt) && + (!(mig->graphics =3D qemuMigrationCookieGraphicsXMLParse(ctxt)))) + goto error; + + if ((flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) && + virXPathBoolean("count(./lockstate) > 0", ctxt)) { + mig->lockDriver =3D virXPathString("string(./lockstate[1]/@driver)= ", ctxt); + if (!mig->lockDriver) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing lock driver name in migration cookie= ")); + goto error; + } + mig->lockState =3D virXPathString("string(./lockstate[1]/leases[1]= )", ctxt); + if (mig->lockState && STREQ(mig->lockState, "")) + VIR_FREE(mig->lockState); + } + + if ((flags & QEMU_MIGRATION_COOKIE_PERSISTENT) && + virXPathBoolean("count(./domain) > 0", ctxt)) { + if ((n =3D virXPathNodeSet("./domain", ctxt, &nodes)) > 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Too many domain elements in " + "migration cookie: %d"), + n); + goto error; + } + mig->persistent =3D virDomainDefParseNode(doc, nodes[0], + caps, driver->xmlopt, NULL, + VIR_DOMAIN_DEF_PARSE_INACT= IVE | + VIR_DOMAIN_DEF_PARSE_ABI_U= PDATE | + VIR_DOMAIN_DEF_PARSE_SKIP_= VALIDATE); + if (!mig->persistent) { + /* virDomainDefParseNode already reported + * an error for us */ + goto error; + } + VIR_FREE(nodes); + } + + if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) && + virXPathBoolean("count(./network) > 0", ctxt) && + (!(mig->network =3D qemuMigrationCookieNetworkXMLParse(ctxt)))) + goto error; + + if (flags & QEMU_MIGRATION_COOKIE_NBD && + virXPathBoolean("boolean(./nbd)", ctxt) && + (!(mig->nbd =3D qemuMigrationCookieNBDXMLParse(ctxt)))) + goto error; + + if (flags & QEMU_MIGRATION_COOKIE_STATS && + virXPathBoolean("boolean(./statistics)", ctxt) && + (!(mig->jobInfo =3D qemuMigrationCookieStatisticsXMLParse(ctxt)))) + goto error; + + virObjectUnref(caps); + return 0; + + error: + VIR_FREE(tmp); + VIR_FREE(nodes); + virObjectUnref(caps); + return -1; +} + + +static int +qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + const char *xml, + unsigned int flags) +{ + xmlDocPtr doc =3D NULL; + xmlXPathContextPtr ctxt =3D NULL; + int ret =3D -1; + + VIR_DEBUG("xml=3D%s", NULLSTR(xml)); + + if (!(doc =3D virXMLParseStringCtxt(xml, _("(qemu_migration_cookie)"),= &ctxt))) + goto cleanup; + + ret =3D qemuMigrationCookieXMLParse(mig, driver, doc, ctxt, flags); + + cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return ret; +} + + +int +qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr dom, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + if (!cookieout || !cookieoutlen) + return 0; + + *cookieoutlen =3D 0; + + if (flags & QEMU_MIGRATION_COOKIE_GRAPHICS && + qemuMigrationCookieAddGraphics(mig, driver, dom) < 0) + return -1; + + if (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE && + qemuMigrationCookieAddLockstate(mig, driver, dom) < 0) + return -1; + + if (flags & QEMU_MIGRATION_COOKIE_NETWORK && + qemuMigrationCookieAddNetwork(mig, driver, dom) < 0) { + return -1; + } + + if ((flags & QEMU_MIGRATION_COOKIE_NBD) && + qemuMigrationCookieAddNBD(mig, driver, dom) < 0) + return -1; + + if (flags & QEMU_MIGRATION_COOKIE_STATS && + qemuMigrationCookieAddStatistics(mig, dom) < 0) + return -1; + + if (flags & QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG) + mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG; + + if (flags & QEMU_MIGRATION_COOKIE_CPU_HOTPLUG) + mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_CPU_HOTPLUG; + + if (!(*cookieout =3D qemuMigrationCookieXMLFormatStr(driver, mig))) + return -1; + + *cookieoutlen =3D strlen(*cookieout) + 1; + + VIR_DEBUG("cookielen=3D%d cookie=3D%s", *cookieoutlen, *cookieout); + + return 0; +} + + +qemuMigrationCookiePtr +qemuMigrationEatCookie(virQEMUDriverPtr driver, + virDomainObjPtr dom, + const char *cookiein, + int cookieinlen, + unsigned int flags) +{ + qemuMigrationCookiePtr mig =3D NULL; + + /* Parse & validate incoming cookie (if any) */ + if (cookiein && cookieinlen && + cookiein[cookieinlen-1] !=3D '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie was not NULL terminated")); + goto error; + } + + VIR_DEBUG("cookielen=3D%d cookie=3D'%s'", cookieinlen, NULLSTR(cookiei= n)); + + if (!(mig =3D qemuMigrationCookieNew(dom))) + return NULL; + + if (cookiein && cookieinlen && + qemuMigrationCookieXMLParseStr(mig, + driver, + cookiein, + flags) < 0) + goto error; + + if (flags & QEMU_MIGRATION_COOKIE_PERSISTENT && + mig->persistent && + STRNEQ(dom->def->name, mig->persistent->name)) { + VIR_FREE(mig->persistent->name); + if (VIR_STRDUP(mig->persistent->name, dom->def->name) < 0) + goto error; + } + + if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) { + if (!mig->lockDriver) { + if (virLockManagerPluginUsesState(driver->lockManager)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing %s lock state for migration cook= ie"), + virLockManagerPluginGetName(driver->lockMan= ager)); + goto error; + } + } else if (STRNEQ(mig->lockDriver, + virLockManagerPluginGetName(driver->lockManager)= )) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Source host lock driver %s different from ta= rget %s"), + mig->lockDriver, + virLockManagerPluginGetName(driver->lockManager= )); + goto error; + } + } + + return mig; + + error: + qemuMigrationCookieFree(mig); + return NULL; +} diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_coo= kie.h new file mode 100644 index 000000000..ca3d639a3 --- /dev/null +++ b/src/qemu/qemu_migration_cookie.h @@ -0,0 +1,153 @@ +/* + * qemu_migration_cookie.h: QEMU migration cookie handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#ifndef __QEMU_MIGRATION_COOKIE_H__ +# define __QEMU_MIGRATION_COOKIE_H__ + +enum qemuMigrationCookieFlags { + QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, + QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, + QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT, + QEMU_MIGRATION_COOKIE_FLAG_NETWORK, + QEMU_MIGRATION_COOKIE_FLAG_NBD, + QEMU_MIGRATION_COOKIE_FLAG_STATS, + QEMU_MIGRATION_COOKIE_FLAG_MEMORY_HOTPLUG, + QEMU_MIGRATION_COOKIE_FLAG_CPU_HOTPLUG, + + QEMU_MIGRATION_COOKIE_FLAG_LAST +}; + +VIR_ENUM_DECL(qemuMigrationCookieFlag); + +enum qemuMigrationCookieFeatures { + QEMU_MIGRATION_COOKIE_GRAPHICS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_G= RAPHICS), + QEMU_MIGRATION_COOKIE_LOCKSTATE =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_L= OCKSTATE), + QEMU_MIGRATION_COOKIE_PERSISTENT =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_= PERSISTENT), + QEMU_MIGRATION_COOKIE_NETWORK =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_NET= WORK), + QEMU_MIGRATION_COOKIE_NBD =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_NBD), + QEMU_MIGRATION_COOKIE_STATS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS= ), + QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_F= LAG_MEMORY_HOTPLUG), + QEMU_MIGRATION_COOKIE_CPU_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_FLAG= _CPU_HOTPLUG), +}; + +typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; +typedef qemuMigrationCookieGraphics *qemuMigrationCookieGraphicsPtr; +struct _qemuMigrationCookieGraphics { + int type; + int port; + int tlsPort; + char *listen; + char *tlsSubject; +}; + +typedef struct _qemuMigrationCookieNetData qemuMigrationCookieNetData; +typedef qemuMigrationCookieNetData *qemuMigrationCookieNetDataPtr; +struct _qemuMigrationCookieNetData { + int vporttype; /* enum virNetDevVPortProfile */ + + /* + * Array of pointers to saved data. Each VIF will have its own + * data to transfer. + */ + char *portdata; +}; + +typedef struct _qemuMigrationCookieNetwork qemuMigrationCookieNetwork; +typedef qemuMigrationCookieNetwork *qemuMigrationCookieNetworkPtr; +struct _qemuMigrationCookieNetwork { + /* How many virtual NICs are we saving data for? */ + int nnets; + + qemuMigrationCookieNetDataPtr net; +}; + +typedef struct _qemuMigrationCookieNBD qemuMigrationCookieNBD; +typedef qemuMigrationCookieNBD *qemuMigrationCookieNBDPtr; +struct _qemuMigrationCookieNBD { + int port; /* on which port does NBD server listen for incoming data */ + + size_t ndisks; /* Number of items in @disk array */ + struct { + char *target; /* Disk target */ + unsigned long long capacity; /* And its capacity */ + } *disks; +}; + +typedef struct _qemuMigrationCookie qemuMigrationCookie; +typedef qemuMigrationCookie *qemuMigrationCookiePtr; +struct _qemuMigrationCookie { + unsigned int flags; + unsigned int flagsMandatory; + + /* Host properties */ + unsigned char localHostuuid[VIR_UUID_BUFLEN]; + unsigned char remoteHostuuid[VIR_UUID_BUFLEN]; + char *localHostname; + char *remoteHostname; + + /* Guest properties */ + unsigned char uuid[VIR_UUID_BUFLEN]; + char *name; + + /* If (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) */ + char *lockState; + char *lockDriver; + + /* If (flags & QEMU_MIGRATION_COOKIE_GRAPHICS) */ + qemuMigrationCookieGraphicsPtr graphics; + + /* If (flags & QEMU_MIGRATION_COOKIE_PERSISTENT) */ + virDomainDefPtr persistent; + + /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */ + qemuMigrationCookieNetworkPtr network; + + /* If (flags & QEMU_MIGRATION_COOKIE_NBD) */ + qemuMigrationCookieNBDPtr nbd; + + /* If (flags & QEMU_MIGRATION_COOKIE_STATS) */ + qemuDomainJobInfoPtr jobInfo; +}; + + +int +qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, + virQEMUDriverPtr driver, + virDomainObjPtr dom, + char **cookieout, + int *cookieoutlen, + unsigned int flags); + +qemuMigrationCookiePtr +qemuMigrationEatCookie(virQEMUDriverPtr driver, + virDomainObjPtr dom, + const char *cookiein, + int cookieinlen, + unsigned int flags); + +void +qemuMigrationCookieFree(qemuMigrationCookiePtr mig); + +int +qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, + virDomainDefPtr def); + +virDomainDefPtr +qemuMigrationCookieGetPersistent(qemuMigrationCookiePtr mig); + +#endif --=20 2.12.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Mon May 6 02:09:52 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1490370023203118.13203226641099; Fri, 24 Mar 2017 08:40:23 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7874D6A6DE; Fri, 24 Mar 2017 15:40:21 +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 12E7F7DB53; Fri, 24 Mar 2017 15:40:21 +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 BEF9F18523C7; Fri, 24 Mar 2017 15:40:20 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v2OFeE7T023343 for ; Fri, 24 Mar 2017 11:40:14 -0400 Received: by smtp.corp.redhat.com (Postfix) id B5A1482FAA; Fri, 24 Mar 2017 15:40:14 +0000 (UTC) Received: from virval.usersys.redhat.com (dhcp129-92.brq.redhat.com [10.34.129.92]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 88BD482FB1 for ; Fri, 24 Mar 2017 15:40:11 +0000 (UTC) Received: by virval.usersys.redhat.com (Postfix, from userid 500) id B56FE10322A; Fri, 24 Mar 2017 16:40:09 +0100 (CET) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 7874D6A6DE Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 7874D6A6DE From: Jiri Denemark To: libvir-list@redhat.com Date: Fri, 24 Mar 2017 16:40:06 +0100 Message-Id: <4b8cdb6e100ec596e79cd85864a5995d7d4ea0d8.1490369794.git.jdenemar@redhat.com> In-Reply-To: References: In-Reply-To: References: Mail-Followup-To: libvir-list@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 2/4] qemu: Fix formatting in qemu_migration_cookie.c 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Fri, 24 Mar 2017 15:40:23 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Jiri Denemark --- src/qemu/qemu_migration_cookie.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_coo= kie.c index 7b237c546..0f4bcaddc 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -51,7 +51,8 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag, "cpu-hotplug"); =20 =20 -static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr= grap) +static void +qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) { if (!grap) return; @@ -78,7 +79,8 @@ qemuMigrationCookieNetworkFree(qemuMigrationCookieNetwork= Ptr network) } =20 =20 -static void qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd) +static void +qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd) { if (!nbd) return; @@ -90,7 +92,8 @@ static void qemuMigrationCookieNBDFree(qemuMigrationCooki= eNBDPtr nbd) } =20 =20 -void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) +void +qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { if (!mig) return; @@ -259,6 +262,7 @@ qemuMigrationCookieNetworkAlloc(virQEMUDriverPtr driver= ATTRIBUTE_UNUSED, return NULL; } =20 + static qemuMigrationCookiePtr qemuMigrationCookieNew(virDomainObjPtr dom) { @@ -513,8 +517,9 @@ qemuMigrationCookieAddStatistics(qemuMigrationCookiePtr= mig, } =20 =20 -static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, - qemuMigrationCookieGraphi= csPtr grap) +static void +qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, + qemuMigrationCookieGraphicsPtr grap) { virBufferAsprintf(buf, "type), @@ -754,8 +759,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, } =20 =20 -static char *qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver, - qemuMigrationCookiePtr mig) +static char * +qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver, + qemuMigrationCookiePtr mig) { virBuffer buf =3D VIR_BUFFER_INITIALIZER; =20 --=20 2.12.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Mon May 6 02:09:52 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1490370018195364.15349600070397; Fri, 24 Mar 2017 08:40:18 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8AA82C05B1D4; Fri, 24 Mar 2017 15:40:17 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 559E87A238; Fri, 24 Mar 2017 15:40:17 +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 09ED95ED66; Fri, 24 Mar 2017 15:40:17 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v2OFeDbs023335 for ; Fri, 24 Mar 2017 11:40:13 -0400 Received: by smtp.corp.redhat.com (Postfix) id C58AB7E663; Fri, 24 Mar 2017 15:40:13 +0000 (UTC) Received: from virval.usersys.redhat.com (dhcp129-92.brq.redhat.com [10.34.129.92]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 95BCF7D682 for ; Fri, 24 Mar 2017 15:40:11 +0000 (UTC) Received: by virval.usersys.redhat.com (Postfix, from userid 500) id B75B310322B; Fri, 24 Mar 2017 16:40:09 +0100 (CET) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8AA82C05B1D4 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8AA82C05B1D4 From: Jiri Denemark To: libvir-list@redhat.com Date: Fri, 24 Mar 2017 16:40:07 +0100 Message-Id: <4bf39e513b24726598a563445d2c705eb5493174.1490369794.git.jdenemar@redhat.com> In-Reply-To: References: In-Reply-To: References: Mail-Followup-To: libvir-list@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 3/4] qemu: Typedef migration cookie enums 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 24 Mar 2017 15:40:18 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Jiri Denemark --- src/qemu/qemu_migration_cookie.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_coo= kie.h index ca3d639a3..87eeb8682 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -19,7 +19,7 @@ #ifndef __QEMU_MIGRATION_COOKIE_H__ # define __QEMU_MIGRATION_COOKIE_H__ =20 -enum qemuMigrationCookieFlags { +typedef enum { QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT, @@ -30,11 +30,11 @@ enum qemuMigrationCookieFlags { QEMU_MIGRATION_COOKIE_FLAG_CPU_HOTPLUG, =20 QEMU_MIGRATION_COOKIE_FLAG_LAST -}; +} qemuMigrationCookieFlags; =20 VIR_ENUM_DECL(qemuMigrationCookieFlag); =20 -enum qemuMigrationCookieFeatures { +typedef enum { QEMU_MIGRATION_COOKIE_GRAPHICS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_G= RAPHICS), QEMU_MIGRATION_COOKIE_LOCKSTATE =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_L= OCKSTATE), QEMU_MIGRATION_COOKIE_PERSISTENT =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_= PERSISTENT), @@ -43,7 +43,7 @@ enum qemuMigrationCookieFeatures { QEMU_MIGRATION_COOKIE_STATS =3D (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS= ), QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_F= LAG_MEMORY_HOTPLUG), QEMU_MIGRATION_COOKIE_CPU_HOTPLUG =3D (1 << QEMU_MIGRATION_COOKIE_FLAG= _CPU_HOTPLUG), -}; +} qemuMigrationCookieFeatures; =20 typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; typedef qemuMigrationCookieGraphics *qemuMigrationCookieGraphicsPtr; --=20 2.12.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Mon May 6 02:09:52 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1490370016750841.5502714132723; Fri, 24 Mar 2017 08:40:16 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 520E9C00AFCE; Fri, 24 Mar 2017 15:40:15 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2217B82FA0; Fri, 24 Mar 2017 15:40:15 +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 CCE905ED64; Fri, 24 Mar 2017 15:40:14 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v2OFeDrX023330 for ; Fri, 24 Mar 2017 11:40:13 -0400 Received: by smtp.corp.redhat.com (Postfix) id F176884010; Fri, 24 Mar 2017 15:40:12 +0000 (UTC) Received: from virval.usersys.redhat.com (dhcp129-92.brq.redhat.com [10.34.129.92]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C352D60BEF for ; Fri, 24 Mar 2017 15:40:10 +0000 (UTC) Received: by virval.usersys.redhat.com (Postfix, from userid 500) id B9358103262; Fri, 24 Mar 2017 16:40:09 +0100 (CET) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 520E9C00AFCE Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 520E9C00AFCE From: Jiri Denemark To: libvir-list@redhat.com Date: Fri, 24 Mar 2017 16:40:08 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: Mail-Followup-To: libvir-list@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 4/4] qemu: Free persistent def inside qemuMigrationCookieFree 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 24 Mar 2017 15:40:16 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Creating a copy of the definition we want to add in a migration cookie makes the code cleaner and less prone to memory leaks or double free errors. Signed-off-by: Jiri Denemark --- src/qemu/qemu_migration.c | 18 ++++++++---------- src/qemu/qemu_migration_cookie.c | 8 +++++--- src/qemu/qemu_migration_cookie.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index b1d141755..9e0e63cf0 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3291,11 +3291,13 @@ qemuMigrationRun(virQEMUDriverPtr driver, if (persist_xml) { persistDef =3D qemuMigrationPrepareDef(driver, persist_xml, NULL, NULL); - if (!persistDef) - goto cleanup; } else { - persistDef =3D vm->newDef; + persistDef =3D qemuDomainDefCopy(driver, vm->newDef, + VIR_DOMAIN_XML_SECURE | + VIR_DOMAIN_XML_MIGRATABLE); } + if (!persistDef) + goto cleanup; } =20 mig =3D qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen, @@ -3505,14 +3507,13 @@ qemuMigrationRun(virQEMUDriverPtr driver, QEMU_MIGRATION_COOKIE_STATS; =20 if (ret =3D=3D 0 && - (qemuMigrationCookieAddPersistent(mig, persistDef) < 0 || + (qemuMigrationCookieAddPersistent(mig, &persistDef) < 0 || qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, cookieFlags) < 0)) { VIR_WARN("Unable to encode migration cookie"); } =20 - if (persistDef !=3D vm->newDef) - virDomainDefFree(persistDef); + virDomainDefFree(persistDef); qemuMigrationCookieFree(mig); =20 if (events) @@ -4997,10 +4998,7 @@ qemuMigrationFinish(virQEMUDriverPtr driver, qemuMonitorSetDomainLog(priv->mon, NULL, NULL, NULL); VIR_FREE(priv->origname); virDomainObjEndAPI(&vm); - if (mig) { - virDomainDefFree(qemuMigrationCookieGetPersistent(mig)); - qemuMigrationCookieFree(mig); - } + qemuMigrationCookieFree(mig); if (orig_err) { virSetError(orig_err); virFreeError(orig_err); diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_coo= kie.c index 0f4bcaddc..bd12f1124 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -99,6 +99,7 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig) return; =20 qemuMigrationCookieGraphicsFree(mig->graphics); + virDomainDefFree(mig->persistent); qemuMigrationCookieNetworkFree(mig->network); qemuMigrationCookieNBDFree(mig->nbd); =20 @@ -385,7 +386,7 @@ qemuMigrationCookieAddLockstate(qemuMigrationCookiePtr = mig, =20 int qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, - virDomainDefPtr def) + virDomainDefPtr *def) { if (mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -393,10 +394,11 @@ qemuMigrationCookieAddPersistent(qemuMigrationCookieP= tr mig, return -1; } =20 - if (!def) + if (!def || !*def) return 0; =20 - mig->persistent =3D def; + mig->persistent =3D *def; + *def =3D NULL; mig->flags |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; mig->flagsMandatory |=3D QEMU_MIGRATION_COOKIE_PERSISTENT; return 0; diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_coo= kie.h index 87eeb8682..f4de4da68 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -145,7 +145,7 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig); =20 int qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, - virDomainDefPtr def); + virDomainDefPtr *def); =20 virDomainDefPtr qemuMigrationCookieGetPersistent(qemuMigrationCookiePtr mig); --=20 2.12.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list