Explicitly represent balloon device in XML and handle PCI address

To allow compatibility with older QEMU PCI device slot assignment
it is necessary to explicitly track the balloon device in the
XML. This introduces a new device

   <memballoon model='virtio|xen'/>

It can also have a PCI address, auto-assigned if necessary.

The memballoon will be automatically added to all Xen and QEMU
guests by default.

* docs/schemas/domain.rng: Add <memballoon> element
* src/conf/domain_conf.c, src/conf/domain_conf.h: parsing
  and formatting for memballoon device. Always add a memory
  balloon device to Xen/QEMU if none exists in XML
* src/libvirt_private.syms: Export memballoon model APIs
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Honour the
  PCI device address in memory balloon device
* tests/*: Update to test new functionality
This commit is contained in:
Daniel P. Berrange
2010-07-15 14:02:42 +01:00
committed by Daniel P. Berrange
parent ccd2c82ee4
commit b2f1863533
102 changed files with 377 additions and 11 deletions

View File

@@ -189,6 +189,10 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
"pcspk",
"ac97")
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
"virtio",
"xen");
VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST,
"i6300esb",
"ib700")
@@ -567,6 +571,16 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
VIR_FREE(def);
}
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
if (!def)
return;
virDomainDeviceInfoClear(&def->info);
VIR_FREE(def);
}
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
if (!def)
@@ -1001,6 +1015,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
if (def->watchdog)
if (cb(def, &def->watchdog->info, opaque) < 0)
return -1;
if (def->memballoon)
if (cb(def, &def->memballoon->info, opaque) < 0)
return -1;
if (def->console)
if (cb(def, &def->console->info, opaque) < 0)
return -1;
@@ -3170,6 +3187,40 @@ error:
}
static virDomainMemballoonDefPtr
virDomainMemballoonDefParseXML(const xmlNodePtr node,
int flags)
{
char *model;
virDomainMemballoonDefPtr def;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
return NULL;
}
model = virXMLPropString(node, "model");
if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown memory balloon model '%s'"), model);
goto error;
}
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
goto error;
cleanup:
VIR_FREE(model);
return def;
error:
virDomainMemballoonDefFree(def);
def = NULL;
goto cleanup;
}
int
virDomainVideoDefaultRAM(virDomainDefPtr def,
int type)
@@ -4634,6 +4685,41 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
VIR_FREE(nodes);
}
/* analysis of the memballoon devices */
def->memballoon = NULL;
if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot extract memory balloon devices"));
goto error;
}
if (n > 1) {
virDomainReportError (VIR_ERR_INTERNAL_ERROR,
"%s", _("only a single memory balloon device is supported"));
goto error;
}
if (n > 0) {
virDomainMemballoonDefPtr memballoon =
virDomainMemballoonDefParseXML(nodes[0], flags);
if (!memballoon)
goto error;
def->memballoon = memballoon;
VIR_FREE(nodes);
} else {
if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
def->virtType == VIR_DOMAIN_VIRT_QEMU ||
def->virtType == VIR_DOMAIN_VIRT_KQEMU ||
def->virtType == VIR_DOMAIN_VIRT_KVM) {
virDomainMemballoonDefPtr memballoon;
if (VIR_ALLOC(memballoon) < 0)
goto no_memory;
memballoon->model = def->virtType == VIR_DOMAIN_VIRT_XEN ?
VIR_DOMAIN_MEMBALLOON_MODEL_XEN :
VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
def->memballoon = memballoon;
}
}
/* analysis of security label */
if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1)
goto error;
@@ -5671,6 +5757,35 @@ virDomainSoundDefFormat(virBufferPtr buf,
}
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
virDomainMemballoonDefPtr def,
int flags)
{
const char *model = virDomainMemballoonModelTypeToString(def->model);
if (!model) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected memballoon model %d"), def->model);
return -1;
}
virBufferVSprintf(buf, " <memballoon model='%s'",
model);
if (virDomainDeviceInfoIsSet(&def->info)) {
virBufferAddLit(buf, ">\n");
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
virBufferAddLit(buf, " </memballoon>\n");
} else {
virBufferAddLit(buf, "/>\n");
}
return 0;
}
static int
virDomainWatchdogDefFormat(virBufferPtr buf,
virDomainWatchdogDefPtr def,
@@ -6280,6 +6395,9 @@ char *virDomainDefFormat(virDomainDefPtr def,
if (def->watchdog)
virDomainWatchdogDefFormat (&buf, def->watchdog, flags);
if (def->memballoon)
virDomainMemballoonDefFormat (&buf, def->memballoon, flags);
virBufferAddLit(&buf, " </devices>\n");
if (def->seclabel.model) {

View File

@@ -560,6 +560,22 @@ struct _virDomainHostdevDef {
virDomainDeviceInfo info; /* Guest address */
};
enum {
VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO,
VIR_DOMAIN_MEMBALLOON_MODEL_XEN,
VIR_DOMAIN_MEMBALLOON_MODEL_LAST
};
typedef struct _virDomainMemballoonDef virDomainMemballoonDef;
typedef virDomainMemballoonDef *virDomainMemballoonDefPtr;
struct _virDomainMemballoonDef {
int model;
virDomainDeviceInfo info;
};
/* Flags for the 'type' field in next struct */
enum virDomainDeviceType {
VIR_DOMAIN_DEVICE_DISK,
@@ -871,6 +887,7 @@ struct _virDomainDef {
virDomainChrDefPtr console;
virSecurityLabelDef seclabel;
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
virCPUDefPtr cpu;
};
@@ -931,6 +948,7 @@ void virDomainFSDefFree(virDomainFSDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
void virDomainVideoDefFree(virDomainVideoDefPtr def);
void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
@@ -1109,6 +1127,7 @@ VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChrTarget)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainMemballoonModel)
VIR_ENUM_DECL(virDomainWatchdogModel)
VIR_ENUM_DECL(virDomainWatchdogAction)
VIR_ENUM_DECL(virDomainVideo)

View File

@@ -170,6 +170,8 @@ virDomainSaveStatus;
virDomainSoundDefFree;
virDomainSoundModelTypeFromString;
virDomainSoundModelTypeToString;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainWatchdogModelTypeFromString;
virDomainWatchdogModelTypeToString;
virDomainWatchdogActionTypeFromString;

View File

@@ -2023,6 +2023,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
goto no_memory;
}
if (def->memballoon) {
if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0)
goto no_memory;
}
return 0;
@@ -2296,8 +2300,17 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
}
/* VirtIO balloon always at slot 3 by default */
if (qemuDomainPCIAddressReserveSlot(addrs, 3) < 0)
goto error;
if (def->memballoon &&
def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
def->memballoon->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
def->memballoon->info.addr.pci.domain = 0;
def->memballoon->info.addr.pci.bus = 0;
def->memballoon->info.addr.pci.slot = 3;
def->memballoon->info.addr.pci.function = 0;
if (qemuDomainPCIAddressReserveSlot(addrs, 3) < 0)
goto error;
}
for (i = 0; i < def->ndisks ; i++) {
if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
@@ -2912,6 +2925,29 @@ error:
}
char *
qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "virtio-balloon-pci");
virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
goto error;
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
}
return virBufferContentAndReset(&buf);
error:
virBufferFreeAndReset(&buf);
return NULL;
}
char *
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
{
@@ -4771,12 +4807,25 @@ int qemudBuildCommandLine(virConnectPtr conn,
* NB: Earlier we declared that VirtIO balloon will always be in
* slot 0x3 on bus 0x0
*/
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
ADD_ARG_LIT("-device");
ADD_ARG_LIT("virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3");
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
ADD_ARG_LIT("-balloon");
ADD_ARG_LIT("virtio");
if (def->memballoon) {
if (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Memory balloon device type '%s' is not supported by this version of qemu"),
virDomainMemballoonModelTypeToString(def->memballoon->model));
goto error;
}
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
char *optstr;
ADD_ARG_LIT("-device");
optstr = qemuBuildMemballoonDevStr(def->memballoon);
if (!optstr)
goto error;
ADD_ARG(optstr);
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
ADD_ARG_LIT("-balloon");
ADD_ARG_LIT("virtio");
}
}
if (current_snapshot && current_snapshot->def->active) {
@@ -6346,6 +6395,15 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
def->videos[def->nvideos++] = vid;
}
if (!def->memballoon) {
virDomainMemballoonDefPtr memballoon;
if (VIR_ALLOC(memballoon) < 0)
goto no_memory;
memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
def->memballoon = memballoon;
}
VIR_FREE(nics);
if (!def->name) {

View File

@@ -243,6 +243,8 @@ char * qemuBuildControllerDevStr(virDomainControllerDefPtr def);
char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev);
char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev);
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev);
char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound);

