[libvirt PATCH v2 00/15] WIP/RFC: add QEMU "-display dbus" support

From: Marc-André Lureau <marcandre.lureau@redhat.com> Hi, This series implements supports for the upcoming QEMU "-display dbus" support. Development is still in progress, but I hope to land the QEMU support early in 6.3 (last version posted: https://patchew.org/QEMU/20211009210838.2219430-1-marcandre.lureau@redhat.co...). By default, libvirt will start a private VM bus (sharing and reusing the existing "vmstate" VM bus & code). The feature set should cover the needs to replace Spice as local client of choice, including 3daccel/dmabuf, audio, clipboard sharing, usb redirection, and arbitrary chardev/channels (for serial etc). The test Gtk4 client is also in progress, currently in development at https://gitlab.com/marcandre.lureau/qemu-display/. A few dependencies, such as zbus, require an upcoming release. virt-viewer & boxes will need a port to Gtk4 to make use of the shared widget. Comments welcome, as we can still adjust the QEMU side etc. thanks v2: after Michal review - split patches for conf & qemu changes - start D-Bus in qemuExtDevicesStart() - use symlinks for xml2xml tests - teach domdisplay to return a dbus URI - rebase & bug fixes Marc-André Lureau (15): qemu: add chardev-vdagent capability check qemu: add -display dbus capability check (to update to 6.3) conf: add <graphics type='dbus'> qemu: start the D-Bus daemon for the display qemu: add -display dbus support virsh: refactor/split cmdDomDisplay() virsh: report the D-Bus bus URI for domdisplay conf: add <audio type='dbus'> support qemu: add audio type 'dbus' conf: add dbus <clipboard> qemu: add dbus clipboard sharing conf: add <serial type='dbus'> qemu: add -chardev dbus support qemu: add usbredir type 'dbus' docs: document <graphics> type dbus docs/formatdomain.rst | 43 +- docs/schemas/basictypes.rng | 7 + docs/schemas/domaincommon.rng | 71 ++++ src/bhyve/bhyve_command.c | 1 + src/conf/domain_conf.c | 141 ++++++- src/conf/domain_conf.h | 15 + src/conf/domain_validate.c | 41 +- src/libxl/libxl_conf.c | 1 + src/qemu/qemu_capabilities.c | 6 + src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_command.c | 80 +++- src/qemu/qemu_domain.c | 1 + src/qemu/qemu_driver.c | 10 +- src/qemu/qemu_extdevice.c | 13 + src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_monitor_json.c | 10 + src/qemu/qemu_process.c | 40 +- src/qemu/qemu_validate.c | 33 ++ src/security/security_dac.c | 2 + src/vmx/vmx.c | 1 + .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 1 + .../caps_6.1.0.x86_64.xml | 1 + .../caps_6.2.0.aarch64.xml | 1 + .../caps_6.2.0.x86_64.replies | 10 +- .../caps_6.2.0.x86_64.xml | 2 + .../graphics-dbus-address.args | 30 ++ .../graphics-dbus-address.xml | 35 ++ .../qemuxml2argvdata/graphics-dbus-audio.args | 33 ++ .../qemuxml2argvdata/graphics-dbus-audio.xml | 45 +++ .../graphics-dbus-chardev.args | 32 ++ .../graphics-dbus-chardev.xml | 43 ++ .../graphics-dbus-clipboard.args | 31 ++ .../graphics-dbus-clipboard.xml | 35 ++ tests/qemuxml2argvdata/graphics-dbus-p2p.args | 30 ++ tests/qemuxml2argvdata/graphics-dbus-p2p.xml | 33 ++ .../graphics-dbus-usbredir.args | 34 ++ .../graphics-dbus-usbredir.xml | 30 ++ tests/qemuxml2argvdata/graphics-dbus.args | 30 ++ tests/qemuxml2argvdata/graphics-dbus.xml | 33 ++ tests/qemuxml2argvtest.c | 21 + .../graphics-dbus-address.xml | 1 + .../graphics-dbus-audio.xml | 1 + .../graphics-dbus-chardev.xml | 1 + .../graphics-dbus-clipboard.xml | 1 + .../qemuxml2xmloutdata/graphics-dbus-p2p.xml | 1 + tests/qemuxml2xmloutdata/graphics-dbus.xml | 1 + tests/qemuxml2xmltest.c | 20 + tools/virsh-domain.c | 366 +++++++++--------- 50 files changed, 1231 insertions(+), 192 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-address.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-address.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-audio.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-audio.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-chardev.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-chardev.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-clipboard.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-clipboard.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-p2p.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-p2p.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-usbredir.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-usbredir.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-address.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-audio.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-chardev.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-clipboard.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-p2p.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus.xml -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@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 + 5 files changed, 6 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 0e6e73774a04..6fee5bc1a418 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -652,6 +652,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "device.json", /* QEMU_CAPS_DEVICE_JSON */ "query-dirty-rate", /* QEMU_CAPS_QUERY_DIRTY_RATE */ "rbd-encryption", /* QEMU_CAPS_RBD_ENCRYPTION */ + "chardev-vdagent", /* QEMU_CAPS_CHARDEV_VDAGENT */ ); @@ -1571,6 +1572,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "query-named-block-nodes/arg-type/flat", QEMU_CAPS_QMP_QUERY_NAMED_BLOCK_NODES_FLAT }, { "screendump/arg-type/device", QEMU_CAPS_SCREENDUMP_DEVICE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, + { "chardev-add/arg-type/backend/+qemu-vdagent", QEMU_CAPS_CHARDEV_VDAGENT }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 716e09123c33..15547e59c83d 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -631,6 +631,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_DEVICE_JSON, /* -device accepts JSON */ QEMU_CAPS_QUERY_DIRTY_RATE, /* accepts query-dirty-rate */ QEMU_CAPS_RBD_ENCRYPTION, /* Ceph RBD encryption support */ + QEMU_CAPS_CHARDEV_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 1f4f49eb34ad..75cf496e7712 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='piix4.acpi-root-pci-hotplug'/> <flag name='query-dirty-rate'/> <flag name='rbd-encryption'/> + <flag name='chardev-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 9662214cd882..032776706d7e 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_6.2.0.aarch64.xml @@ -204,6 +204,7 @@ <flag name='device.json'/> <flag name='query-dirty-rate'/> <flag name='rbd-encryption'/> + <flag name='chardev-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 39179916c5d3..145137ddfa08 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml @@ -240,6 +240,7 @@ <flag name='device.json'/> <flag name='query-dirty-rate'/> <flag name='rbd-encryption'/> + <flag name='chardev-vdagent'/> <version>6001050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies | 10 +++++++++- tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 6fee5bc1a418..495f7171da1c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -653,6 +653,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "query-dirty-rate", /* QEMU_CAPS_QUERY_DIRTY_RATE */ "rbd-encryption", /* QEMU_CAPS_RBD_ENCRYPTION */ "chardev-vdagent", /* QEMU_CAPS_CHARDEV_VDAGENT */ + "display-dbus", /* QEMU_CAPS_DISPLAY_DBUS */ ); @@ -1573,6 +1574,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "screendump/arg-type/device", QEMU_CAPS_SCREENDUMP_DEVICE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "chardev-add/arg-type/backend/+qemu-vdagent", QEMU_CAPS_CHARDEV_VDAGENT }, + { "query-display-options/ret-type/+dbus", QEMU_CAPS_DISPLAY_DBUS }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 15547e59c83d..4c6a7c020b73 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -632,6 +632,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_QUERY_DIRTY_RATE, /* accepts query-dirty-rate */ QEMU_CAPS_RBD_ENCRYPTION, /* Ceph RBD encryption support */ QEMU_CAPS_CHARDEV_VDAGENT, /* -chardev qemu-vdagent */ + QEMU_CAPS_DISPLAY_DBUS, /* -display dbus */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies index 69d3b1b12a6e..e823ad1188b8 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies @@ -5000,6 +5000,10 @@ { "case": "spice-app", "type": "0" + }, + { + "case": "dbus", + "type": "0" } ], "members": [ @@ -11456,6 +11460,9 @@ }, { "name": "spice-app" + }, + { + "name": "dbus" } ], "meta-type": "enum", @@ -11465,7 +11472,8 @@ "sdl", "egl-headless", "curses", - "spice-app" + "spice-app", + "dbus" ] }, { diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml index 145137ddfa08..8001ddde8887 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='query-dirty-rate'/> <flag name='rbd-encryption'/> <flag name='chardev-vdagent'/> + <flag name='display-dbus'/> <version>6001050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/schemas/basictypes.rng | 7 ++ docs/schemas/domaincommon.rng | 33 ++++++++ src/conf/domain_conf.c | 78 ++++++++++++++++++- src/conf/domain_conf.h | 8 ++ src/conf/domain_validate.c | 9 ++- src/libxl/libxl_conf.c | 1 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_command.c | 2 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_driver.c | 6 +- src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_process.c | 4 + src/qemu/qemu_validate.c | 1 + src/vmx/vmx.c | 1 + .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 1 + .../graphics-dbus-address.xml | 35 +++++++++ tests/qemuxml2argvdata/graphics-dbus-p2p.xml | 33 ++++++++ tests/qemuxml2argvdata/graphics-dbus.xml | 33 ++++++++ .../graphics-dbus-address.xml | 1 + .../qemuxml2xmloutdata/graphics-dbus-p2p.xml | 1 + tests/qemuxml2xmloutdata/graphics-dbus.xml | 1 + tests/qemuxml2xmltest.c | 10 +++ 24 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-address.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus-p2p.xml create mode 100644 tests/qemuxml2argvdata/graphics-dbus.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-address.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-p2p.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus.xml diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng index a221ff6295c0..ae4d5682229c 100644 --- a/docs/schemas/basictypes.rng +++ b/docs/schemas/basictypes.rng @@ -220,6 +220,13 @@ </define> <!--======================================================================--> + <!-- A D-Bus server address: https://dbus.freedesktop.org/doc/dbus-specification.html#addresses --> + <define name="dbusAddr"> + <data type="string"> + <param name="pattern">.+</param> + </data> + </define> + <!-- An ipv4 "dotted quad" address --> <define name="ipv4Addr"> <data type="string"> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index f01b7a64704b..1dba199db7ec 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3996,6 +3996,39 @@ </optional> </interleave> </group> + <group> + <attribute name="type"> + <value>dbus</value> + </attribute> + <optional> + <choice> + <group> + <attribute name="address"> + <ref name="dbusAddr"/> + </attribute> + </group> + <group> + <attribute name="p2p"> + <ref name="virYesNo"/> + </attribute> + </group> + </choice> + </optional> + <interleave> + <optional> + <element name="gl"> + <attribute name="enable"> + <ref name="virYesNo"/> + </attribute> + <optional> + <attribute name="rendernode"> + <ref name="absFilePath"/> + </attribute> + </optional> + </element> + </optional> + </interleave> + </group> <group> <attribute name="type"> <value>rdp</value> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index bdcc3dc2c12f..11eb1422d8c1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -911,6 +911,7 @@ VIR_ENUM_IMPL(virDomainGraphics, "desktop", "spice", "egl-headless", + "dbus", ); VIR_ENUM_IMPL(virDomainGraphicsListen, @@ -1891,6 +1892,11 @@ void virDomainGraphicsDefFree(virDomainGraphicsDef *def) g_free(def->data.egl_headless.rendernode); break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + g_free(def->data.dbus.address); + g_free(def->data.dbus.rendernode); + break; + case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -12866,6 +12872,39 @@ virDomainGraphicsDefParseXMLEGLHeadless(virDomainGraphicsDef *def, } +static int +virDomainGraphicsDefParseXMLDBus(virDomainGraphicsDef *def, + xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt) + xmlNodePtr cur; + virTristateBool p2p; + + if (virXMLPropTristateBool(node, "p2p", VIR_XML_PROP_NONE, + &p2p) < 0) + return -1; + def->data.dbus.p2p = p2p == VIR_TRISTATE_BOOL_YES; + + def->data.dbus.address = virXMLPropString(node, "address"); + def->data.dbus.fromConfig = def->data.dbus.address != NULL; + + ctxt->node = node; + + if ((cur = virXPathNode("./gl", ctxt))) { + def->data.dbus.rendernode = virXMLPropString(cur, + "rendernode"); + + if (virXMLPropTristateBool(cur, "enable", + VIR_XML_PROP_REQUIRED, + &def->data.dbus.gl) < 0) + return -1; + } + + return 0; +} + + virDomainGraphicsDef * virDomainGraphicsDefNew(virDomainXMLOption *xmlopt) { @@ -12940,6 +12979,10 @@ virDomainGraphicsDefParseXML(virDomainXMLOption *xmlopt, case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: virDomainGraphicsDefParseXMLEGLHeadless(def, node, ctxt); break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + if (virDomainGraphicsDefParseXMLDBus(def, node, ctxt) < 0) + goto error; + break; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -26622,6 +26665,27 @@ virDomainGraphicsDefFormat(virBuffer *buf, def->data.egl_headless.rendernode); virBufferAddLit(buf, "/>\n"); break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + if (def->data.dbus.p2p) + virBufferAddLit(buf, " p2p='yes'"); + if (def->data.dbus.address) + virBufferAsprintf(buf, " address='%s'", + def->data.dbus.address); + + if (!def->data.dbus.gl) + break; + + if (!children) { + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + children = true; + } + + virBufferAsprintf(buf, "<gl enable='%s'", + virTristateBoolTypeToString(def->data.dbus.gl)); + virBufferEscapeString(buf, " rendernode='%s'", def->data.dbus.rendernode); + virBufferAddLit(buf, "/>\n"); + break; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -31336,6 +31400,11 @@ virDomainGraphicsDefHasOpenGL(const virDomainDef *def) case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: return true; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + if (graphics->data.dbus.gl == VIR_TRISTATE_BOOL_YES) + return true; + + continue; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -31351,7 +31420,8 @@ virDomainGraphicsSupportsRenderNode(const virDomainGraphicsDef *graphics) bool ret = false; if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE || - graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS) + graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS || + graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_DBUS) ret = true; return ret; @@ -31370,6 +31440,9 @@ virDomainGraphicsGetRenderNode(const virDomainGraphicsDef *graphics) case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: ret = graphics->data.egl_headless.rendernode; break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + ret = graphics->data.dbus.rendernode; + break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_VNC: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: @@ -31391,6 +31464,9 @@ virDomainGraphicsNeedsAutoRenderNode(const virDomainGraphicsDef *graphics) if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && graphics->data.spice.gl != VIR_TRISTATE_BOOL_YES) return false; + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_DBUS && + graphics->data.dbus.gl != VIR_TRISTATE_BOOL_YES) + return false; if (virDomainGraphicsGetRenderNode(graphics)) return false; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index c0c07ea6ba24..384b85db3a2c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1733,6 +1733,7 @@ typedef enum { VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP, VIR_DOMAIN_GRAPHICS_TYPE_SPICE, VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS, + VIR_DOMAIN_GRAPHICS_TYPE_DBUS, VIR_DOMAIN_GRAPHICS_TYPE_LAST } virDomainGraphicsType; @@ -1916,6 +1917,13 @@ struct _virDomainGraphicsDef { struct { char *rendernode; } egl_headless; + struct { + bool p2p; + char *address; + char *rendernode; + virTristateBool gl; + bool fromConfig; /* true if the @address is config file originated */ + } dbus; } data; /* nListens, listens, and *port are only useful if type is vnc, * rdp, or spice. They've been extracted from the union only to diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index a4271f12479f..c13472516fec 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2240,8 +2240,15 @@ static int virDomainGraphicsDefValidate(const virDomainDef *def, const virDomainGraphicsDef *graphics) { - if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { return virDomainEnsureAudioID(def, graphics->data.vnc.audioId); + } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_DBUS) { + if (graphics->data.dbus.p2p && graphics->data.dbus.address) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("D-Bus p2p with an address is not supported")); + return -1; + } + } return 0; } diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index f37c2281390b..398f29ad3257 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1551,6 +1551,7 @@ libxlMakeVfb(virPortAllocatorRange *graphicsports, case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 495f7171da1c..12d3ca8c903d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6081,6 +6081,8 @@ virQEMUCapsFillDomainDeviceGraphicsCaps(virQEMUCaps *qemuCaps, VIR_DOMAIN_CAPS_ENUM_SET(dev->type, VIR_DOMAIN_GRAPHICS_TYPE_SPICE); if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_EGL_HEADLESS)) VIR_DOMAIN_CAPS_ENUM_SET(dev->type, VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DISPLAY_DBUS)) + VIR_DOMAIN_CAPS_ENUM_SET(dev->type, VIR_DOMAIN_GRAPHICS_TYPE_DBUS); } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index c47998aabdf1..0fb55fc94365 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8672,6 +8672,7 @@ qemuBuildGraphicsCommandLine(virQEMUDriverConfig *cfg, graphics) < 0) return -1; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: break; case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: @@ -10444,6 +10445,7 @@ qemuBuildCommandLineValidate(virQEMUDriver *driver, case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: ++egl_headless; break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 2c10f185f86c..32cb1d8713d5 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3453,6 +3453,7 @@ qemuDomainDefSuggestDefaultAudioBackend(virQEMUDriver *driver, case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: break; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: default: diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b88fb470323a..006b893b80bf 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15668,12 +15668,13 @@ qemuDomainOpenGraphics(virDomainPtr dom, case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: protocol = "spice"; break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Can only open VNC or SPICE graphics backends, not %s"), + _("Can only open VNC, SPICE or D-Bus p2p graphics backends, not %s"), virDomainGraphicsTypeToString(vm->def->graphics[idx]->type)); goto endjob; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: @@ -15736,12 +15737,13 @@ qemuDomainOpenGraphicsFD(virDomainPtr dom, case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: protocol = "spice"; break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Can only open VNC or SPICE graphics backends, not %s"), + _("Can only open VNC, SPICE or D-Bus p2p graphics backends, not %s"), virDomainGraphicsTypeToString(vm->def->graphics[idx]->type)); goto cleanup; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 71c068619042..421ead96ecd5 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -4378,6 +4378,7 @@ qemuDomainChangeGraphics(virQEMUDriver *driver, case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to change config on '%s' graphics type"), type); break; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6b83a571b916..53b5dcaff5d7 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4782,6 +4782,7 @@ qemuProcessGraphicsReservePorts(virDomainGraphicsDef *graphics, case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -4821,6 +4822,7 @@ qemuProcessGraphicsAllocatePorts(virQEMUDriver *driver, case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -4977,6 +4979,7 @@ qemuProcessGraphicsSetupListen(virQEMUDriver *driver, case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -5281,6 +5284,7 @@ qemuProcessStartValidateGraphics(virDomainObj *vm) case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 1de6e0510128..05792f4e4c0a 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4170,6 +4170,7 @@ qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index d3540acd84a8..2c48bbc5e812 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -3446,6 +3446,7 @@ virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOption *xmlopt, virDomainDef case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported graphics type '%s'"), virDomainGraphicsTypeToString(def->graphics[i]->type)); diff --git a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml index 9d68c0a404bb..303378e3e1fb 100644 --- a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml @@ -154,6 +154,7 @@ <value>vnc</value> <value>spice</value> <value>egl-headless</value> + <value>dbus</value> </enum> </graphics> <video supported='yes'> diff --git a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml index 8db840faac9e..04b5f72e0dde 100644 --- a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml @@ -160,6 +160,7 @@ <value>vnc</value> <value>spice</value> <value>egl-headless</value> + <value>dbus</value> </enum> </graphics> <video supported='yes'> diff --git a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml index 0f89790b60e2..a946f96b1db0 100644 --- a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml @@ -154,6 +154,7 @@ <value>vnc</value> <value>spice</value> <value>egl-headless</value> + <value>dbus</value> </enum> </graphics> <video supported='yes'> diff --git a/tests/qemuxml2argvdata/graphics-dbus-address.xml b/tests/qemuxml2argvdata/graphics-dbus-address.xml new file mode 100644 index 000000000000..1e8526b2748e --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-address.xml @@ -0,0 +1,35 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'> + <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='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' address='unix:path=/tmp/foo'> + <gl enable='yes' rendernode='/dev/dri/foo'/> + </graphics> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/graphics-dbus-p2p.xml b/tests/qemuxml2argvdata/graphics-dbus-p2p.xml new file mode 100644 index 000000000000..a99e695471cb --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-p2p.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'> + <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='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/graphics-dbus.xml b/tests/qemuxml2argvdata/graphics-dbus.xml new file mode 100644 index 000000000000..be8442b3cdb3 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'> + <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='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/graphics-dbus-address.xml b/tests/qemuxml2xmloutdata/graphics-dbus-address.xml new file mode 120000 index 000000000000..c2ff4590c161 --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus-address.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus-address.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/graphics-dbus-p2p.xml b/tests/qemuxml2xmloutdata/graphics-dbus-p2p.xml new file mode 120000 index 000000000000..8f705412b30b --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus-p2p.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus-p2p.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/graphics-dbus.xml b/tests/qemuxml2xmloutdata/graphics-dbus.xml new file mode 120000 index 000000000000..e52af445d941 --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index b535cda1879f..ba891df0dfb6 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -373,6 +373,16 @@ mymain(void) QEMU_CAPS_VNC, QEMU_CAPS_EGL_HEADLESS); + DO_TEST("graphics-dbus", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-address", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-p2p", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); + DO_TEST_CAPS_ARCH_LATEST("default-video-type-aarch64", "aarch64"); DO_TEST_CAPS_ARCH_LATEST("default-video-type-ppc64", "ppc64"); DO_TEST_CAPS_ARCH_LATEST("default-video-type-riscv64", "riscv64"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Start the daemon if necessary (it is already stopped in qemuProcessStop) Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_extdevice.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c index 537b13039488..8ada8324bed1 100644 --- a/src/qemu/qemu_extdevice.c +++ b/src/qemu/qemu_extdevice.c @@ -201,6 +201,19 @@ qemuExtDevicesStart(virQEMUDriver *driver, } } + for (i = 0; i < def->ngraphics; i++) { + virDomainGraphicsDef *graphics = def->graphics[i]; + + if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_DBUS) + continue; + + if (graphics->data.dbus.p2p || graphics->data.dbus.fromConfig) + continue; + + if (qemuDBusStart(driver, vm) < 0) + return -1; + } + return 0; } -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> By default, libvirt will start a private bus and tell QEMU to connect to it. Instead, a D-Bus "address" to connect to can be specified, or the p2p mode enabled. D-Bus display works best with GL & a rendernode, which can be specified with <gl> child element. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_command.c | 41 ++++++++++++++++++- src/qemu/qemu_driver.c | 4 ++ src/qemu/qemu_process.c | 36 +++++++++++++++- .../graphics-dbus-address.args | 30 ++++++++++++++ tests/qemuxml2argvdata/graphics-dbus-p2p.args | 30 ++++++++++++++ tests/qemuxml2argvdata/graphics-dbus.args | 30 ++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++ 7 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-address.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-p2p.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 0fb55fc94365..7265aae0f503 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8637,6 +8637,36 @@ qemuBuildGraphicsEGLHeadlessCommandLine(virQEMUDriverConfig *cfg G_GNUC_UNUSED, } +static int +qemuBuildGraphicsDBusCommandLine(virCommand *cmd, + virDomainGraphicsDef *graphics) +{ + g_auto(virBuffer) opt = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&opt, "dbus"); + + if (graphics->data.dbus.p2p) { + virBufferAddLit(&opt, ",p2p=on"); + } else { + virBufferAddLit(&opt, ",addr="); + virQEMUBuildBufferEscapeComma(&opt, graphics->data.dbus.address); + } + if (graphics->data.dbus.gl != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(&opt, ",gl=%s", + virTristateSwitchTypeToString(graphics->data.dbus.gl)); + if (graphics->data.dbus.rendernode) { + virBufferAddLit(&opt, ",rendernode="); + virQEMUBuildBufferEscapeComma(&opt, + graphics->data.dbus.rendernode); + } + + virCommandAddArg(cmd, "-display"); + virCommandAddArgBuffer(cmd, &opt); + + return 0; +} + + static int qemuBuildGraphicsCommandLine(virQEMUDriverConfig *cfg, virCommand *cmd, @@ -8672,7 +8702,11 @@ qemuBuildGraphicsCommandLine(virQEMUDriverConfig *cfg, graphics) < 0) return -1; + break; case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + if (qemuBuildGraphicsDBusCommandLine(cmd, graphics) < 0) + return -1; + break; case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: @@ -10401,6 +10435,7 @@ qemuBuildCommandLineValidate(virQEMUDriver *driver, int vnc = 0; int spice = 0; int egl_headless = 0; + int dbus = 0; if (!driver->privileged) { /* If we have no cgroups then we can have no tunings that @@ -10446,6 +10481,8 @@ qemuBuildCommandLineValidate(virQEMUDriver *driver, ++egl_headless; break; case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + ++dbus; + break; case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: @@ -10453,10 +10490,10 @@ qemuBuildCommandLineValidate(virQEMUDriver *driver, } } - if (sdl > 1 || vnc > 1 || spice > 1 || egl_headless > 1) { + if (sdl > 1 || vnc > 1 || spice > 1 || egl_headless > 1 || dbus > 1) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("only 1 graphics device of each type " - "(sdl, vnc, spice, headless) is supported")); + "(sdl, vnc, spice, headless, dbus) is supported")); return -1; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 006b893b80bf..b06f4b2e4126 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15669,6 +15669,8 @@ qemuDomainOpenGraphics(virDomainPtr dom, protocol = "spice"; break; case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + protocol = "@dbus-display"; + break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: @@ -15738,6 +15740,8 @@ qemuDomainOpenGraphicsFD(virDomainPtr dom, protocol = "spice"; break; case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + protocol = "@dbus-display"; + break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 53b5dcaff5d7..0f8add10a754 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4952,6 +4952,22 @@ qemuProcessGraphicsSetupNetworkAddress(virDomainGraphicsListenDef *glisten, } +static int +qemuProcessGraphicsSetupDBus(virQEMUDriver *driver, + virDomainGraphicsDef *graphics, + virDomainObj *vm) +{ + if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_DBUS) + return 0; + + if (!graphics->data.dbus.p2p && !graphics->data.dbus.address) { + graphics->data.dbus.address = qemuDBusGetAddress(driver, vm); + } + + return 0; +} + + static int qemuProcessGraphicsSetupListen(virQEMUDriver *driver, virDomainGraphicsDef *graphics, @@ -5043,16 +5059,29 @@ qemuProcessGraphicsSetupRenderNode(virDomainGraphicsDef *graphics, return 0; /* Don't bother picking a DRM node if QEMU doesn't support it. */ - if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { + switch (graphics->type) { + case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_RENDERNODE)) return 0; rendernode = &graphics->data.spice.rendernode; - } else { + break; + case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_EGL_HEADLESS_RENDERNODE)) return 0; rendernode = &graphics->data.egl_headless.rendernode; + break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + rendernode = &graphics->data.dbus.rendernode; + break; + case VIR_DOMAIN_GRAPHICS_TYPE_SDL: + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + case VIR_DOMAIN_GRAPHICS_TYPE_RDP: + case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: + case VIR_DOMAIN_GRAPHICS_TYPE_LAST: + virReportEnumRangeError(virDomainGraphicsType, graphics->type); + break; } if (!(*rendernode = virHostGetDRMRenderNode())) @@ -5080,6 +5109,9 @@ qemuProcessSetupGraphics(virQEMUDriver *driver, if (qemuProcessGraphicsSetupListen(driver, graphics, vm) < 0) return -1; + + if (qemuProcessGraphicsSetupDBus(driver, graphics, vm) < 0) + return -1; } if (allocate) { diff --git a/tests/qemuxml2argvdata/graphics-dbus-address.args b/tests/qemuxml2argvdata/graphics-dbus-address.args new file mode 100644 index 000000000000..5332728a6175 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-address.args @@ -0,0 +1,30 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-display dbus,addr=unix:path=/tmp/foo,gl=on,rendernode=/dev/dri/foo \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/graphics-dbus-p2p.args b/tests/qemuxml2argvdata/graphics-dbus-p2p.args new file mode 100644 index 000000000000..e90a0eeeea4d --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-p2p.args @@ -0,0 +1,30 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-display dbus,p2p=on \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/graphics-dbus.args b/tests/qemuxml2argvdata/graphics-dbus.args new file mode 100644 index 000000000000..80ab9ed7b477 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus.args @@ -0,0 +1,30 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-display dbus,addr=unix:path=/bad-test-used-env-xdg-runtime-dir/libvirt/qemu/run/dbus/-1-QEMUGuest1-dbus.sock \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 5e4cd7389c02..d024a657af8e 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1513,6 +1513,13 @@ mymain(void) DO_TEST_CAPS_LATEST_PARSE_ERROR("graphics-spice-invalid-egl-headless"); DO_TEST_CAPS_LATEST("graphics-spice-gl-auto-rendernode"); + DO_TEST("graphics-dbus", + QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-address", + QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-p2p", + QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST_NOCAPS("input-usbmouse"); DO_TEST_NOCAPS("input-usbtablet"); DO_TEST_NOCAPS("misc-acpi"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> The function is large and quite complex. Move the inner loop for each scheme in a separate function cmdDomDisplayScheme(). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tools/virsh-domain.c | 341 +++++++++++++++++++++---------------------- 1 file changed, 169 insertions(+), 172 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index e179e24ca9c3..fbe8ec3ea782 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11441,209 +11441,213 @@ static const vshCmdOptDef opts_domdisplay[] = { }; static bool -cmdDomDisplay(vshControl *ctl, const vshCmd *cmd) +cmdDomDisplayScheme(vshControl *ctl, const char *scheme, + xmlXPathContext *ctxt, virBuffer *buf) { - g_autoptr(xmlDoc) xml = NULL; - g_autoptr(xmlXPathContext) ctxt = NULL; - g_autoptr(virshDomain) dom = NULL; - g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; - bool ret = false; - char *xpath = NULL; - char *listen_addr = NULL; - int port, tls_port = 0; - char *type_conn = NULL; - char *sockpath = NULL; - char *passwd = NULL; - char *output = NULL; - const char *scheme[] = { "vnc", "spice", "rdp", NULL }; - const char *type = NULL; - int iter = 0; - int tmp; - int flags = 0; - bool params = false; - bool all = vshCommandOptBool(cmd, "all"); + g_autofree char *xpath = NULL; + g_autofree char *listen_addr = NULL; + g_autofree char *type_conn = NULL; + g_autofree char *sockpath = NULL; + g_autofree char *passwd = NULL; const char *xpath_fmt = "string(/domain/devices/graphics[@type='%s']/%s)"; virSocketAddr addr; + int port, tls_port = 0; + bool params = false; + int tmp; - VSH_EXCLUSIVE_OPTIONS("all", "type"); + /* Create our XPATH lookup for the current display's port */ + xpath = g_strdup_printf(xpath_fmt, scheme, "@port"); - if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) - return false; + /* Attempt to get the port number for the current graphics scheme */ + tmp = virXPathInt(xpath, ctxt, &port); + VIR_FREE(xpath); - if (!virDomainIsActive(dom)) { - vshError(ctl, _("Domain is not running")); - goto cleanup; - } + /* If there is no port number for this type, then jump to the next + * scheme */ + if (tmp) + port = 0; - if (vshCommandOptBool(cmd, "include-password")) - flags |= VIR_DOMAIN_XML_SECURE; + /* Create our XPATH lookup for TLS Port (automatically skipped + * for unsupported schemes */ + xpath = g_strdup_printf(xpath_fmt, scheme, "@tlsPort"); - if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0) - goto cleanup; + /* Attempt to get the TLS port number */ + tmp = virXPathInt(xpath, ctxt, &tls_port); + VIR_FREE(xpath); + if (tmp) + tls_port = 0; - if (virshDomainGetXMLFromDom(ctl, dom, flags, &xml, &ctxt) < 0) - goto cleanup; + /* Create our XPATH lookup for the current display's address */ + xpath = g_strdup_printf(xpath_fmt, scheme, "@listen"); - /* Attempt to grab our display info */ - for (iter = 0; scheme[iter] != NULL; iter++) { - /* Particular scheme requested */ - if (!all && type && STRNEQ(type, scheme[iter])) - continue; + /* Attempt to get the listening addr if set for the current + * graphics scheme */ + listen_addr = virXPathString(xpath, ctxt); + VIR_FREE(xpath); - /* Create our XPATH lookup for the current display's port */ - VIR_FREE(xpath); - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "@port"); + /* Create our XPATH lookup for the current spice type. */ + xpath = g_strdup_printf(xpath_fmt, scheme, "listen/@type"); - /* Attempt to get the port number for the current graphics scheme */ - tmp = virXPathInt(xpath, ctxt, &port); - VIR_FREE(xpath); + /* Attempt to get the type of spice connection */ + type_conn = virXPathString(xpath, ctxt); + VIR_FREE(xpath); - /* If there is no port number for this type, then jump to the next - * scheme */ - if (tmp) - port = 0; + if (STREQ_NULLABLE(type_conn, "socket")) { + if (!sockpath) { + xpath = g_strdup_printf(xpath_fmt, scheme, "listen/@socket"); - /* Create our XPATH lookup for TLS Port (automatically skipped - * for unsupported schemes */ - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "@tlsPort"); + sockpath = virXPathString(xpath, ctxt); - /* Attempt to get the TLS port number */ - tmp = virXPathInt(xpath, ctxt, &tls_port); - VIR_FREE(xpath); - if (tmp) - tls_port = 0; + VIR_FREE(xpath); + } + } - /* Create our XPATH lookup for the current display's address */ - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "@listen"); + if (!port && !tls_port && !sockpath) + return false; + + if (!listen_addr) { + /* The subelement address - <listen address='xyz'/> - + * *should* have been automatically backfilled into its + * parent <graphics listen='xyz'> (which we just tried to + * retrieve into listen_addr above) but in some cases it + * isn't, so we also do an explicit check for the + * subelement (which, by the way, doesn't exist on libvirt + * < 0.9.4, so we really do need to check both places) + */ + xpath = g_strdup_printf(xpath_fmt, scheme, "listen/@address"); - /* Attempt to get the listening addr if set for the current - * graphics scheme */ - VIR_FREE(listen_addr); listen_addr = virXPathString(xpath, ctxt); VIR_FREE(xpath); + } else { + /* If listen_addr is 0.0.0.0 or [::] we should try to parse URI and set + * listen_addr based on current URI. */ + if (virSocketAddrParse(&addr, listen_addr, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&addr)) { + + virConnectPtr conn = ((virshControl *)(ctl->privData))->conn; + char *uriStr = virConnectGetURI(conn); + virURI *uri = NULL; + + if (uriStr) { + uri = virURIParse(uriStr); + VIR_FREE(uriStr); + } - /* Create our XPATH lookup for the current spice type. */ - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "listen/@type"); + /* It's safe to free the listen_addr even if parsing of URI + * fails, if there is no listen_addr we will print "localhost". */ + VIR_FREE(listen_addr); - /* Attempt to get the type of spice connection */ - VIR_FREE(type_conn); - type_conn = virXPathString(xpath, ctxt); - VIR_FREE(xpath); + if (uri) { + listen_addr = g_strdup(uri->server); + virURIFree(uri); + } + } + } - if (STREQ_NULLABLE(type_conn, "socket")) { - if (!sockpath) { - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "listen/@socket"); + /* We can query this info for all the graphics types since we'll + * get nothing for the unsupported ones (just rdp for now). + * Also the parameter '--include-password' was already taken + * care of when getting the XML */ - sockpath = virXPathString(xpath, ctxt); + /* Create our XPATH lookup for the password */ + xpath = g_strdup_printf(xpath_fmt, scheme, "@passwd"); - VIR_FREE(xpath); - } + /* Attempt to get the password */ + passwd = virXPathString(xpath, ctxt); + VIR_FREE(xpath); + + /* Build up the full URI, starting with the scheme */ + if (sockpath) + virBufferAsprintf(buf, "%s+unix://", scheme); + else + virBufferAsprintf(buf, "%s://", scheme); + + /* There is no user, so just append password if there's any */ + if (STREQ(scheme, "vnc") && passwd) + virBufferAsprintf(buf, ":%s@", passwd); + + /* Then host name or IP */ + if (!listen_addr && !sockpath) + virBufferAddLit(buf, "localhost"); + else if (!sockpath && strchr(listen_addr, ':')) + virBufferAsprintf(buf, "[%s]", listen_addr); + else if (sockpath) + virBufferAsprintf(buf, "%s", sockpath); + else + virBufferAsprintf(buf, "%s", listen_addr); + + /* Add the port */ + if (port) { + if (STREQ(scheme, "vnc")) { + /* VNC protocol handlers take their port number as + * 'port' - 5900 */ + port -= 5900; } - if (!port && !tls_port && !sockpath) - continue; + virBufferAsprintf(buf, ":%d", port); + } - if (!listen_addr) { - /* The subelement address - <listen address='xyz'/> - - * *should* have been automatically backfilled into its - * parent <graphics listen='xyz'> (which we just tried to - * retrieve into listen_addr above) but in some cases it - * isn't, so we also do an explicit check for the - * subelement (which, by the way, doesn't exist on libvirt - * < 0.9.4, so we really do need to check both places) - */ - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "listen/@address"); - - listen_addr = virXPathString(xpath, ctxt); - VIR_FREE(xpath); - } else { - /* If listen_addr is 0.0.0.0 or [::] we should try to parse URI and set - * listen_addr based on current URI. */ - if (virSocketAddrParse(&addr, listen_addr, AF_UNSPEC) > 0 && - virSocketAddrIsWildcard(&addr)) { - - virConnectPtr conn = ((virshControl *)(ctl->privData))->conn; - char *uriStr = virConnectGetURI(conn); - virURI *uri = NULL; - - if (uriStr) { - uri = virURIParse(uriStr); - VIR_FREE(uriStr); - } + /* TLS Port */ + if (tls_port) { + virBufferAsprintf(buf, + "?tls-port=%d", + tls_port); + params = true; + } - /* It's safe to free the listen_addr even if parsing of URI - * fails, if there is no listen_addr we will print "localhost". */ - VIR_FREE(listen_addr); + if (STREQ(scheme, "spice") && passwd) { + virBufferAsprintf(buf, + "%spassword=%s", + params ? "&" : "?", + passwd); + params = true; + } - if (uri) { - listen_addr = g_strdup(uri->server); - virURIFree(uri); - } - } - } + return true; +} - /* We can query this info for all the graphics types since we'll - * get nothing for the unsupported ones (just rdp for now). - * Also the parameter '--include-password' was already taken - * care of when getting the XML */ +static bool +cmdDomDisplay(vshControl *ctl, const vshCmd *cmd) +{ + g_autoptr(xmlDoc) xml = NULL; + g_autoptr(xmlXPathContext) ctxt = NULL; + g_autoptr(virshDomain) dom = NULL; + g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; + g_autofree char *output = NULL; + bool ret = false; + const char *scheme[] = { "vnc", "spice", "rdp", NULL }; + const char *type = NULL; + int iter = 0; + int flags = 0; + bool all = vshCommandOptBool(cmd, "all"); - /* Create our XPATH lookup for the password */ - xpath = g_strdup_printf(xpath_fmt, scheme[iter], "@passwd"); + VSH_EXCLUSIVE_OPTIONS("all", "type"); - /* Attempt to get the password */ - VIR_FREE(passwd); - passwd = virXPathString(xpath, ctxt); - VIR_FREE(xpath); + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) + return false; - /* Build up the full URI, starting with the scheme */ - if (sockpath) - virBufferAsprintf(&buf, "%s+unix://", scheme[iter]); - else - virBufferAsprintf(&buf, "%s://", scheme[iter]); - - /* There is no user, so just append password if there's any */ - if (STREQ(scheme[iter], "vnc") && passwd) - virBufferAsprintf(&buf, ":%s@", passwd); - - /* Then host name or IP */ - if (!listen_addr && !sockpath) - virBufferAddLit(&buf, "localhost"); - else if (!sockpath && strchr(listen_addr, ':')) - virBufferAsprintf(&buf, "[%s]", listen_addr); - else if (sockpath) - virBufferAsprintf(&buf, "%s", sockpath); - else - virBufferAsprintf(&buf, "%s", listen_addr); + if (!virDomainIsActive(dom)) { + vshError(ctl, _("Domain is not running")); + return false; + } - /* Free socket to prepare the pointer for the next iteration */ - VIR_FREE(sockpath); + if (vshCommandOptBool(cmd, "include-password")) + flags |= VIR_DOMAIN_XML_SECURE; - /* Add the port */ - if (port) { - if (STREQ(scheme[iter], "vnc")) { - /* VNC protocol handlers take their port number as - * 'port' - 5900 */ - port -= 5900; - } + if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0) + return false; - virBufferAsprintf(&buf, ":%d", port); - } + if (virshDomainGetXMLFromDom(ctl, dom, flags, &xml, &ctxt) < 0) + return false; - /* TLS Port */ - if (tls_port) { - virBufferAsprintf(&buf, - "?tls-port=%d", - tls_port); - params = true; - } + /* Attempt to grab our display info */ + for (iter = 0; scheme[iter] != NULL; iter++) { + /* Particular scheme requested */ + if (!all && type && STRNEQ(type, scheme[iter])) + continue; - if (STREQ(scheme[iter], "spice") && passwd) { - virBufferAsprintf(&buf, - "%spassword=%s", - params ? "&" : "?", - passwd); - params = true; - } + if (!cmdDomDisplayScheme(ctl, scheme[iter], ctxt, &buf)) + continue; /* Print out our full URI */ VIR_FREE(output); @@ -11664,13 +11668,6 @@ cmdDomDisplay(vshControl *ctl, const vshCmd *cmd) vshError(ctl, _("No graphical display found")); } - cleanup: - VIR_FREE(xpath); - VIR_FREE(type_conn); - VIR_FREE(sockpath); - VIR_FREE(passwd); - VIR_FREE(listen_addr); - VIR_FREE(output); return ret; } -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> This implementation reports only Unix bus address using the URI format proposed in https://gitlab.freedesktop.org/dbus/dbus/-/issues/348. We prefer a URI form over the D-Bus address form, since all other display protocols use a URI, allowing to distinguish between protocols and making client implementation simpler. Other transports (for example TCP) are not yet handled. The client is assumed to know what to lookup on the bus (the bus name, path & interface of the VM, eventually matching its UUID) P2P mode doesn't report any available URI. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- tools/virsh-domain.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index fbe8ec3ea782..89a9546c4a74 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11431,7 +11431,7 @@ static const vshCmdOptDef opts_domdisplay[] = { {.name = "type", .type = VSH_OT_STRING, .help = N_("select particular graphical display " - "(e.g. \"vnc\", \"spice\", \"rdp\")") + "(e.g. \"vnc\", \"spice\", \"rdp\", \"dbus\")") }, {.name = "all", .type = VSH_OT_BOOL, @@ -11440,6 +11440,26 @@ static const vshCmdOptDef opts_domdisplay[] = { {.name = NULL} }; +static bool +cmdDomDisplayDBus(vshControl *ctl, xmlXPathContext *ctxt, virBuffer *buf) +{ + g_autofree char *addr = NULL; + const char *xpath = "string(/domain/devices/graphics[@type='dbus']/@address)"; + + addr = virXPathString(xpath, ctxt); + if (!addr) + return false; + + if (STRPREFIX(addr, "unix:path=")) { + virBufferAsprintf(buf, "dbus+unix://%s", addr + 10); + } else { + vshError(ctl, _("'%s' D-Bus address is not handled"), addr); + return false; + } + + return true; +} + static bool cmdDomDisplayScheme(vshControl *ctl, const char *scheme, xmlXPathContext *ctxt, virBuffer *buf) @@ -11455,6 +11475,9 @@ cmdDomDisplayScheme(vshControl *ctl, const char *scheme, bool params = false; int tmp; + if (STREQ(scheme, "dbus")) + return cmdDomDisplayDBus(ctl, ctxt, buf); + /* Create our XPATH lookup for the current display's port */ xpath = g_strdup_printf(xpath_fmt, scheme, "@port"); @@ -11615,7 +11638,7 @@ cmdDomDisplay(vshControl *ctl, const vshCmd *cmd) g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; g_autofree char *output = NULL; bool ret = false; - const char *scheme[] = { "vnc", "spice", "rdp", NULL }; + const char *scheme[] = { "vnc", "spice", "rdp", "dbus", NULL }; const char *type = NULL; int iter = 0; int flags = 0; -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/schemas/domaincommon.rng | 29 ++++++++++++ src/bhyve/bhyve_command.c | 1 + src/conf/domain_conf.c | 34 +++++++++++--- src/conf/domain_conf.h | 2 + src/qemu/qemu_command.c | 7 +++ src/qemu/qemu_validate.c | 3 ++ .../qemuxml2argvdata/graphics-dbus-audio.xml | 45 +++++++++++++++++++ .../graphics-dbus-audio.xml | 1 + tests/qemuxml2xmltest.c | 4 ++ 9 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-audio.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-audio.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 1dba199db7ec..fcd14162bc9a 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4027,6 +4027,13 @@ </optional> </element> </optional> + <optional> + <element name="audio"> + <attribute name="id"> + <ref name="uint8"/> + </attribute> + </element> + </optional> </interleave> </group> <group> @@ -4839,6 +4846,11 @@ <ref name="audiocommonchild"/> </define> + <define name="audiodbus"> + <ref name="audiocommonattr"/> + <ref name="audiocommonchild"/> + </define> + <define name="audio"> <element name="audio"> <attribute name="id"> @@ -4867,6 +4879,23 @@ </optional> </interleave> </group> + <group> + <attribute name="type"> + <value>dbus</value> + </attribute> + <interleave> + <optional> + <element name="input"> + <ref name="audiodbus"/> + </element> + </optional> + <optional> + <element name="output"> + <ref name="audiodbus"/> + </element> + </optional> + </interleave> + </group> <group> <attribute name="type"> <value>alsa</value> diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index cf858dfcd6e8..0ed58384c5ea 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -551,6 +551,7 @@ bhyveBuildSoundArgStr(const virDomainDef *def G_GNUC_UNUSED, case VIR_DOMAIN_AUDIO_TYPE_SDL: case VIR_DOMAIN_AUDIO_TYPE_SPICE: case VIR_DOMAIN_AUDIO_TYPE_FILE: + case VIR_DOMAIN_AUDIO_TYPE_DBUS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported audio backend '%s'"), virDomainAudioTypeTypeToString(audio->type)); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 11eb1422d8c1..45bbed8dcced 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -755,6 +755,7 @@ VIR_ENUM_IMPL(virDomainAudioType, "sdl", "spice", "file", + "dbus", ); VIR_ENUM_IMPL(virDomainAudioSDLDriver, @@ -3023,6 +3024,7 @@ virDomainAudioDefFree(virDomainAudioDef *def) g_free(def->backend.file.path); break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: case VIR_DOMAIN_AUDIO_TYPE_LAST: break; } @@ -12901,6 +12903,14 @@ virDomainGraphicsDefParseXMLDBus(virDomainGraphicsDef *def, return -1; } + cur = virXPathNode("./audio", ctxt); + if (cur) { + if (virXMLPropUInt(cur, "id", 10, + VIR_XML_PROP_REQUIRED | VIR_XML_PROP_NONZERO, + &def->data.dbus.audioId) < 0) + return -1; + } + return 0; } @@ -13391,6 +13401,9 @@ virDomainAudioDefParseXML(virDomainXMLOption *xmlopt G_GNUC_UNUSED, def->backend.file.path = virXMLPropString(node, "path"); break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: + break; + case VIR_DOMAIN_AUDIO_TYPE_LAST: default: virReportEnumRangeError(virDomainAudioType, def->type); @@ -25738,6 +25751,9 @@ virDomainAudioDefFormat(virBuffer *buf, virBufferEscapeString(&attrBuf, " path='%s'", def->backend.file.path); break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: + break; + case VIR_DOMAIN_AUDIO_TYPE_LAST: default: virReportEnumRangeError(virDomainAudioType, def->type); @@ -26672,7 +26688,7 @@ virDomainGraphicsDefFormat(virBuffer *buf, virBufferAsprintf(buf, " address='%s'", def->data.dbus.address); - if (!def->data.dbus.gl) + if (!def->data.dbus.gl && def->data.dbus.audioId <= 0) break; if (!children) { @@ -26681,10 +26697,17 @@ virDomainGraphicsDefFormat(virBuffer *buf, children = true; } - virBufferAsprintf(buf, "<gl enable='%s'", - virTristateBoolTypeToString(def->data.dbus.gl)); - virBufferEscapeString(buf, " rendernode='%s'", def->data.dbus.rendernode); - virBufferAddLit(buf, "/>\n"); + if (def->data.dbus.gl) { + virBufferAsprintf(buf, "<gl enable='%s'", + virTristateBoolTypeToString(def->data.dbus.gl)); + virBufferEscapeString(buf, " rendernode='%s'", def->data.dbus.rendernode); + virBufferAddLit(buf, "/>\n"); + } + + if (def->data.dbus.audioId > 0) + virBufferAsprintf(buf, "<audio id='%d'/>\n", + def->data.dbus.audioId); + break; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; @@ -29991,6 +30014,7 @@ virDomainAudioBackendIsEqual(virDomainAudioDef *this, case VIR_DOMAIN_AUDIO_TYPE_FILE: return STREQ_NULLABLE(this->backend.file.path, that->backend.file.path); + case VIR_DOMAIN_AUDIO_TYPE_DBUS: case VIR_DOMAIN_AUDIO_TYPE_LAST: default: return false; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 384b85db3a2c..ff765e4cc282 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1504,6 +1504,7 @@ typedef enum { VIR_DOMAIN_AUDIO_TYPE_SDL, VIR_DOMAIN_AUDIO_TYPE_SPICE, VIR_DOMAIN_AUDIO_TYPE_FILE, + VIR_DOMAIN_AUDIO_TYPE_DBUS, VIR_DOMAIN_AUDIO_TYPE_LAST } virDomainAudioType; @@ -1922,6 +1923,7 @@ struct _virDomainGraphicsDef { char *address; char *rendernode; virTristateBool gl; + unsigned int audioId; bool fromConfig; /* true if the @address is config file originated */ } dbus; } data; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7265aae0f503..fd1943e94a2d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -152,6 +152,7 @@ VIR_ENUM_IMPL(qemuAudioDriver, "sdl", "spice", "wav", + "dbus", ); @@ -8038,6 +8039,9 @@ qemuBuildAudioCommandLineArg(virCommand *cmd, return -1; break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: + break; + case VIR_DOMAIN_AUDIO_TYPE_LAST: default: virReportEnumRangeError(virDomainAudioType, def->type); @@ -8242,6 +8246,9 @@ qemuBuildAudioCommandLineEnv(virCommand *cmd, audio->backend.file.path); break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: + break; + case VIR_DOMAIN_AUDIO_TYPE_LAST: default: virReportEnumRangeError(virDomainAudioType, audio->type); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 05792f4e4c0a..cebaa81361cb 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4417,6 +4417,9 @@ qemuValidateDomainDeviceDefAudio(virDomainAudioDef *audio, case VIR_DOMAIN_AUDIO_TYPE_FILE: break; + case VIR_DOMAIN_AUDIO_TYPE_DBUS: + break; + case VIR_DOMAIN_AUDIO_TYPE_LAST: default: virReportEnumRangeError(virDomainAudioType, audio->type); diff --git a/tests/qemuxml2argvdata/graphics-dbus-audio.xml b/tests/qemuxml2argvdata/graphics-dbus-audio.xml new file mode 100644 index 000000000000..b1304e3f6ff8 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-audio.xml @@ -0,0 +1,45 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</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'> + <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='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'> + <audio id='1'/> + </graphics> + <audio id='1' type='dbus'> + <input mixingEngine='no'/> + <output mixingEngine='no'/> + </audio> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/graphics-dbus-audio.xml b/tests/qemuxml2xmloutdata/graphics-dbus-audio.xml new file mode 120000 index 000000000000..fe0f4a81d9e4 --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus-audio.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus-audio.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index ba891df0dfb6..e3bcd49c810f 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -382,6 +382,10 @@ mymain(void) DO_TEST("graphics-dbus-p2p", QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-audio", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS, + QEMU_CAPS_AUDIODEV); DO_TEST_CAPS_ARCH_LATEST("default-video-type-aarch64", "aarch64"); DO_TEST_CAPS_ARCH_LATEST("default-video-type-ppc64", "ppc64"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_command.c | 12 +++++-- src/qemu/qemu_validate.c | 30 ++++++++++++++++- .../qemuxml2argvdata/graphics-dbus-audio.args | 33 +++++++++++++++++++ tests/qemuxml2argvtest.c | 2 ++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-audio.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index fd1943e94a2d..bc29b7de7ec4 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8645,7 +8645,8 @@ qemuBuildGraphicsEGLHeadlessCommandLine(virQEMUDriverConfig *cfg G_GNUC_UNUSED, static int -qemuBuildGraphicsDBusCommandLine(virCommand *cmd, +qemuBuildGraphicsDBusCommandLine(virDomainDef *def, + virCommand *cmd, virDomainGraphicsDef *graphics) { g_auto(virBuffer) opt = VIR_BUFFER_INITIALIZER; @@ -8667,6 +8668,13 @@ qemuBuildGraphicsDBusCommandLine(virCommand *cmd, graphics->data.dbus.rendernode); } + if (graphics->data.dbus.audioId > 0) { + g_autofree char *audioid = qemuGetAudioIDString(def, graphics->data.dbus.audioId); + if (!audioid) + return -1; + virBufferAsprintf(&opt, ",audiodev=%s", audioid); + } + virCommandAddArg(cmd, "-display"); virCommandAddArgBuffer(cmd, &opt); @@ -8711,7 +8719,7 @@ qemuBuildGraphicsCommandLine(virQEMUDriverConfig *cfg, break; case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: - if (qemuBuildGraphicsDBusCommandLine(cmd, graphics) < 0) + if (qemuBuildGraphicsDBusCommandLine(def, cmd, graphics) < 0) return -1; break; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index cebaa81361cb..0c12feb68b1f 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4090,6 +4090,24 @@ qemuValidateDomainDeviceDefVNCGraphics(const virDomainGraphicsDef *graphics, } +static int +qemuValidateDomainDeviceDefDBusGraphics(const virDomainGraphicsDef *graphics, + const virDomainDef *def) +{ + if (graphics->data.dbus.audioId > 0) { + virDomainAudioDef *audio = virDomainDefFindAudioByID(def, graphics->data.dbus.audioId); + + if (audio && audio->type != VIR_DOMAIN_AUDIO_TYPE_DBUS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The associated audio is not of 'dbus' kind.")); + return -1; + } + } + + return 0; +} + + static int qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, const virDomainDef *def, @@ -4167,10 +4185,15 @@ qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, break; + case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: + if (qemuValidateDomainDeviceDefDBusGraphics(graphics, def) < 0) + return -1; + + break; + case VIR_DOMAIN_GRAPHICS_TYPE_SDL: case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: - case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; } @@ -4418,6 +4441,11 @@ qemuValidateDomainDeviceDefAudio(virDomainAudioDef *audio, break; case VIR_DOMAIN_AUDIO_TYPE_DBUS: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DISPLAY_DBUS)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("D-Bus audio is not supported with this QEMU")); + return -1; + } break; case VIR_DOMAIN_AUDIO_TYPE_LAST: diff --git a/tests/qemuxml2argvdata/graphics-dbus-audio.args b/tests/qemuxml2argvdata/graphics-dbus-audio.args new file mode 100644 index 000000000000..ab23f6ac1cda --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-audio.args @@ -0,0 +1,33 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-audiodev '{"id":"audio1","driver":"dbus","in":{"mixing-engine":false},"out":{"mixing-engine":false}}' \ +-display dbus,p2p=on,audiodev=audio1 \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d024a657af8e..4186bec86671 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1519,6 +1519,8 @@ mymain(void) QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); DO_TEST("graphics-dbus-p2p", QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-audio", + QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS, QEMU_CAPS_AUDIODEV); DO_TEST_NOCAPS("input-usbmouse"); DO_TEST_NOCAPS("input-usbtablet"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/schemas/domaincommon.rng | 8 +++++ src/conf/domain_conf.c | 13 ++++++- src/conf/domain_conf.h | 1 + .../graphics-dbus-clipboard.xml | 35 +++++++++++++++++++ .../graphics-dbus-clipboard.xml | 1 + tests/qemuxml2xmltest.c | 3 ++ 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-clipboard.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-clipboard.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index fcd14162bc9a..a8777acf9ea8 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4034,6 +4034,14 @@ </attribute> </element> </optional> + <optional> + <element name="clipboard"> + <attribute name="copypaste"> + <ref name="virYesNo"/> + </attribute> + <empty/> + </element> + </optional> </interleave> </group> <group> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 45bbed8dcced..3d89fed72e2d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -12911,6 +12911,13 @@ virDomainGraphicsDefParseXMLDBus(virDomainGraphicsDef *def, return -1; } + if ((cur = virXPathNode("./clipboard", ctxt))) { + if (virXMLPropTristateBool(cur, "copypaste", + VIR_XML_PROP_REQUIRED, + &def->data.dbus.copypaste) < 0) + return -1; + } + return 0; } @@ -26688,7 +26695,7 @@ virDomainGraphicsDefFormat(virBuffer *buf, virBufferAsprintf(buf, " address='%s'", def->data.dbus.address); - if (!def->data.dbus.gl && def->data.dbus.audioId <= 0) + if (!def->data.dbus.gl && def->data.dbus.audioId <= 0 && !def->data.dbus.copypaste) break; if (!children) { @@ -26708,6 +26715,10 @@ virDomainGraphicsDefFormat(virBuffer *buf, virBufferAsprintf(buf, "<audio id='%d'/>\n", def->data.dbus.audioId); + if (def->data.dbus.copypaste) + virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n", + virTristateBoolTypeToString(def->data.dbus.copypaste)); + break; case VIR_DOMAIN_GRAPHICS_TYPE_LAST: break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index ff765e4cc282..676d2893913e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1924,6 +1924,7 @@ struct _virDomainGraphicsDef { char *rendernode; virTristateBool gl; unsigned int audioId; + virTristateBool copypaste; bool fromConfig; /* true if the @address is config file originated */ } dbus; } data; diff --git a/tests/qemuxml2argvdata/graphics-dbus-clipboard.xml b/tests/qemuxml2argvdata/graphics-dbus-clipboard.xml new file mode 100644 index 000000000000..46ba6abb58bc --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-clipboard.xml @@ -0,0 +1,35 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'> + <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='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'> + <clipboard copypaste='yes'/> + </graphics> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/graphics-dbus-clipboard.xml b/tests/qemuxml2xmloutdata/graphics-dbus-clipboard.xml new file mode 120000 index 000000000000..a4dc520711ad --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus-clipboard.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus-clipboard.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index e3bcd49c810f..f9eb4052517b 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -386,6 +386,9 @@ mymain(void) QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS, QEMU_CAPS_AUDIODEV); + DO_TEST("graphics-dbus-clipboard", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); DO_TEST_CAPS_ARCH_LATEST("default-video-type-aarch64", "aarch64"); DO_TEST_CAPS_ARCH_LATEST("default-video-type-ppc64", "ppc64"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> This feature requires to setup a "-chardev qemu-vdagent,clipboard=on". "qemu-vdagent" is not a typical chardev that you can connect to another end, so it doesn't map to a <serial> or <channel>. Set it up along with "-display dbus" code instead. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_command.c | 12 +++++++ .../graphics-dbus-clipboard.args | 31 +++++++++++++++++++ tests/qemuxml2argvtest.c | 4 +++ 3 files changed, 47 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-clipboard.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index bc29b7de7ec4..e4d39dc5b8fd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8649,6 +8649,7 @@ qemuBuildGraphicsDBusCommandLine(virDomainDef *def, virCommand *cmd, virDomainGraphicsDef *graphics) { + g_autofree char *charAlias = NULL; g_auto(virBuffer) opt = VIR_BUFFER_INITIALIZER; virBufferAddLit(&opt, "dbus"); @@ -8678,6 +8679,17 @@ qemuBuildGraphicsDBusCommandLine(virDomainDef *def, virCommandAddArg(cmd, "-display"); virCommandAddArgBuffer(cmd, &opt); + + if (graphics->data.dbus.copypaste == VIR_TRISTATE_BOOL_YES) { + if (!(charAlias = qemuAliasChardevFromDevAlias("qemu-vdagent"))) + return -1; + + virBufferAsprintf(&opt, "qemu-vdagent,id=%s", charAlias); + virBufferAddLit(&opt, ",clipboard=on"); + virCommandAddArg(cmd, "-chardev"); + virCommandAddArgBuffer(cmd, &opt); + } + return 0; } diff --git a/tests/qemuxml2argvdata/graphics-dbus-clipboard.args b/tests/qemuxml2argvdata/graphics-dbus-clipboard.args new file mode 100644 index 000000000000..fd0c3e7a253e --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-clipboard.args @@ -0,0 +1,31 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-display dbus,addr=unix:path=/bad-test-used-env-xdg-runtime-dir/libvirt/qemu/run/dbus/-1-QEMUGuest1-dbus.sock \ +-chardev qemu-vdagent,id=charqemu-vdagent,clipboard=on \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4186bec86671..fc8f11d268d0 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1521,6 +1521,10 @@ mymain(void) QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); DO_TEST("graphics-dbus-audio", QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS, QEMU_CAPS_AUDIODEV); + DO_TEST("graphics-dbus-clipboard", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS, + QEMU_CAPS_CHARDEV_VDAGENT); DO_TEST_NOCAPS("input-usbmouse"); DO_TEST_NOCAPS("input-usbtablet"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Like a Spice port, a dbus serial must specify an associated channel name. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 26 +++++++++++ src/conf/domain_conf.h | 4 ++ src/conf/domain_validate.c | 32 ++++++++++---- src/qemu/qemu_command.c | 2 + src/qemu/qemu_monitor_json.c | 1 + src/qemu/qemu_validate.c | 1 + src/security/security_dac.c | 2 + .../graphics-dbus-chardev.xml | 43 +++++++++++++++++++ .../graphics-dbus-chardev.xml | 1 + tests/qemuxml2xmltest.c | 3 ++ 11 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-chardev.xml create mode 120000 tests/qemuxml2xmloutdata/graphics-dbus-chardev.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index a8777acf9ea8..2499b71c59dc 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4506,6 +4506,7 @@ <value>spicevmc</value> <value>spiceport</value> <value>nmdm</value> + <value>dbus</value> </choice> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3d89fed72e2d..49b5cdb7c0f3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -701,6 +701,7 @@ VIR_ENUM_IMPL(virDomainChr, "spicevmc", "spiceport", "nmdm", + "dbus", ); VIR_ENUM_IMPL(virDomainChrTcpProtocol, @@ -2681,6 +2682,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_DBUS: case VIR_DOMAIN_CHR_TYPE_LAST: return NULL; } @@ -2724,6 +2726,10 @@ virDomainChrSourceDefClear(virDomainChrSourceDef *def) case VIR_DOMAIN_CHR_TYPE_SPICEPORT: VIR_FREE(def->data.spiceport.channel); break; + + case VIR_DOMAIN_CHR_TYPE_DBUS: + VIR_FREE(def->data.dbus.channel); + break; } VIR_FREE(def->logfile); @@ -2778,7 +2784,14 @@ virDomainChrSourceDefCopy(virDomainChrSourceDef *dest, case VIR_DOMAIN_CHR_TYPE_NMDM: dest->data.nmdm.master = g_strdup(src->data.nmdm.master); dest->data.nmdm.slave = g_strdup(src->data.nmdm.slave); + break; + + case VIR_DOMAIN_CHR_TYPE_SPICEPORT: + dest->data.spiceport.channel = g_strdup(src->data.spiceport.channel); + break; + case VIR_DOMAIN_CHR_TYPE_DBUS: + dest->data.dbus.channel = g_strdup(src->data.dbus.channel); break; } @@ -2860,6 +2873,11 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src, case VIR_DOMAIN_CHR_TYPE_SPICEVMC: return src->data.spicevmc == tgt->data.spicevmc; + case VIR_DOMAIN_CHR_TYPE_DBUS: + return STREQ_NULLABLE(src->data.dbus.channel, + tgt->data.dbus.channel); + break; + case VIR_DOMAIN_CHR_TYPE_NULL: case VIR_DOMAIN_CHR_TYPE_VC: case VIR_DOMAIN_CHR_TYPE_STDIO: @@ -11374,6 +11392,10 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDef *def, def->data.spiceport.channel = virXMLPropString(sources[0], "channel"); break; + case VIR_DOMAIN_CHR_TYPE_DBUS: + def->data.dbus.channel = virXMLPropString(sources[0], "channel"); + break; + case VIR_DOMAIN_CHR_TYPE_NMDM: def->data.nmdm.master = virXMLPropString(sources[0], "master"); def->data.nmdm.slave = virXMLPropString(sources[0], "slave"); @@ -25224,6 +25246,10 @@ virDomainChrSourceDefFormat(virBuffer *buf, def->data.spiceport.channel); break; + case VIR_DOMAIN_CHR_TYPE_DBUS: + virBufferEscapeString(buf, "<source channel='%s'/>\n", + def->data.dbus.channel); + break; } if (def->logfile) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 676d2893913e..fdf8981b3f66 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1209,6 +1209,7 @@ typedef enum { VIR_DOMAIN_CHR_TYPE_SPICEVMC, VIR_DOMAIN_CHR_TYPE_SPICEPORT, VIR_DOMAIN_CHR_TYPE_NMDM, + VIR_DOMAIN_CHR_TYPE_DBUS, VIR_DOMAIN_CHR_TYPE_LAST } virDomainChrType; @@ -1277,6 +1278,9 @@ struct _virDomainChrSourceDef { struct { char *channel; } spiceport; + struct { + char *channel; + } dbus; } data; char *logfile; virTristateSwitch logappend; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index c13472516fec..97b581ddb11d 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -832,6 +832,24 @@ virDomainDiskDefValidate(const virDomainDef *def, #define SERIAL_CHANNEL_NAME_CHARS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." + +static int +virDomainChrSourceDefValidateChannelName(const char *name) +{ + if (!name) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Missing source channel attribute for char device")); + return -1; + } + if (strspn(name, SERIAL_CHANNEL_NAME_CHARS) < strlen(name)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Invalid character in source channel for char device")); + return -1; + } + + return 0; +} + static int virDomainChrSourceDefValidate(const virDomainChrSourceDef *src_def, const virDomainChrDef *chr_def, @@ -917,17 +935,13 @@ virDomainChrSourceDefValidate(const virDomainChrSourceDef *src_def, break; case VIR_DOMAIN_CHR_TYPE_SPICEPORT: - if (!src_def->data.spiceport.channel) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Missing source channel attribute for char device")); + if (virDomainChrSourceDefValidateChannelName(src_def->data.spiceport.channel) < 0) return -1; - } - if (strspn(src_def->data.spiceport.channel, - SERIAL_CHANNEL_NAME_CHARS) < strlen(src_def->data.spiceport.channel)) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Invalid character in source channel for char device")); + break; + + case VIR_DOMAIN_CHR_TYPE_DBUS: + if (virDomainChrSourceDefValidateChannelName(src_def->data.dbus.channel) < 0) return -1; - } break; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index e4d39dc5b8fd..308ccbf72a1a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5297,6 +5297,7 @@ qemuBuildChrChardevStr(virLogManager *logManager, dev->data.spiceport.channel); break; + case VIR_DOMAIN_CHR_TYPE_DBUS: case VIR_DOMAIN_CHR_TYPE_NMDM: case VIR_DOMAIN_CHR_TYPE_LAST: default: @@ -8781,6 +8782,7 @@ qemuInterfaceVhostuserConnect(virQEMUDriver *driver, case VIR_DOMAIN_CHR_TYPE_SPICEVMC: case VIR_DOMAIN_CHR_TYPE_SPICEPORT: case VIR_DOMAIN_CHR_TYPE_NMDM: + case VIR_DOMAIN_CHR_TYPE_DBUS: 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 c10ea583fd78..c0906fe70f8f 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6772,6 +6772,7 @@ qemuMonitorJSONAttachCharDevGetProps(const char *chrID, break; + case VIR_DOMAIN_CHR_TYPE_DBUS: case VIR_DOMAIN_CHR_TYPE_SPICEPORT: case VIR_DOMAIN_CHR_TYPE_PIPE: case VIR_DOMAIN_CHR_TYPE_STDIO: diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 0c12feb68b1f..ca34afcc7daa 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1955,6 +1955,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_DBUS: case VIR_DOMAIN_CHR_TYPE_LAST: break; } diff --git a/src/security/security_dac.c b/src/security/security_dac.c index e9e316551ebb..d24f4fef1e73 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_DBUS: 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_DBUS: case VIR_DOMAIN_CHR_TYPE_LAST: break; } diff --git a/tests/qemuxml2argvdata/graphics-dbus-chardev.xml b/tests/qemuxml2argvdata/graphics-dbus-chardev.xml new file mode 100644 index 000000000000..d2ca208bd932 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-chardev.xml @@ -0,0 +1,43 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'> + <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='pci' index='0' model='pci-root'/> + <serial type='dbus'> + <source channel='org.qemu.console.serial.0'/> + <target type='isa-serial' port='1'> + <model name='isa-serial'/> + </target> + </serial> + <console type='dbus'> + <source channel='org.qemu.console.serial.0'/> + <target type='serial' port='1'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/graphics-dbus-chardev.xml b/tests/qemuxml2xmloutdata/graphics-dbus-chardev.xml new file mode 120000 index 000000000000..85dabfad7689 --- /dev/null +++ b/tests/qemuxml2xmloutdata/graphics-dbus-chardev.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/graphics-dbus-chardev.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index f9eb4052517b..b23aee1389b8 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -389,6 +389,9 @@ mymain(void) DO_TEST("graphics-dbus-clipboard", QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-chardev", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); DO_TEST_CAPS_ARCH_LATEST("default-video-type-aarch64", "aarch64"); DO_TEST_CAPS_ARCH_LATEST("default-video-type-ppc64", "ppc64"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_command.c | 8 +++++ src/qemu/qemu_monitor_json.c | 9 ++++++ .../graphics-dbus-chardev.args | 32 +++++++++++++++++++ tests/qemuxml2argvtest.c | 4 +++ 4 files changed, 53 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-chardev.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 308ccbf72a1a..582f41ada9ee 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5298,6 +5298,14 @@ qemuBuildChrChardevStr(virLogManager *logManager, break; case VIR_DOMAIN_CHR_TYPE_DBUS: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DISPLAY_DBUS)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("D-Bus chardev is not supported")); + } + virBufferAsprintf(&buf, "dbus,id=%s,name=%s", charAlias, + dev->data.dbus.channel); + break; + case VIR_DOMAIN_CHR_TYPE_NMDM: case VIR_DOMAIN_CHR_TYPE_LAST: default: diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index c0906fe70f8f..ada987d0a4d5 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6773,6 +6773,15 @@ qemuMonitorJSONAttachCharDevGetProps(const char *chrID, break; case VIR_DOMAIN_CHR_TYPE_DBUS: + backendType = "dbus"; + + if (virJSONValueObjectAdd(&backendData, + "s:name", chr->data.dbus.channel, + 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/tests/qemuxml2argvdata/graphics-dbus-chardev.args b/tests/qemuxml2argvdata/graphics-dbus-chardev.args new file mode 100644 index 000000000000..98debbbfa775 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-chardev.args @@ -0,0 +1,32 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-chardev dbus,id=charserial0,name=org.qemu.console.serial.0 \ +-device isa-serial,chardev=charserial0,id=serial0 \ +-display dbus,p2p=on \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index fc8f11d268d0..aed30080b7a5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1525,6 +1525,10 @@ mymain(void) QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS, QEMU_CAPS_CHARDEV_VDAGENT); + DO_TEST("graphics-dbus-chardev", + QEMU_CAPS_DEVICE_ISA_SERIAL, + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS); DO_TEST_NOCAPS("input-usbmouse"); DO_TEST_NOCAPS("input-usbtablet"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> The USB device redirection works in a similar way as Spice. The underlying 'dbus' channel is set to "org.qemu.usbredir" by default for the client to identify the channel purpose (as specified in -display dbus documentation). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/conf/domain_conf.c | 2 ++ .../graphics-dbus-usbredir.args | 34 +++++++++++++++++++ .../graphics-dbus-usbredir.xml | 30 ++++++++++++++++ tests/qemuxml2argvtest.c | 4 +++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-dbus-usbredir.args create mode 100644 tests/qemuxml2argvdata/graphics-dbus-usbredir.xml diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 49b5cdb7c0f3..713df74e03df 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -14530,6 +14530,8 @@ virDomainRedirdevDefParseXML(virDomainXMLOption *xmlopt, if (def->source->type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) def->source->data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR; + if (def->source->type == VIR_DOMAIN_CHR_TYPE_DBUS && !def->source->data.dbus.channel) + def->source->data.dbus.channel = g_strdup("org.qemu.usbredir"); if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) < 0) diff --git a/tests/qemuxml2argvdata/graphics-dbus-usbredir.args b/tests/qemuxml2argvdata/graphics-dbus-usbredir.args new file mode 100644 index 000000000000..f76693ac1e83 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-usbredir.args @@ -0,0 +1,34 @@ +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-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel tcg \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-display dbus,p2p=on \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-chardev dbus,id=charredir0,name=org.qemu.usbredir \ +-device usb-redir,chardev=charredir0,id=redir0,bus=usb.0,port=1 \ +-chardev dbus,id=charredir1,name=org.qemu.usbredir \ +-device usb-redir,chardev=charredir1,id=redir1,bus=usb.0,port=2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/graphics-dbus-usbredir.xml b/tests/qemuxml2argvdata/graphics-dbus-usbredir.xml new file mode 100644 index 000000000000..fad6cd8b5f98 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-dbus-usbredir.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>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-i386</emulator> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'/> + <redirdev bus='usb' type='dbus'/> + <redirdev bus='usb' type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index aed30080b7a5..ec07a1aa5779 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1529,6 +1529,10 @@ mymain(void) QEMU_CAPS_DEVICE_ISA_SERIAL, QEMU_CAPS_DEVICE_CIRRUS_VGA, QEMU_CAPS_DISPLAY_DBUS); + DO_TEST("graphics-dbus-usbredir", + QEMU_CAPS_DEVICE_CIRRUS_VGA, + QEMU_CAPS_DISPLAY_DBUS, + QEMU_CAPS_USB_REDIR); DO_TEST_NOCAPS("input-usbmouse"); DO_TEST_NOCAPS("input-usbtablet"); -- 2.34.1.8.g35151cf07204

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/formatdomain.rst | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index eb8c973cf1fc..ac298fbafa7f 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -6060,6 +6060,39 @@ interaction with the admin. <gl rendernode='/dev/dri/renderD128'/> </graphics> + ``dbus``:since:`Since X.X.X` + Export the display over D-Bus. By default, it will use a private bus, + except when ``p2p`` or ``address`` are specified. + + :: + + <graphics type='dbus'/> + + ``p2p`` (accepts ``on`` or ``off``) enables peer-to-peer connections, + established through virDomainOpenGraphics() APIs. + + ``address`` (accepts a `D-Bus address + <https://dbus.freedesktop.org/doc/dbus-specification.html#addresses>`_), + will connect to the specified bus address. + + This element accepts a ``<gl/>`` sub-element with an optional attribute + ``rendernode`` which can be used to specify an absolute path to a host's + DRI device to be used for OpenGL rendering. + + Copy & Paste functionality (via Spice agent) is set by the ``clipboard`` + element. It is disabled by default, and can be disabled by setting the + ``copypaste`` property to ``yes``. + + D-Bus can export an audio backend using the ``<audio>`` sub-element: + + :: + + <graphics type='dbus' ...> + <audio id='1'> + </graphics> + + Where ``1`` is an id of the `audio device <#elementsAudio>`__. + Graphics device uses a ``<listen>`` to set up where the device should listen for clients. It has a mandatory attribute ``type`` which specifies the listen type. Only ``vnc``, ``spice`` and ``rdp`` supports ``<listen>`` element. :since:`Since @@ -6973,7 +7006,7 @@ to the guest sound device. ``type`` The required ``type`` attribute specifies audio backend type. Currently, the supported values are 'none', 'alsa', 'coreaudio', - 'jack', 'oss', 'pulseaudio', 'sdl', 'spice', 'file'. + 'dbus', jack', 'oss', 'pulseaudio', 'sdl', 'spice', 'file'. ``id`` Integer id of the audio device. Must be greater than 0. @@ -7100,6 +7133,14 @@ and ``<output>`` elements :since:`Since 7.2.0, qemu` +D-Bus audio backend +^^^^^^^^^^^^^^^^^^^ + +The 'dbus' audio backend does not connect to any host audio framework. It +exports a D-Bus interface when associated with a D-Bus display. + +:since:`Since X.X.X, qemu` + Jack audio backend ^^^^^^^^^^^^^^^^^^ -- 2.34.1.8.g35151cf07204

On 12/2/21 15:24, marcandre.lureau@redhat.com wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- docs/formatdomain.rst | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)
I think this patch should be dissolved in patches that introduce corresponding XML knobs. The idea is that when backporting one gets all the changes. But I can live with this being separate - it's very unlikely that only a part is backported (e.g. <graphics/> but not <audio/>). Michal

