Add domain support for virtio channel

Add support for virtio-serial by defining a new 'virtio' channel target type
and a virtio-serial controller. Allows the following to be specified in a
domain:

<controller type='virtio-serial' index='0' ports='16' vectors='4'/>
<channel type='pty'>
  <target type='virtio' name='org.linux-kvm.port.0'/>
  <address type='virtio-serial' controller='0' bus='0'/>
</channel>

* docs/schemas/domain.rng: Add virtio-serial controller and virtio
  channel type.
* src/conf/domain_conf.[ch]: Domain parsing/serialization for
  virtio-serial controller and virtio channel.
* tests/qemuxml2xmltest.c
  tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml: add domain xml
  parsing test
* src/libvirt_private.syms src/qemu/qemu_conf.c:
  virDomainDefAddDiskControllers() renamed to
  virDomainDefAddImplicitControllers()
This commit is contained in:
Matthew Booth 2010-02-18 17:52:03 +01:00 committed by Daniel Veillard
parent 07e318b3db
commit 7813a0f81c
7 changed files with 305 additions and 38 deletions

View File

@ -523,16 +523,36 @@
</define>
<define name="controller">
<element name="controller">
<optional>
<attribute name="type">
<choice>
<value>fdc</value>
<value>ide</value>
<value>scsi</value>
<value>sata</value>
</choice>
</attribute>
</optional>
<choice>
<group>
<optional>
<attribute name="type">
<choice>
<value>fdc</value>
<value>ide</value>
<value>scsi</value>
<value>sata</value>
</choice>
</attribute>
</optional>
</group>
<!-- virtio-serial can have 2 additional attributes -->
<group>
<attribute name="type">
<value>virtio-serial</value>
</attribute>
<optional>
<attribute name="ports">
<ref name="unsignedInt"/>
</attribute>
</optional>
<optional>
<attribute name="vectors">
<ref name="unsignedInt"/>
</attribute>
</optional>
</group>
</choice>
<attribute name="index">
<ref name="unsignedInt"/>
</attribute>
@ -1139,12 +1159,25 @@
<attribute name="port"/>
</element>
</define>
<define name="virtioTarget">
<element name="target">
<attribute name="type">
<value>virtio</value>
</attribute>
<optional>
<attribute name="name"/>
</optional>
</element>
</define>
<define name="channel">
<element name="channel">
<ref name="qemucdevSrcType"/>
<interleave>
<ref name="qemucdevSrcDef"/>
<ref name="guestfwdTarget"/>
<choice>
<ref name="guestfwdTarget"/>
<ref name="virtioTarget"/>
</choice>
<optional>
<ref name="address"/>
</optional>
@ -1269,6 +1302,16 @@
<ref name="driveUnit"/>
</attribute>
</define>
<define name="virtioserialaddress">
<attribute name="controller">
<ref name="driveController"/>
</attribute>
<optional>
<attribute name="bus">
<ref name="driveBus"/>
</attribute>
</optional>
</define>
<!--
Devices attached to a domain.
-->
@ -1413,6 +1456,12 @@
</attribute>
<ref name="driveaddress"/>
</group>
<group>
<attribute name="type">
<value>virtio-serial</value>
</attribute>
<ref name="virtioserialaddress"/>
</group>
</choice>
</element>
</define>

View File

