[libvirt] [V2 PATCH 0/3] Transport Open vSwitch per-port data during live migration

This series of commits has the end goal of allowing per-port data stored in the Open vSwitch DB to be transported during live migration. This is done by first providing a generic infrastructure for transporting network data, adding some utility functions specific to Open vSwitch, and hooking the two together. The framework provided is generic in that other networking data could be transferred as well by simply adding in additional hooks as needed. ---- V2 of this patch series fixes some issues found when migrating VMs on standard Linux bridges. Kyle Mestery (3): Add the ability for the Qemu V3 migration protocol to include transporting network configuration. A generic framework is proposed with this patch to allow for the transfer of opaque data. Add utility functions for Open vSwitch to both save per-port data before a live migration, and restore the per-port data after a live migration. Transport Open vSwitch per-port data during live migration by using the utility functions virNetDevOpenvswitchGetMigrateData() and virNetDevOpenvswitchSetMigrateData(). src/libvirt_private.syms | 2 + src/qemu/qemu_migration.c | 291 +++++++++++++++++++++++++++++++++++++++- src/util/virnetdevopenvswitch.c | 71 ++++++++++ src/util/virnetdevopenvswitch.h | 6 + 4 files changed, 368 insertions(+), 2 deletions(-) -- 1.7.11.4

