On 5/20/25 13:12, Stefan Kober wrote:
> ---
>  src/ch/ch_conf.h                  |   4 +
>  src/ch/ch_domain.h                |   2 +
>  src/ch/ch_driver.c                | 362 +++++++++++++++++++++++++++++-
>  src/ch/ch_monitor.c               | 156 +++++++++++++
>  src/ch/ch_monitor.h               |   8 +
>  src/ch/ch_process.c               | 136 ++++++++++-
>  src/ch/ch_process.h               |   6 +
>  src/hypervisor/domain_interface.c |   1 +
>  src/libvirt-domain.c              |  15 +-
>  9 files changed, 680 insertions(+), 10 deletions(-)

There's quite a lot happening in just this one patch.
Nevertheless, couple of overall comments:

1) Do NOT change VIR_DEBUG() to VIR_WARN(). It cloggs logs for no
additional value. If you want to see debug logs there is plenty of ways
to do that: https://libvirt.org/kbase/debuglogs.html

2) In general we tend to use the following pattern for functions:

int f(..)
{
   int ret = -1;

   if (cond)
       goto cleanup;

   if (otherCond)
       goto cleanup;

   ret = 0;
 cleanup:
   cleanupCode();
   return ret;
}


See comments below.

> 
> diff --git a/src/ch/ch_conf.h b/src/ch/ch_conf.h
> index b08573476e..40d639eb2a 100644
> --- a/src/ch/ch_conf.h
> +++ b/src/ch/ch_conf.h
> @@ -26,6 +26,7 @@
>  #include "ch_capabilities.h"
>  #include "virebtables.h"
>  #include "object_event.h"
> +#include "virportallocator.h"
>  
>  #define CH_DRIVER_NAME "CH"
>  #define CH_CMD "cloud-hypervisor"
> @@ -90,6 +91,9 @@ struct _virCHDriver
>  
>      /* Immutable pointer, self-locking APIs */
>      virObjectEventState *domainEventState;
> +
> +    /* Immutable pointer, immutable object */
> +    virPortAllocatorRange *migrationPorts;
>  };
>  
>  #define CH_SAVE_MAGIC "libvirt-xml\n \0 \r"
> diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h
> index 69a657f6af..f9ad18b518 100644
> --- a/src/ch/ch_domain.h
> +++ b/src/ch/ch_domain.h
> @@ -25,6 +25,7 @@
>  #include "virchrdev.h"
>  #include "vircgroup.h"
>  #include "virdomainjob.h"
> +#include "virthread.h"
>  
>  
>  typedef struct _virCHDomainObjPrivate virCHDomainObjPrivate;
> @@ -32,6 +33,7 @@ struct _virCHDomainObjPrivate {
>      virChrdevs *chrdevs;
>      virCHDriver *driver;
>      virCHMonitor *monitor;
> +    virThread *migrationDstReceiveThr;
>      char *machineName;
>      virBitmap *autoCpuset;
>      virBitmap *autoNodeset;
> diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c
> index 3bdcf66ebd..c53607251b 100644
> --- a/src/ch/ch_driver.c
> +++ b/src/ch/ch_driver.c
> @@ -29,20 +29,25 @@
>  #include "ch_process.h"
>  #include "domain_cgroup.h"
>  #include "domain_event.h"
> +#include "domain_interface.h"
>  #include "datatypes.h"
>  #include "driver.h"
> +#include "viralloc.h"
>  #include "viraccessapicheck.h"
>  #include "virchrdev.h"
>  #include "virerror.h"
>  #include "virlog.h"
>  #include "virobject.h"
>  #include "virfile.h"
> +#include "virtime.h"
>  #include "virtypedparam.h"
>  #include "virutil.h"
>  #include "viruuid.h"
>  #include "virnuma.h"
>  #include "virhostmem.h"
>  
> +#include "util/virportallocator.h"
> +
>  #define VIR_FROM_THIS VIR_FROM_CH
>  
>  VIR_LOG_INIT("ch.ch_driver");
> @@ -1453,6 +1458,13 @@ chStateInitialize(bool privileged,
>      if (!(ch_driver->domainEventState = virObjectEventStateNew()))
>          goto cleanup;
>  
> +        /* Allocate bitmap for migration port reservation */
> +    if (!(ch_driver->migrationPorts =
> +          virPortAllocatorRangeNew(_("migration"),
> +                                   49152,
> +                                   49216)))

These magic constants should be declared as macros somewhere in
ch_conf.h.

> +        goto cleanup;
> +
>      if ((rv = chExtractVersion(ch_driver)) < 0) {
>          if (rv == -2)
>              ret = VIR_DRV_STATE_INIT_SKIPPED;
> @@ -1495,8 +1507,9 @@ chConnectSupportsFeature(virConnectPtr conn,
>                             _("Global feature %1$d should have already been 
> handled"),
>                             feature);
>              return -1;
> -        case VIR_DRV_FEATURE_MIGRATION_V2:
>          case VIR_DRV_FEATURE_MIGRATION_V3:
> +            return 1;
> +        case VIR_DRV_FEATURE_MIGRATION_V2:
>          case VIR_DRV_FEATURE_MIGRATION_P2P:
>          case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
>          case VIR_DRV_FEATURE_XML_MIGRATABLE:
> @@ -2338,6 +2351,348 @@ chDomainInterfaceAddresses(virDomain *dom,
>      return ret;
>  }
>  
> +/*******************************************************************
> + * Migration Protocol Version 3
> + *******************************************************************/
> +
> +static char *
> +chDomainMigrateBegin3(virDomainPtr domain,
> +                      const char *xmlin,
> +                      char **cookieout,
> +                      int *cookieoutlen,
> +                      unsigned long flags,
> +                      const char *dname,
> +                      unsigned long resource G_GNUC_UNUSED)
> +{
> +    virDomainObj *vm;
> +    char *xml = NULL;
> +    virCHDriver *driver = domain->conn->privateData;
> +
> +    VIR_WARN("chDomainMigrateBegin3 %p %s %p %p %lu %s",
> +              domain, xmlin, cookieout, cookieoutlen, flags, dname);

I don't see any plausible reason for VIR_WARN() here. We do not need to
warn user about arguments. VIR_DEBUG() would be a better fit, but not
really - the only caller of this function (virDomainMigrateBegin3())
already did that.

> +    if (!(vm = virCHDomainObjFromDomain(domain)))
> +        return NULL;
> +
> +    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) {
> +        virDomainObjEndAPI(&vm);
> +        return NULL;
> +    }
> +
> +    // Copied from libxl_migration.c:386

We use C89 style of comments.

> +    if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0)
> +        goto cleanup;
> +
> +    xml = virDomainDefFormat(vm->def, driver->xmlopt, 
> VIR_DOMAIN_DEF_FORMAT_SECURE);
> +
> +    if (xml) {
> +        VIR_WARN("chDomainMigrateBegin3 success. xml: %s", xml);
> +        goto cleanup;
> +    }
> +
> +    return NULL;
> + cleanup:
> +    virDomainObjEndAPI(&vm);
> +    return xml;
> +}
> +
> +static
> +virDomainDef *
> +chMigrationAnyPrepareDef(virCHDriver *driver,
> +                           const char *dom_xml,
> +                           const char *dname)
> +{
> +    virDomainDef *def;
> +    char *name = NULL;
> +
> +    if (!dom_xml) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("no domain XML passed"));
> +        return NULL;
> +    }
> +
> +    if (!(def = virDomainDefParseString(dom_xml, driver->xmlopt,
> +                                        NULL,
> +                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
> +        goto cleanup;
> +
> +    if (dname) {
> +        VIR_FREE(name);

I bet what you've meant to say here is:

VIR_FREE(def->name);

which renders 'name' variable unused.

> +        def->name = g_strdup(dname);
> +    }
> +
> + cleanup:
> +    return def;
> +}
> +
> +typedef struct _chMigrationDstArgs {
> +    unsigned int port;
> +    virCHDomainObjPrivate *priv;
> +} chMigrationDstArgs;
> +
> +static void
> +chDoMigrateDstReceive(void *opaque)
> +{
> +    chMigrationDstArgs *args = opaque;
> +    virCHDomainObjPrivate *priv = args->priv;
> +    g_autofree char* rcv_uri = NULL;
> +
> +    VIR_WARN("In thread. %u %p", args->port, args->priv);
> +    if (!priv->monitor) {
> +        VIR_ERROR(_("VMs monitor not initialized"));
> +    }
> +
> +    rcv_uri = g_strdup_printf("tcp:0.0.0.0:%d", args->port);
> +
> +    if (virCHMonitorMigrationReceive(priv->monitor, rcv_uri) < 0) {
> +        VIR_WARN("Migration receive failed.");
> +    }
> +
> +    VIR_WARN("Migration thread finished its duty");
> +}
> +
> +/**
> + * Runs on the destination and prepares the empty cloud hypervisor process to
> + * receive the migration.
> + * Allocates some tcp port number to use as a migration channel.
> + */
> +static int
> +chDomainMigratePrepare3(virConnectPtr dconn,
> +                        const char *cookiein,
> +                        int cookieinlen,
> +                        char **cookieout,
> +                        int *cookieoutlen,
> +                        const char *uri_in,
> +                        char **uri_out,
> +                        unsigned long flags,
> +                        const char *dname,
> +                        unsigned long resource G_GNUC_UNUSED,
> +                        const char *dom_xml)
> +{
> +    virCHDriver *driver = dconn->privateData;
> +    virDomainObj *vm = NULL;
> +    virCHDomainObjPrivate *priv = NULL;
> +    chMigrationDstArgs *args = g_new0(chMigrationDstArgs, 1);

This is allocated but never freed.

> +    unsigned short port = 0;
> +    g_autofree char *hostname = NULL;
> +    const char *threadname = "mig-ch";
> +    g_autoptr(virDomainDef) def = NULL;
> +    int rc = 0;
> +    const char *incFormat = "%s:%s:%d"; // seems to differ for AF_INET6
> +
> +    VIR_WARN("chDomainMigratePrepare3 %p %s %u %p %p %s %p %lu %s %s",
> +              dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, 
> uri_out, flags, dname, dom_xml);
> +
> +    if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0)
> +        return -1;
> +
> +    if (!(def = chMigrationAnyPrepareDef(driver, dom_xml, dname)))
> +        return -1;
> +
> +    VIR_WARN("Got DomainDef prepared successfully");
> +
> +    if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
> +        rc = -1;
> +        goto cleanup;
> +    }
> +    VIR_WARN("Got port %i", port);
> +
> +    if ((hostname = virGetHostname()) == NULL) {
> +        rc = -1;
> +        goto cleanup;
> +    }
> +
> +    *uri_out = g_strdup_printf(incFormat, "tcp", hostname, port);
> +    VIR_WARN("uri out %s", *uri_out);
> +
> +    if (!(vm = virDomainObjListAdd(driver->domains, &def,
> +                                   driver->xmlopt,
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
> +                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
> +                                   NULL)))
> +    {
> +        rc = -1;
> +        VIR_WARN("Could not add Domain Obj to List");
> +        goto cleanup;
> +    }
> +
> +    if (virCHProcessInit(driver, vm) < 0) {
> +        rc = -1;
> +        VIR_WARN("Could not init process");
> +        goto cleanup;
> +    }
> +
> +    VIR_WARN("Try creating migration thread");
> +    priv = vm->privateData;
> +    args->port = port;
> +    args->priv = priv;
> +
> +    // VM receiving is blocking which we cannot do here, because it would 
> block
> +    // the Libvirt migration protocol.
> +    // Prepare a thread to receive the migration data
> +    // VIR_FREE(priv->migrationDstReceiveThr);

This VIR_FREE() must be called in virCHDomainObjPrivateFree() at least.

> +    priv->migrationDstReceiveThr = g_new0(virThread, 1);
> +    if (virThreadCreateFull(priv->migrationDstReceiveThr, true,
> +                            chDoMigrateDstReceive,
> +                            threadname,
> +                            false,
> +                            args) < 0) {
> +        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
> +                       _("Failed to create thread for receiving migration 
> data"));
> +        goto cleanup;
> +    }
> +
> +    VIR_WARN("Finished creating migration thread");
> +
> +
> +    VIR_WARN("Fin migrationPrepare");
> +
> +
> + cleanup:
> +    virDomainObjEndAPI(&vm);
> +    return rc;
> +}


This is the place where I acquired so much of changed lines that I
stopped my review. Please see the diff at EOL which I think should be
squashed in. It covers also other fixes that I haven't raised explicitly
here.

> +
> +static int
> +chDomainMigratePerform3(virDomainPtr dom,
> +                        const char *xmlin,
> +                        const char *cookiein,
> +                        int cookieinlen,
> +                        char **cookieout,
> +                        int *cookieoutlen,
> +                        const char *dconnuri,
> +                        const char *uri,
> +                        unsigned long flags,
> +                        const char *dname,
> +                        unsigned long resource)
> +{
> +    size_t i;
> +    virDomainObj *vm;
> +    g_autoptr(virCHDriverConfig) cfg = 
> virCHDriverGetConfig(dom->conn->privateData);
> +    virCHDomainObjPrivate *priv = NULL;
> +    g_autofree char *id = g_strdup_printf("bla");
> +    VIR_WARN("chDomainMigratePerform3 %p %s %s %u %p %p %s %s %lu %s %lu",
> +              dom, xmlin, cookiein, cookieinlen, cookieout, cookieoutlen, 
> dconnuri, uri, flags, dname, resource);
> +
> +    if (!(vm = virCHDomainObjFromDomain(dom)))
> +        return -1;
> +
> +    priv = vm->privateData;
> +
> +    if (!priv->monitor) {
> +        VIR_ERROR(_("VMs monitor not initialized"));
> +        goto cleanup;
> +    }
> +
> +    if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0) {
> +        goto cleanup;
> +    }
> +
> +    // Net device id hardcoded currently
> +    // We need to remove network devices from the VM before live migration.
> +    // Libvirt pre-allocates network devices and passes only the FD to CHV. 
> CHV
> +    // is not able to migrate those devices.
> +    // See following CHV issue: 
> https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7054
> +        /* de-activate netdevs after stopping vm */
> +    ignore_value(virDomainInterfaceStopDevices(vm->def));
> +    for (i = 0; i < vm->def->nnets; i++) {
> +        virDomainInterfaceDeleteDevice(vm->def, vm->def->nets[i], false, 
> cfg->stateDir);
> +        id = g_strdup_printf("net_%lu", i);
> +        if (virCHMonitorRemoveDevice(priv->monitor, id) < 0) {
> +            VIR_WARN("Could not remove net device. Continue to migrate 
> regardless.");
> +        }
> +    }
> +
> +    if (virCHMonitorMigrationSend(priv->monitor, uri) < 0) {
> +        VIR_WARN("Migration send failed.");
> +        goto cleanup;
> +    }
> +
> + cleanup:
> +    virDomainObjEndAPI(&vm);
> +    return 0;
> +}
> +
> +static virDomainPtr
> +chDomainMigrateFinish3(virConnectPtr dconn,
> +                       const char *dname,
> +                       const char *cookiein,
> +                       int cookieinlen,
> +                       char **cookieout,
> +                       int *cookieoutlen,
> +                       const char *dconnuri G_GNUC_UNUSED,
> +                       const char *uri G_GNUC_UNUSED,
> +                       unsigned long flags,
> +                       int cancelled)
> +{
> +    virCHDriver *driver = dconn->privateData;
> +    virDomainObj *vm = NULL;
> +    virDomainPtr dom = NULL;
> +
> +    VIR_WARN("chDomainMigrateFinish3 %p %s %s %d %p %p %lu %d",
> +              dconn, dname, cookiein, cookieinlen, cookieout, cookieoutlen, 
> flags, cancelled);
> +
> +    vm = virDomainObjListFindByName(driver->domains, dname);
> +    if (!vm) {
> +        virReportError(VIR_ERR_NO_DOMAIN,
> +                       _("no domain with matching name '%1$s'"), dname);
> +        return NULL;
> +    }
> +
> +    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) {
> +        virDomainObjEndAPI(&vm);
> +        return NULL;
> +    }
> +    if (!(dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, 
> vm->def->id))) {
> +        virDomainObjEndAPI(&vm);
> +        VIR_WARN("virGetDomain failed.");
> +        return NULL;
> +
> +    }
> +    if (virCHProcessUpdateInfo(vm) < 0) {
> +        VIR_WARN("Could not update console info. Consider that non-fatal.");
> +    }
> +
> +    if (virCHProcessInitNetwork(driver, vm) < 0) {
> +        VIR_WARN("Could not updatenetwork info. Consider that non-fatal.");
> +    }
> +
> +    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, 
> VIR_DOMAIN_RUNNING_MIGRATED);
> +
> +    virDomainObjEndAPI(&vm);
> +    return dom;
> +}
> +
> +static int
> +chDomainMigrateConfirm3(virDomainPtr domain,
> +                        const char *cookiein,
> +                        int cookieinlen,
> +                        unsigned long flags,
> +                        int cancelled)
> +{
> +    virCHDriver *driver = domain->conn->privateData;
> +    virObjectEvent *event = NULL;
> +    virDomainObj *vm;
> +
> +    VIR_WARN("chDomainMigrateConfirm3 %p %s %d %lu %d",
> +              domain, cookiein, cookieinlen, flags, cancelled);
> +
> +    if (!(vm = virCHDomainObjFromDomain(domain)))
> +        return -1;
> +
> +    if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0) {
> +        virDomainObjEndAPI(&vm);
> +        return -1;
> +    }
> +
> +    // Code from chDestroyFlags
> +    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, 
> VIR_DOMAIN_SHUTOFF_MIGRATED);
> +    virCHProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
> +    virCHDomainRemoveInactive(driver, vm);
> +    virDomainObjEndAPI(&vm);
> +
> +    virObjectEventStateQueue(driver->domainEventState, event);
> +    return 0;
> +}
>  
>  /* Function Tables */
>  static virHypervisorDriver chHypervisorDriver = {
> @@ -2400,6 +2755,11 @@ static virHypervisorDriver chHypervisorDriver = {
>      .connectDomainEventRegisterAny = chConnectDomainEventRegisterAny,       
> /* 10.10.0 */
>      .connectDomainEventDeregisterAny = chConnectDomainEventDeregisterAny,   
> /* 10.10.0 */
>      .domainInterfaceAddresses = chDomainInterfaceAddresses, /* 11.0.0 */
> +    .domainMigrateBegin3 = chDomainMigrateBegin3, /* 11.4.0 */
> +    .domainMigratePrepare3 = chDomainMigratePrepare3, /* 11.4.0 */
> +    .domainMigratePerform3 = chDomainMigratePerform3, /* 11.4.0 */
> +    .domainMigrateFinish3 = chDomainMigrateFinish3, /* 11.4.0 */
> +    .domainMigrateConfirm3 = chDomainMigrateConfirm3, /* 11.4.0 */
>  };
>  
>  static virConnectDriver chConnectDriver = {
> diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c
> index 3d3b4cb87d..595fa30be0 100644
> --- a/src/ch/ch_monitor.c
> +++ b/src/ch/ch_monitor.c
> @@ -548,6 +548,7 @@ virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef 
> *vmdef,
>      if (!(*jsonstr = virJSONValueToString(content, false)))
>          return -1;
>  
> +    VIR_WARN("Build VM JSON: \n %s \n", *jsonstr);
>      return 0;
>  }
>  
> @@ -684,6 +685,8 @@ virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg, 
> int logfile)
>          return NULL;
>      }
>  
> +    VIR_WARN("Start emulator with cmd: %s", vm->def->emulator);
> +
>      cmd = virCommandNew(vm->def->emulator);
>      virCommandSetOutputFD(cmd, &logfile);
>      virCommandSetErrorFD(cmd, &logfile);
> @@ -1163,6 +1166,159 @@ virCHMonitorSaveVM(virCHMonitor *mon,
>      return ret;
>  }
>  
> +int virCHMonitorRemoveDevice(virCHMonitor *mon,
> +                             const char* device_id)
> +{
> +    g_autofree char *url = NULL;
> +    int responseCode = 0;
> +    int ret = -1;
> +    g_autofree char *payload = NULL;
> +    struct curl_slist *headers = NULL;
> +    struct curl_data data = {0};
> +
> +    url = g_strdup_printf("%s/%s", URL_ROOT, URL_VM_REMOVE_DEVICE);
> +
> +    headers = curl_slist_append(headers, "Accept: application/json");
> +    headers = curl_slist_append(headers, "Content-Type: application/json");
> +
> +    if (virCHMonitorBuildKeyValueStringJson(&payload, "id", device_id) != 0)
> +        return -1;
> +
> +    VIR_WARN("Remove device id %s json %s", device_id, payload);
> +
> +    VIR_WITH_OBJECT_LOCK_GUARD(mon) {
> +        /* reset all options of a libcurl session handle at first */
> +        curl_easy_reset(mon->handle);
> +
> +        curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, 
> mon->socketpath);
> +        curl_easy_setopt(mon->handle, CURLOPT_URL, url);
> +        curl_easy_setopt(mon->handle, CURLOPT_CUSTOMREQUEST, "PUT");
> +        curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers);
> +        curl_easy_setopt(mon->handle, CURLOPT_POSTFIELDS, payload);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data);
> +
> +        responseCode = virCHMonitorCurlPerform(mon->handle);
> +    }
> +
> +    if (responseCode == 200 || responseCode == 204) {
> +        ret = 0;
> +    } else {
> +        data.content = g_realloc(data.content, data.size + 1);
> +        data.content[data.size] = 0;
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       data.content);
> +        g_free(data.content);
> +    }
> +
> +    /* reset the libcurl handle to avoid leaking a stack pointer to data */
> +    curl_easy_reset(mon->handle);
> +    curl_slist_free_all(headers);
> +    return ret;
> +}
> +
> +int virCHMonitorMigrationSend(virCHMonitor *mon,
> +                              const char *dst_uri)
> +{
> +    g_autofree char *url = NULL;
> +    int responseCode = 0;
> +    int ret = -1;
> +    g_autofree char *payload = NULL;
> +    struct curl_slist *headers = NULL;
> +    struct curl_data data = {0};
> +
> +    url = g_strdup_printf("%s/%s", URL_ROOT, URL_VM_SEND_MIGRATION);
> +
> +    headers = curl_slist_append(headers, "Accept: application/json");
> +    headers = curl_slist_append(headers, "Content-Type: application/json");
> +
> +    if (virCHMonitorBuildKeyValueStringJson(&payload, "destination_url", 
> dst_uri) != 0)
> +        return -1;
> +
> +    VIR_WARN("Send VM to url %s json %s", dst_uri, payload);
> +
> +    VIR_WITH_OBJECT_LOCK_GUARD(mon) {
> +        /* reset all options of a libcurl session handle at first */
> +        curl_easy_reset(mon->handle);
> +
> +        curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, 
> mon->socketpath);
> +        curl_easy_setopt(mon->handle, CURLOPT_URL, url);
> +        curl_easy_setopt(mon->handle, CURLOPT_CUSTOMREQUEST, "PUT");
> +        curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers);
> +        curl_easy_setopt(mon->handle, CURLOPT_POSTFIELDS, payload);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data);
> +
> +        responseCode = virCHMonitorCurlPerform(mon->handle);
> +    }
> +
> +    if (responseCode == 200 || responseCode == 204) {
> +        ret = 0;
> +    } else {
> +        data.content = g_realloc(data.content, data.size + 1);
> +        data.content[data.size] = 0;
> +        virReportError(VIR_ERR_INTERNAL_ERROR, _("Error sending VM: '%1$s'"),
> +                       data.content);
> +        g_free(data.content);
> +    }
> +
> +    /* reset the libcurl handle to avoid leaking a stack pointer to data */
> +    curl_easy_reset(mon->handle);
> +    curl_slist_free_all(headers);
> +    return ret;
> +}
> +
> +int virCHMonitorMigrationReceive(virCHMonitor *mon,
> +                                 const char *rcv_uri)
> +{
> +    g_autofree char *url = NULL;
> +    int responseCode = 0;
> +    int ret = -1;
> +    g_autofree char *payload = NULL;
> +    struct curl_slist *headers = NULL;
> +    struct curl_data data = {0};
> +
> +    url = g_strdup_printf("%s/%s", URL_ROOT, URL_VM_RECEIVE_MIGRATION);
> +
> +    headers = curl_slist_append(headers, "Accept: application/json");
> +    headers = curl_slist_append(headers, "Content-Type: application/json");
> +
> +    if (virCHMonitorBuildKeyValueStringJson(&payload, "receiver_url", 
> rcv_uri) != 0)
> +        return -1;
> +
> +    VIR_WARN("Receive VM from url %s json: %s", rcv_uri, payload);
> +
> +    VIR_WITH_OBJECT_LOCK_GUARD(mon) {
> +        /* reset all options of a libcurl session handle at first */
> +        curl_easy_reset(mon->handle);
> +
> +        curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, 
> mon->socketpath);
> +        curl_easy_setopt(mon->handle, CURLOPT_URL, url);
> +        curl_easy_setopt(mon->handle, CURLOPT_CUSTOMREQUEST, "PUT");
> +        curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers);
> +        curl_easy_setopt(mon->handle, CURLOPT_POSTFIELDS, payload);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback);
> +        curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data);
> +
> +        responseCode = virCHMonitorCurlPerform(mon->handle);
> +    }
> +
> +    if (responseCode == 200 || responseCode == 204) {
> +        ret = 0;
> +    } else {
> +        data.content = g_realloc(data.content, data.size + 1);
> +        data.content[data.size] = 0;
> +        virReportError(VIR_ERR_INTERNAL_ERROR, _("Error receiving VM: 
> '%1$s'"),
> +                       data.content);
> +        g_free(data.content);
> +    }
> +
> +    /* reset the libcurl handle to avoid leaking a stack pointer to data */
> +    curl_easy_reset(mon->handle);
> +    curl_slist_free_all(headers);
> +    return ret;
> +}
> +
>  int
>  virCHMonitorBuildRestoreJson(virDomainDef *vmdef,
>                               const char *from,
> diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h
> index ffac9e938e..256ab0d8a1 100644
> --- a/src/ch/ch_monitor.h
> +++ b/src/ch/ch_monitor.h
> @@ -40,6 +40,9 @@
>  #define URL_VM_INFO "vm.info"
>  #define URL_VM_SAVE "vm.snapshot"
>  #define URL_VM_RESTORE "vm.restore"
> +#define URL_VM_RECEIVE_MIGRATION "vm.receive-migration"
> +#define URL_VM_SEND_MIGRATION "vm.send-migration"
> +#define URL_VM_REMOVE_DEVICE "vm.remove-device"
>  
>  #define VIRCH_THREAD_NAME_LEN   16
>  
> @@ -128,6 +131,11 @@ int virCHMonitorSuspendVM(virCHMonitor *mon);
>  int virCHMonitorResumeVM(virCHMonitor *mon);
>  int virCHMonitorSaveVM(virCHMonitor *mon,
>                         const char *to);
> +int virCHMonitorMigrationSend(virCHMonitor *mon,
> +                              const char *dst_uri);
> +int virCHMonitorMigrationReceive(virCHMonitor *mon,
> +                                 const char *rcv_uri);
> +int virCHMonitorRemoveDevice(virCHMonitor *mon, const char* device_id);
>  int virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info);
>  
>  size_t virCHMonitorGetThreadInfo(virCHMonitor *mon, bool refresh,
> diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c
> index 95c808cb41..4d2bbc2b3d 100644
> --- a/src/ch/ch_process.c
> +++ b/src/ch/ch_process.c
> @@ -135,6 +135,7 @@ int
>  virCHProcessUpdateInfo(virDomainObj *vm)
>  {
>      g_autoptr(virJSONValue) info = NULL;
> +
>      virCHDomainObjPrivate *priv = vm->privateData;
>      if (virCHMonitorGetInfo(priv->monitor, &info) < 0)
>          return -1;
> @@ -643,7 +644,7 @@ chProcessAddNetworkDevices(virCHDriver *driver,
>                             int **nicindexes,
>                             size_t *nnicindexes)
>  {
> -    size_t i;
> +    size_t i, j;
>      VIR_AUTOCLOSE mon_sockfd = -1;
>      g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
>      g_auto(virBuffer) http_headers = VIR_BUFFER_INITIALIZER;
> @@ -654,8 +655,10 @@ chProcessAddNetworkDevices(virCHDriver *driver,
>          return -1;
>      }
>  
> -    if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0)
> +    if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0) {
> +        VIR_WARN("chProcessAddNetworkDevices failed");
>          return -1;
> +    }
>  
>      virBufferAddLit(&http_headers, "PUT /api/v1/vm.add-net HTTP/1.1\r\n");
>      virBufferAddLit(&http_headers, "Host: localhost\r\n");
> @@ -681,24 +684,33 @@ chProcessAddNetworkDevices(virCHDriver *driver,
>          if (virCHDomainValidateActualNetDef(vmdef->nets[i]) < 0) {
>              virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                             _("net definition failed validation"));
> +            VIR_WARN("virCHDomainValidateActualNetDef failed.");
>              return -1;
>          }
>  
>          tapfds = g_new0(int, tapfd_len);
>          memset(tapfds, -1, (tapfd_len) * sizeof(int));
>  
> +        VIR_WARN("net type: %u", vmdef->nets[i]->type);
>          /* Connect Guest interfaces */
>          if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], 
> tapfds,
> -                                         nicindexes, nnicindexes) < 0)
> +                                         nicindexes, nnicindexes) < 0) {
> +            VIR_WARN("chProcessAddNetworkDevices failed.");
>              return -1;
> +        }
>  
>          if (virCHMonitorBuildNetJson(vmdef->nets[i], i, &payload) < 0) {
>              virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                             _("Failed to build net json"));
> +            VIR_WARN("virCHMonitorBuildNetJson failed.");
>              return -1;
>          }
>  
> -        VIR_DEBUG("payload sent with net-add request to CH = %s", payload);
> +        VIR_WARN("payload sent with net-add request to CH = %s", payload);
> +
> +        for (j = 0; j < tapfd_len; j++) {
> +            VIR_WARN("tapfd %lu : %d", j, tapfds[j]);
> +        }
>  
>          virBufferAsprintf(&buf, "%s", 
> virBufferCurrentContent(&http_headers));
>          virBufferAsprintf(&buf, "Content-Length: %zu\r\n\r\n", 
> strlen(payload));
> @@ -892,6 +904,122 @@ virCHProcessPrepareDomain(virDomainObj *vm)
>      return 0;
>  }
>  
> +int virCHProcessInitNetwork(virCHDriver *driver,
> +                            virDomainObj *vm)
> +{
> +    int ret = -1;
> +    virCHDomainObjPrivate *priv = vm->privateData;
> +    g_autoptr(virCHDriverConfig) cfg = virCHDriverGetConfig(priv->driver);
> +    g_autofree int *nicindexes = NULL;
> +    size_t nnicindexes = 0;
> +
> +    if (chProcessAddNetworkDevices(driver, priv->monitor, vm->def,
> +                                   &nicindexes, &nnicindexes) < 0) {
> +        VIR_WARN("Failed chProcessAddNetworkDevices");
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Failed while adding guest interfaces"));
> +        goto cleanup;
> +    }
> +
> +    /* Bring up netdevs before starting CPUs */
> +    if (virDomainInterfaceStartDevices(vm->def) < 0) {
> +        VIR_WARN("Failed virDomainInterfaceStartDevices");
> +        return -1;
> +    }
> +
> +    return 0;
> +
> + cleanup:
> +
> +    return ret;
> +}
> +
> +/**
> + * A variant of virCHProcessStart that does not start the vCPU threads and 
> the
> + * VM. Sets up the CH process along most configuration.
> + * Is used to setup CH in order to receive a live migration afterwards.
> + */
> +int
> +virCHProcessInit(virCHDriver *driver,
> +                 virDomainObj *vm)
> +{


This function copied parts of virCHProcessStart. If there's a thing that
needs to be changed then we have two places to change. I think
virCHProcessStart() should call virCHProcessInit(). You can invent an
additional argument to do hacks around incoming migration ().

> +    int ret = -1;
> +    virCHDomainObjPrivate *priv = vm->privateData;
> +    g_autoptr(virCHDriverConfig) cfg = virCHDriverGetConfig(priv->driver);
> +    g_autofree int *nicindexes = NULL;
> +    size_t nnicindexes = 0;
> +    g_autoptr(domainLogContext) logCtxt = NULL;
> +    int logfile = -1;
> +
> +    if (virDomainObjIsActive(vm)) {
> +        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                       _("VM is already active"));
> +        return -1;
> +    }
> +
> +    if (virCHProcessStartValidate(driver, vm) < 0) {
> +        return -1;
> +    }
> +
> +    VIR_WARN("Creating domain log file for %s domain", vm->def->name);
> +    if (!(logCtxt = domainLogContextNew(cfg->stdioLogD, cfg->logDir,
> +                                        CH_DRIVER_NAME,
> +                                        vm, driver->privileged,
> +                                        vm->def->name))) {
> +        virLastErrorPrefixMessage("%s", _("can't connect to virtlogd"));
> +        return -1;
> +    }
> +    logfile = domainLogContextGetWriteFD(logCtxt);
> +
> +    if (virCHProcessPrepareDomain(vm) < 0) {
> +        return -1;
> +    }
> +
> +    if (virCHProcessPrepareHost(driver, vm) < 0)
> +        return -1;
> +
> +    if (!priv->monitor) {
> +        /* And we can get the first monitor connection now too */
> +        if (!(priv->monitor = virCHProcessConnectMonitor(driver, vm, 
> logfile))) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("failed to create connection to CH socket"));
> +            goto cleanup;
> +        }
> +
> +        if (virCHMonitorCreateVM(driver, priv->monitor) < 0) {
> +            VIR_WARN("Failed virCHMonitorCreateVM");
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("failed to create guest VM"));
> +            goto cleanup;
> +        }
> +    }
> +
> +    vm->def->id = vm->pid;
> +    priv->machineName = virCHDomainGetMachineName(vm);
> +
> +    if (virDomainCgroupSetupCgroup("ch", vm,
> +                                   nnicindexes, nicindexes,
> +                                   &priv->cgroup,
> +                                   cfg->cgroupControllers,
> +                                   0, /*maxThreadsPerProc*/
> +                                   priv->driver->privileged,
> +                                   priv->machineName) < 0)
> +    {
> +        VIR_WARN("Failed virDomainCgroupSetupCgroup");
> +        goto cleanup;
> +    }
> +
> +    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_MIGRATION);
> +
> +    return 0;
> +
> + cleanup:
> +    if (ret)
> +        virCHProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
> +
> +    return ret;
> +}
> +
>  /**
>   * virCHProcessStart:
>   * @driver: pointer to driver structure
> diff --git a/src/ch/ch_process.h b/src/ch/ch_process.h
> index 7a6995b7cf..3a5a2d17d7 100644
> --- a/src/ch/ch_process.h
> +++ b/src/ch/ch_process.h
> @@ -23,6 +23,9 @@
>  #include "ch_conf.h"
>  #include "internal.h"
>  
> +int virCHProcessInit(virCHDriver *driver,
> +                     virDomainObj *vm);
> +
>  int virCHProcessStart(virCHDriver *driver,
>                        virDomainObj *vm,
>                        virDomainRunningReason reason);
> @@ -38,3 +41,6 @@ int virCHProcessStartRestore(virCHDriver *driver,
>                           const char *from);
>  
>  int virCHProcessUpdateInfo(virDomainObj *vm);
> +
> +int virCHProcessInitNetwork(virCHDriver *driver,
> +                            virDomainObj *vm);
> diff --git a/src/hypervisor/domain_interface.c 
> b/src/hypervisor/domain_interface.c
> index 5bc698d272..a13fcfb7d2 100644
> --- a/src/hypervisor/domain_interface.c
> +++ b/src/hypervisor/domain_interface.c
> @@ -82,6 +82,7 @@ virDomainInterfaceEthernetConnect(virDomainDef *def,
>      bool template_ifname = false;
>      const char *tunpath = "/dev/net/tun";
>      const char *auditdev = tunpath;
> +    VIR_WARN("virDomainInterfaceEthernetConnect %s", net->ifname);
>  
>      if (net->backend.tap) {
>          tunpath = net->backend.tap;
> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
> index 93e8f5b853..867876b23f 100644
> --- a/src/libvirt-domain.c
> +++ b/src/libvirt-domain.c
> @@ -3307,6 +3307,11 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>                       "params=%p, nparams=%d, useParams=%d, flags=0x%x",
>                       dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
>                       bandwidth, params, nparams, useParams, flags);
> +    VIR_WARN(
> +                     "dconn=%p, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu, "
> +                     "params=%p, nparams=%d, useParams=%d, flags=0x%x",
> +                     dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
> +                     bandwidth, params, nparams, useParams, flags);
>      VIR_TYPED_PARAMS_DEBUG(params, nparams);
>  
>      virCheckNonEmptyOptStringArgReturn(dname, NULL);
> @@ -3337,7 +3342,7 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>      if (ret)
>          protection = VIR_MIGRATE_CHANGE_PROTECTION;
>  
> -    VIR_DEBUG("Begin3 %p", domain->conn);
> +    VIR_WARN("Begin3 %p", domain->conn);
>      if (useParams) {
>          dom_xml = domain->conn->driver->domainMigrateBegin3Params
>              (domain, params, nparams, &cookieout, &cookieoutlen,
> @@ -3366,7 +3371,7 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>      destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
>                            VIR_MIGRATE_AUTO_CONVERGE);
>  
> -    VIR_DEBUG("Prepare3 %p flags=0x%x", dconn, destflags);
> +    VIR_WARN("Prepare3 %p flags=0x%x", dconn, destflags);
>      cookiein = g_steal_pointer(&cookieout);
>      cookieinlen = cookieoutlen;
>      cookieoutlen = 0;
> @@ -3427,7 +3432,7 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>       * running, but in paused state until the destination can
>       * confirm migration completion.
>       */
> -    VIR_DEBUG("Perform3 %p uri=%s", domain->conn, uri);
> +    VIR_WARN("Perform3 %p uri=%s", domain->conn, uri);
>      VIR_FREE(cookiein);
>      cookiein = g_steal_pointer(&cookieout);
>      cookieinlen = cookieoutlen;
> @@ -3465,7 +3470,7 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>       * send all migration data. Returns NULL for ddomain if
>       * the dest was unable to complete migration.
>       */
> -    VIR_DEBUG("Finish3 %p ret=%d", dconn, ret);
> +    VIR_WARN("Finish3 %p ret=%d", dconn, ret);
>      VIR_FREE(cookiein);
>      cookiein = g_steal_pointer(&cookieout);
>      cookieinlen = cookieoutlen;
> @@ -3540,7 +3545,7 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
>       * cancelled there.
>       */
>      if (notify_source) {
> -        VIR_DEBUG("Confirm3 %p ret=%d domain=%p", domain->conn, ret, domain);
> +        VIR_WARN("Confirm3 %p ret=%d domain=%p", domain->conn, ret, domain);
>          VIR_FREE(cookiein);
>          cookiein = g_steal_pointer(&cookieout);
>          cookieinlen = cookieoutlen;


diff --git c/src/ch/ch_conf.h w/src/ch/ch_conf.h
index 40d639eb2a..042507fcc6 100644
--- c/src/ch/ch_conf.h
+++ w/src/ch/ch_conf.h
@@ -31,6 +31,9 @@
 #define CH_DRIVER_NAME "CH"
 #define CH_CMD "cloud-hypervisor"
 
+#define CH_MIGRATION_PORT_MIN 49152
+#define CH_MIGRATION_PORT_MAX 49216
+
 typedef struct _virCHDriver virCHDriver;
 
 typedef struct _virCHDriverConfig virCHDriverConfig;
diff --git c/src/ch/ch_domain.c w/src/ch/ch_domain.c
index 7231fdc49f..c15410e474 100644
--- c/src/ch/ch_domain.c
+++ w/src/ch/ch_domain.c
@@ -68,6 +68,11 @@ virCHDomainObjPrivateFree(void *data)
     virBitmapFree(priv->autoCpuset);
     virBitmapFree(priv->autoNodeset);
     virCgroupFree(priv->cgroup);
+    if (priv->migrationDstReceiveThr) {
+        virThreadCancel(priv->migrationDstReceiveThr);
+        virThreadJoin(priv->migrationDstReceiveThr);
+        g_free(priv->migrationDstReceiveThr);
+    }
     g_free(priv->pidfile);
     g_free(priv);
 }