@ -93,7 +93,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
"pci",
"drive");
"drive",
"virtio-serial");
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
"block",
@ -125,7 +126,8 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
"fdc",
"scsi",
"sata")
"sata",
"virtio-serial")
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
"mount",
@ -150,7 +152,8 @@ VIR_ENUM_IMPL(virDomainChrTarget, VIR_DOMAIN_CHR_TARGET_TYPE_LAST,
"parallel",
"serial",
"console",
"guestfwd")
"guestfwd",
"virtio")
VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
"null",
@ -459,6 +462,10 @@ void virDomainChrDefFree(virDomainChrDefPtr def)
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
VIR_FREE(def->target.addr);
break;
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
VIR_FREE(def->target.name);
break;
}
switch (def->type) {
@ -811,6 +818,13 @@ int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRI
/*return addr->controller || addr->bus || addr->unit;*/
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
}
int virDomainDeviceVirtioSerialAddressIsValid(
virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED)
{
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
}
#endif /* !PROXY */
@ -952,6 +966,12 @@ static int virDomainDeviceInfoFormat(virBufferPtr buf,
info->addr.drive.unit);
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
virBufferVSprintf(buf, " controller='%d' bus='%d'",
info->addr.vioserial.controller,
info->addr.vioserial.bus);
break;
default:
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown address type '%d'"), info->type);
@ -1075,6 +1095,50 @@ cleanup:
return ret;
}
static int
virDomainDeviceVirtioSerialAddressParseXML(
xmlNodePtr node,
virDomainDeviceVirtioSerialAddressPtr addr
)
{
char *controller, *bus;
int ret = -1;
memset(addr, 0, sizeof(*addr));
controller = virXMLPropString(node, "controller");
bus = virXMLPropString(node, "bus");
if (controller &&
virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <address> 'controller' attribute"));
goto cleanup;
}
if (bus &&
virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <address> 'bus' attribute"));
goto cleanup;
}
if (!virDomainDeviceVirtioSerialAddressIsValid(addr)) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Insufficient specification for "
"virtio serial address"));
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(controller);
VIR_FREE(bus);
return ret;
}
/* Parse the XML definition for a device address
* @param node XML nodeset to parse for device address definition
*/
@ -1137,6 +1201,12 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
goto cleanup;
break;
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
if (virDomainDeviceVirtioSerialAddressParseXML
(address, &info->addr.vioserial) < 0)
goto cleanup;
break;
default:
/* Should not happen */
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@ -1462,9 +1532,9 @@ virDomainControllerDefParseXML(xmlNodePtr node,
type = virXMLPropString(node, "type");
if (type) {
if ((def->type = virDomainDiskBusTypeFromString(type)) < 0) {
if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown disk controller type '%s'"), type);
_("Unknown controller type '%s'"), type);
goto error;
}
}
@ -1473,7 +1543,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
if (idx) {
if (virStrToLong_i(idx, NULL, 10, &def->idx) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse disk controller index %s"), idx);
_("Cannot parse controller index %s"), idx);
goto error;
}
}
@ -1481,10 +1551,48 @@ virDomainControllerDefParseXML(xmlNodePtr node,
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
goto error;
switch (def->type) {
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: {
char *ports = virXMLPropString(node, "ports");
if (ports) {
int r = virStrToLong_i(ports, NULL, 10,
&def->opts.vioserial.ports);
if (r != 0 || def->opts.vioserial.ports < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid ports: %s"), ports);
VIR_FREE(ports);
goto error;
}
} else {
def->opts.vioserial.ports = -1;
}
VIR_FREE(ports);
char *vectors = virXMLPropString(node, "vectors");
if (vectors) {
int r = virStrToLong_i(vectors, NULL, 10,
&def->opts.vioserial.vectors);
if (r != 0 || def->opts.vioserial.vectors < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid vectors: %s"), vectors);
VIR_FREE(vectors);
goto error;
}
} else {
def->opts.vioserial.vectors = -1;
}
VIR_FREE(vectors);
break;
}
default:
break;
}
if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Disk controllers must use the 'pci' address type"));
_("Controllers must use the 'pci' address type"));
goto error;
}
@ -2086,6 +2194,10 @@ virDomainChrDefParseXML(xmlNodePtr node,
virSocketSetPort(def->target.addr, port);
break;
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
def->target.name = virXMLPropString(cur, "name");
break;
default:
virDomainReportError(VIR_ERR_XML_ERROR,
_("unexpected target type type %u"),
@ -2096,7 +2208,6 @@ virDomainChrDefParseXML(xmlNodePtr node,
cur = cur->next;
}
switch (def->type) {
case VIR_DOMAIN_CHR_TYPE_NULL:
/* Nada */
@ -3629,12 +3740,6 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
}
VIR_FREE(nodes);
/* Auto-add any further disk controllers implied by declared <disk>
* elements, but not present as <controller> elements
*/
if (virDomainDefAddDiskControllers(def) < 0)
goto error;
/* analysis of the filesystems */
if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@ -3948,6 +4053,11 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
goto error;
}
/* Auto-add any implied controllers which aren't present
*/
if (virDomainDefAddImplicitControllers(def) < 0)
goto error;
return def;
no_memory:
@ -4211,9 +4321,9 @@ cleanup:
return obj;
}
static int virDomainDefMaybeAddDiskController(virDomainDefPtr def,
int type,
int idx)
static int virDomainDefMaybeAddController(virDomainDefPtr def,
int type,
int idx)
{
int found = 0;
int i;
@ -4266,7 +4376,7 @@ static int virDomainDefAddDiskControllersForType(virDomainDefPtr def,
}
for (i = 0 ; i <= maxController ; i++) {
if (virDomainDefMaybeAddDiskController(def, controllerType, i) < 0)
if (virDomainDefMaybeAddController(def, controllerType, i) < 0)
return -1;
}
@ -4274,13 +4384,33 @@ static int virDomainDefAddDiskControllersForType(virDomainDefPtr def,
}
static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
{
/* Look for any virtio serial device */
int i;
for (i = 0 ; i < def->nchannels ; i++) {
virDomainChrDefPtr channel = def->channels[i];
if (channel->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO) {
/* Try to add a virtio serial controller with index 0 */
if (virDomainDefMaybeAddController(def,
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, 0) < 0)
return -1;
break;
}
}
return 0;
}
/*
* Based on the declared <address type=drive> info for any disks,
* Based on the declared <address/> info for any devices,
* add neccessary drive controllers which are not already present
* in the XML. This is for compat with existing apps which will
* not know/care about <controller> info in the XML
*/
int virDomainDefAddDiskControllers(virDomainDefPtr def)
int virDomainDefAddImplicitControllers(virDomainDefPtr def)
{
if (virDomainDefAddDiskControllersForType(def,
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
@ -4297,6 +4427,9 @@ int virDomainDefAddDiskControllers(virDomainDefPtr def)
VIR_DOMAIN_DISK_BUS_IDE) < 0)
return -1;
if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
return -1;
return 0;
}
@ -4622,6 +4755,22 @@ virDomainControllerDefFormat(virBufferPtr buf,
" <controller type='%s' index='%d'",
type, def->idx);
switch (def->type) {
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
if (def->opts.vioserial.ports != -1) {
virBufferVSprintf(buf, " ports='%d'",
def->opts.vioserial.ports);
}
if (def->opts.vioserial.vectors != -1) {
virBufferVSprintf(buf, " vectors='%d'",
def->opts.vioserial.vectors);
}
break;
default:
break;
}
if (virDomainDeviceInfoIsSet(&def->info)) {
virBufferAddLit(buf, ">\n");
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
@ -4792,6 +4941,7 @@ virDomainChrDefFormat(virBufferPtr buf,
switch (def->targetType) {
/* channel types are in a common channel element */
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
elementName = "channel";
break;
@ -4905,11 +5055,18 @@ virDomainChrDefFormat(virBufferPtr buf,
break;
}
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
virBufferAddLit(buf, " <target type='virtio'");
if (def->target.name) {
virBufferEscapeString(buf, " name='%s'", def->target.name);
}
virBufferAddLit(buf, "/>\n");
break;
case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
virBufferVSprintf(buf, " <target port='%d'/>\n",
def->target.port);
virBufferVSprintf(buf, " <target port='%d'/>\n", def->target.port);
break;
default:
@ -4919,8 +5076,10 @@ virDomainChrDefFormat(virBufferPtr buf,
return -1;
}
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
if (virDomainDeviceInfoIsSet(&def->info)) {
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
}
virBufferVSprintf(buf, " </%s>\n",
elementName);

View File

@ -68,6 +68,7 @@ enum virDomainDeviceAddressType {
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST
};
@ -89,6 +90,13 @@ struct _virDomainDeviceDriveAddress {
unsigned int unit;
};
typedef struct _virDomainDeviceVirtioSerialAddress virDomainDeviceVirtioSerialAddress;
typedef virDomainDeviceVirtioSerialAddress *virDomainDeviceVirtioSerialAddressPtr;
struct _virDomainDeviceVirtioSerialAddress {
unsigned int controller;
unsigned int bus;
};
typedef struct _virDomainDeviceInfo virDomainDeviceInfo;
typedef virDomainDeviceInfo *virDomainDeviceInfoPtr;
struct _virDomainDeviceInfo {
@ -97,6 +105,7 @@ struct _virDomainDeviceInfo {
union {
virDomainDevicePCIAddress pci;
virDomainDeviceDriveAddress drive;
virDomainDeviceVirtioSerialAddress vioserial;
} addr;
};
@ -166,16 +175,27 @@ enum virDomainControllerType {
VIR_DOMAIN_CONTROLLER_TYPE_FDC,
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
VIR_DOMAIN_CONTROLLER_TYPE_LAST
};
typedef struct _virDomainVirtioSerialOpts virDomainVirtioSerialOpts;
typedef virDomainVirtioSerialOpts *virDomainVirtioSerialOptsPtr;
struct _virDomainVirtioSerialOpts {
int ports; /* -1 == undef */
int vectors; /* -1 == undef */
};
/* Stores the virtual disk controller configuration */
typedef struct _virDomainControllerDef virDomainControllerDef;
typedef virDomainControllerDef *virDomainControllerDefPtr;
struct _virDomainControllerDef {
int type;
int idx;
union {
virDomainVirtioSerialOpts vioserial;
} opts;
virDomainDeviceInfo info;
};
@ -271,6 +291,7 @@ enum virDomainChrTargetType {
VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL,
VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE,
VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD,
VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO,
VIR_DOMAIN_CHR_TARGET_TYPE_LAST
};
@ -304,6 +325,7 @@ struct _virDomainChrDef {
union {
int port; /* parallel, serial, console */
virSocketAddrPtr addr; /* guestfwd */
char *name; /* virtio */
} target;
int type;
@ -744,6 +766,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
int type);
int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr);
int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr);
int virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddressPtr addr);
int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info);
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
@ -790,7 +813,7 @@ virDomainObjPtr virDomainObjParseNode(virCapsPtr caps,
xmlDocPtr xml,
xmlNodePtr root);
int virDomainDefAddDiskControllers(virDomainDefPtr def);
int virDomainDefAddImplicitControllers(virDomainDefPtr def);
#endif
char *virDomainDefFormat(virDomainDefPtr def,

View File

@ -185,7 +185,7 @@ virDomainDeviceInfoIsSet;
virDomainControllerTypeToString;
virDomainControllerDefFree;
virDomainDeviceAddressTypeToString;
virDomainDefAddDiskControllers;
virDomainDefAddImplicitControllers;
virDomainDefClearPCIAddresses;
virDomainDefClearDeviceAliases;
virDomainDeviceInfoIterate;

View File

@ -5709,7 +5709,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
goto no_memory;
}
if (virDomainDefAddDiskControllers(def) < 0)
if (virDomainDefAddImplicitControllers(def) < 0)
goto error;
return def;

View File

@ -0,0 +1,35 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219200</memory>
<currentMemory>219200</currentMemory>
<vcpu cpuset='1-4,8-20,525'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<controller type='virtio-serial' index='0' ports='16' vectors='4'/>
<controller type='virtio-serial' index='1'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
</controller>
<channel type='pty'>
<target type='virtio' name='org.linux-kvm.port.0'/>
</channel>
<channel type='pty'>
<target type='virtio' name='org.linux-kvm.port.1'/>
<address type='virtio-serial' controller='1' bus='0'/>
</channel>
</devices>
</domain>

View File

@ -133,6 +133,7 @@ mymain(int argc, char **argv)
DO_TEST("parallel-tcp");
DO_TEST("console-compat");
DO_TEST("channel-guestfwd");
DO_TEST("channel-virtio");
DO_TEST("hostdev-usb-address");
DO_TEST("hostdev-pci-address");