On 12/2/21 15:23, marcandre.lureau@redhat.com wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Hi,
This series implements supports for the upcoming QEMU "-display dbus" support. Development is still in progress, but I hope to land the QEMU support early in 6.3 (last version posted: https://patchew.org/QEMU/20211009210838.2219430-1-marcandre.lureau@redhat.co...).
By default, libvirt will start a private VM bus (sharing and reusing the existing "vmstate" VM bus & code).
The feature set should cover the needs to replace Spice as local client of choice, including 3daccel/dmabuf, audio, clipboard sharing, usb redirection, and arbitrary chardev/channels (for serial etc).
The test Gtk4 client is also in progress, currently in development at https://gitlab.com/marcandre.lureau/qemu-display/. A few dependencies, such as zbus, require an upcoming release. virt-viewer & boxes will need a port to Gtk4 to make use of the shared widget.
Comments welcome, as we can still adjust the QEMU side etc.
thanks
v2: after Michal review - split patches for conf & qemu changes - start D-Bus in qemuExtDevicesStart() - use symlinks for xml2xml tests - teach domdisplay to return a dbus URI - rebase & bug fixes
Marc-André Lureau (15): qemu: add chardev-vdagent capability check qemu: add -display dbus capability check (to update to 6.3) conf: add <graphics type='dbus'> qemu: start the D-Bus daemon for the display qemu: add -display dbus support virsh: refactor/split cmdDomDisplay() virsh: report the D-Bus bus URI for domdisplay conf: add <audio type='dbus'> support qemu: add audio type 'dbus' conf: add dbus <clipboard> qemu: add dbus clipboard sharing conf: add <serial type='dbus'> qemu: add -chardev dbus support qemu: add usbredir type 'dbus' docs: document <graphics> type dbus
50 files changed, 1231 insertions(+), 192 deletions(-)
LGTM. Now we have to wait for QEMU to merge patches. Michal

On Thu, Dec 02, 2021 at 06:23:56PM +0400, marcandre.lureau@redhat.com wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Hi,
This series implements supports for the upcoming QEMU "-display dbus" support. Development is still in progress, but I hope to land the QEMU support early in 6.3 (last version posted: https://patchew.org/QEMU/20211009210838.2219430-1-marcandre.lureau@redhat.co...).
By default, libvirt will start a private VM bus (sharing and reusing the existing "vmstate" VM bus & code).
The feature set should cover the needs to replace Spice as local client of choice, including 3daccel/dmabuf, audio, clipboard sharing, usb redirection, and arbitrary chardev/channels (for serial etc).
The test Gtk4 client is also in progress, currently in development at https://gitlab.com/marcandre.lureau/qemu-display/. A few dependencies, such as zbus, require an upcoming release. virt-viewer & boxes will need a port to Gtk4 to make use of the shared widget.
How is this intended to work permissions wise ? For the qemu:///session instance, everything is running the same user account, so its fairly easy. For the qemu:///system instance, the VM's private dbus-daemon bus will be running under a qemu:qemu user account, while the user wishing to have a client window will be a completely different account. How will the Gtk4 client get permission to connect to dbus-daemon ? Also what are the long term implications for the rest of the QEMU builtin display backends ? It feels like all of VNC, SPICE, SDL and GTK backends that are currently run in the main QEMU process, could be split off to be separate programs using dbus. Libvirt currently represents each fo these backenjds as a <graphics> type, and I think we'd want to continue to use that syntax even if they were separate processes. ie, i would want something more like <graphics type="spice"> <backend type="builtin|dbus"/> </graphics> to request that libvirt spawn a SPICE server, connecting over dbus vs built-in. Likewise for the other options. IOW, do we actually want to expose type="dbus" as a concept long term, or are we better off just having it as an internal impl detail ? Of course we would actually need the dbus clients to exist first... 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 Fri, Dec 3, 2021 at 8:29 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
On Thu, Dec 02, 2021 at 06:23:56PM +0400, marcandre.lureau@redhat.com wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Hi,
This series implements supports for the upcoming QEMU "-display dbus" support. Development is still in progress, but I hope to land the QEMU support early in 6.3 (last version posted: https://patchew.org/QEMU/20211009210838.2219430-1-marcandre.lureau@redhat.co...).
By default, libvirt will start a private VM bus (sharing and reusing the existing "vmstate" VM bus & code).
The feature set should cover the needs to replace Spice as local client of choice, including 3daccel/dmabuf, audio, clipboard sharing, usb redirection, and arbitrary chardev/channels (for serial etc).
The test Gtk4 client is also in progress, currently in development at https://gitlab.com/marcandre.lureau/qemu-display/. A few dependencies, such as zbus, require an upcoming release. virt-viewer & boxes will need a port to Gtk4 to make use of the shared widget.
How is this intended to work permissions wise ?
For the qemu:///session instance, everything is running the same user account, so its fairly easy.
For the qemu:///system instance, the VM's private dbus-daemon bus will be running under a qemu:qemu user account, while the user wishing to have a client window will be a completely different account. How will the Gtk4 client get permission to connect to dbus-daemon ?
Tbh, I haven't tried system instance yet! The per-vm bus needs to allow user connections (just like the dbus system bus). I'll add this to my todo/tocheck list for the next iteration.
Also what are the long term implications for the rest of the QEMU builtin display backends ?
It feels like all of VNC, SPICE, SDL and GTK backends that are currently run in the main QEMU process, could be split off to be separate programs using dbus.
Yes, I even started a VNC server (https://gitlab.com/marcandre.lureau/qemu-display/-/tree/master/qemu-vnc), although it's really a toy compared to qemu implementation at this point. I would rather focus on an RDP server though.
Libvirt currently represents each fo these backenjds as a <graphics> type, and I think we'd want to continue to use that syntax even if they were separate processes.
ie, i would want something more like
<graphics type="spice"> <backend type="builtin|dbus"/> </graphics>
to request that libvirt spawn a SPICE server, connecting over dbus vs built-in. Likewise for the other options.
IOW, do we actually want to expose type="dbus" as a concept long term, or are we better off just having it as an internal impl detail ?
If we can make it an internal impl detail, that would be great (like we did for slirp-helper - even if nobody really uses it ;)
Of course we would actually need the dbus clients to exist first...
Yes, it will take a while to get there.
participants (4)
-
Daniel P. Berrangé
-
Marc-André Lureau
-
marcandre.lureau@redhat.com
-
Michal Prívozník