diff --git c/src/ch/ch_driver.c w/src/ch/ch_driver.c
index c53607251b..a0df931c80 100644
--- c/src/ch/ch_driver.c
+++ w/src/ch/ch_driver.c
@@ -1458,11 +1458,10 @@ chStateInitialize(bool privileged,
     if (!(ch_driver->domainEventState = virObjectEventStateNew()))
         goto cleanup;
 
-        /* Allocate bitmap for migration port reservation */
-    if (!(ch_driver->migrationPorts =
-          virPortAllocatorRangeNew(_("migration"),
-                                   49152,
-                                   49216)))
+    /* Allocate bitmap for migration port reservation */
+    if (!(ch_driver->migrationPorts = virPortAllocatorRangeNew(_("migration"),
+                                                               
CH_MIGRATION_PORT_MIN,
+                                                               
CH_MIGRATION_PORT_MAX)))
         goto cleanup;
 
     if ((rv = chExtractVersion(ch_driver)) < 0) {
@@ -2358,51 +2357,52 @@ chDomainInterfaceAddresses(virDomain *dom,
 static char *
 chDomainMigrateBegin3(virDomainPtr domain,
                       const char *xmlin,
-                      char **cookieout,
-                      int *cookieoutlen,
+                      char **cookieout G_GNUC_UNUSED,
+                      int *cookieoutlen G_GNUC_UNUSED,
                       unsigned long flags,
-                      const char *dname,
-                      unsigned long resource G_GNUC_UNUSED)
+                      const char *dname G_GNUC_UNUSED,
+                      unsigned long bandwidth)
 {
+    virCHDriver *driver = domain->conn->privateData;
     virDomainObj *vm;
     char *xml = NULL;
-    virCHDriver *driver = domain->conn->privateData;
 
-    VIR_WARN("chDomainMigrateBegin3 %p %s %p %p %lu %s",
-              domain, xmlin, cookieout, cookieoutlen, flags, dname);
+    virCheckFlags(0, NULL);
+
+    if (xmlin) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("xml modification unsupported"));
+        return NULL;
+    }
+
+    if (bandwidth != 0) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("migration bandwidth unsupported"));
+        return NULL;
+    }
+
     if (!(vm = virCHDomainObjFromDomain(domain)))
         return NULL;
 
