[libvirt PATCH 0/3] Enable copy/paste for vnc displays

This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics. The guest must be configured with something like the following: <channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel> Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work. More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/ OPEN QUESTIONS: - I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome. - There may be an expectation that vnc clipboard is enabled using the <graphics type='vnc'><clipboard copypaste='yes'/></graphics> similar to what spice offers. In fact, it seems that this is the approach Marc-Andre took when adding copy/paste support in his dbus display patch series. But even for spice, this <clipboard> configuration element is not enough to enable the copy/paste feature. It also requires a 'spicevmc' character device to be added to the domain. Jonathon Jongsma (3): qemu: add capability for qemu-vdagent chardev conf: add qemu-vdagent channel qemu: add support for qemu-vdagent channel docs/formatdomain.rst | 17 ++++++ src/conf/domain_conf.c | 49 ++++++++++++++++- src/conf/domain_conf.h | 7 +++ src/conf/domain_validate.c | 1 + src/conf/schemas/domaincommon.rng | 11 ++++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 13 +++++ src/qemu/qemu_monitor_json.c | 10 ++++ src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + src/security/security_dac.c | 2 + .../caps_6.1.0.x86_64.xml | 1 + .../caps_6.2.0.aarch64.xml | 1 + .../caps_6.2.0.x86_64.xml | 1 + .../caps_7.0.0.x86_64.xml | 1 + .../channel-qemu-vdagent.x86_64-latest.args | 41 ++++++++++++++ .../qemuxml2argvdata/channel-qemu-vdagent.xml | 34 ++++++++++++ tests/qemuxml2argvtest.c | 1 + .../channel-qemu-vdagent.x86_64-latest.xml | 55 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + tests/testutilsqemu.c | 1 + 22 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.xml create mode 100644 tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml -- 2.35.1

Detect whether qemu supports the qemu-vdagent character device. This enables support for copy/paste with VNC graphics. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_6.1.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml | 1 + 6 files changed, 7 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 32980e7330..550463a8e8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -668,6 +668,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 425 */ "blockdev.nbd.tls-hostname", /* QEMU_CAPS_BLOCKDEV_NBD_TLS_HOSTNAME */ + "chardev.qemu-vdagent", /* QEMU_CAPS_CHARDEV_QEMU_VDAGENT */ ); @@ -1628,6 +1629,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "object-add/arg-type/+sev-guest/kernel-hashes", QEMU_CAPS_SEV_GUEST_KERNEL_HASHES }, { "calc-dirty-rate/arg-type/mode", QEMU_CAPS_DIRTYRATE_MODE }, + { "chardev-add/arg-type/backend/+qemu-vdagent", QEMU_CAPS_CHARDEV_QEMU_VDAGENT }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 0a215a11d5..cf2ba9d18d 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -643,6 +643,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 425 */ QEMU_CAPS_BLOCKDEV_NBD_TLS_HOSTNAME, /* tls hostname can be overriden for NBD clients */ + QEMU_CAPS_CHARDEV_QEMU_VDAGENT, /* -chardev qemu-vdagent */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_6.1.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.1.0.x86_64.xml index ba1aecc37e..b15352f5d1 100644 --- a/tests/qemucapabilitiesdata/caps_6.1.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.1.0.x86_64.xml @@ -239,6 +239,7 @@ <flag name='rbd-encryption'/> <flag name='sev-inject-launch-secret'/> <flag name='calc-dirty-rate'/> + <flag name='chardev.qemu-vdagent'/> <version>6001000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100243</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml index 17d563eb5b..0604f975a3 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml @@ -203,6 +203,7 @@ <flag name='query-dirty-rate'/> <flag name='rbd-encryption'/> <flag name='calc-dirty-rate'/> + <flag name='chardev.qemu-vdagent'/> <version>6001050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>61700244</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml index d77907af55..a6c66e091d 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml @@ -241,6 +241,7 @@ <flag name='sev-inject-launch-secret'/> <flag name='calc-dirty-rate'/> <flag name='dirtyrate-param.mode'/> + <flag name='chardev.qemu-vdagent'/> <version>6002000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml index 0f34a341af..7ec33e8496 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml @@ -244,6 +244,7 @@ <flag name='calc-dirty-rate'/> <flag name='dirtyrate-param.mode'/> <flag name='blockdev.nbd.tls-hostname'/> + <flag name='chardev.qemu-vdagent'/> <version>6002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100243</microcodeVersion> -- 2.35.1

