From 05e1b06ab7b30a3d505b9a5799f00eb3ae8acf44 Mon Sep 17 00:00:00 2001 From: Chegu Vinod Date: Thu, 6 Feb 2014 15:44:36 -0800 Subject: [PATCH] libvirt support to force convergence of live guest migration Busy enterprise workloads hosted on large sized VM's tend to dirty memory faster than the transfer rate achieved via live guest migration. Despite some good recent improvements (& using dedicated 10Gig NICs between hosts) the live migration may NOT converge. Recently support was added in qemu (version 1.6) to allow a user to choose if they wish to force convergence of their migration via a new migration capability : "auto-converge". This feature allows for qemu to auto-detect lack of convergence and trigger a throttle-down of the VCPUs. This patch includes the libvirt support needed to trigger this feature. (Testing is in progress) Signed-off-by: Chegu Vinod Signed-off-by: Jiri Denemark --- include/libvirt/libvirt.h.in | 1 + src/libvirt.c | 9 ++++--- src/qemu/qemu_migration.c | 46 ++++++++++++++++++++++++++++++++++-- src/qemu/qemu_migration.h | 3 ++- src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 1 + tools/virsh-domain.c | 7 ++++++ 7 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 295d5511b9..82c602b6d1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1200,6 +1200,7 @@ typedef enum { VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */ + VIR_MIGRATE_AUTO_CONVERGE = (1 << 13), /* force convergence */ } virDomainMigrateFlags; diff --git a/src/libvirt.c b/src/libvirt.c index 2201b07336..c5c3136d0b 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -4408,7 +4408,8 @@ virDomainMigrateVersion1(virDomainPtr domain, if (ret == 0 && info.state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); /* Prepare the migration. * @@ -4538,7 +4539,8 @@ virDomainMigrateVersion2(virDomainPtr domain, if (ret == 0 && info.state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare2 %p flags=%lx", dconn, destflags); ret = dconn->driver->domainMigratePrepare2 @@ -4710,7 +4712,8 @@ virDomainMigrateVersion3Full(virDomainPtr domain, if (ret == 0 && state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare3 %p flags=%x", dconn, destflags); cookiein = cookieout; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ab6f2878ad..57e2436949 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1621,6 +1621,41 @@ cleanup: return ret; } +static int +qemuMigrationSetAutoConverge(virQEMUDriverPtr driver, + virDomainObjPtr vm, + enum qemuDomainAsyncJob job) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) + return -1; + + ret = qemuMonitorGetMigrationCapability( + priv->mon, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); + + if (ret < 0) { + goto cleanup; + } else if (ret == 0) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Auto-Converge is not supported by " + "QEMU binary")); + ret = -1; + goto cleanup; + } + + ret = qemuMonitorSetMigrationCapability( + priv->mon, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); + +cleanup: + qemuDomainObjExitMonitor(driver, vm); + return ret; +} + + static int qemuMigrationWaitForSpice(virQEMUDriverPtr driver, virDomainObjPtr vm) @@ -3234,6 +3269,11 @@ qemuMigrationRun(virQEMUDriverPtr driver, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; + if (flags & VIR_MIGRATE_AUTO_CONVERGE && + qemuMigrationSetAutoConverge(driver, vm, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + goto cleanup; + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; @@ -3587,7 +3627,8 @@ static int doPeer2PeerMigrate2(virQEMUDriverPtr driver, if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare2 %p", dconn); if (flags & VIR_MIGRATE_TUNNELLED) { @@ -3780,7 +3821,8 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare3 %p", dconn); cookiein = cookieout; diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index cafa2a2998..a802fb7ee6 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -39,7 +39,8 @@ VIR_MIGRATE_UNSAFE | \ VIR_MIGRATE_OFFLINE | \ VIR_MIGRATE_COMPRESSED | \ - VIR_MIGRATE_ABORT_ON_ERROR) + VIR_MIGRATE_ABORT_ON_ERROR | \ + VIR_MIGRATE_AUTO_CONVERGE) /* All supported migration parameters and their types. */ # define QEMU_MIGRATION_PARAMETERS \ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 48fc51cf87..357c9709fc 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -121,7 +121,7 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus, VIR_ENUM_IMPL(qemuMonitorMigrationCaps, QEMU_MONITOR_MIGRATION_CAPS_LAST, - "xbzrle") + "xbzrle", "auto-converge") VIR_ENUM_IMPL(qemuMonitorVMStatus, QEMU_MONITOR_VM_STATUS_LAST, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index f626cc1223..d8f1d10c32 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -451,6 +451,7 @@ int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon, typedef enum { QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, QEMU_MONITOR_MIGRATION_CAPS_LAST } qemuMonitorMigrationCaps; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index eb3397df56..0664774341 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -8757,6 +8757,10 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_BOOL, .help = N_("compress repeated pages during live migration") }, + {.name = "auto-converge", + .type = VSH_OT_BOOL, + .help = N_("force convergence during live migration") + }, {.name = "abort-on-error", .type = VSH_OT_BOOL, .help = N_("abort on soft errors during migration") @@ -8901,6 +8905,9 @@ doMigrate(void *opaque) if (vshCommandOptBool(cmd, "compressed")) flags |= VIR_MIGRATE_COMPRESSED; + if (vshCommandOptBool(cmd, "auto-converge")) + flags |= VIR_MIGRATE_AUTO_CONVERGE; + if (vshCommandOptBool(cmd, "offline")) { flags |= VIR_MIGRATE_OFFLINE; }