``name='com.redhat.spice.0'``. The optional ``address`` element can tie the
channel to a particular ``type='virtio-serial'`` controller. :since:`Since
0.8.8`
+``qemu-vdagent``
+ Paravirtualized qemu vdagent channel. This channel implements the SPICE
+ vdagent protocol, but is handled internally by qemu and therefore does not
+ require a SPICE graphics device. Like the spicevmc channel, the ``target``
+ element must be present, with attribute ``type='virtio'``; an optional
+ attribute ``name`` controls how the guest will have access to the channel,
+ and defaults to ``name='com.redhat.spice.0'``. The optional ``address``
+ element can tie the channel to a particular ``type='virtio-serial'``
+ controller. Certain vdagent protocol features can by enabled or disabled
+ using the ``source`` element.
+
+ Copy & Paste functionality is set by the ``clipboard`` element. It is
+ disabled by default, and can be enabled by setting the ``copypaste``
+ property to ``yes``. This allows the guest's clipboard to be synchronized
+ with the qemu clipboard manager. This can enable copy and paste between a
+ guest and a client when using a VNC `graphics device <#elementsGraphics>`__
+ (when using a VNC client that supports the copy/paste feature) or other
+ graphics types that support the qemu clipboard manager.
+
+ Mouse mode is set by the ``mouse`` element, setting its ``mode`` attribute
+ to one of ``server`` or ``client``. If no mode is specified, the qemu
+ default will be used (client mode).
+ :since:`Since 8.2.0`
:anchor:`<a id="elementsCharHostInterface"/>`
"spicevmc",
"spiceport",
"nmdm",
+ "qemu-vdagent",
);
VIR_ENUM_IMPL(virDomainChrTcpProtocol,
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
return NULL;
}
dest->data.spiceport.channel = g_strdup(src->data.spiceport.channel);
break;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
+ dest->data.qemuVdagent.clipboard = src->data.qemuVdagent.clipboard;
+ dest->data.qemuVdagent.mouse = src->data.qemuVdagent.mouse;
+ break;
+
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
return src->data.spicevmc == tgt->data.spicevmc;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
+ return src->data.qemuVdagent.clipboard == tgt->data.qemuVdagent.clipboard &&
+ src->data.qemuVdagent.mouse == tgt->data.qemuVdagent.mouse;
+
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_STDIO:
}
+static int
+virDomainChrSourceDefParseQemuVdagent(virDomainChrSourceDef *def,
+ xmlNodePtr source,
+ xmlXPathContextPtr ctxt)
+{
+ xmlNodePtr cur;
+ VIR_XPATH_NODE_AUTORESTORE(ctxt)
+
+ ctxt->node = source;
+ if ((cur = virXPathNode("./clipboard", ctxt))) {
+ if (virXMLPropTristateBool(cur, "copypaste",
+ VIR_XML_PROP_REQUIRED,
+ &def->data.qemuVdagent.clipboard) < 0)
+ return -1;
+ }
+ if ((cur = virXPathNode("./mouse", ctxt))) {
+ if (virXMLPropEnum(cur, "mode",
+ virDomainMouseModeTypeFromString,
+ VIR_XML_PROP_REQUIRED | VIR_XML_PROP_NONZERO,
+ &def->data.qemuVdagent.mouse) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
/* Parse the source half of the XML definition for a character device,
* where node is the first element of node->children of the parent
* element. def->type must already be valid.
def->data.nmdm.slave = virXMLPropString(sources[0], "slave");
break;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
+ if (virDomainChrSourceDefParseQemuVdagent(def, sources[0], ctxt) < 0)
+ goto error;
+
+ break;
+
case VIR_DOMAIN_CHR_TYPE_LAST:
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_VC:
/* nada */
break;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
+ if (def->data.qemuVdagent.mouse != VIR_DOMAIN_MOUSE_MODE_DEFAULT ||
+ def->data.qemuVdagent.clipboard != VIR_TRISTATE_BOOL_ABSENT) {
+ virBufferAddLit(buf, "<source>\n");
+ virBufferAdjustIndent(buf, 2);
+ if (def->data.qemuVdagent.clipboard != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferEscapeString(buf, "<clipboard copypaste='%s'/>\n",
+ virTristateBoolTypeToString(def->data.qemuVdagent.clipboard));
+ if (def->data.qemuVdagent.mouse != VIR_DOMAIN_MOUSE_MODE_DEFAULT)
+ virBufferEscapeString(buf, "<mouse mode='%s'/>\n",
+ virDomainMouseModeTypeToString(def->data.qemuVdagent.mouse));
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</source>\n");
+ }
+ break;
+
case VIR_DOMAIN_CHR_TYPE_PTY:
case VIR_DOMAIN_CHR_TYPE_DEV:
case VIR_DOMAIN_CHR_TYPE_FILE:
virBufferEscapeString(buf, "<source channel='%s'/>\n",
def->data.spiceport.channel);
break;
-
}
if (def->logfile) {
return 0;
}
-
static int
virDomainChrDefFormat(virBuffer *buf,
virDomainChrDef *def,
VIR_DOMAIN_CHR_TYPE_SPICEVMC,
VIR_DOMAIN_CHR_TYPE_SPICEPORT,
VIR_DOMAIN_CHR_TYPE_NMDM,
+ VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT,
VIR_DOMAIN_CHR_TYPE_LAST
} virDomainChrType;
unsigned int timeout;
};
+typedef enum {
+ VIR_DOMAIN_MOUSE_MODE_DEFAULT = 0,
+ VIR_DOMAIN_MOUSE_MODE_SERVER,
+ VIR_DOMAIN_MOUSE_MODE_CLIENT,
+
+ VIR_DOMAIN_MOUSE_MODE_LAST
+} virDomainMouseMode;
/* The host side information for a character device. */
struct _virDomainChrSourceDef {
struct {
char *channel;
} spiceport;
+ struct {
+ virDomainMouseMode mouse;
+ virTristateBool clipboard;
+ } qemuVdagent;
} data;
char *logfile;
virTristateSwitch logappend;
VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST
} virDomainGraphicsSpiceZlibCompression;
-typedef enum {
- VIR_DOMAIN_MOUSE_MODE_DEFAULT = 0,
- VIR_DOMAIN_MOUSE_MODE_SERVER,
- VIR_DOMAIN_MOUSE_MODE_CLIENT,
-
- VIR_DOMAIN_MOUSE_MODE_LAST
-} virDomainMouseMode;
-
typedef enum {
VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_DEFAULT = 0,
VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_FILTER,
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
break;
</element>
</optional>
<optional>
- <element name="clipboard">
- <attribute name="copypaste">
- <ref name="virYesNo"/>
- </attribute>
- <empty/>
- </element>
+ <ref name="clipboard"/>
</optional>
<optional>
- <element name="mouse">
- <attribute name="mode">
- <choice>
- <value>server</value>
- <value>client</value>
- </choice>
- </attribute>
- <empty/>
- </element>
+ <ref name="mousemode"/>
</optional>
<optional>
<element name="filetransfer">
</element>
</define>
+ <define name="clipboard">
+ <element name="clipboard">
+ <attribute name="copypaste">
+ <ref name="virYesNo"/>
+ </attribute>
+ <empty/>
+ </element>
+ </define>
+ <define name="mousemode">
+ <element name="mouse">
+ <attribute name="mode">
+ <choice>
+ <value>server</value>
+ <value>client</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </define>
<define name="listenElements">
<zeroOrMore>
<element name="listen">
<value>spicevmc</value>
<value>spiceport</value>
<value>nmdm</value>
+ <value>qemu-vdagent</value>
</choice>
</define>
<optional>
<ref name="reconnect"/>
</optional>
- <zeroOrMore>
- <ref name="devSeclabel"/>
- </zeroOrMore>
+ <interleave>
+ <zeroOrMore>
+ <ref name="devSeclabel"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="clipboard"/>
+ </optional>
+ <optional>
+ <ref name="mousemode"/>
+ </optional>
+ </interleave>
</element>
</zeroOrMore>
<optional>
break;
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
default:
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
break;
case VIR_DOMAIN_CHR_TYPE_NMDM:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("vhost-user type '%s' not supported"),
case VIR_DOMAIN_CHR_TYPE_PIPE:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
virReportError(VIR_ERR_OPERATION_FAILED,
_("Hotplug unsupported for char device type '%s'"),
virDomainChrTypeToString(chr->type));
case VIR_DOMAIN_CHR_TYPE_TCP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
break;
case VIR_DOMAIN_CHR_TYPE_FILE: {
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
break;
}
case VIR_DOMAIN_CHR_TYPE_TCP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
ret = 0;
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
ret = 0;
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
break;
}
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
case VIR_DOMAIN_CHR_TYPE_NMDM:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
case VIR_DOMAIN_CHR_TYPE_LAST:
break;
}
case VIR_DOMAIN_CHR_TYPE_TCP:
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
break;
case VIR_DOMAIN_CHR_TYPE_FILE: