diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 53b82ce20d..0fc8fc0b78 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -523,16 +523,36 @@
-
-
-
- fdc
- ide
- scsi
- sata
-
-
-
+
+
+
+
+
+ fdc
+ ide
+ scsi
+ sata
+
+
+
+
+
+
+
+ virtio-serial
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1139,12 +1159,25 @@
+
+
+
+ virtio
+
+
+
+
+
+
-
+
+
+
+
@@ -1269,6 +1302,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1413,6 +1456,12 @@
+
+
+ virtio-serial
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 59fd2519c4..eee31fd9fa 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -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
'controller' attribute"));
+ goto cleanup;
+ }
+
+ if (bus &&
+ virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse '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
- * elements, but not present as 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 info for any disks,
+ * Based on the declared 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 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,
" 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.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, " \n",
- def->target.port);
+ virBufferVSprintf(buf, " \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);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 782af95a3a..f906c79b8f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -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,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4dd7e987aa..b1de480ca1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -185,7 +185,7 @@ virDomainDeviceInfoIsSet;
virDomainControllerTypeToString;
virDomainControllerDefFree;
virDomainDeviceAddressTypeToString;
-virDomainDefAddDiskControllers;
+virDomainDefAddImplicitControllers;
virDomainDefClearPCIAddresses;
virDomainDefClearDeviceAliases;
virDomainDeviceInfoIterate;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 79bd1e843c..ebbd1a7749 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -5709,7 +5709,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
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 0000000000..6c3317b670
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.xml
@@ -0,0 +1,35 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219200
+ 219200
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index e807d7bda4..ace2be851f 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-address");
DO_TEST("hostdev-pci-address");