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

[libvirt] [PATCH 10/10] linkstate: qemu: Add link state modification support to qemu driver.



Adds support for the new API. While starting a qemu link state
cannot be set with an command line argument and therefore is done
by entering monitor.
---
 src/qemu/qemu_driver.c  |  228 +++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_process.c |   37 ++++++++
 2 files changed, 265 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 19e749f..a6a76be 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6887,6 +6887,232 @@ qemudDomainInterfaceStats (virDomainPtr dom,
 #endif

 static int
+qemudDomainInterfaceLinkGetState (virDomainPtr dom,
+                                  const char *path,
+                                  unsigned int flags)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    int i;
+    int ret = -1;
+    unsigned char mac[VIR_MAC_BUFLEN];
+    virDomainDefPtr def = NULL;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
+                  VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    qemuDriverUnlock(driver);
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                        _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (virParseMacAddr(path, mac) < 0) {
+    qemuReportError(VIR_ERR_INVALID_ARG,
+                        _("Couldn't parse MAC address: %s"), path);
+        goto cleanup;
+    }
+
+    if (virDomainObjIsActive(vm)) {
+        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+            if (!(def = virDomainObjGetPersistentDef(driver->caps, vm))) {
+                qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                _("Couldn't get persistent domain configuration"));
+                goto cleanup;
+            }
+        } else {
+            def = vm->def;
+        }
+    } else {
+        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+            qemuReportError(VIR_ERR_OPERATION_INVALID,
+                            "%s", _("domain is not running"));
+            goto cleanup;
+        }
+        if (!(def = virDomainObjGetPersistentDef(driver->caps, vm))) {
+            qemuReportError(VIR_ERR_OPERATION_FAILED,
+                            _("Couldn't get persistent domain configuration"));
+            goto cleanup;
+        }
+    }
+
+    /* Check the path is one of the domain's network interfaces. */
+    /* Qemu does not support reading the link state, report saved state */
+    for (i = 0 ; i < def->nnets ; i++) {
+        if (memcmp(def->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+            ret = def->nets[i]->linkstate;
+            break;
+        }
+    }
+
+    if (ret < 0)
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("invalid path, '%s' is not a known interface"), path);
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
+
+}
+
+static int
+qemudDomainInterfaceLinkSetState (virDomainPtr dom,
+                                  const char *path,
+                                  unsigned int state,
+                                  unsigned int flags)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    qemuDomainObjPrivatePtr priv = NULL;
+    virDomainObjPtr vm;
+    virDomainDefPtr def = NULL;
+    virDomainDefPtr persistentDef = NULL;
+
+    bool isActive;
+    int i;
+    int ret = -1;
+    bool found = false;
+    unsigned char mac[VIR_MAC_BUFLEN];
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
+                  VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    qemuDriverUnlock(driver);
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                        _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    priv = vm->privateData;
+
+    if (virParseMacAddr(path, mac) < 0) {
+        qemuReportError(VIR_ERR_INVALID_ARG,
+                        _("Couldn't parse MAC address: %s"), path);
+        goto cleanup;
+    }
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    isActive = virDomainObjIsActive(vm);
+
+    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+        if (isActive)
+            flags |= VIR_DOMAIN_AFFECT_LIVE;
+        else
+            flags |= VIR_DOMAIN_AFFECT_CONFIG;
+    }
+
+    if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                         _("domain is not running"));
+        goto endjob;
+    }
+
+    if (!vm->persistent && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        _("cannot change persistent config of a transient domain"));
+        goto endjob;
+    }
+
+    def = vm->def;
+    if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm))) {
+        qemuReportError(VIR_ERR_OPERATION_FAILED,
+                        _("Couldn't get persistent domain configuration"));
+        goto endjob;
+    }
+
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        for (i = 0; i < persistentDef->nnets; i++) {
+            if (memcmp(persistentDef->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+                found = true;
+                persistentDef->nets[i]->linkstate = state;
+                break;
+            }
+        }
+
+        if (!found) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("Interface %s not found"), path);
+            goto endjob;
+        }
+    }
+
+    found = false;
+
+    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        for (i = 0; i < def->nnets; i++) {
+            if (memcmp(def->nets[i]->mac, mac, VIR_MAC_BUFLEN) == 0) {
+                if (def->nets[i]->info.alias) {
+
+                    if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_LINK_SET)) {
+                        qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                        _("This qemu doesn't support setting link state"));
+                        goto endjob;
+                    }
+
+                    qemuDomainObjEnterMonitor(driver, vm);
+                    ret = qemuMonitorSetLink(priv->mon, def->nets[i]->info.alias, state);
+                    qemuDomainObjExitMonitor(driver, vm);
+                } else {
+                    qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                    _("Device alias not found. (QEMU probably doesn't support device naming)"));
+                    goto endjob;
+                }
+
+                found = true;
+                if (ret == 0)
+                    def->nets[i]->linkstate = state;
+
+                break;
+            }
+        }
+
+        if (!found) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("Interface %s not found"), path);
+            goto endjob;
+        }
+
+        if (ret < 0)
+            goto endjob;
+    }
+
+    /* one or both configurations successfuly altered */
+
+    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+        virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+                    goto endjob;
+
+    /* everything went well */
+    ret = 0;
+
+endjob:
+    if (qemuDomainObjEndJob(driver, vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+
+    return ret;
+}
+
+static int
 qemudDomainMemoryStats (virDomainPtr dom,
                         struct _virDomainMemoryStat *stats,
                         unsigned int nr_stats,
@@ -9473,6 +9699,8 @@ static virDriver qemuDriver = {
     .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
     .domainBlockStats = qemudDomainBlockStats, /* 0.4.1 */
     .domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */
+    .domainInterfaceLinkGetState = qemudDomainInterfaceLinkGetState, /* 0.9.5 */
+    .domainInterfaceLinkSetState = qemudDomainInterfaceLinkSetState, /* 0.9.5 */
     .domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */
     .domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
     .domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 30c8b28..c0bf30b 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1441,6 +1441,29 @@ qemuProcessInitCpuAffinity(virDomainObjPtr vm)
     return 0;
 }

+/* set link states to down on interfaces at qemu start */
+static int
+qemuProcessSetLinkStates(virDomainObjPtr vm)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDefPtr def = vm->def;
+    int i;
+    int ret = 0;
+
+    for (i = 0; i < def->nnets; i++) {
+        if (def->nets[i]->linkstate == VIR_LINK_STATE_DOWN) {
+            ret = qemuMonitorSetLink(priv->mon,
+                                     def->nets[i]->info.alias,
+                                     VIR_LINK_STATE_DOWN);
+
+            if (ret != 0)
+                break;
+        }
+    }
+
+    return ret;
+}
+
 /* Set CPU affinites for vcpus if vcpupin xml provided. */
 static int
 qemuProcessSetVcpuAffinites(virConnectPtr conn,
@@ -2980,6 +3003,20 @@ int qemuProcessStart(virConnectPtr conn,
             goto cleanup;
     }

+    /* set default link states */
+    /* qemu doesn't support setting this on the command line, so
+     * enter the monitor */
+    if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_LINK_SET)) {
+        VIR_DEBUG("Setting network link states");
+        qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        if (qemuProcessSetLinkStates(vm) < 0) {
+            qemuDomainObjExitMonitorWithDriver(driver, vm);
+            goto cleanup;
+        }
+
+        qemuDomainObjExitMonitorWithDriver(driver, vm);
+    }
+
     /* Technically, qemuProcessStart can be called from inside
      * QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like
      * a sync job since no other job can call into the domain until
-- 
1.7.6


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