diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index dcb7af887e..e6a8162f7f 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1102,6 +1102,18 @@ qemu-kvm -net nic,model=? /dev/null
The listen
attribute is an IP address for the server to
listen on. The passwd
attribute provides a VNC password
in clear text. The keymap
attribute specifies the keymap
+ to use.
+
+
"spice"
+
+ Starts a SPICE server. The port
attribute specifies the TCP
+ port number (with -1 as legacy syntax indicating that it should be
+ auto-allocated), while tlsPort
gives an alternative
+ secure port number. The autoport
attribute is the new
+ preferred syntax for indicating autoallocation of both port numbers.
+ The listen
attribute is an IP address for the server to
+ listen on. The passwd
attribute provides a SPICE password
+ in clear text. The keymap
attribute specifies the keymap
to use.
"rdp"
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 16fc444df7..7903000680 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1094,6 +1094,44 @@
+
+
+ spice
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ yes
+ no
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
rdp
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 09f415b711..1f3bca8cad 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -268,7 +268,8 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
"sdl",
"vnc",
"rdp",
- "desktop")
+ "desktop",
+ "spice")
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
"subsystem",
@@ -451,6 +452,12 @@ void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
VIR_FREE(def->data.desktop.display);
break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ VIR_FREE(def->data.spice.listenAddr);
+ VIR_FREE(def->data.spice.keymap);
+ VIR_FREE(def->data.spice.passwd);
+ break;
}
VIR_FREE(def);
@@ -3204,6 +3211,50 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
def->data.desktop.fullscreen = 0;
def->data.desktop.display = virXMLPropString(node, "display");
+ } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
+ char *port = virXMLPropString(node, "port");
+ char *tlsPort;
+ char *autoport;
+
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse spice port %s"), port);
+ VIR_FREE(port);
+ goto error;
+ }
+ VIR_FREE(port);
+ } else {
+ def->data.spice.port = 5900;
+ }
+
+ tlsPort = virXMLPropString(node, "tlsPort");
+ if (tlsPort) {
+ if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse spice tlsPort %s"), tlsPort);
+ VIR_FREE(tlsPort);
+ goto error;
+ }
+ VIR_FREE(tlsPort);
+ } else {
+ def->data.spice.tlsPort = 0;
+ }
+
+ if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
+ if (STREQ(autoport, "yes")) {
+ if (flags & VIR_DOMAIN_XML_INACTIVE) {
+ def->data.spice.port = 0;
+ def->data.spice.tlsPort = 0;
+ }
+ def->data.spice.autoport = 1;
+ }
+ VIR_FREE(autoport);
+ }
+
+ def->data.spice.listenAddr = virXMLPropString(node, "listen");
+ def->data.spice.passwd = virXMLPropString(node, "passwd");
+ def->data.spice.keymap = virXMLPropString(node, "keymap");
}
cleanup:
@@ -6517,6 +6568,33 @@ virDomainGraphicsDefFormat(virBufferPtr buf,
break;
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ if (def->data.spice.port)
+ virBufferVSprintf(buf, " port='%d'",
+ def->data.spice.port);
+
+ if (def->data.spice.tlsPort)
+ virBufferVSprintf(buf, " tlsPort='%d'",
+ def->data.spice.tlsPort);
+
+ virBufferVSprintf(buf, " autoport='%s'",
+ def->data.spice.autoport ? "yes" : "no");
+
+ if (def->data.spice.listenAddr)
+ virBufferVSprintf(buf, " listen='%s'",
+ def->data.spice.listenAddr);
+
+ if (def->data.spice.keymap)
+ virBufferEscapeString(buf, " keymap='%s'",
+ def->data.spice.keymap);
+
+ if (def->data.spice.passwd &&
+ (flags & VIR_DOMAIN_XML_SECURE))
+ virBufferEscapeString(buf, " passwd='%s'",
+ def->data.spice.passwd);
+
+ break;
+
}
virBufferAddLit(buf, "/>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 834eafeb23..c6699e2e54 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -512,6 +512,7 @@ enum virDomainGraphicsType {
VIR_DOMAIN_GRAPHICS_TYPE_VNC,
VIR_DOMAIN_GRAPHICS_TYPE_RDP,
VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
VIR_DOMAIN_GRAPHICS_TYPE_LAST,
};
@@ -544,6 +545,14 @@ struct _virDomainGraphicsDef {
char *display;
unsigned int fullscreen :1;
} desktop;
+ struct {
+ int port;
+ int tlsPort;
+ char *listenAddr;
+ char *keymap;
+ char *passwd;
+ unsigned int autoport :1;
+ } spice;
} data;
};
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index e0064f75e1..e8342be48b 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -5072,7 +5072,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (def->nvideos) {
if (def->nvideos > 1) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("only one video card is currently supported"));
goto error;
}