-    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) {
-        virDomainObjEndAPI(&vm);
-        return NULL;
-    }
+    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0)
+        goto cleanup;
 
-    // Copied from libxl_migration.c:386
     if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0)
         goto cleanup;
 
     xml = virDomainDefFormat(vm->def, driver->xmlopt, 
VIR_DOMAIN_DEF_FORMAT_SECURE);
 
-    if (xml) {
-        VIR_WARN("chDomainMigrateBegin3 success. xml: %s", xml);
-        goto cleanup;
-    }
-
-    return NULL;
  cleanup:
     virDomainObjEndAPI(&vm);
     return xml;
 }
 
-static
-virDomainDef *
+static virDomainDef *
 chMigrationAnyPrepareDef(virCHDriver *driver,
-                           const char *dom_xml,
-                           const char *dname)
+                         const char *dom_xml,
+                         const char *dname)
 {
     virDomainDef *def;
-    char *name = NULL;
 
     if (!dom_xml) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2412,15 +2412,15 @@ chMigrationAnyPrepareDef(virCHDriver *driver,
 
     if (!(def = virDomainDefParseString(dom_xml, driver->xmlopt,
                                         NULL,
-                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
-        goto cleanup;
+                                        VIR_DOMAIN_DEF_PARSE_INACTIVE))) {
+        return NULL;
+    }
 
     if (dname) {
-        VIR_FREE(name);
+        VIR_FREE(def->name);
         def->name = g_strdup(dname);
     }
 
- cleanup:
     return def;
 }
 
@@ -2432,13 +2432,14 @@ typedef struct _chMigrationDstArgs {
 static void
 chDoMigrateDstReceive(void *opaque)
 {
-    chMigrationDstArgs *args = opaque;
+    g_autofree chMigrationDstArgs *args = opaque;
     virCHDomainObjPrivate *priv = args->priv;
     g_autofree char* rcv_uri = NULL;
 
-    VIR_WARN("In thread. %u %p", args->port, args->priv);
+    VIR_DEBUG("In thread. %u %p", args->port, args->priv);
     if (!priv->monitor) {
         VIR_ERROR(_("VMs monitor not initialized"));
+        return;
     }
 
     rcv_uri = g_strdup_printf("tcp:0.0.0.0:%d", args->port);
@@ -2447,7 +2448,7 @@ chDoMigrateDstReceive(void *opaque)
         VIR_WARN("Migration receive failed.");
     }
 
-    VIR_WARN("Migration thread finished its duty");
+    VIR_DEBUG("Migration thread finished its duty");
 }
 
 /**
@@ -2457,30 +2458,27 @@ chDoMigrateDstReceive(void *opaque)
  */
 static int
 chDomainMigratePrepare3(virConnectPtr dconn,
-                        const char *cookiein,
-                        int cookieinlen,
-                        char **cookieout,
-                        int *cookieoutlen,
-                        const char *uri_in,
+                        const char *cookiein G_GNUC_UNUSED,
+                        int cookieinlen G_GNUC_UNUSED,
+                        char **cookieout G_GNUC_UNUSED,
+                        int *cookieoutlen G_GNUC_UNUSED,
+                        const char *uri_in G_GNUC_UNUSED,
                         char **uri_out,
                         unsigned long flags,
                         const char *dname,
-                        unsigned long resource G_GNUC_UNUSED,
+                        unsigned long bandwidth G_GNUC_UNUSED,
                         const char *dom_xml)
 {
     virCHDriver *driver = dconn->privateData;
     virDomainObj *vm = NULL;
     virCHDomainObjPrivate *priv = NULL;
-    chMigrationDstArgs *args = g_new0(chMigrationDstArgs, 1);
+    g_autofree chMigrationDstArgs *args = g_new0(chMigrationDstArgs, 1);
     unsigned short port = 0;
     g_autofree char *hostname = NULL;
-    const char *threadname = "mig-ch";
     g_autoptr(virDomainDef) def = NULL;
-    int rc = 0;
-    const char *incFormat = "%s:%s:%d"; // seems to differ for AF_INET6
+    int ret = -1;
 
-    VIR_WARN("chDomainMigratePrepare3 %p %s %u %p %p %s %p %lu %s %s",
-              dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, 
uri_out, flags, dname, dom_xml);
+    virCheckFlags(0, -1);
 
     if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0)
         return -1;
@@ -2488,68 +2486,55 @@ chDomainMigratePrepare3(virConnectPtr dconn,
     if (!(def = chMigrationAnyPrepareDef(driver, dom_xml, dname)))
         return -1;
 
-    VIR_WARN("Got DomainDef prepared successfully");
+    if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
+        return -1;
 
-    if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
-        rc = -1;
-        goto cleanup;
-    }
-    VIR_WARN("Got port %i", port);
+    if (!(hostname = virGetHostname()))
+        return -1;
 
-    if ((hostname = virGetHostname()) == NULL) {
-        rc = -1;
-        goto cleanup;
-    }
-
-    *uri_out = g_strdup_printf(incFormat, "tcp", hostname, port);
-    VIR_WARN("uri out %s", *uri_out);
+    /* Seems to differ for AF_INET6 */
+    *uri_out = g_strdup_printf("tcp:%s:%d", hostname, port);
+    VIR_DEBUG("uri out %s", *uri_out);
 
     if (!(vm = virDomainObjListAdd(driver->domains, &def,
                                    driver->xmlopt,
                                    VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                    VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
-                                   NULL)))
-    {
-        rc = -1;
-        VIR_WARN("Could not add Domain Obj to List");
+                                   NULL))) {
         goto cleanup;
     }
 