View File

@@ -2360,6 +2360,8 @@ cleanup:
#define QEMU_PCI_PRODUCT_DISK_VIRTIO 0x1001
#define QEMU_PCI_PRODUCT_BALLOON_VIRTIO 0x1002
#define QEMU_PCI_PRODUCT_NIC_NE2K 0x8029
#define QEMU_PCI_PRODUCT_NIC_PCNET 0x2000
#define QEMU_PCI_PRODUCT_NIC_RTL8139 0x8139
@@ -2568,6 +2570,25 @@ qemuGetPCIWatchdogVendorProduct(virDomainWatchdogDefPtr def,
}
static int
qemuGetPCIMemballoonVendorProduct(virDomainMemballoonDefPtr def,
unsigned *vendor,
unsigned *product)
{
switch (def->model) {
case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO:
*vendor = QEMU_PCI_VENDOR_REDHAT;
*product = QEMU_PCI_PRODUCT_BALLOON_VIRTIO;
break;
default:
return -1;
}
return 0;
}
/*
* This entire method assumes that PCI devices in 'info pci'
* match ordering of devices specified on the command line
@@ -2649,7 +2670,7 @@ qemuDetectPCIAddresses(virDomainObjPtr vm,
continue;
if (qemuAssignNextPCIAddress(&(vm->def->sounds[i]->info),
vendor, product,
vendor, product,
addrs, naddrs) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find PCI address for sound adapter %s"),
@@ -2671,6 +2692,18 @@ qemuDetectPCIAddresses(virDomainObjPtr vm,
}
}
if (vm->def->memballoon &&
qemuGetPCIMemballoonVendorProduct(vm->def->memballoon, &vendor, &product) == 0) {
if (qemuAssignNextPCIAddress(&(vm->def->memballoon->info),
vendor, product,
addrs, naddrs) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find PCI address for balloon %s"),
virDomainMemballoonModelTypeToString(vm->def->memballoon->model));
return -1;
}
}
/* XXX console (virtio) */
@@ -2678,8 +2711,6 @@ qemuDetectPCIAddresses(virDomainObjPtr vm,
/* XXX USB controller ? */
/* XXXX virtio balloon ? */
/* XXX what about other PCI devices (ie bridges) */
return 0;