[libvirt] [PATCH v2 0/2] Support for VNC WebSocket

This series, which is meant to be applied _after_ 1.0.5 release, is adding support for the VNC WebSocket to be configured for QEMU. Documentation from qemu_options.hx: qemu -vnc ...,websocket[=<port>] Opens an additional TCP listening port dedicated to VNC Websocket connections. By definition the Websocket port is 5700+@var{display}. If @var{host} is specified connections will only be allowed from this host. As an alternative the Websocket port could be specified by using @code{websocket}=@var{port}. v2: - Incorporated recommendations from RFC [1] [1] http://www.redhat.com/archives/libvir-list/2013-April/msg02056.html Martin Kletzander (2): Add VNC WebSocket support qemu: Add VNC WebSocket support docs/formatdomain.html.in | 5 ++++ docs/schemas/domaincommon.rng | 5 ++++ src/conf/domain_conf.c | 16 ++++++++++ src/conf/domain_conf.h | 1 + src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 7 +++++ src/qemu/qemu_capabilities.c | 11 +++++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 60 ++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_command.h | 5 +++- src/qemu/qemu_conf.c | 32 ++++++++++++++++++++ src/qemu/qemu_conf.h | 6 ++++ src/qemu/qemu_driver.c | 5 ++++ src/qemu/qemu_process.c | 31 ++++++++++++++++---- src/qemu/test_libvirtd_qemu.aug.in | 2 ++ tests/qemuargv2xmltest.c | 1 + tests/qemuxml2argvtest.c | 1 + tests/qemuxml2xmltest.c | 1 + 18 files changed, 180 insertions(+), 12 deletions(-) -- 1.8.2.1

Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 16 ++++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 27 insertions(+) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index f325c3c..dfea434 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3530,6 +3530,11 @@ qemu-kvm -net nic,model=? /dev/null Rather than using listen/port, QEMU supports a <code>socket</code> attribute for listening on a unix domain socket path.<span class="since">Since 0.8.8</span> + + For VNC WebSocket functionality, <code>websocket</code> + attribute may be used to specify port to listen on (with -1 + meaning auto-allocation). <span class="since">Since + 1.0.6</span> </dd> <dt><code>"spice"</code></dt> <dd> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 10596dc..59999a1 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2071,6 +2071,11 @@ </attribute> </optional> <optional> + <attribute name="websocket"> + <ref name="PortNumber"/> + </attribute> + </optional> + <optional> <attribute name="listen"> <ref name="addrIPorName"/> </attribute> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a8b5dfd..fd9e926 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7546,6 +7546,7 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { char *port = virXMLPropString(node, "port"); + char *websocket = virXMLPropString(node, "websocket"); char *autoport; if (port) { @@ -7576,6 +7577,18 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, VIR_FREE(autoport); } + if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port); + VIR_FREE(websocket); + goto error; + } + VIR_FREE(websocket); + } + def->data.vnc.socket = virXMLPropString(node, "socket"); def->data.vnc.keymap = virXMLPropString(node, "keymap"); @@ -14980,6 +14993,9 @@ virDomainGraphicsDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " autoport='%s'", def->data.vnc.autoport ? "yes" : "no"); + if (def->data.vnc.websocket) + virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket); + if (listenAddr) virBufferAsprintf(buf, " listen='%s'", listenAddr); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3a0f23a..79deaf3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1401,6 +1401,7 @@ struct _virDomainGraphicsDef { union { struct { int port; + int websocket; bool autoport; char *keymap; char *socket; -- 1.8.2.1

On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 16 ++++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 27 insertions(+)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index f325c3c..dfea434 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3530,6 +3530,11 @@ qemu-kvm -net nic,model=? /dev/null Rather than using listen/port, QEMU supports a <code>socket</code> attribute for listening on a unix domain socket path.<span class="since">Since 0.8.8</span> + + For VNC WebSocket functionality, <code>websocket</code> + attribute may be used to specify port to listen on (with -1 + meaning auto-allocation). <span class="since">Since + 1.0.6</span> </dd> <dt><code>"spice"</code></dt> <dd> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 10596dc..59999a1 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2071,6 +2071,11 @@ </attribute> </optional> <optional> + <attribute name="websocket"> + <ref name="PortNumber"/> + </attribute> + </optional> + <optional> <attribute name="listen"> <ref name="addrIPorName"/> </attribute> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a8b5dfd..fd9e926 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7546,6 +7546,7 @@ virDomainGraphicsDefParseXML(xmlNodePtr node,
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { char *port = virXMLPropString(node, "port"); + char *websocket = virXMLPropString(node, "websocket"); char *autoport;
if (port) { @@ -7576,6 +7577,18 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, VIR_FREE(autoport); }
+ if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port);
I think you meant websocket, not port for the string... it's a cut-n-paste error it seems. "port" will be VIR_FREE()'d already (or it may not have been found, so it's already NULL. John
+ VIR_FREE(websocket); + goto error; + } + VIR_FREE(websocket); + } + def->data.vnc.socket = virXMLPropString(node, "socket"); def->data.vnc.keymap = virXMLPropString(node, "keymap");
@@ -14980,6 +14993,9 @@ virDomainGraphicsDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " autoport='%s'", def->data.vnc.autoport ? "yes" : "no");
+ if (def->data.vnc.websocket) + virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket); + if (listenAddr) virBufferAsprintf(buf, " listen='%s'", listenAddr); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3a0f23a..79deaf3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1401,6 +1401,7 @@ struct _virDomainGraphicsDef { union { struct { int port; + int websocket; bool autoport; char *keymap; char *socket;

On 04/30/2013 09:18 AM, John Ferlan wrote:
On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> ---
+ if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port);
I think you meant websocket, not port for the string... it's a cut-n-paste error it seems.
"port" will be VIR_FREE()'d already (or it may not have been found, so it's already NULL.
But I like the proposal, and agree with the docs calling it out as 1.0.6 material. ACK with John's finding fixed. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 04/30/2013 06:21 PM, Eric Blake wrote:
On 04/30/2013 09:18 AM, John Ferlan wrote:
On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> ---
+ if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port);
I think you meant websocket, not port for the string... it's a cut-n-paste error it seems.
"port" will be VIR_FREE()'d already (or it may not have been found, so it's already NULL.
But I like the proposal, and agree with the docs calling it out as 1.0.6 material.
ACK with John's finding fixed.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 04/30/2013 06:21 PM, Eric Blake wrote:
On 04/30/2013 09:18 AM, John Ferlan wrote:
On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> ---
+ if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port);
I think you meant websocket, not port for the string... it's a cut-n-paste error it seems.
"port" will be VIR_FREE()'d already (or it may not have been found, so it's already NULL.
But I like the proposal, and agree with the docs calling it out as 1.0.6 material.
ACK with John's finding fixed.
I fixed what John found out and will push the series after I'll check one more thing. Sorry it took so long, I just found out about this mail since I wasn't one of the recipients. Thanks, Martin

On 05/10/2013 03:19 PM, Martin Kletzander wrote:
On 04/30/2013 06:21 PM, Eric Blake wrote:
On 04/30/2013 09:18 AM, John Ferlan wrote:
On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding support for new attribute 'websocket' in the '<graphics>' element, the attribute value is the port to listen on with '-1' meaning auto-allocation, '0' meaning no websockets.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> ---
+ if (websocket) { + if (virStrToLong_i(websocket, + NULL, 10, + &def->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc websocket port %s"), port);
I think you meant websocket, not port for the string... it's a cut-n-paste error it seems.
"port" will be VIR_FREE()'d already (or it may not have been found, so it's already NULL.
But I like the proposal, and agree with the docs calling it out as 1.0.6 material.
ACK with John's finding fixed.
I fixed what John found out and will push the series after I'll check one more thing. Sorry it took so long, I just found out about this mail since I wasn't one of the recipients.
I've found out there was missing call for virPortAllocatorRelease, plus the number of comments made me send a v3 just to be sure. So rebased version is available now [1]. Martin [1] http://www.redhat.com/archives/libvir-list/2013-May/msg00906.html

Adding a VNC WebSocket support for QEMU driver. This funcitonality is in upstream qemu from commit described as v1.3.0-982-g7536ee4, so the capability is being recognized based on QEMU version for now. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 7 +++++ src/qemu/qemu_capabilities.c | 11 +++++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 60 ++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_command.h | 5 +++- src/qemu/qemu_conf.c | 32 ++++++++++++++++++++ src/qemu/qemu_conf.h | 6 ++++ src/qemu/qemu_driver.c | 5 ++++ src/qemu/qemu_process.c | 31 ++++++++++++++++---- src/qemu/test_libvirtd_qemu.aug.in | 2 ++ tests/qemuargv2xmltest.c | 1 + tests/qemuxml2argvtest.c | 1 + tests/qemuxml2xmltest.c | 1 + 14 files changed, 153 insertions(+), 12 deletions(-) diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index a3dcb30..5344125 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -41,6 +41,8 @@ module Libvirtd_qemu = let remote_display_entry = int_entry "remote_display_port_min" | int_entry "remote_display_port_max" + | int_entry "remote_websocket_port_min" + | int_entry "remote_websocket_port_max" let security_entry = str_entry "security_driver" | bool_entry "security_default_confined" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 0f0a24c..9257d3d 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -153,6 +153,13 @@ #remote_display_port_min = 5900 #remote_display_port_max = 65535 +# VNC WebSocket port policies, same rules apply as with remote display +# ports. VNC WebSockets use similar display <-> port mappings, with +# the exception being that ports starts from 5700 instead of 5900. +# This is what may have be changed here. +# +#remote_websocket_port_min = 5700 +#remote_websocket_port_max = 65535 # The default security driver is SELinux. If SELinux is disabled # on the host, then the security driver will automatically disable diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2acf535..9e5eedf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -222,9 +222,10 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tpm-tis", "nvram", /* 140 */ - "pci-bridge", /* 141 */ - "vfio-pci", /* 142 */ - "vfio-pci.bootindex", /* 143 */ + "pci-bridge", + "vfio-pci", + "vfio-pci.bootindex", + "vnc-websocket", ); struct _virQEMUCaps { @@ -2520,6 +2521,10 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, if (qemuCaps->version >= 1003000) virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_USB_OPT); + /* WebSockets were introduced between 1.3.0 and 1.3.1 */ + if (qemuCaps->version >= 1003001) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET); + if (!(archstr = qemuMonitorGetTargetArch(mon))) goto cleanup; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 213f63c..c647274 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -182,6 +182,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_DEVICE_PCI_BRIDGE = 141, /* -device pci-bridge */ QEMU_CAPS_DEVICE_VFIO_PCI = 142, /* -device vfio-pci */ QEMU_CAPS_VFIO_PCI_BOOTINDEX = 143, /* bootindex param for vfio-pci device */ + QEMU_CAPS_VNC_WEBSOCKET = 144, /* bootindex param for vfio-pci device */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3184e5b..f718434 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5903,6 +5903,17 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg, } } + if (graphics->data.vnc.websocket) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC websockets are not supported " + "with this QEMU binary")); + goto error; + } + + virBufferAsprintf(&opt, ",websocket=%d", graphics->data.vnc.websocket); + } + virCommandAddArg(cmd, "-vnc"); virCommandAddArgBuffer(cmd, &opt); if (graphics->data.vnc.keymap) @@ -9726,6 +9737,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, * -vnc some.host.name:4 */ char *opts; + char *port; const char *sep = ":"; if (val[0] == '[') sep = "]:"; @@ -9736,11 +9748,12 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, _("missing VNC port number in '%s'"), val); goto error; } - if (virStrToLong_i(tmp+strlen(sep), &opts, 10, + port = tmp + strlen(sep); + if (virStrToLong_i(port, &opts, 10, &vnc->data.vnc.port) < 0) { virDomainGraphicsDefFree(vnc); virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse VNC port '%s'"), tmp+1); + _("cannot parse VNC port '%s'"), port); goto error; } if (val[0] == '[') @@ -9753,6 +9766,49 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, virDomainGraphicsDefFree(vnc); goto no_memory; } + + if (*opts == ',') { + char *orig_opts = strdup(opts + 1); + if (!orig_opts) { + virDomainGraphicsDefFree(vnc); + goto no_memory; + } + opts = orig_opts; + + while (opts && *opts) { + char *nextopt = strchr(opts, ','); + if (nextopt) + *(nextopt++) = '\0'; + + if (STRPREFIX(opts, "websocket")) { + char *websocket = opts + strlen("websocket"); + if (*(websocket++) == '=' && + *websocket) { + /* If the websocket continues with + * '=<something>', we'll parse it */ + if (virStrToLong_i(websocket, + NULL, 0, + &vnc->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse VNC " + "websocket port '%s'"), + websocket); + virDomainGraphicsDefFree(vnc); + VIR_FREE(orig_opts); + } + } else { + /* Otherwise, we'll compute the port the same + * way QEMU does, by adding a 5700 to the + * display value. */ + vnc->data.vnc.websocket = + vnc->data.vnc.port + 5700; + } + } + + opts = nextopt; + } + VIR_FREE(orig_opts); + } vnc->data.vnc.port += 5900; vnc->data.vnc.autoport = false; } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index a706942..724e88e 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -1,7 +1,7 @@ /* * qemu_command.h: QEMU command generation * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2013 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -48,6 +48,9 @@ # define QEMU_REMOTE_PORT_MIN 5900 # define QEMU_REMOTE_PORT_MAX 65535 +# define QEMU_WEBSOCKET_PORT_MIN 5700 +# define QEMU_WEBSOCKET_PORT_MAX 65535 + virCommandPtr qemuBuildCommandLine(virConnectPtr conn, virQEMUDriverPtr driver, diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 7c3f317..1e56c5b 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -228,6 +228,9 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) cfg->remotePortMin = QEMU_REMOTE_PORT_MIN; cfg->remotePortMax = QEMU_REMOTE_PORT_MAX; + cfg->webSocketPortMin = QEMU_WEBSOCKET_PORT_MIN; + cfg->webSocketPortMax = QEMU_WEBSOCKET_PORT_MAX; + #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R /* For privileged driver, try and find hugepage mount automatically. * Non-privileged driver requires admin to create a dir for the @@ -404,6 +407,35 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_STR("spice_password", cfg->spicePassword); + GET_VALUE_LONG("remote_websocket_port_min", cfg->webSocketPortMin); + if (cfg->webSocketPortMin < QEMU_WEBSOCKET_PORT_MIN) { + /* if the port is too low, we can't get the display name + * to tell to vnc (usually subtract 5700, e.g. localhost:1 + * for port 5701) */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_min: port must be greater " + "than or equal to %d"), + filename, QEMU_WEBSOCKET_PORT_MIN); + goto cleanup; + } + + GET_VALUE_LONG("remote_websocket_port_max", cfg->webSocketPortMax); + if (cfg->webSocketPortMax > QEMU_WEBSOCKET_PORT_MAX || + cfg->webSocketPortMax < cfg->webSocketPortMin) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_max: port must be between " + "the minimal port and %d"), + filename, QEMU_WEBSOCKET_PORT_MAX); + goto cleanup; + } + + if (cfg->webSocketPortMin > cfg->webSocketPortMax) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_min: min port must not be " + "greater than max port"), filename); + goto cleanup; + } + GET_VALUE_LONG("remote_display_port_min", cfg->remotePortMin); if (cfg->remotePortMin < QEMU_REMOTE_PORT_MIN) { /* if the port is too low, we can't get the display name diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 77d3d2f..8392729 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -114,6 +114,9 @@ struct _virQEMUDriverConfig { int remotePortMin; int remotePortMax; + int webSocketPortMin; + int webSocketPortMax; + char *hugetlbfsMount; char *hugepagePath; char *bridgeHelperName; @@ -210,6 +213,9 @@ struct _virQEMUDriver { /* Immutable pointer, self-locking APIs */ virPortAllocatorPtr remotePorts; + /* Immutable pointer, self-locking APIs */ + virPortAllocatorPtr webSocketPorts; + /* Immutable pointer, lockless APIs*/ virSysinfoDefPtr hostsysinfo; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 296efe3..cf0bc55 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -663,6 +663,11 @@ qemuStateInitialize(bool privileged, cfg->remotePortMax)) == NULL) goto error; + if ((qemu_driver->webSocketPorts = + virPortAllocatorNew(cfg->webSocketPortMin, + cfg->webSocketPortMax)) == NULL) + goto error; + if (qemuSecurityInit(qemu_driver) < 0) goto error; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index e75c8c9..296e9b3 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3233,6 +3233,29 @@ qemuSetUnprivSGIO(virDomainDiskDefPtr disk) return ret; } +static int +qemuProcessVNCAllocatePorts(virQEMUDriverPtr driver, + virDomainGraphicsDefPtr graphics) +{ + unsigned short port; + + if (graphics->data.vnc.socket) + return 0; + + if (graphics->data.vnc.autoport) { + if (virPortAllocatorAcquire(driver->remotePorts, &port) < 0) + return -1; + graphics->data.vnc.port = port; + } + + if (graphics->data.vnc.websocket == -1) { + if (virPortAllocatorAcquire(driver->webSocketPorts, &port) < 0) + return -1; + graphics->data.vnc.websocket = port; + } + + return 0; +} static int qemuProcessSPICEAllocatePorts(virQEMUDriverPtr driver, @@ -3448,13 +3471,9 @@ int qemuProcessStart(virConnectPtr conn, for (i = 0 ; i < vm->def->ngraphics; ++i) { virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; - if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && - !graphics->data.vnc.socket && - graphics->data.vnc.autoport) { - unsigned short port; - if (virPortAllocatorAcquire(driver->remotePorts, &port) < 0) + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { + if (qemuProcessVNCAllocatePorts(driver, graphics) < 0) goto cleanup; - graphics->data.vnc.port = port; } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { if (qemuProcessSPICEAllocatePorts(driver, cfg, graphics) < 0) goto cleanup; diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index 26ca068..d4e4fae 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -17,6 +17,8 @@ module Test_libvirtd_qemu = { "spice_password" = "XYZ12345" } { "remote_display_port_min" = "5900" } { "remote_display_port_max" = "65535" } +{ "remote_websocket_port_min" = "5700" } +{ "remote_websocket_port_max" = "65535" } { "security_driver" = "selinux" } { "security_default_confined" = "1" } { "security_require_confined" = "1" } diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 9f1bb24..c8e7825 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -200,6 +200,7 @@ mymain(void) DO_TEST("disk-usb"); DO_TEST("graphics-vnc"); DO_TEST("graphics-vnc-socket"); + DO_TEST("graphics-vnc-websocket"); DO_TEST("graphics-vnc-sasl"); DO_TEST("graphics-vnc-tls"); diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9699f77..0db3181 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -597,6 +597,7 @@ mymain(void) DO_TEST("graphics-vnc", QEMU_CAPS_VNC); DO_TEST("graphics-vnc-socket", QEMU_CAPS_VNC); + DO_TEST("graphics-vnc-websocket", QEMU_CAPS_VNC, QEMU_CAPS_VNC_WEBSOCKET); driver.config->vncSASL = 1; VIR_FREE(driver.config->vncSASLdir); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index a81cfcf..7400779 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -186,6 +186,7 @@ mymain(void) DO_TEST_FULL("disk-mirror", true, WHEN_INACTIVE); DO_TEST("graphics-listen-network"); DO_TEST("graphics-vnc"); + DO_TEST("graphics-vnc-websocket"); DO_TEST("graphics-vnc-sasl"); DO_TEST("graphics-vnc-tls"); DO_TEST("graphics-sdl"); -- 1.8.2.1

On 04/30/2013 08:42 AM, Martin Kletzander wrote:
Adding a VNC WebSocket support for QEMU driver. This funcitonality is
s/funcitonality/functionality/
in upstream qemu from commit described as v1.3.0-982-g7536ee4, so the capability is being recognized based on QEMU version for now.
I wish we could do better than just a version check; is there anything we can probe in QMP, or possibly even use qemu 1.5's query-command-line-parameters as an additional method for checking when this has been backported to a build earlier than 1.2? At any rate, don't let that hold up this patch; we can improve detection methods as followup patches when (and if) a downstream distro even decides to backport websocket support.
+++ b/src/qemu/qemu.conf @@ -153,6 +153,13 @@ #remote_display_port_min = 5900 #remote_display_port_max = 65535
+# VNC WebSocket port policies, same rules apply as with remote display +# ports. VNC WebSockets use similar display <-> port mappings, with +# the exception being that ports starts from 5700 instead of 5900. +# This is what may have be changed here.
Not sure this last sentence adds anything here.
+# +#remote_websocket_port_min = 5700 +#remote_websocket_port_max = 65535
+++ b/src/qemu/qemu_capabilities.h @@ -182,6 +182,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_DEVICE_PCI_BRIDGE = 141, /* -device pci-bridge */ QEMU_CAPS_DEVICE_VFIO_PCI = 142, /* -device vfio-pci */ QEMU_CAPS_VFIO_PCI_BOOTINDEX = 143, /* bootindex param for vfio-pci device */ + QEMU_CAPS_VNC_WEBSOCKET = 144, /* bootindex param for vfio-pci device */
Comment needs fixing. Rest of patch looks fine. ACK with problems fixed. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding a VNC WebSocket support for QEMU driver. This funcitonality is
s/funcitonality/functionality
in upstream qemu from commit described as v1.3.0-982-g7536ee4, so the capability is being recognized based on QEMU version for now.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 7 +++++ src/qemu/qemu_capabilities.c | 11 +++++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 60 ++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_command.h | 5 +++- src/qemu/qemu_conf.c | 32 ++++++++++++++++++++ src/qemu/qemu_conf.h | 6 ++++ src/qemu/qemu_driver.c | 5 ++++ src/qemu/qemu_process.c | 31 ++++++++++++++++---- src/qemu/test_libvirtd_qemu.aug.in | 2 ++ tests/qemuargv2xmltest.c | 1 + tests/qemuxml2argvtest.c | 1 + tests/qemuxml2xmltest.c | 1 + 14 files changed, 153 insertions(+), 12 deletions(-)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index a3dcb30..5344125 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -41,6 +41,8 @@ module Libvirtd_qemu =
let remote_display_entry = int_entry "remote_display_port_min" | int_entry "remote_display_port_max" + | int_entry "remote_websocket_port_min" + | int_entry "remote_websocket_port_max"
let security_entry = str_entry "security_driver" | bool_entry "security_default_confined" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 0f0a24c..9257d3d 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -153,6 +153,13 @@ #remote_display_port_min = 5900 #remote_display_port_max = 65535
+# VNC WebSocket port policies, same rules apply as with remote display +# ports. VNC WebSockets use similar display <-> port mappings, with +# the exception being that ports starts from 5700 instead of 5900. +# This is what may have be changed here. +# +#remote_websocket_port_min = 5700 +#remote_websocket_port_max = 65535
# The default security driver is SELinux. If SELinux is disabled # on the host, then the security driver will automatically disable diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2acf535..9e5eedf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -222,9 +222,10 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tpm-tis",
"nvram", /* 140 */ - "pci-bridge", /* 141 */ - "vfio-pci", /* 142 */ - "vfio-pci.bootindex", /* 143 */ + "pci-bridge", + "vfio-pci", + "vfio-pci.bootindex", + "vnc-websocket",
This list doesn't match below... I also remember reading a comment recently about counting every 5th and leaving proper spacing between groups of 5.
);
struct _virQEMUCaps { @@ -2520,6 +2521,10 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, if (qemuCaps->version >= 1003000) virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_USB_OPT);
+ /* WebSockets were introduced between 1.3.0 and 1.3.1 */ + if (qemuCaps->version >= 1003001) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET); + if (!(archstr = qemuMonitorGetTargetArch(mon))) goto cleanup;
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 213f63c..c647274 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -182,6 +182,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_DEVICE_PCI_BRIDGE = 141, /* -device pci-bridge */ QEMU_CAPS_DEVICE_VFIO_PCI = 142, /* -device vfio-pci */ QEMU_CAPS_VFIO_PCI_BOOTINDEX = 143, /* bootindex param for vfio-pci device */ + QEMU_CAPS_VNC_WEBSOCKET = 144, /* bootindex param for vfio-pci device */
This doesn't match above
QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3184e5b..f718434 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5903,6 +5903,17 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg, } }
+ if (graphics->data.vnc.websocket) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC websockets are not supported "
Should it be "WebSockets" or does it matter?
+ "with this QEMU binary")); + goto error; + } + + virBufferAsprintf(&opt, ",websocket=%d", graphics->data.vnc.websocket); + } + virCommandAddArg(cmd, "-vnc"); virCommandAddArgBuffer(cmd, &opt); if (graphics->data.vnc.keymap) @@ -9726,6 +9737,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, * -vnc some.host.name:4 */ char *opts; + char *port; const char *sep = ":"; if (val[0] == '[') sep = "]:"; @@ -9736,11 +9748,12 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, _("missing VNC port number in '%s'"), val); goto error; } - if (virStrToLong_i(tmp+strlen(sep), &opts, 10, + port = tmp + strlen(sep); + if (virStrToLong_i(port, &opts, 10, &vnc->data.vnc.port) < 0) { virDomainGraphicsDefFree(vnc); virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse VNC port '%s'"), tmp+1); + _("cannot parse VNC port '%s'"), port); goto error; } if (val[0] == '[') @@ -9753,6 +9766,49 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, virDomainGraphicsDefFree(vnc); goto no_memory; } + + if (*opts == ',') { + char *orig_opts = strdup(opts + 1); + if (!orig_opts) { + virDomainGraphicsDefFree(vnc); + goto no_memory; + } + opts = orig_opts; + + while (opts && *opts) { + char *nextopt = strchr(opts, ','); + if (nextopt) + *(nextopt++) = '\0'; + + if (STRPREFIX(opts, "websocket")) { + char *websocket = opts + strlen("websocket"); + if (*(websocket++) == '=' && + *websocket) { + /* If the websocket continues with + * '=<something>', we'll parse it */ + if (virStrToLong_i(websocket, + NULL, 0, + &vnc->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse VNC " + "websocket port '%s'"),
Do we care to make it "WebSocket"?
+ websocket); + virDomainGraphicsDefFree(vnc); + VIR_FREE(orig_opts); + } + } else { + /* Otherwise, we'll compute the port the same + * way QEMU does, by adding a 5700 to the + * display value. */ + vnc->data.vnc.websocket = + vnc->data.vnc.port + 5700;
s/5700/QEMU_WEBSOCKET_PORT_MIN I see there is a QEMU_REMOTE_PORT_MIN in qemu_command.h, but it's not used in qemu_command.c either....
+ } + } + + opts = nextopt; + } + VIR_FREE(orig_opts); + } vnc->data.vnc.port += 5900; vnc->data.vnc.autoport = false; } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index a706942..724e88e 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -1,7 +1,7 @@ /* * qemu_command.h: QEMU command generation * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2013 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -48,6 +48,9 @@ # define QEMU_REMOTE_PORT_MIN 5900 # define QEMU_REMOTE_PORT_MAX 65535
+# define QEMU_WEBSOCKET_PORT_MIN 5700 +# define QEMU_WEBSOCKET_PORT_MAX 65535 +
virCommandPtr qemuBuildCommandLine(virConnectPtr conn, virQEMUDriverPtr driver, diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 7c3f317..1e56c5b 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -228,6 +228,9 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) cfg->remotePortMin = QEMU_REMOTE_PORT_MIN; cfg->remotePortMax = QEMU_REMOTE_PORT_MAX;
+ cfg->webSocketPortMin = QEMU_WEBSOCKET_PORT_MIN; + cfg->webSocketPortMax = QEMU_WEBSOCKET_PORT_MAX; + #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R /* For privileged driver, try and find hugepage mount automatically. * Non-privileged driver requires admin to create a dir for the @@ -404,6 +407,35 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_STR("spice_password", cfg->spicePassword);
+ GET_VALUE_LONG("remote_websocket_port_min", cfg->webSocketPortMin); + if (cfg->webSocketPortMin < QEMU_WEBSOCKET_PORT_MIN) { + /* if the port is too low, we can't get the display name + * to tell to vnc (usually subtract 5700, e.g. localhost:1 + * for port 5701) */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_min: port must be greater " + "than or equal to %d"), + filename, QEMU_WEBSOCKET_PORT_MIN); + goto cleanup; + } + + GET_VALUE_LONG("remote_websocket_port_max", cfg->webSocketPortMax); + if (cfg->webSocketPortMax > QEMU_WEBSOCKET_PORT_MAX || + cfg->webSocketPortMax < cfg->webSocketPortMin) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_max: port must be between " + "the minimal port and %d"), + filename, QEMU_WEBSOCKET_PORT_MAX); + goto cleanup; + } + + if (cfg->webSocketPortMin > cfg->webSocketPortMax) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: remote_websocket_port_min: min port must not be " + "greater than max port"), filename); + goto cleanup; + } + GET_VALUE_LONG("remote_display_port_min", cfg->remotePortMin); if (cfg->remotePortMin < QEMU_REMOTE_PORT_MIN) { /* if the port is too low, we can't get the display name diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 77d3d2f..8392729 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -114,6 +114,9 @@ struct _virQEMUDriverConfig { int remotePortMin; int remotePortMax;
+ int webSocketPortMin; + int webSocketPortMax; + char *hugetlbfsMount; char *hugepagePath; char *bridgeHelperName; @@ -210,6 +213,9 @@ struct _virQEMUDriver { /* Immutable pointer, self-locking APIs */ virPortAllocatorPtr remotePorts;
+ /* Immutable pointer, self-locking APIs */ + virPortAllocatorPtr webSocketPorts; + /* Immutable pointer, lockless APIs*/ virSysinfoDefPtr hostsysinfo;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 296efe3..cf0bc55 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -663,6 +663,11 @@ qemuStateInitialize(bool privileged, cfg->remotePortMax)) == NULL) goto error;
+ if ((qemu_driver->webSocketPorts = + virPortAllocatorNew(cfg->webSocketPortMin, + cfg->webSocketPortMax)) == NULL) + goto error; + if (qemuSecurityInit(qemu_driver) < 0) goto error;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index e75c8c9..296e9b3 100644You'd have to use %d and def->data.vnc.port, assuming it's valid...
--- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3233,6 +3233,29 @@ qemuSetUnprivSGIO(virDomainDiskDefPtr disk) return ret; }
+static int +qemuProcessVNCAllocatePorts(virQEMUDriverPtr driver, + virDomainGraphicsDefPtr graphics) +{ + unsigned short port; + + if (graphics->data.vnc.socket) + return 0; + + if (graphics->data.vnc.autoport) { + if (virPortAllocatorAcquire(driver->remotePorts, &port) < 0) + return -1; + graphics->data.vnc.port = port; + } + + if (graphics->data.vnc.websocket == -1) { + if (virPortAllocatorAcquire(driver->webSocketPorts, &port) < 0) + return -1; + graphics->data.vnc.websocket = port; + } + + return 0; +}
static int qemuProcessSPICEAllocatePorts(virQEMUDriverPtr driver, @@ -3448,13 +3471,9 @@ int qemuProcessStart(virConnectPtr conn,
for (i = 0 ; i < vm->def->ngraphics; ++i) { virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; - if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && - !graphics->data.vnc.socket && - graphics->data.vnc.autoport) { - unsigned short port; - if (virPortAllocatorAcquire(driver->remotePorts, &port) < 0) + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { + if (qemuProcessVNCAllocatePorts(driver, graphics) < 0) goto cleanup; - graphics->data.vnc.port = port; } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { if (qemuProcessSPICEAllocatePorts(driver, cfg, graphics) < 0) goto cleanup; diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index 26ca068..d4e4fae 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -17,6 +17,8 @@ module Test_libvirtd_qemu = { "spice_password" = "XYZ12345" } { "remote_display_port_min" = "5900" } { "remote_display_port_max" = "65535" } +{ "remote_websocket_port_min" = "5700" } +{ "remote_websocket_port_max" = "65535" } { "security_driver" = "selinux" } { "security_default_confined" = "1" } { "security_require_confined" = "1" } diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 9f1bb24..c8e7825 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -200,6 +200,7 @@ mymain(void) DO_TEST("disk-usb"); DO_TEST("graphics-vnc"); DO_TEST("graphics-vnc-socket"); + DO_TEST("graphics-vnc-websocket");
DO_TEST("graphics-vnc-sasl"); DO_TEST("graphics-vnc-tls"); diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9699f77..0db3181 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -597,6 +597,7 @@ mymain(void)
DO_TEST("graphics-vnc", QEMU_CAPS_VNC); DO_TEST("graphics-vnc-socket", QEMU_CAPS_VNC); + DO_TEST("graphics-vnc-websocket", QEMU_CAPS_VNC, QEMU_CAPS_VNC_WEBSOCKET);
driver.config->vncSASL = 1; VIR_FREE(driver.config->vncSASLdir); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index a81cfcf..7400779 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -186,6 +186,7 @@ mymain(void) DO_TEST_FULL("disk-mirror", true, WHEN_INACTIVE); DO_TEST("graphics-listen-network"); DO_TEST("graphics-vnc"); + DO_TEST("graphics-vnc-websocket"); DO_TEST("graphics-vnc-sasl"); DO_TEST("graphics-vnc-tls"); DO_TEST("graphics-sdl");

On 04/30/2013 06:53 PM, John Ferlan wrote:
On 04/30/2013 10:42 AM, Martin Kletzander wrote:
Adding a VNC WebSocket support for QEMU driver. This funcitonality is
s/funcitonality/functionality
in upstream qemu from commit described as v1.3.0-982-g7536ee4, so the capability is being recognized based on QEMU version for now.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 7 +++++ src/qemu/qemu_capabilities.c | 11 +++++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 60 ++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_command.h | 5 +++- src/qemu/qemu_conf.c | 32 ++++++++++++++++++++ src/qemu/qemu_conf.h | 6 ++++ src/qemu/qemu_driver.c | 5 ++++ src/qemu/qemu_process.c | 31 ++++++++++++++++---- src/qemu/test_libvirtd_qemu.aug.in | 2 ++ tests/qemuargv2xmltest.c | 1 + tests/qemuxml2argvtest.c | 1 + tests/qemuxml2xmltest.c | 1 + 14 files changed, 153 insertions(+), 12 deletions(-)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index a3dcb30..5344125 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -41,6 +41,8 @@ module Libvirtd_qemu =
let remote_display_entry = int_entry "remote_display_port_min" | int_entry "remote_display_port_max" + | int_entry "remote_websocket_port_min" + | int_entry "remote_websocket_port_max"
let security_entry = str_entry "security_driver" | bool_entry "security_default_confined" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 0f0a24c..9257d3d 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -153,6 +153,13 @@ #remote_display_port_min = 5900 #remote_display_port_max = 65535
+# VNC WebSocket port policies, same rules apply as with remote display +# ports. VNC WebSockets use similar display <-> port mappings, with +# the exception being that ports starts from 5700 instead of 5900. +# This is what may have be changed here. +# +#remote_websocket_port_min = 5700 +#remote_websocket_port_max = 65535
# The default security driver is SELinux. If SELinux is disabled # on the host, then the security driver will automatically disable diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2acf535..9e5eedf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -222,9 +222,10 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tpm-tis",
"nvram", /* 140 */ - "pci-bridge", /* 141 */ - "vfio-pci", /* 142 */ - "vfio-pci.bootindex", /* 143 */ + "pci-bridge", + "vfio-pci", + "vfio-pci.bootindex", + "vnc-websocket",
This list doesn't match below... I also remember reading a comment recently about counting every 5th and leaving proper spacing between groups of 5.
This is actually counting only every 5th (but starting with 0, so it's the "nvram" /* 140 */ here.
);
struct _virQEMUCaps { @@ -2520,6 +2521,10 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, if (qemuCaps->version >= 1003000) virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_USB_OPT);
+ /* WebSockets were introduced between 1.3.0 and 1.3.1 */ + if (qemuCaps->version >= 1003001) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET); + if (!(archstr = qemuMonitorGetTargetArch(mon))) goto cleanup;
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 213f63c..c647274 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -182,6 +182,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_DEVICE_PCI_BRIDGE = 141, /* -device pci-bridge */ QEMU_CAPS_DEVICE_VFIO_PCI = 142, /* -device vfio-pci */ QEMU_CAPS_VFIO_PCI_BOOTINDEX = 143, /* bootindex param for vfio-pci device */ + QEMU_CAPS_VNC_WEBSOCKET = 144, /* bootindex param for vfio-pci device */
This doesn't match above
QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3184e5b..f718434 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5903,6 +5903,17 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg, } }
+ if (graphics->data.vnc.websocket) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC websockets are not supported "
Should it be "WebSockets" or does it matter?
I think it doesn't matter, but I changed it to WebSocket everywhere.
+ "with this QEMU binary")); + goto error; + } + + virBufferAsprintf(&opt, ",websocket=%d", graphics->data.vnc.websocket); + } + virCommandAddArg(cmd, "-vnc"); virCommandAddArgBuffer(cmd, &opt); if (graphics->data.vnc.keymap) @@ -9726,6 +9737,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, * -vnc some.host.name:4 */ char *opts; + char *port; const char *sep = ":"; if (val[0] == '[') sep = "]:"; @@ -9736,11 +9748,12 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, _("missing VNC port number in '%s'"), val); goto error; } - if (virStrToLong_i(tmp+strlen(sep), &opts, 10, + port = tmp + strlen(sep); + if (virStrToLong_i(port, &opts, 10, &vnc->data.vnc.port) < 0) { virDomainGraphicsDefFree(vnc); virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse VNC port '%s'"), tmp+1); + _("cannot parse VNC port '%s'"), port); goto error; } if (val[0] == '[') @@ -9753,6 +9766,49 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr qemuCaps, virDomainGraphicsDefFree(vnc); goto no_memory; } + + if (*opts == ',') { + char *orig_opts = strdup(opts + 1); + if (!orig_opts) { + virDomainGraphicsDefFree(vnc); + goto no_memory; + } + opts = orig_opts; + + while (opts && *opts) { + char *nextopt = strchr(opts, ','); + if (nextopt) + *(nextopt++) = '\0'; + + if (STRPREFIX(opts, "websocket")) { + char *websocket = opts + strlen("websocket"); + if (*(websocket++) == '=' && + *websocket) { + /* If the websocket continues with + * '=<something>', we'll parse it */ + if (virStrToLong_i(websocket, + NULL, 0, + &vnc->data.vnc.websocket) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse VNC " + "websocket port '%s'"),
Do we care to make it "WebSocket"?
Same here.
+ websocket); + virDomainGraphicsDefFree(vnc); + VIR_FREE(orig_opts); + } + } else { + /* Otherwise, we'll compute the port the same + * way QEMU does, by adding a 5700 to the + * display value. */ + vnc->data.vnc.websocket = + vnc->data.vnc.port + 5700;
s/5700/QEMU_WEBSOCKET_PORT_MIN
I see there is a QEMU_REMOTE_PORT_MIN in qemu_command.h, but it's not used in qemu_command.c either....
Actually no. This is parsing the command line of qemu, which always adds 5700, but not our minimum. I failed to see your mail because you didn't reply-all, noticed it now. I'll go through Eric's comments and push afterwards. Martin
participants (3)
-
Eric Blake
-
John Ferlan
-
Martin Kletzander