[libvirt] [PATCHv2 4/5] Add virDomain{S, G}etInterfaceParameters support to qemu driver
Hu Tao
hutao at cn.fujitsu.com
Wed Dec 28 09:56:26 UTC 2011
On Wed, Dec 28, 2011 at 03:23:39PM +0800, Osier Yang wrote:
> On 2011年12月23日 15:09, Hu Tao wrote:
> >* 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;
> >+ }
>
> == From
> >+
> >+ 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;
> >+ }
>
> == To
>
> The above block can be shortened with using helper function
> virDomainLiveConfigHelperMethod. See commit ae52342.
>
> >+
> >+ 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 =¶ms[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;
> >+ }
> >+ }
> >+ }
>
> Should we have a helper function to find the net device? accepting
> both MAC and ifname. Per it's used twice in this function, and
> once in qemuDomainGetInterfaceParameters. And also it's very likely
> be used in future.
>
> >+ if (!net) {
> >+ qemuReportError(VIR_ERR_INVALID_ARG,
> >+ _("cannt find device %s"),
> >+ device);
> >+ goto cleanup;
> >+ }
>
> And it's better to quit ealier before allocating memory for
> bandwidth and parsing params if the device can't be found, it's
> just waste to do those work if the device even doesn't exist.
>
> >+ if (virNetDevBandwidthSet(net->ifname, bandwidth)< 0) {
> >+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
> >+ _("cannot set bandwidth limits on %s"),
> >+ device);
> >+ ret = -1;
>
> Is this intended? to me it's wrong to change the net config below,
> since it bandwidth setting already failed. "goto cleanup;" makes
> sense.
>
> >+ }
> >+
> >+ 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;
>
> Again, failed on setting the bandwidth, but net config is changed.
>
>
> >+ 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;
> >+ }
>
> Likewise,
>
> >+
> >+ 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;
> >+ }
>
> Should we force *nparams >= QEMU_NB_BANDWIDTH_PARAM? IMO it's
> not neccessary.
>
> >+
> >+ 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;
>
> If we allow *nprams < QEMU_NB_BANDWIDTH_PARAM, this should be updated.
>
> >+ 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 */
> > };
> >
> >
>
> Others looks fine.
Thanks for your review, I posted a v3 to address the problems you
pointed out.
--
Thanks,
Hu Tao
More information about the libvir-list
mailing list