[libvirt] [PATCHv2 4/5] Add virDomain{S, G}etInterfaceParameters support to qemu driver

Hu Tao hutao at cn.fujitsu.com
Fri Dec 23 07:09:33 UTC 2011


* src/qemu/qemu_driver.c: implement the qemu driver support
---
 src/qemu/qemu_driver.c |  434 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 434 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c908135..2fab489 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -119,6 +119,8 @@
 
 #define QEMU_NB_BLKIO_PARAM  2
 
+#define QEMU_NB_BANDWIDTH_PARAM 6
+
 static void processWatchdogEvent(void *data, void *opaque);
 
 static int qemudShutdown(void);
@@ -7846,6 +7848,436 @@ qemudDomainInterfaceStats (virDomainPtr dom,
 #endif
 
 static int
+qemuDomainSetInterfaceParameters(virDomainPtr dom,
+                                 const char *device,
+                                 virTypedParameterPtr params,
+                                 int nparams,
+                                 unsigned int flags)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    int i;
+    virCgroupPtr group = NULL;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr persistentDef = NULL;
+    int ret = -1;
+    virDomainNetDefPtr net = NULL;
+    bool isMac = false;
+    virNetDevBandwidthPtr bandwidth;
+    unsigned char mac[VIR_MAC_BUFLEN];
+    bool isActive;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+    qemuDriverLock(driver);
+
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+    if (vm == NULL) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("No such domain %s"), dom->uuid);
+        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 (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        if (!isActive) {
+            qemuReportError(VIR_ERR_OPERATION_INVALID,
+                            "%s", _("domain is not running"));
+            goto cleanup;
+        }
+    }
+
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        if (!vm->persistent) {
+            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                            _("cannot change persistent config of a transient domain"));
+            goto cleanup;
+        }
+        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
+            goto cleanup;
+    }
+
+    if (VIR_ALLOC(bandwidth) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+    if (VIR_ALLOC(bandwidth->in) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+    memset(bandwidth->in, 0, sizeof(*bandwidth->in));
+    if (VIR_ALLOC(bandwidth->out) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+    memset(bandwidth->out, 0, sizeof(*bandwidth->out));
+
+    for (i = 0; i < nparams; i++) {
+        virTypedParameterPtr param = &params[i];
+
+        if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth average tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->in->average = params[i].value.ui;
+        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_PEAK)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth peak tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->in->peak = params[i].value.ui;
+        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_BURST)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth burst tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->in->burst = params[i].value.ui;
+        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth average tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->out->average = params[i].value.ui;
+        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth peak tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->out->peak = params[i].value.ui;
+        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_BURST)) {
+            if (param->type != VIR_TYPED_PARAM_UINT) {
+                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                _("invalid type for bandwidth burst tunable, expected a 'unsigned int'"));
+                goto cleanup;
+            }
+
+            bandwidth->out->burst = params[i].value.ui;
+        } else {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("Parameter `%s' not supported"),
+                            param->field);
+            goto cleanup;
+        }
+    }
+
+    /* average is mandatory, peak and burst is optional. So if no
+     * average is given, we free inbound/outbound here which causes
+     * inbound/outbound won't be set. */
+    if (!bandwidth->in->average)
+        VIR_FREE(bandwidth->in);
+    if (!bandwidth->out->average)
+        VIR_FREE(bandwidth->out);
+
+    if (virParseMacAddr(device, mac) == 0)
+        isMac = true;
+
+    ret = 0;
+    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        if (isMac) {
+            for (i = 0; i < vm->def->nnets; i++) {
+                if (memcmp(mac, vm->def->nets[i]->mac, VIR_MAC_BUFLEN) == 0) {
+                    net = vm->def->nets[i];
+                    break;
+                }
+            }
+        } else { /* ifname */
+            for (i = 0; i < vm->def->nnets; i++) {
+                if (STREQ(device, vm->def->nets[i]->ifname)) {
+                    net = vm->def->nets[i];
+                    break;
+                }
+            }
+        }
+        if (!net) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("cannt find device %s"),
+                            device);
+            goto cleanup;
+        }
+        if (virNetDevBandwidthSet(net->ifname, bandwidth) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot set bandwidth limits on %s"),
+                            device);
+            ret = -1;
+        }
+
+        if (!net->bandwidth) {
+            net->bandwidth = bandwidth;
+            bandwidth = NULL;
+        } else {
+            if (bandwidth->in) {
+                VIR_FREE(net->bandwidth->in);
+                net->bandwidth->in = bandwidth->in;
+                bandwidth->in = NULL;
+            }
+            if (bandwidth->out) {
+                VIR_FREE(net->bandwidth->out);
+                net->bandwidth->out = bandwidth->out;
+                bandwidth->out = NULL;
+            }
+        }
+    }
+    if (ret < 0)
+        goto cleanup;
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        if (isMac) {
+            for (i = 0; i < persistentDef->nnets; i++) {
+                if (memcmp(mac, persistentDef->nets[i]->mac, VIR_MAC_BUFLEN) == 0) {
+                    net = persistentDef->nets[i];
+                    break;
+                }
+            }
+        } else { /* ifname */
+            for (i = 0; i < persistentDef->nnets; i++) {
+                if (STREQ(device, persistentDef->nets[i]->ifname)) {
+                    net = persistentDef->nets[i];
+                    break;
+                }
+            }
+        }
+        if (!net) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            _("Can't find device %s"), device);
+            ret = -1;
+            goto cleanup;
+        }
+
+        if (!net->bandwidth) {
+            net->bandwidth = bandwidth;
+            bandwidth = NULL;
+        } else {
+            if (bandwidth->in) {
+                VIR_FREE(net->bandwidth->in);
+                net->bandwidth->in = bandwidth->in;
+                bandwidth->in = NULL;
+            }
+            if (bandwidth->out) {
+                VIR_FREE(net->bandwidth->out);
+                net->bandwidth->out = bandwidth->out;
+                bandwidth->out = NULL;
+            }
+        }
+
+        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+            ret = -1;
+    }
+
+cleanup:
+    if (bandwidth) {
+        VIR_FREE(bandwidth->in);
+        VIR_FREE(bandwidth->out);
+        VIR_FREE(bandwidth);
+    }
+    virCgroupFree(&group);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+}
+
+static int
+qemuDomainGetInterfaceParameters(virDomainPtr dom,
+                                 const char *device,
+                                 virTypedParameterPtr params,
+                                 int *nparams,
+                                 unsigned int flags)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    int i;
+    virCgroupPtr group = NULL;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr def = NULL;
+    virDomainNetDefPtr net = NULL;
+    bool isMac = false;
+    unsigned char mac[VIR_MAC_BUFLEN];
+    int ret = -1;
+    bool isActive;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+    qemuDriverLock(driver);
+
+    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+    if (vm == NULL) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("No such domain %s"), dom->uuid);
+        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 (flags & VIR_DOMAIN_AFFECT_LIVE) {
+        if (!isActive) {
+            qemuReportError(VIR_ERR_OPERATION_INVALID,
+                            "%s", _("domain is not running"));
+            goto cleanup;
+        }
+        def = vm->def;
+    }
+
+    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+        if (!vm->persistent) {
+            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                            _("cannot change persistent config of a transient domain"));
+            goto cleanup;
+        }
+        if (!(def = virDomainObjGetPersistentDef(driver->caps, vm)))
+            goto cleanup;
+    }
+
+    if ((*nparams) == 0) {
+        *nparams = QEMU_NB_BANDWIDTH_PARAM;
+        ret = 0;
+        goto cleanup;
+    }
+
+    if ((*nparams) < QEMU_NB_BANDWIDTH_PARAM) {
+        qemuReportError(VIR_ERR_INVALID_ARG,
+                        "%s", _("Invalid parameter count"));
+        goto cleanup;
+    }
+
+    if (virParseMacAddr(device, mac) == 0)
+        isMac = true;
+
+    if (isMac) {
+        for (i = 0; i < def->nnets; i++) {
+            if (memcmp(mac, def->nets[i]->mac, VIR_MAC_BUFLEN) == 0) {
+                net = def->nets[i];
+                break;
+            }
+        }
+    } else { /* ifname */
+        for (i = 0; i < def->nnets; i++) {
+            if (STREQ(device, def->nets[i]->ifname)) {
+                net = def->nets[i];
+                break;
+            }
+        }
+    }
+
+    if (!net) {
+        qemuReportError(VIR_ERR_INVALID_ARG,
+                        _("Can't find device %s"), device);
+        ret = -1;
+        goto cleanup;
+    }
+
+    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
+        params[i].value.ui = 0;
+        params[i].type = VIR_TYPED_PARAM_UINT;
+
+        switch(i) {
+        case 0: /* inbound.average */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_IN_AVERAGE);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->in)
+                params[i].value.ui = net->bandwidth->in->average;
+            break;
+        case 1: /* inbound.peak */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_PEAK) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_IN_PEAK);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->in)
+                params[i].value.ui = net->bandwidth->in->peak;
+            break;
+        case 2: /* inbound.burst */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_BURST) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_IN_BURST);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->in)
+                params[i].value.ui = net->bandwidth->in->burst;
+            break;
+        case 3: /* outbound.average */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->out)
+                params[i].value.ui = net->bandwidth->out->average;
+            break;
+        case 4: /* outbound.peak */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_OUT_PEAK);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->out)
+                params[i].value.ui = net->bandwidth->out->peak;
+            break;
+        case 5: /* outbound.burst */
+            if (virStrcpyStatic(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_BURST) == NULL) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Field name '%s' too long"),
+                                VIR_DOMAIN_BANDWIDTH_OUT_BURST);
+                goto cleanup;
+            }
+            if (net->bandwidth && net->bandwidth->out)
+                params[i].value.ui = net->bandwidth->out->burst;
+            break;
+        default:
+            break;
+            /* should not hit here */
+        }
+    }
+
+    *nparams = QEMU_NB_BANDWIDTH_PARAM;
+    ret = 0;
+
+cleanup:
+    if (group)
+        virCgroupFree(&group);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+}
+
+static int
 qemudDomainMemoryStats (virDomainPtr dom,
                         struct _virDomainMemoryStat *stats,
                         unsigned int nr_stats,
@@ -11636,6 +12068,8 @@ static virDriver qemuDriver = {
     .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
     .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
     .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
+    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
+    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
 };
 
 
-- 
1.7.4.4




More information about the libvir-list mailing list