[libvirt] [PATCH v2 2/2] qemu: Add VNC WebSocket support
John Ferlan
jferlan at redhat.com
Tue Apr 30 16:53:26 UTC 2013
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 at 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");
>
More information about the libvir-list
mailing list