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'/>
<channel type='pty'>
<target type='virtio' name='org.linux-kvm.port.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()
---
docs/schemas/domain.rng | 25 ++++-
src/conf/domain_conf.c | 124 +++++++++++++++++---
src/conf/domain_conf.h | 10 ++-
src/libvirt_private.syms | 2 +-
src/qemu/qemu_conf.c | 2 +-
.../qemuxml2argv-channel-virtio.xml | 28 +++++
tests/qemuxml2xmltest.c | 1 +
7 files changed, 173 insertions(+), 19 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 827ff6f..a3247b9 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -530,6 +530,7 @@
<value>ide</value>
<value>scsi</value>
<value>sata</value>
+ <value>virtio-serial</value>
</choice>
</attribute>
</optional>
@@ -1120,12 +1121,34 @@
<attribute name="port"/>
</element>
</define>
+ <define name="virtioTarget">
+ <element name="target">
+ <attribute name="type">
+ <value>virtio</value>
+ </attribute>
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <optional>
+ <attribute name="bytelimit"/>
+ </optional>
+ <optional>
+ <attribute name="guestbytelimit"/>
+ </optional>
+ <optional>
+ <attribute name="cachebuffers"/>
+ </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>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e548d1d..3b96086 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -124,7 +124,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",
@@ -148,7 +149,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",
@@ -449,6 +451,13 @@ 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.virtio.name);
+ VIR_FREE(def->target.virtio.byteLimit);
+ VIR_FREE(def->target.virtio.guestByteLimit);
+ VIR_FREE(def->target.virtio.cacheBuffers);
+ break;
}
switch (def->type) {
@@ -1460,7 +1469,7 @@ virDomainControllerDefParseXML(virConnectPtr conn,
type = virXMLPropString(node, "type");
if (type) {
- if ((def->type = virDomainDiskBusTypeFromString(type)) < 0) {
+ if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("unknown disk controller type
'%s'"), type);
goto error;
@@ -2081,6 +2090,48 @@ virDomainChrDefParseXML(virConnectPtr conn,
virSocketSetPort(def->target.addr, port);
break;
+ case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
+ def->target.virtio.name
+ = virXMLPropString(cur, "name");
+ def->target.virtio.byteLimit
+ = virXMLPropString(cur, "bytelimit");
+ def->target.virtio.guestByteLimit
+ = virXMLPropString(cur, "guestbytelimit");
+ def->target.virtio.cacheBuffers
+ = virXMLPropString(cur, "cachebuffers");
+
+ /* Ensure bytelimit and guestbytelimit are positive integers
+ * if they are defined */
+ unsigned int testUI;
+ if (def->target.virtio.byteLimit &&
+ virStrToLong_ui(def->target.virtio.byteLimit,
+ NULL, 10, &testUI) < 0) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ _("Invalid byte_limit: %s"),
+ def->target.virtio.byteLimit);
+ goto error;
+ }
+ if (def->target.virtio.guestByteLimit &&
+ virStrToLong_ui(def->target.virtio.guestByteLimit,
+ NULL, 10, &testUI) < 0) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ _("Invalid guest_byte_limit:
%s"),
+ def->target.virtio.guestByteLimit);
+ goto error;
+ }
+
+ /* Ensure that cacheBuffers is either 0 or 1 if it defined
+ */
+ if (def->target.virtio.cacheBuffers &&
+ STRNEQ(def->target.virtio.cacheBuffers, "0")
&&
+ STRNEQ(def->target.virtio.cacheBuffers, "1")) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ _("Invalid cache_buffers: %s"),
+ def->target.virtio.cacheBuffers);
+ goto error;
+ }
+ break;
+
default:
virDomainReportError(conn, VIR_ERR_XML_ERROR,
_("unexpected target type type %u"),
@@ -3640,12 +3691,6 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
}
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(conn, "./devices/filesystem", ctxt, &nodes))
< 0) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -3970,6 +4015,11 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
goto error;
}
+ /* Auto-add any implied controllers which aren't present
+ */
+ if (virDomainDefAddImplicitControllers(def) < 0)
+ goto error;
+
return def;
no_memory:
@@ -4247,9 +4297,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;
@@ -4302,7 +4352,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;
}
@@ -4310,13 +4360,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,
@@ -4333,6 +4403,9 @@ int virDomainDefAddDiskControllers(virDomainDefPtr def)
VIR_DOMAIN_DISK_BUS_IDE) < 0)
return -1;
+ if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
+ return -1;
+
return 0;
}
@@ -4837,6 +4910,7 @@ virDomainChrDefFormat(virConnectPtr conn,
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;
@@ -4950,6 +5024,26 @@ virDomainChrDefFormat(virConnectPtr conn,
break;
}
+ case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
+ virBufferVSprintf(buf, " <target type='virtio'");
+ if (def->target.virtio.name) {
+ virBufferVSprintf(buf, " name='%s'",
def->target.virtio.name);
+ }
+ if (def->target.virtio.byteLimit) {
+ virBufferVSprintf(buf, " bytelimit='%s'",
+ def->target.virtio.byteLimit);
+ }
+ if (def->target.virtio.guestByteLimit) {
+ virBufferVSprintf(buf, " guestbytelimit='%s'",
+ def->target.virtio.guestByteLimit);
+ }
+ if (def->target.virtio.cacheBuffers) {
+ virBufferVSprintf(buf, " cachebuffers='%s'",
+ def->target.virtio.cacheBuffers);
+ }
+ virBufferVSprintf(buf, "/>\n");
+ break;
+
case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7be090d..da2115e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -166,6 +166,7 @@ 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
};
@@ -260,6 +261,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
};
@@ -293,6 +295,12 @@ struct _virDomainChrDef {
union {
int port; /* parallel, serial, console */
virSocketAddrPtr addr; /* guestfwd */
+ struct {
+ char *name;
+ char *byteLimit;
+ char *guestByteLimit;
+ char *cacheBuffers;
+ } virtio; /* virtio */
} target;
int type;
@@ -782,7 +790,7 @@ virDomainObjPtr virDomainObjParseNode(virConnectPtr conn,
xmlDocPtr xml,
xmlNodePtr root);
-int virDomainDefAddDiskControllers(virDomainDefPtr def);
+int virDomainDefAddImplicitControllers(virDomainDefPtr def);
#endif
char *virDomainDefFormat(virConnectPtr conn,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d56fb7d..9dd1866 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -184,7 +184,7 @@ virDomainDeviceInfoIsSet;
virDomainControllerTypeToString;
virDomainControllerDefFree;
virDomainDeviceAddressTypeToString;
-virDomainDefAddDiskControllers;
+virDomainDefAddImplicitControllers;
virDomainDefClearPCIAddresses;
virDomainDefClearDeviceAliases;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 3b7793f..0c67334 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -5410,7 +5410,7 @@ virDomainDefPtr qemuParseCommandLine(virConnectPtr conn,
goto no_memory;
}
- if (virDomainDefAddDiskControllers(def) < 0)
+ if (virDomainDefAddImplicitControllers(def) < 0)
goto error;
return def;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml
b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml
new file mode 100644
index 0000000..da5fa6c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml
@@ -0,0 +1,28 @@
+<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'/>
+ <channel type='pty'>
+ <target type='virtio' name='org.linux-kvm.port.0'
bytelimit='1048576' guestbytelimit='1048576'
cachebuffers='1'/>
+ </channel>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 0302696..7ea8e79 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -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-product");
DO_TEST("hostdev-usb-address");
--
1.6.6