-    if (virCHProcessInit(driver, vm) < 0) {
-        rc = -1;
-        VIR_WARN("Could not init process");
+    if (virCHProcessInit(driver, vm) < 0)
         goto cleanup;
-    }
 
-    VIR_WARN("Try creating migration thread");
     priv = vm->privateData;
     args->port = port;
     args->priv = priv;
 
-    // VM receiving is blocking which we cannot do here, because it would block
-    // the Libvirt migration protocol.
-    // Prepare a thread to receive the migration data
-    // VIR_FREE(priv->migrationDstReceiveThr);
+    /* VM receiving is blocking which we cannot do here, because it would block
+     * the Libvirt migration protocol. Prepare a thread to receive the
+     * migration data. */
     priv->migrationDstReceiveThr = g_new0(virThread, 1);
-    if (virThreadCreateFull(priv->migrationDstReceiveThr, true,
+    VIR_DEBUG("Creating migration thread");
+    if (virThreadCreateFull(priv->migrationDstReceiveThr,
+                            true,
                             chDoMigrateDstReceive,
-                            threadname,
+                            "mig-ch",
                             false,
                             args) < 0) {
         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("Failed to create thread for receiving migration 
data"));
         goto cleanup;
     }
+    VIR_DEBUG("Finished creating migration thread");
 
-    VIR_WARN("Finished creating migration thread");
-
-
-    VIR_WARN("Fin migrationPrepare");
-
+    /* The thread owns the @args now. */
+    args = NULL;
 
+    ret = 0;
  cleanup:
     virDomainObjEndAPI(&vm);
-    return rc;
+    return ret;
 }
 
 static int
diff --git c/src/ch/ch_monitor.c w/src/ch/ch_monitor.c
index 595fa30be0..a6fa37e9f8 100644
--- c/src/ch/ch_monitor.c
+++ w/src/ch/ch_monitor.c
@@ -1286,7 +1286,7 @@ int virCHMonitorMigrationReceive(virCHMonitor *mon,
     if (virCHMonitorBuildKeyValueStringJson(&payload, "receiver_url", rcv_uri) 
!= 0)
         return -1;
 
-    VIR_WARN("Receive VM from url %s json: %s", rcv_uri, payload);
+    VIR_DEBUG("Receive VM from url %s json: %s", rcv_uri, payload);
 
     VIR_WITH_OBJECT_LOCK_GUARD(mon) {
         /* reset all options of a libcurl session handle at first */
diff --git c/src/hypervisor/domain_interface.c 
w/src/hypervisor/domain_interface.c
index a13fcfb7d2..5bc698d272 100644
--- c/src/hypervisor/domain_interface.c
+++ w/src/hypervisor/domain_interface.c
@@ -82,7 +82,6 @@ virDomainInterfaceEthernetConnect(virDomainDef *def,
     bool template_ifname = false;
     const char *tunpath = "/dev/net/tun";
     const char *auditdev = tunpath;
-    VIR_WARN("virDomainInterfaceEthernetConnect %s", net->ifname);
 
     if (net->backend.tap) {
         tunpath = net->backend.tap;
diff --git c/src/libvirt-domain.c w/src/libvirt-domain.c
index 28347947d1..86ede6b038 100644
--- c/src/libvirt-domain.c
+++ w/src/libvirt-domain.c
@@ -3307,11 +3307,6 @@ virDomainMigrateVersion3Full(virDomainPtr domain,
                      "params=%p, nparams=%d, useParams=%d, flags=0x%x",
                      dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
                      bandwidth, params, nparams, useParams, flags);
-    VIR_WARN(
-                     "dconn=%p, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu, "
-                     "params=%p, nparams=%d, useParams=%d, flags=0x%x",
-                     dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
-                     bandwidth, params, nparams, useParams, flags);
     VIR_TYPED_PARAMS_DEBUG(params, nparams);
 
     virCheckNonEmptyOptStringArgReturn(dname, NULL);


Michal

Reply via email to