Add the ability for the Qemu V3 migration protocol to include transporting network configuration. A generic framework is proposed with this patch to allow for the transfer of opaque data. Signed-off-by: Kyle Mestery <kmestery@cisco.com> --- src/qemu/qemu_migration.c | 276 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 274 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 99fc8ce..3d89b62 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -70,6 +70,7 @@ 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_LAST }; @@ -77,12 +78,13 @@ enum qemuMigrationCookieFlags { VIR_ENUM_DECL(qemuMigrationCookieFlag); VIR_ENUM_IMPL(qemuMigrationCookieFlag, QEMU_MIGRATION_COOKIE_FLAG_LAST, - "graphics", "lockstate", "persistent"); + "graphics", "lockstate", "persistent", "network"); enum qemuMigrationCookieFeatures { QEMU_MIGRATION_COOKIE_GRAPHICS = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS), QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE), QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT), + QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK), }; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -95,6 +97,22 @@ struct _qemuMigrationCookieGraphics { char *tlsSubject; }; +typedef struct _qemuMigrationCookieNetwork qemuMigrationCookieNetwork; +typedef qemuMigrationCookieNetwork *qemuMigrationCookieNetworkPtr; +struct _qemuMigrationCookieNetwork { + /* How many virtual NICs are we saving data for? */ + int nnets; + + /* + * Array of pointers to saved data. Each VIF will have it's own + * data to transfer. + */ + char **netdata; + + /* What type is each VIF? */ + int **viftype; +}; + typedef struct _qemuMigrationCookie qemuMigrationCookie; typedef qemuMigrationCookie *qemuMigrationCookiePtr; struct _qemuMigrationCookie { @@ -120,6 +138,9 @@ struct _qemuMigrationCookie { /* If (flags & QEMU_MIGRATION_COOKIE_PERSISTENT) */ virDomainDefPtr persistent; + + /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */ + qemuMigrationCookieNetworkPtr network; }; static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) @@ -132,6 +153,27 @@ static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) } +static void qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr + network) +{ + int i; + + if (!network) + return; + + for (i = 0; i < network->nnets; i++) { + VIR_FREE(network->viftype[i]); + VIR_FREE(network->netdata[i]); + } + + VIR_FREE(network->viftype); + + VIR_FREE(network->netdata); + + VIR_FREE(network); +} + + static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { if (!mig) @@ -140,6 +182,10 @@ static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) if (mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) qemuMigrationCookieGraphicsFree(mig->graphics); + if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) { + qemuMigrationCookieNetworkFree(mig->network); + } + VIR_FREE(mig->localHostname); VIR_FREE(mig->remoteHostname); VIR_FREE(mig->name); @@ -256,6 +302,64 @@ error: } +static qemuMigrationCookieNetworkPtr +qemuMigrationCookieNetworkAlloc(struct qemud_driver *driver ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + qemuMigrationCookieNetworkPtr mig; + int i; + virDomainNetDefPtr netptr ATTRIBUTE_UNUSED; + + if (VIR_ALLOC(mig) < 0) + goto no_memory; + + mig->nnets = def->nnets; + + if (VIR_ALLOC_N(mig->netdata, def->nnets) < 0) + goto no_memory; + + if (VIR_ALLOC_N(mig->viftype, def->nnets) < 0) + goto no_memory; + + for (i = 0; i < def->nnets; i++) { + virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(def->nets[i]); + netptr = def->nets[i]; + + if (vport) { + if (VIR_ALLOC(mig->viftype[i]) < 0) + goto no_memory; + + *mig->viftype[i] = vport->virtPortType; + + switch (vport->virtPortType) { + case VIR_NETDEV_VPORT_PROFILE_NONE: + mig->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_8021QBG: + mig->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_8021QBH: + mig->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + mig->netdata[i] = NULL; + break; + default: + mig->netdata[i] = NULL; + break; + } + } + } + + return mig; + +no_memory: + virReportOOMError(); + qemuMigrationCookieNetworkFree(mig); + return NULL; +} + + static qemuMigrationCookiePtr qemuMigrationCookieNew(virDomainObjPtr dom) { @@ -370,6 +474,27 @@ qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig, } +static int +qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig, + struct qemud_driver *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 >= 1) { + if (!(mig->network = qemuMigrationCookieNetworkAlloc( + driver, dom->def))) + return -1; + mig->flags |= QEMU_MIGRATION_COOKIE_NETWORK; + } + + return 0; +} + static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, qemuMigrationCookieGraphicsPtr grap) @@ -389,6 +514,32 @@ static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, } +static void qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf, + qemuMigrationCookieNetworkPtr optr) +{ + int i; + + virBufferAsprintf(buf, " <network nnets='%d'>\n", optr->nnets); + if (optr->nnets > 0) + virBufferAsprintf(buf, " <vifs>\n"); + for (i = 0; i < optr->nnets; i++) { + /* If optr->viftype[i] is not set, there is nothing to transfer */ + if (optr->viftype[i]) { + if (!optr->netdata[i]) + virBufferAsprintf(buf, " <vif num='%d' viftype='%d'/>\n", + i, *optr->viftype[i]); + else + virBufferAsprintf(buf, " <vif num='%d' viftype='%d' netdata='%s'/>\n", + i, *optr->viftype[i], optr->netdata[i]); + } + } + if (optr->nnets > 0) + virBufferAsprintf(buf, " </vifs>\n"); + + virBufferAddLit(buf, " </network>\n"); +} + + static int qemuMigrationCookieXMLFormat(struct qemud_driver *driver, virBufferPtr buf, @@ -439,6 +590,10 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver, virBufferAdjustIndent(buf, -2); } + if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && + mig->network) + qemuMigrationCookieNetworkXMLFormat(buf, mig->network); + virBufferAddLit(buf, "</qemu-migration>\n"); return 0; } @@ -516,6 +671,71 @@ error: } +static qemuMigrationCookieNetworkPtr +qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieNetworkPtr optr; + int i; + int n; + xmlNodePtr *vifs = NULL; + char *viftype; + + if (VIR_ALLOC(optr) < 0) + goto no_memory; + + if (virXPathInt("string(./network/@nnets)", ctxt, &optr->nnets) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing nnets attribute in migration data")); + goto error; + } + + if (VIR_ALLOC_N(optr->netdata, optr->nnets) < 0) + goto no_memory; + + if (VIR_ALLOC_N(optr->viftype, optr->nnets) < 0) + goto no_memory; + + if ((n = virXPathNodeSet("./network/vifs/vif", ctxt, &vifs)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing vif information")); + goto error; + } + + for (i = 0; i < n; i++) { + if (VIR_ALLOC(optr->netdata[i]) < 0) + goto no_memory; + + if (VIR_ALLOC(optr->viftype[i]) < 0) + goto no_memory; + + /* netdata is optional, and may not exist */ + optr->netdata[i] = virXMLPropString(vifs[i], "netdata"); + + if (!(viftype = virXMLPropString(vifs[i], "viftype"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing viftype attribute in migration data")); + goto error; + } + + *optr->viftype[i] = atoi(viftype); + + VIR_FREE(viftype); + } + + VIR_FREE(vifs); + + return optr; + +no_memory: + virReportOOMError(); +error: + if (vifs) + VIR_FREE(vifs); + qemuMigrationCookieNetworkFree(optr); + return NULL; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, struct qemud_driver *driver, @@ -662,6 +882,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, VIR_FREE(nodes); } + if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) && + virXPathBoolean("count(./network) > 0", ctxt) && + (!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt)))) + goto error; + return 0; error: @@ -721,6 +946,10 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, qemuMigrationCookieAddPersistent(mig, dom) < 0) return -1; + if (flags & QEMU_MIGRATION_COOKIE_NETWORK && + qemuMigrationCookieAddNetwork(mig, driver, dom) < 0) + return -1; + if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig))) return -1; @@ -1050,6 +1279,43 @@ qemuDomainMigrateGraphicsRelocate(struct qemud_driver *driver, } +static int +qemuDomainMigrateOPDRelocate(struct qemud_driver *driver ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + qemuMigrationCookiePtr cookie) +{ + virDomainNetDefPtr netptr ATTRIBUTE_UNUSED; + int ret = 0; + int i; + + for (i = 0; i < cookie->network->nnets; i++) { + netptr = vm->def->nets[i]; + + if (cookie->network->viftype[i]) { + switch (*cookie->network->viftype[i]) { + case VIR_NETDEV_VPORT_PROFILE_NONE: + cookie->network->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_8021QBG: + cookie->network->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_8021QBH: + cookie->network->netdata[i] = NULL; + break; + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + cookie->network->netdata[i] = NULL; + break; + default: + cookie->network->netdata[i] = NULL; + break; + } + } + } + + return ret; +} + + /* This is called for outgoing non-p2p migrations when a connection to the * client which initiated the migration was closed but we were waiting for it * to follow up with the next phase, that is, in between @@ -1994,7 +2260,8 @@ cleanup: if (ret == 0 && qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, - QEMU_MIGRATION_COOKIE_PERSISTENT ) < 0) + QEMU_MIGRATION_COOKIE_PERSISTENT | + QEMU_MIGRATION_COOKIE_NETWORK) < 0) VIR_WARN("Unable to encode migration cookie"); qemuMigrationCookieFree(mig); @@ -2929,6 +3196,7 @@ qemuMigrationFinish(struct qemud_driver *driver, qemuDomainCleanupRemove(vm, qemuMigrationPrepareCleanup); + cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK; if (flags & VIR_MIGRATE_PERSIST_DEST) cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT; @@ -2956,6 +3224,10 @@ qemuMigrationFinish(struct qemud_driver *driver, goto endjob; } + if (mig->network) + if (qemuDomainMigrateOPDRelocate(driver, vm, mig) < 0) + VIR_WARN("unable to provide network data for relocation"); + if (flags & VIR_MIGRATE_PERSIST_DEST) { virDomainDefPtr vmdef; if (vm->persistent) -- 1.7.11.4

Add utility functions for Open vSwitch to both save per-port data before a live migration, and restore the per-port data after a live migration. Signed-off-by: Kyle Mestery <kmestery@cisco.com> --- src/libvirt_private.syms | 2 ++ src/util/virnetdevopenvswitch.c | 71 +++++++++++++++++++++++++++++++++++++++++ src/util/virnetdevopenvswitch.h | 6 ++++ 3 files changed, 79 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 064e2a6..9e8edf8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1452,7 +1452,9 @@ virNetDevMacVLanVPortProfileRegisterCallback; # virnetdevopenvswitch.h virNetDevOpenvswitchAddPort; +virNetDevOpenvswitchGetMigrateData; virNetDevOpenvswitchRemovePort; +virNetDevOpenvswitchSetMigrateData; # virnetdevtap.h diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index 97b9d52..1763a25 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -179,3 +179,74 @@ int virNetDevOpenvswitchRemovePort(const char *brname ATTRIBUTE_UNUSED, const ch virCommandFree(cmd); return ret; } + +/** + * virNetDevOpenvswitchGetMigrateData: + * @migrate: a pointer to store the data into, allocated by this function + * @ifname: name of the interface for which data is being migrated + * + * Allocates data to be migrated specific to Open vSwitch + * + * Returns 0 in case of success or -1 in case of failure + */ +int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname) +{ + virCommandPtr cmd = NULL; + int ret = 0; + + cmd = virCommandNewArgList(OVSVSCTL, "get", "Interface", + ifname, "external_ids:PortData", NULL); + + virCommandSetOutputBuffer(cmd, migrate); + + /* Run the command */ + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(VIR_ERR_INTERNAL_ERROR, + _("Unable to run command to get OVS port data for " + "interface %s"), ifname); + ret = -1; + goto error; + } + + /* Wipeout the newline */ + (*migrate)[strlen(*migrate) - 1] = '\0'; + +error: + return ret; +} + +/** + * virNetDevOpenvswitchSetMigrateData: + * @migrate: the data which was transferred during migration + * @ifname: the name of the interface the data is associated with + * + * Repopulates OVS per-port data on destination host + * + * Returns 0 in case of success or -1 in case of failure + */ +int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) +{ + virCommandPtr cmd = NULL; + int ret = 0; + virBufferPtr buf; + + if (VIR_ALLOC(buf) < 0) { + ret = -1; + goto error; + } + + virBufferAsprintf(buf, "external_ids:PortData=%s", migrate); + + cmd = virCommandNewArgList(OVSVSCTL, "set", "Interface", ifname, + virBufferCurrentContent(buf), NULL); + /* Run the command */ + if ((ret = virCommandRun(cmd, NULL)) < 0) { + virReportSystemError(VIR_ERR_INTERNAL_ERROR, + _("Unable to run command to set OVS port data for " + "interface %s"), ifname); + } + +error: + return ret; +} + diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h index 58b4dda..a80fbef 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -42,4 +42,10 @@ int virNetDevOpenvswitchAddPort(const char *brname, int virNetDevOpenvswitchRemovePort(const char *brname, const char *ifname) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + #endif /* __VIR_NETDEV_OPENVSWITCH_H__ */ -- 1.7.11.4

Transport Open vSwitch per-port data during live migration by using the utility functions virNetDevOpenvswitchGetMigrateData() and virNetDevOpenvswitchSetMigrateData(). Signed-off-by: Kyle Mestery <kmestery@cisco.com> --- src/qemu/qemu_migration.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 3d89b62..cc81765 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -308,7 +308,7 @@ qemuMigrationCookieNetworkAlloc(struct qemud_driver *driver ATTRIBUTE_UNUSED, { qemuMigrationCookieNetworkPtr mig; int i; - virDomainNetDefPtr netptr ATTRIBUTE_UNUSED; + virDomainNetDefPtr netptr; if (VIR_ALLOC(mig) < 0) goto no_memory; @@ -342,7 +342,13 @@ qemuMigrationCookieNetworkAlloc(struct qemud_driver *driver ATTRIBUTE_UNUSED, mig->netdata[i] = NULL; break; case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: - mig->netdata[i] = NULL; + if (virNetDevOpenvswitchGetMigrateData(&mig->netdata[i], + netptr->ifname) != 0) { + virReportSystemError(VIR_ERR_INTERNAL_ERROR, + _("Unable to run command to get OVS port data for " + "interface %s"), netptr->ifname); + goto error; + } break; default: mig->netdata[i] = NULL; @@ -351,6 +357,7 @@ qemuMigrationCookieNetworkAlloc(struct qemud_driver *driver ATTRIBUTE_UNUSED, } } +error: return mig; no_memory: @@ -1284,7 +1291,7 @@ qemuDomainMigrateOPDRelocate(struct qemud_driver *driver ATTRIBUTE_UNUSED, virDomainObjPtr vm, qemuMigrationCookiePtr cookie) { - virDomainNetDefPtr netptr ATTRIBUTE_UNUSED; + virDomainNetDefPtr netptr; int ret = 0; int i; @@ -1303,7 +1310,14 @@ qemuDomainMigrateOPDRelocate(struct qemud_driver *driver ATTRIBUTE_UNUSED, cookie->network->netdata[i] = NULL; break; case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: - cookie->network->netdata[i] = NULL; + if (virNetDevOpenvswitchSetMigrateData(cookie->network->netdata[i], + netptr->ifname) != 0) { + virReportSystemError(VIR_ERR_INTERNAL_ERROR, + _("Unable to run command to set OVS port data for " + "interface %s"), netptr->ifname); + ret = -1; + goto error; + } break; default: cookie->network->netdata[i] = NULL; @@ -1312,6 +1326,7 @@ qemuDomainMigrateOPDRelocate(struct qemud_driver *driver ATTRIBUTE_UNUSED, } } +error: return ret; } -- 1.7.11.4

On 09/14/2012 03:01 PM, Kyle Mestery wrote:
This series of commits has the end goal of allowing per-port data stored in the Open vSwitch DB to be transported during live migration. This is done by first providing a generic infrastructure for transporting network data, adding some utility functions specific to Open vSwitch, and hooking the two together.
The framework provided is generic in that other networking data could be transferred as well by simply adding in additional hooks as needed. ---- V2 of this patch series fixes some issues found when migrating VMs on standard Linux bridges.
Oops. I just made some comments on one of the V1 patches before I scrolled down and saw these v2 patches. It looks like the same comments apply. This is definitely looking better - it will make it much simpler for the next interface type that needs to send migration data to do so, and it gets the running of ovs-vsctl commands isolated into virnetdevopenvswitch.c.
Kyle Mestery (3): Add the ability for the Qemu V3 migration protocol to include transporting network configuration. A generic framework is proposed with this patch to allow for the transfer of opaque data. Add utility functions for Open vSwitch to both save per-port data before a live migration, and restore the per-port data after a live migration. Transport Open vSwitch per-port data during live migration by using the utility functions virNetDevOpenvswitchGetMigrateData() and virNetDevOpenvswitchSetMigrateData().
src/libvirt_private.syms | 2 + src/qemu/qemu_migration.c | 291 +++++++++++++++++++++++++++++++++++++++- src/util/virnetdevopenvswitch.c | 71 ++++++++++ src/util/virnetdevopenvswitch.h | 6 + 4 files changed, 368 insertions(+), 2 deletions(-)

On Sep 14, 2012, at 9:04 PM, Laine Stump wrote:
On 09/14/2012 03:01 PM, Kyle Mestery wrote:
This series of commits has the end goal of allowing per-port data stored in the Open vSwitch DB to be transported during live migration. This is done by first providing a generic infrastructure for transporting network data, adding some utility functions specific to Open vSwitch, and hooking the two together.
The framework provided is generic in that other networking data could be transferred as well by simply adding in additional hooks as needed. ---- V2 of this patch series fixes some issues found when migrating VMs on standard Linux bridges.
Oops. I just made some comments on one of the V1 patches before I scrolled down and saw these v2 patches. It looks like the same comments apply.
Thanks Laine, I see your comments on the V1 patch set. I'll try to get these updated, but I'm traveling next week, and will have to fit it into that schedule. Stay tuned and thanks! Kyle
This is definitely looking better - it will make it much simpler for the next interface type that needs to send migration data to do so, and it gets the running of ovs-vsctl commands isolated into virnetdevopenvswitch.c.
Kyle Mestery (3): Add the ability for the Qemu V3 migration protocol to include transporting network configuration. A generic framework is proposed with this patch to allow for the transfer of opaque data. Add utility functions for Open vSwitch to both save per-port data before a live migration, and restore the per-port data after a live migration. Transport Open vSwitch per-port data during live migration by using the utility functions virNetDevOpenvswitchGetMigrateData() and virNetDevOpenvswitchSetMigrateData().
src/libvirt_private.syms | 2 + src/qemu/qemu_migration.c | 291 +++++++++++++++++++++++++++++++++++++++- src/util/virnetdevopenvswitch.c | 71 ++++++++++ src/util/virnetdevopenvswitch.h | 6 + 4 files changed, 368 insertions(+), 2 deletions(-)
participants (3)
-
Kyle Mestery
-
Kyle Mestery (kmestery)
-
Laine Stump