[libvirt PATCH v2 3/4] conf: add qemu-vdagent channel
Marc-André Lureau
marcandre.lureau at redhat.com
Fri Mar 25 13:06:43 UTC 2022
Hi
On Thu, Mar 24, 2022 at 11:26 PM Jonathon Jongsma <jjongsma at redhat.com> 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.
>
> Sample configuration:
> <channel type='qemu-vdagent'>
> <target type='virtio' name='com.redhat.spice.0'/>
> <source>
> <clipboard copypaste='yes'/>
> <mouse mode='client'/>
> </source>
> </channel>
>
> Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
I guess you could have added some domain XML tests here, but the next
patch covers it, so
Reviewed-by: Marc-André Lureau <marcandre.lureau at redhat.com>
> ---
> docs/formatdomain.rst | 23 ++++++++++++
> src/conf/domain_conf.c | 62 ++++++++++++++++++++++++++++++-
> src/conf/domain_conf.h | 20 ++++++----
> src/conf/domain_validate.c | 1 +
> src/conf/schemas/domaincommon.rng | 51 ++++++++++++++++---------
> src/qemu/qemu_command.c | 3 ++
> src/qemu/qemu_monitor_json.c | 1 +
> src/qemu/qemu_process.c | 1 +
> src/qemu/qemu_validate.c | 1 +
> src/security/security_apparmor.c | 2 +
> src/security/security_dac.c | 2 +
> tests/testutilsqemu.c | 1 +
> 12 files changed, 140 insertions(+), 28 deletions(-)
>
> diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
> index e492532004..75339c2fda 100644
> --- a/docs/formatdomain.rst
> +++ b/docs/formatdomain.rst
> @@ -6662,6 +6662,29 @@ 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.
> +
> + 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"/>`
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 6f9954638c..3b97de89f4 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:
> @@ -11244,6 +11255,33 @@ virDomainChrSourceDefParseLog(virDomainChrSourceDef *def,
> }
>
>
> +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.
> @@ -11325,6 +11363,12 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDef *def,
> 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:
> @@ -24996,6 +25040,22 @@ virDomainChrSourceDefFormat(virBuffer *buf,
> /* 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:
> @@ -25081,7 +25141,6 @@ virDomainChrSourceDefFormat(virBuffer *buf,
> virBufferEscapeString(buf, "<source channel='%s'/>\n",
> def->data.spiceport.channel);
> break;
> -
> }
>
> if (def->logfile) {
> @@ -25211,7 +25270,6 @@ virDomainChrTargetDefFormat(virBuffer *buf,
> return 0;
> }
>
> -
> static int
> virDomainChrDefFormat(virBuffer *buf,
> virDomainChrDef *def,
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 2b00099431..484fc08f81 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;
> @@ -1266,6 +1267,13 @@ struct _virDomainChrSourceReconnectDef {
> 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 {
> @@ -1307,6 +1315,10 @@ struct _virDomainChrSourceDef {
> struct {
> char *channel;
> } spiceport;
> + struct {
> + virDomainMouseMode mouse;
> + virTristateBool clipboard;
> + } qemuVdagent;
> } data;
> char *logfile;
> virTristateSwitch logappend;
> @@ -1843,14 +1855,6 @@ typedef enum {
> 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,
> 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 34bccee2f5..60aad8cabe 100644
> --- a/src/conf/schemas/domaincommon.rng
> +++ b/src/conf/schemas/domaincommon.rng
> @@ -3965,23 +3965,10 @@
> </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">
> @@ -4070,6 +4057,25 @@
> </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">
> @@ -4470,6 +4476,7 @@
> <value>spicevmc</value>
> <value>spiceport</value>
> <value>nmdm</value>
> + <value>qemu-vdagent</value>
> </choice>
> </define>
>
> @@ -4555,9 +4562,17 @@
> <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>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 7834aece35..1eef9fb6d0 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -1390,6 +1390,7 @@ qemuBuildChardevStr(const virDomainChrSourceDef *dev,
> break;
>
> case VIR_DOMAIN_CHR_TYPE_NMDM:
> + case VIR_DOMAIN_CHR_TYPE_QEMU_VDAGENT:
> case VIR_DOMAIN_CHR_TYPE_LAST:
> default:
> break;
> @@ -1473,6 +1474,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:
> @@ -8613,6 +8615,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..1ac5377449 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -6818,6 +6818,7 @@ qemuMonitorJSONAttachCharDevGetProps(const char *chrID,
> 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));
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 1ed60917ea..423a10738d 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -6834,6 +6834,7 @@ qemuProcessPrepareHostBackendChardevOne(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: {
> diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
> index e0708b8a76..5ad3d914dc 100644
> --- a/src/qemu/qemu_validate.c
> +++ b/src/qemu/qemu_validate.c
> @@ -1991,6 +1991,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_apparmor.c b/src/security/security_apparmor.c
> index 8f7acba980..55c0193940 100644
> --- a/src/security/security_apparmor.c
> +++ b/src/security/security_apparmor.c
> @@ -1021,6 +1021,7 @@ AppArmorSetChardevLabel(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:
> ret = 0;
> break;
> @@ -1083,6 +1084,7 @@ AppArmorSetNetdevLabel(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:
> ret = 0;
> 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/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
>
More information about the libvir-list
mailing list