[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 1/3] qemu_migration: Add hooks to transport network port data during migration



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 | 278 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 276 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8e85875..06981db 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,35 @@ struct _qemuMigrationCookieGraphics {
     char *tlsSubject;
 };
 
+VIR_ENUM_DECL(virInterface);
+VIR_ENUM_IMPL(virInterface, VIR_NETDEV_VPORT_PROFILE_LAST,
+              "none",
+              "802.1QBg",
+              "802.1QBh",
+              "openvswitch");
+
+typedef struct _qemuMigrationCookieNetdata qemuMigrationCookieNetdata;
+typedef qemuMigrationCookieNetdata *qemuMigrationCookieNetdataPtr;
+struct _qemuMigrationCookieNetdata {
+    /* What type is each interace ? virInterface above ... */
+    char *interfacetype;
+
+    /*
+     * Array of pointers to saved data. Each VIF will have it's 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 _qemuMigrationCookie qemuMigrationCookie;
 typedef qemuMigrationCookie *qemuMigrationCookiePtr;
 struct _qemuMigrationCookie {
@@ -120,6 +151,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 +166,28 @@ static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap)
 }
 
 
+static void qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr
+                                               network)
+{
+    int i;
+
+    if (!network)
+        return;
+
+    for (i = 0; i < network->nnets; i++) {
+        if (network->net[i]) {
+            if (network->net[i]->interfacetype)
+                VIR_FREE(network->net[i]->interfacetype);
+            if (network->net[i]->portdata)
+                VIR_FREE(network->net[i]->portdata);
+            VIR_FREE(network->net[i]);
+        }
+    }
+    VIR_FREE(network->net);
+    VIR_FREE(network);
+}
+
+
 static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
 {
     if (!mig)
@@ -140,6 +196,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 +316,65 @@ error:
 }
 
 
+static qemuMigrationCookieNetworkPtr
+qemuMigrationCookieNetworkAlloc(struct qemud_driver *driver ATTRIBUTE_UNUSED,
+                                    virDomainDefPtr def)
+{
+    qemuMigrationCookieNetworkPtr mig;
+    int i;
+    virDomainNetDefPtr netptr ATTRIBUTE_UNUSED;
+    const char *interfacetype;
+
+    if (VIR_ALLOC(mig) < 0)
+        goto no_memory;
+
+    mig->nnets = def->nnets;
+
+    if (VIR_ALLOC_N(mig->net, 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->net[i]) < 0)
+                goto no_memory;
+            if (VIR_ALLOC(mig->net[i]->interfacetype) < 0)
+                goto no_memory;
+
+            interfacetype = virInterfaceTypeToString(vport->virtPortType);
+            strncpy(mig->net[i]->interfacetype, interfacetype, strlen(interfacetype));
+
+            switch (vport->virtPortType) {
+            case VIR_NETDEV_VPORT_PROFILE_NONE:
+                mig->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_8021QBG:
+                mig->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_8021QBH:
+                mig->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
+                mig->net[i]->portdata = NULL;
+                break;
+            default:
+                mig->net[i]->portdata = NULL;
+                break;
+            }
+        }
+    }
+
+    return mig;
+
+no_memory:
+    virReportOOMError();
+    qemuMigrationCookieNetworkFree(mig);
+    return NULL;
+}
+
+
 static qemuMigrationCookiePtr
 qemuMigrationCookieNew(virDomainObjPtr dom)
 {
@@ -370,6 +489,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 +529,28 @@ static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf,
 }
 
 
+static void qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf,
+                                                    qemuMigrationCookieNetworkPtr optr)
+{
+    int i;
+
+    virBufferAsprintf(buf, "  <network>\n");
+    for (i = 0; i < optr->nnets; i++) {
+        /* If optr->net->interfacetype[i] is not set, there is nothing to transfer */
+        if (optr->net[i] && optr->net[i]->interfacetype) {
+            if (!optr->net[i]->portdata)
+                virBufferAsprintf(buf, "      <interface index='%d' vporttype='%s'/>\n",
+                                  i, optr->net[i]->interfacetype);
+            else
+                virBufferAsprintf(buf, "      <interface index='%d' vporttype='%s' portdata='%s'/>\n",
+                                  i, optr->net[i]->interfacetype, optr->net[i]->portdata);
+        }
+    }
+
+    virBufferAddLit(buf, "  </network>\n");
+}
+
+
 static int
 qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
                              virBufferPtr buf,
@@ -439,6 +601,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 +682,60 @@ error:
 }
 
 
+static qemuMigrationCookieNetworkPtr
+qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt)
+{
+    qemuMigrationCookieNetworkPtr optr;
+    int i;
+    int n;
+    xmlNodePtr *interfaces = NULL;
+
+    if (VIR_ALLOC(optr) < 0)
+        goto no_memory;
+
+    if ((n = virXPathNodeSet("./network/interface", ctxt, &interfaces)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("missing interace information"));
+        goto error;
+    }
+
+    optr->nnets = n;
+    if (VIR_ALLOC_N(optr->net, optr->nnets) <0)
+        goto no_memory;
+
+    for (i = 0; i < n; i++) {
+        if (VIR_ALLOC(optr->net[i]) < 0)
+            goto no_memory;
+        if (VIR_ALLOC(optr->net[i]->portdata) < 0)
+            goto no_memory;
+
+        if (VIR_ALLOC(optr->net[i]->interfacetype) < 0)
+            goto no_memory;
+
+        /* portdata is optional, and may not exist */
+        optr->net[i]->portdata = virXMLPropString(interfaces[i], "portdata");
+
+        if (!(optr->net[i]->interfacetype = virXMLPropString(interfaces[i], "vporttype"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s", _("missing vporttype attribute in migration data"));
+            goto error;
+        }
+    }
+
+    VIR_FREE(interfaces);
+
+    return optr;
+
+no_memory:
+    virReportOOMError();
+error:
+    if (interfaces)
+        VIR_FREE(interfaces);
+    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,45 @@ 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;
+    int interfacetype;
+
+    for (i = 0; i < cookie->network->nnets; i++) {
+        netptr = vm->def->nets[i];
+
+        if (cookie->network->net[i]->interfacetype) {
+            interfacetype = virInterfaceTypeFromString(cookie->network->net[i]->interfacetype);
+            switch (interfacetype) {
+            case VIR_NETDEV_VPORT_PROFILE_NONE:
+                cookie->network->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_8021QBG:
+                cookie->network->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_8021QBH:
+                cookie->network->net[i]->portdata = NULL;
+                break;
+            case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
+                cookie->network->net[i]->portdata = NULL;
+                break;
+            default:
+                cookie->network->net[i]->portdata = 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 +2262,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 +3198,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 +3226,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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]