* 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 = ¶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; + } + } + } + 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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list