Add the ability to configure a qemu-vdagent in guest domains. This device is similar to the spice vdagent channel except that qemu handles the spice-vdagent protocol messages itself rather than routing them over a spice protocol channel. The qemu-vdagent device has two notable configuration options which determine whether qemu will handle particular vdagent features: 'clipboard' and 'mouse'. The 'clipboard' option allows qemu to synchronize its internal clipboard manager with the guest clipboard, which enables client<->guest clipboard synchronization for non-spice guests such as vnc. The 'mouse' option allows absolute mouse positioning to be sent over the vdagent channel rather than using a usb or virtio tablet device. These features are configured with <source/> element. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/formatdomain.rst | 17 +++++++++++ src/conf/domain_conf.c | 49 +++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 7 +++++ src/conf/domain_validate.c | 1 + src/conf/schemas/domaincommon.rng | 11 +++++++ 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index d188de4858..e00015d93e 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -6660,6 +6660,23 @@ types have different ``target`` attributes. ``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. The ``mouse`` attribute allows absolute mouse + events to go through the vdagent rather than using a usb or virito tablet + device. The ``clipboard`` attribute 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. + :since:`Since 8.2.0` :anchor:`<a id="elementsCharHostInterface"/>` diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 153954a0b0..3b09b0389f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -713,6 +713,7 @@ VIR_ENUM_IMPL(virDomainChr, "spicevmc", "spiceport", "nmdm", + "qemu-vdagent", ); VIR_ENUM_IMPL(virDomainChrTcpProtocol, @@ -2698,6 +2699,7 @@ virDomainChrSourceDefGetPath(virDomainChrSourceDef *chr) 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; } @@ -2807,6 +2809,11 @@ virDomainChrSourceDefCopy(virDomainChrSourceDef *dest, 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: @@ -2888,6 +2895,10 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src, 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: @@ -11325,6 +11336,16 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDef *def, def->data.nmdm.slave = virXMLPropString(sources[0], "slave"); break; + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + if (virXMLPropTristateSwitch(sources[0], "mouse", VIR_XML_PROP_NONE, + &def->data.qemuVdagent.mouse) < 0) + goto error; + + if (virXMLPropTristateSwitch(sources[0], "clipboard", VIR_XML_PROP_NONE, + &def->data.qemuVdagent.clipboard) < 0) + goto error; + break; + case VIR_DOMAIN_CHR_TYPE_LAST: case VIR_DOMAIN_CHR_TYPE_NULL: case VIR_DOMAIN_CHR_TYPE_VC: @@ -12418,6 +12439,7 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDef *def, g_autofree char *websocketGenerated = virXMLPropString(node, "websocketGenerated"); g_autofree char *autoport = virXMLPropString(node, "autoport"); xmlNodePtr audioNode; + xmlNodePtr clipboardNode; VIR_XPATH_NODE_AUTORESTORE(ctxt) if (virDomainGraphicsListensParseXML(def, node, ctxt, flags) < 0) @@ -12479,6 +12501,13 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDef *def, def->type) < 0) return -1; + if ((clipboardNode = virXPathNode("./clipboard", ctxt))) { + if (virXMLPropTristateBool(clipboardNode, "copypaste", + VIR_XML_PROP_REQUIRED, + &def->data.vnc.copypaste) < 0) + return -1; + } + return 0; } @@ -24989,6 +25018,20 @@ virDomainChrSourceDefFormat(virBuffer *buf, /* nada */ break; + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + if (def->data.qemuVdagent.mouse != VIR_TRISTATE_SWITCH_ABSENT || + def->data.qemuVdagent.clipboard != VIR_TRISTATE_SWITCH_ABSENT) { + virBufferAddLit(buf, "<source"); + if (def->data.qemuVdagent.clipboard != VIR_TRISTATE_SWITCH_ABSENT) + virBufferEscapeString(buf, " clipboard='%s'", + virTristateSwitchTypeToString(def->data.qemuVdagent.clipboard)); + if (def->data.qemuVdagent.mouse != VIR_TRISTATE_SWITCH_ABSENT) + virBufferEscapeString(buf, " mouse='%s'", + virTristateSwitchTypeToString(def->data.qemuVdagent.mouse)); + virBufferAddLit(buf, "/>\n"); + } + break; + case VIR_DOMAIN_CHR_TYPE_PTY: case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: @@ -25074,7 +25117,6 @@ virDomainChrSourceDefFormat(virBuffer *buf, virBufferEscapeString(buf, "<source channel='%s'/>\n", def->data.spiceport.channel); break; - } if (def->logfile) { @@ -25204,7 +25246,6 @@ virDomainChrTargetDefFormat(virBuffer *buf, return 0; } - static int virDomainChrDefFormat(virBuffer *buf, virDomainChrDef *def, @@ -26630,6 +26671,10 @@ virDomainGraphicsDefFormat(virBuffer *buf, if (def->data.vnc.audioId > 0) virBufferAsprintf(buf, "<audio id='%d'/>\n", def->data.vnc.audioId); + + if (def->data.vnc.copypaste) + virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n", + virTristateBoolTypeToString(def->data.vnc.copypaste)); } if (children) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index b69abfa270..888698d226 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1239,6 +1239,7 @@ typedef enum { 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; @@ -1307,6 +1308,10 @@ struct _virDomainChrSourceDef { struct { char *channel; } spiceport; + struct { + virTristateSwitch mouse; + virTristateSwitch clipboard; + } qemuVdagent; } data; char *logfile; virTristateSwitch logappend; @@ -1905,6 +1910,8 @@ struct _virDomainGraphicsDef { virDomainGraphicsVNCSharePolicy sharePolicy; virTristateBool powerControl; unsigned int audioId; + virTristateBool copypaste; + virTristateBool mousemode; } vnc; struct { char *display; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index d6869e8fd8..c0eb2490a8 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -849,6 +849,7 @@ virDomainChrSourceDefValidate(const virDomainChrSourceDef *src_def, 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; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 9c1b64a644..fc0da07f98 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -4463,6 +4463,7 @@ <value>spicevmc</value> <value>spiceport</value> <value>nmdm</value> + <value>qemu-vdagent</value> </choice> </define> @@ -4551,6 +4552,16 @@ <zeroOrMore> <ref name="devSeclabel"/> </zeroOrMore> + <optional> + <attribute name="mouse"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="clipboard"> + <ref name="virOnOff"/> + </attribute> + </optional> </element> </zeroOrMore> <optional> -- 2.35.1

On 3/22/22 3:47 PM, Jonathon Jongsma wrote:
Add the ability to configure a qemu-vdagent in guest domains. This device is similar to the spice vdagent channel except that qemu handles the spice-vdagent protocol messages itself rather than routing them over a spice protocol channel.
The qemu-vdagent device has two notable configuration options which determine whether qemu will handle particular vdagent features: 'clipboard' and 'mouse'.
The 'clipboard' option allows qemu to synchronize its internal clipboard manager with the guest clipboard, which enables client<->guest clipboard synchronization for non-spice guests such as vnc.
The 'mouse' option allows absolute mouse positioning to be sent over the vdagent channel rather than using a usb or virtio tablet device.
These features are configured with <source/> element.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/formatdomain.rst | 17 +++++++++++ src/conf/domain_conf.c | 49 +++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 7 +++++ src/conf/domain_validate.c | 1 + src/conf/schemas/domaincommon.rng | 11 +++++++ 5 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index d188de4858..e00015d93e 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -6660,6 +6660,23 @@ types have different ``target`` attributes. ``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. The ``mouse`` attribute allows absolute mouse + events to go through the vdagent rather than using a usb or virito tablet + device. The ``clipboard`` attribute 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. + :since:`Since 8.2.0`
:anchor:`<a id="elementsCharHostInterface"/>`
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 153954a0b0..3b09b0389f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -713,6 +713,7 @@ VIR_ENUM_IMPL(virDomainChr, "spicevmc", "spiceport", "nmdm", + "qemu-vdagent", );
VIR_ENUM_IMPL(virDomainChrTcpProtocol, @@ -2698,6 +2699,7 @@ virDomainChrSourceDefGetPath(virDomainChrSourceDef *chr) 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; } @@ -2807,6 +2809,11 @@ virDomainChrSourceDefCopy(virDomainChrSourceDef *dest, 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: @@ -2888,6 +2895,10 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src, 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: @@ -11325,6 +11336,16 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDef *def, def->data.nmdm.slave = virXMLPropString(sources[0], "slave"); break;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + if (virXMLPropTristateSwitch(sources[0], "mouse", VIR_XML_PROP_NONE, + &def->data.qemuVdagent.mouse) < 0) + goto error; + + if (virXMLPropTristateSwitch(sources[0], "clipboard", VIR_XML_PROP_NONE, + &def->data.qemuVdagent.clipboard) < 0) + goto error; + break; + case VIR_DOMAIN_CHR_TYPE_LAST: case VIR_DOMAIN_CHR_TYPE_NULL: case VIR_DOMAIN_CHR_TYPE_VC: @@ -12418,6 +12439,7 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDef *def, g_autofree char *websocketGenerated = virXMLPropString(node, "websocketGenerated"); g_autofree char *autoport = virXMLPropString(node, "autoport"); xmlNodePtr audioNode; + xmlNodePtr clipboardNode; VIR_XPATH_NODE_AUTORESTORE(ctxt)
if (virDomainGraphicsListensParseXML(def, node, ctxt, flags) < 0) @@ -12479,6 +12501,13 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDef *def, def->type) < 0) return -1;
+ if ((clipboardNode = virXPathNode("./clipboard", ctxt))) { + if (virXMLPropTristateBool(clipboardNode, "copypaste", + VIR_XML_PROP_REQUIRED, + &def->data.vnc.copypaste) < 0) + return -1; + } +
By the way, I'm not sure how this stuff got into the patch. It was from an earlier experiment where I was exploring the <graphics> approach that I mentioned in the cover letter. But it should have been removed. Also, I'm aware that this patch creates some build warnings when apparmor is enabled. Will be fixed in next version.
return 0; }
@@ -24989,6 +25018,20 @@ virDomainChrSourceDefFormat(virBuffer *buf, /* nada */ break;
+ case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + if (def->data.qemuVdagent.mouse != VIR_TRISTATE_SWITCH_ABSENT || + def->data.qemuVdagent.clipboard != VIR_TRISTATE_SWITCH_ABSENT) { + virBufferAddLit(buf, "<source"); + if (def->data.qemuVdagent.clipboard != VIR_TRISTATE_SWITCH_ABSENT) + virBufferEscapeString(buf, " clipboard='%s'", + virTristateSwitchTypeToString(def->data.qemuVdagent.clipboard)); + if (def->data.qemuVdagent.mouse != VIR_TRISTATE_SWITCH_ABSENT) + virBufferEscapeString(buf, " mouse='%s'", + virTristateSwitchTypeToString(def->data.qemuVdagent.mouse)); + virBufferAddLit(buf, "/>\n"); + } + break; + case VIR_DOMAIN_CHR_TYPE_PTY: case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: @@ -25074,7 +25117,6 @@ virDomainChrSourceDefFormat(virBuffer *buf, virBufferEscapeString(buf, "<source channel='%s'/>\n", def->data.spiceport.channel); break; - }
if (def->logfile) { @@ -25204,7 +25246,6 @@ virDomainChrTargetDefFormat(virBuffer *buf, return 0; }
- static int virDomainChrDefFormat(virBuffer *buf, virDomainChrDef *def, @@ -26630,6 +26671,10 @@ virDomainGraphicsDefFormat(virBuffer *buf, if (def->data.vnc.audioId > 0) virBufferAsprintf(buf, "<audio id='%d'/>\n", def->data.vnc.audioId); + + if (def->data.vnc.copypaste) + virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n", + virTristateBoolTypeToString(def->data.vnc.copypaste));
same here
}
if (children) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index b69abfa270..888698d226 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1239,6 +1239,7 @@ typedef enum { 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; @@ -1307,6 +1308,10 @@ struct _virDomainChrSourceDef { struct { char *channel; } spiceport; + struct { + virTristateSwitch mouse; + virTristateSwitch clipboard; + } qemuVdagent; } data; char *logfile; virTristateSwitch logappend; @@ -1905,6 +1910,8 @@ struct _virDomainGraphicsDef { virDomainGraphicsVNCSharePolicy sharePolicy; virTristateBool powerControl; unsigned int audioId; + virTristateBool copypaste; + virTristateBool mousemode;
and here
} vnc; struct { char *display; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index d6869e8fd8..c0eb2490a8 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -849,6 +849,7 @@ virDomainChrSourceDefValidate(const virDomainChrSourceDef *src_def, 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;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 9c1b64a644..fc0da07f98 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -4463,6 +4463,7 @@ <value>spicevmc</value> <value>spiceport</value> <value>nmdm</value> + <value>qemu-vdagent</value> </choice> </define>
@@ -4551,6 +4552,16 @@ <zeroOrMore> <ref name="devSeclabel"/> </zeroOrMore> + <optional> + <attribute name="mouse"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="clipboard"> + <ref name="virOnOff"/> + </attribute> + </optional> </element> </zeroOrMore> <optional>

Implement the qemu-vdagent channel introduced in the previous commit. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> --- src/qemu/qemu_command.c | 13 +++++ src/qemu/qemu_monitor_json.c | 10 ++++ src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + src/security/security_dac.c | 2 + .../channel-qemu-vdagent.x86_64-latest.args | 41 ++++++++++++++ .../qemuxml2argvdata/channel-qemu-vdagent.xml | 34 ++++++++++++ tests/qemuxml2argvtest.c | 1 + .../channel-qemu-vdagent.x86_64-latest.xml | 55 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + tests/testutilsqemu.c | 1 + 11 files changed, 160 insertions(+) create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.xml create mode 100644 tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index c836799888..d022b001ac 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1389,6 +1389,17 @@ qemuBuildChardevStr(const virDomainChrSourceDef *dev, dev->data.spiceport.channel); break; + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + virBufferAsprintf(&buf, "qemu-vdagent,id=%s,name=vdagent", + charAlias); + if (dev->data.qemuVdagent.clipboard != VIR_TRISTATE_SWITCH_ABSENT) + virBufferAsprintf(&buf, ",clipboard=%s", + virTristateSwitchTypeToString(dev->data.qemuVdagent.clipboard)); + if (dev->data.qemuVdagent.mouse != VIR_TRISTATE_SWITCH_ABSENT) + virBufferAsprintf(&buf, ",mouse=%s", + virTristateSwitchTypeToString(dev->data.qemuVdagent.mouse)); + break; + case VIR_DOMAIN_CHR_TYPE_NMDM: case VIR_DOMAIN_CHR_TYPE_LAST: default: @@ -1473,6 +1484,7 @@ qemuBuildChardevCommand(virCommand *cmd, 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: @@ -8610,6 +8622,7 @@ qemuInterfaceVhostuserConnect(virCommand *cmd, 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"), diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index d5622bd6d9..fcb46d156d 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6814,6 +6814,16 @@ qemuMonitorJSONAttachCharDevGetProps(const char *chrID, break; + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: + backendType = "qemu-vdagent"; + + if (virJSONValueObjectAdd(&backendData, + "T:clipboard", chr->data.qemuVdagent.clipboard, + "T:mouse", chr->data.qemuVdagent.mouse, + NULL) < 0) + return NULL; + break; + case VIR_DOMAIN_CHR_TYPE_SPICEPORT: case VIR_DOMAIN_CHR_TYPE_PIPE: case VIR_DOMAIN_CHR_TYPE_STDIO: diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1ed60917ea..1b089cb0d5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6833,6 +6833,7 @@ qemuProcessPrepareHostBackendChardevOne(virDomainDeviceDef *dev, case VIR_DOMAIN_CHR_TYPE_UDP: case VIR_DOMAIN_CHR_TYPE_TCP: case VIR_DOMAIN_CHR_TYPE_SPICEVMC: + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT: case VIR_DOMAIN_CHR_TYPE_SPICEPORT: break; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index f27e480696..0c3551338d 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1984,6 +1984,7 @@ qemuValidateDomainChrSourceDef(const virDomainChrSourceDef *def, 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; } diff --git a/src/security/security_dac.c b/src/security/security_dac.c index e9e316551e..5b840f4225 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1555,6 +1555,7 @@ virSecurityDACSetChardevLabelHelper(virSecurityManager *mgr, 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; } @@ -1639,6 +1640,7 @@ virSecurityDACRestoreChardevLabelHelper(virSecurityManager *mgr, 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; } diff --git a/tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args b/tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args new file mode 100644 index 0000000000..651246bdfd --- /dev/null +++ b/tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args @@ -0,0 +1,41 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram \ +-accel tcg \ +-cpu qemu64 \ +-m 214 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ +-device '{"driver":"virtio-serial-pci","id":"virtio-serial1","bus":"pci.0","addr":"0xa"}' \ +-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \ +-device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-format","id":"ide0-0-0","bootindex":1}' \ +-chardev qemu-vdagent,id=charchannel0,name=vdagent,clipboard=on,mouse=on \ +-device '{"driver":"virtserialport","bus":"virtio-serial1.0","nr":3,"chardev":"charchannel0","id":"channel0","name":"com.redhat.spice.0"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-vnc 127.0.0.1:3,audiodev=audio1 \ +-device '{"driver":"cirrus-vga","id":"video0","bus":"pci.0","addr":"0x2"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x3"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/channel-qemu-vdagent.xml b/tests/qemuxml2argvdata/channel-qemu-vdagent.xml new file mode 100644 index 0000000000..63a5949065 --- /dev/null +++ b/tests/qemuxml2argvdata/channel-qemu-vdagent.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <vcpu placement='static' 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-system-x86_64</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='virtio-serial' index='1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'/> + <channel type='qemu-vdagent'> + <target type='virtio' name='com.redhat.spice.0'/> + <address type='virtio-serial' controller='1' bus='0' port='3'/> + <source mouse='on' clipboard='on'/> + </channel> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index e7fecb24d3..9df264df57 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1726,6 +1726,7 @@ mymain(void) DO_TEST("channel-spicevmc", QEMU_CAPS_SPICE, QEMU_CAPS_DEVICE_CIRRUS_VGA); + DO_TEST_CAPS_LATEST("channel-qemu-vdagent"); DO_TEST("channel-virtio-default", QEMU_CAPS_SPICE); DO_TEST_NOCAPS("channel-virtio-unix"); diff --git a/tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml b/tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml new file mode 100644 index 0000000000..13b3b6f750 --- /dev/null +++ b/tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml @@ -0,0 +1,55 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='virtio-serial' index='1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <channel type='qemu-vdagent'> + <source clipboard='on' mouse='on'/> + <target type='virtio' name='com.redhat.spice.0'/> + <address type='virtio-serial' controller='1' bus='0' port='3'/> + </channel> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 31917e5238..22c2cacb6c 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -1464,6 +1464,7 @@ mymain(void) QEMU_CAPS_DEVICE_PL011, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM); + DO_TEST_CAPS_LATEST("channel-qemu-vdagent"); cleanup: if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index fe8908f533..10fdeacaa2 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -1042,6 +1042,7 @@ testQemuPrepareHostBackendChardevOne(virDomainDeviceDef *dev, 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: -- 2.35.1

Hi On Wed, Mar 23, 2022 at 12:47 AM Jonathon Jongsma <jjongsma@redhat.com> wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel>
Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work.
More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/
OPEN QUESTIONS:
- I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome.
I am not convinced <channel> is appropriate either for -chardev qemu-vdagent. That's why in my dbus display series it's an implementation detail (https://patchew.org/Libvirt/20211222194345.766352-1-marcandre.lureau@redhat....), and it's not exposed to the domain XML directly. However I realize that my approach is probably broken, as it looks like I totally missed the associated virtserialport! :) As you say "source" is strange to put those extra channel options too. And the only really valid associated device is a virtserialport of name "com.redhat.spice.0", so what's the point in exposing that detail to the user?
- There may be an expectation that vnc clipboard is enabled using the <graphics type='vnc'><clipboard copypaste='yes'/></graphics> similar to what spice offers. In fact, it seems that this is the approach Marc-Andre took when adding copy/paste support in his dbus display patch series. But even for spice, this <clipboard> configuration element is not enough to enable the copy/paste feature. It also requires a 'spicevmc' character device to be added to the domain.
And my dbus solution is not complete, although it should be possible to add the missing virtserialport.
Jonathon Jongsma (3): qemu: add capability for qemu-vdagent chardev conf: add qemu-vdagent channel qemu: add support for qemu-vdagent channel
docs/formatdomain.rst | 17 ++++++ src/conf/domain_conf.c | 49 ++++++++++++++++- src/conf/domain_conf.h | 7 +++ src/conf/domain_validate.c | 1 + src/conf/schemas/domaincommon.rng | 11 ++++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 13 +++++ src/qemu/qemu_monitor_json.c | 10 ++++ src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + src/security/security_dac.c | 2 + .../caps_6.1.0.x86_64.xml | 1 + .../caps_6.2.0.aarch64.xml | 1 + .../caps_6.2.0.x86_64.xml | 1 + .../caps_7.0.0.x86_64.xml | 1 + .../channel-qemu-vdagent.x86_64-latest.args | 41 ++++++++++++++ .../qemuxml2argvdata/channel-qemu-vdagent.xml | 34 ++++++++++++ tests/qemuxml2argvtest.c | 1 + .../channel-qemu-vdagent.x86_64-latest.xml | 55 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + tests/testutilsqemu.c | 1 + 22 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/channel-qemu-vdagent.xml create mode 100644 tests/qemuxml2xmloutdata/channel-qemu-vdagent.x86_64-latest.xml
-- 2.35.1

On Wed, Mar 23, 2022 at 12:01:19PM +0400, Marc-André Lureau wrote:
Hi
On Wed, Mar 23, 2022 at 12:47 AM Jonathon Jongsma <jjongsma@redhat.com> wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel>
Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work.
More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/
OPEN QUESTIONS:
- I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome.
I am not convinced <channel> is appropriate either for -chardev qemu-vdagent. That's why in my dbus display series it's an implementation detail (https://patchew.org/Libvirt/20211222194345.766352-1-marcandre.lureau@redhat....), and it's not exposed to the domain XML directly. However I realize that my approach is probably broken, as it looks like I totally missed the associated virtserialport! :)
As you say "source" is strange to put those extra channel options too.
And the only really valid associated device is a virtserialport of name "com.redhat.spice.0", so what's the point in exposing that detail to the user?
At the QEMU level we have one serial port with chardv -chardev qemu-vdagent,id=ch1,name=vdagent,clipboard=on -device virtio-serial-pci \ -device virtserialport,chardev=ch1,id=ch1,name=com.redhat.spice.0 but IIUC, we can have multiple frontends - ie both VNC and DBus display, and in that case the clipboard=on property on the chardev will apply to both VNC & DBus displays. We can't control clipboard independantly for the displays, so it is right to put the control in the XML for the <channel> for both VNC and DBus. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 3/23/22 4:17 AM, Daniel P. Berrangé wrote:
On Wed, Mar 23, 2022 at 12:01:19PM +0400, Marc-André Lureau wrote:
Hi
On Wed, Mar 23, 2022 at 12:47 AM Jonathon Jongsma <jjongsma@redhat.com> wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel>
Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work.
More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/
OPEN QUESTIONS:
- I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome.
I am not convinced <channel> is appropriate either for -chardev qemu-vdagent. That's why in my dbus display series it's an implementation detail (https://patchew.org/Libvirt/20211222194345.766352-1-marcandre.lureau@redhat....), and it's not exposed to the domain XML directly. However I realize that my approach is probably broken, as it looks like I totally missed the associated virtserialport! :)
As you say "source" is strange to put those extra channel options too.
And the only really valid associated device is a virtserialport of name "com.redhat.spice.0", so what's the point in exposing that detail to the user?
You could say the same thing about the normal spice vdagent, right? And we allow the user to specify a different virtio name for the spicevmc channel. spice-vdagent does offer a --virtio-serial-port-path option that can be used to connect to a different name within the guest, after all.
At the QEMU level we have one serial port with chardv
-chardev qemu-vdagent,id=ch1,name=vdagent,clipboard=on -device virtio-serial-pci \ -device virtserialport,chardev=ch1,id=ch1,name=com.redhat.spice.0
but IIUC, we can have multiple frontends - ie both VNC and DBus display, and in that case the clipboard=on property on the chardev will apply to both VNC & DBus displays. We can't control clipboard independantly for the displays, so it is right to put the control in the XML for the <channel> for both VNC and DBus.
In addition to <channel>, there are several other xml elements that essentially map to a qemu character device: <serial>, <console>, etc. Would it make more sense to introduce a new element like this for the qemu-vdagent? This might make it easier to introduce new configuration options that wouldn't really fit in the general <channel>. For example, something like: <qemuvdagent> <clipboard copypaste="yes"/> <target type='virtio' name='com.redhat.spice.0'/> </qemuvdagent> Jonathon

On Wed, Mar 23, 2022 at 09:44:53AM -0500, Jonathon Jongsma wrote:
On 3/23/22 4:17 AM, Daniel P. Berrangé wrote:
On Wed, Mar 23, 2022 at 12:01:19PM +0400, Marc-André Lureau wrote:
Hi
On Wed, Mar 23, 2022 at 12:47 AM Jonathon Jongsma <jjongsma@redhat.com> wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel>
Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work.
More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/
OPEN QUESTIONS:
- I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome.
I am not convinced <channel> is appropriate either for -chardev qemu-vdagent. That's why in my dbus display series it's an implementation detail (https://patchew.org/Libvirt/20211222194345.766352-1-marcandre.lureau@redhat....), and it's not exposed to the domain XML directly. However I realize that my approach is probably broken, as it looks like I totally missed the associated virtserialport! :)
As you say "source" is strange to put those extra channel options too.
And the only really valid associated device is a virtserialport of name "com.redhat.spice.0", so what's the point in exposing that detail to the user?
You could say the same thing about the normal spice vdagent, right? And we allow the user to specify a different virtio name for the spicevmc channel. spice-vdagent does offer a --virtio-serial-port-path option that can be used to connect to a different name within the guest, after all.
At the QEMU level we have one serial port with chardv
-chardev qemu-vdagent,id=ch1,name=vdagent,clipboard=on -device virtio-serial-pci \ -device virtserialport,chardev=ch1,id=ch1,name=com.redhat.spice.0
but IIUC, we can have multiple frontends - ie both VNC and DBus display, and in that case the clipboard=on property on the chardev will apply to both VNC & DBus displays. We can't control clipboard independantly for the displays, so it is right to put the control in the XML for the <channel> for both VNC and DBus.
In addition to <channel>, there are several other xml elements that essentially map to a qemu character device: <serial>, <console>, etc. Would it make more sense to introduce a new element like this for the qemu-vdagent? This might make it easier to introduce new configuration options that wouldn't really fit in the general <channel>. For example, something like:
<qemuvdagent> <clipboard copypaste="yes"/> <target type='virtio' name='com.redhat.spice.0'/> </qemuvdagent>
The devices in libvirt represent the guest exposed devics, and that's still a virtio-serial port, so <channel> is the right place. The chardev is merely a backend and doesn't need it own top level XML element. This does mean yuo can use qemu-vgagent chardev with any of serial, parallel, channel, etc but that's harmless from libvirt's POV. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Hi On Wed, Mar 23, 2022 at 6:44 PM Jonathon Jongsma <jjongsma@redhat.com> wrote:
On 3/23/22 4:17 AM, Daniel P. Berrangé wrote:
On Wed, Mar 23, 2022 at 12:01:19PM +0400, Marc-André Lureau wrote:
Hi
On Wed, Mar 23, 2022 at 12:47 AM Jonathon Jongsma <jjongsma@redhat.com> wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/> <target type='virtio' name='com.redhat.spice.0'/> </channel>
Copy/paste sync requires a vnc client that has support for copy/paste commands. Currently virt-viewer does not work, but the version of tigervnc provided by fedora (executable name 'vncviewer') does work.
More details about this device on Gerd's blog: https://www.kraxel.org/blog/2021/05/qemu-cut-paste/
OPEN QUESTIONS:
- I'm not fully convinced that the `<source>` element is the right place for the new `clipboard` / `mouse` configuration options, but I'm not sure that adding a new xml element to the `<channel>` is the right approach either. Suggestions welcome.
I am not convinced <channel> is appropriate either for -chardev qemu-vdagent. That's why in my dbus display series it's an implementation detail (https://patchew.org/Libvirt/20211222194345.766352-1-marcandre.lureau@redhat....), and it's not exposed to the domain XML directly. However I realize that my approach is probably broken, as it looks like I totally missed the associated virtserialport! :)
As you say "source" is strange to put those extra channel options too.
And the only really valid associated device is a virtserialport of name "com.redhat.spice.0", so what's the point in exposing that detail to the user?
You could say the same thing about the normal spice vdagent, right? And we allow the user to specify a different virtio name for the spicevmc
Yes, although the spicevmc -chardev can is configurable via its name to transport various content, whereas qemu-vdagent is limited to spice-vdagent.
channel. spice-vdagent does offer a --virtio-serial-port-path option that can be used to connect to a different name within the guest, after all.
Oh my, it's probably a good idea to deprecate it.
At the QEMU level we have one serial port with chardv
-chardev qemu-vdagent,id=ch1,name=vdagent,clipboard=on -device virtio-serial-pci \ -device virtserialport,chardev=ch1,id=ch1,name=com.redhat.spice.0
but IIUC, we can have multiple frontends - ie both VNC and DBus display, and in that case the clipboard=on property on the chardev will apply to both VNC & DBus displays. We can't control clipboard independantly for the displays, so it is right to put the control in the XML for the <channel> for both VNC and DBus.
In addition to <channel>, there are several other xml elements that essentially map to a qemu character device: <serial>, <console>, etc. Would it make more sense to introduce a new element like this for the qemu-vdagent? This might make it easier to introduce new configuration options that wouldn't really fit in the general <channel>. For example, something like:
<qemuvdagent> <clipboard copypaste="yes"/> <target type='virtio' name='com.redhat.spice.0'/> </qemuvdagent>
Jonathon

On Tue, Mar 22, 2022 at 03:47:03PM -0500, Jonathon Jongsma wrote:
This patch series enables support for the qemu-vdagent character device which enables copy/paste support between guest and client when using vnc graphics.
The guest must be configured with something like the following:
<channel type='qemu-vdagent'> <source clipboard='on' mouse='on'/>
I'd suggest we represent these the same way as spice for consistency ie elements rather than attributes <channel type='qemu-vdagent'> <source> <clipboard copypaste='no'/> <mouse mode='client'/> </source> <target type='virtio' name='com.redhat.spice.0'/> </channel> compare with how the vdagent pieces in <graphics> appear: <graphics type='spice' port='-1' tlsPort='-1' autoport='yes'> <channel name='main' mode='secure'/> <channel name='record' mode='insecure'/> <image compression='auto_glz'/> <streaming mode='filter'/> <clipboard copypaste='no'/> <mouse mode='client'/> <filetransfer enable='no'/> <gl enable='yes' rendernode='/dev/dri/by-path/pci-0000:00:02.0-render'/> </graphics> With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (3)
-
Daniel P. Berrangé
-
Jonathon Jongsma
-
Marc-André Lureau