The domain XML now understands the <listen> subelement of its <graphics> element (including when listen type='network'), and the network driver has an internal API that will turn a network name into an IP address, so the final logical step is to put the glue into the qemu driver so that when it is starting up a domain, if it finds <listen type='network' network='xyz'/> in the XML, it will call the network driver to get an IPv4 address associated with network xyz, and tell qemu to listen for vnc (or spice) on that address rather than the default address (localhost). The motivation for this is that a large installation may want the guests' VNC servers listening on physical interfaces rather than localhost, so that users can connect directly from the outside; this requires sending qemu the appropriate IP address to listen on. But this address will of course be different for each host, and if a guest might be migrated around from one host to another, it's important that the guest's config not have any information embedded in it that is specific to one particular host. <listen type='network.../> can solve this problem in the following manner: 1) on each host, define a libvirt network of the same name, associated with the interface on that host that should be used for listening (for example, a simple macvtap network: <forward mode='bridge' dev='eth0'/>, or host bridge network: <forward mode='bridge'/> <bridge name='br0'/> 2) in the <graphics> element of each guest's domain xml, tell vnc to listen on the network name used in step 1: <graphics type='vnc'> <listen type='network'network='example-net' autoport='yes'/> </graphics> (all the above also applies for graphics type='spice'). --- src/qemu/qemu_command.c | 65 +++++++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_hotplug.c | 13 +++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 4a39078..9ee7658 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4111,7 +4111,6 @@ qemuBuildCommandLine(virConnectPtr conn, if ((def->ngraphics == 1) && def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { int port = virDomainGraphicsListenGetPort(def->graphics[0], 0); - const char *listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); virBuffer opt = VIR_BUFFER_INITIALIZER; if (def->graphics[0]->data.vnc.socket || @@ -4127,7 +4126,37 @@ qemuBuildCommandLine(virConnectPtr conn, def->graphics[0]->data.vnc.socket); } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNC_COLON)) { + const char *listenNetwork; + const char *listenAddr = NULL; + char *netAddr = NULL; bool escapeAddr; + int ret; + + switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: + listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); + break; + + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: + listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); + if (!listenNetwork) + break; + ret = networkGetNetworkAddress(listenNetwork, &netAddr); + if (ret <= -2) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("network-based listen not possible, " + "network driver not present")); + goto error; + } + if (ret < 0) { + qemuReportError(VIR_ERR_XML_ERROR, + _("listen network '%s' had no usable address"), + listenNetwork); + goto error; + } + listenAddr = netAddr; + break; + } if (!listenAddr) listenAddr = driver->vncListen; @@ -4139,6 +4168,7 @@ qemuBuildCommandLine(virConnectPtr conn, virBufferAdd(&opt, listenAddr, -1); virBufferAsprintf(&opt, ":%d", port - 5900); + VIR_FREE(netAddr); } else { virBufferAsprintf(&opt, "%d", port - 5900); } @@ -4223,7 +4253,10 @@ qemuBuildCommandLine(virConnectPtr conn, virBuffer opt = VIR_BUFFER_INITIALIZER; int port = virDomainGraphicsListenGetPort(def->graphics[0], 0); int tlsPort = virDomainGraphicsListenGetTlsPort(def->graphics[0], 0); - const char *listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); + const char *listenNetwork; + const char *listenAddr = NULL; + char *netAddr = NULL; + int ret; if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SPICE)) { qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -4236,11 +4269,39 @@ qemuBuildCommandLine(virConnectPtr conn, if (driver->spiceTLS && tlsPort != -1) virBufferAsprintf(&opt, ",tls-port=%u", tlsPort); + switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: + listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); + break; + + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: + listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); + if (!listenNetwork) + break; + ret = networkGetNetworkAddress(listenNetwork, &netAddr); + if (ret <= -2) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("network-based listen not possible, " + "network driver not present")); + goto error; + } + if (ret < 0) { + qemuReportError(VIR_ERR_XML_ERROR, + _("listen network '%s' had no usable address"), + listenNetwork); + goto error; + } + listenAddr = netAddr; + break; + } + if (!listenAddr) listenAddr = driver->spiceListen; if (listenAddr) virBufferAsprintf(&opt, ",addr=%s", listenAddr); + VIR_FREE(netAddr); + /* In the password case we set it via monitor command, to avoid * making it visible on CLI, so there's no use of password=XXX * in this bit of the code */ diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 18b5164..6aa3bef 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1055,6 +1055,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, int oldPort, newPort, oldTlsPort, newTlsPort; bool oldAutoport, newAutoport; const char *oldListenAddr, *newListenAddr; + const char *oldListenNetwork, *newListenNetwork; int ret = -1; if (!olddev) { @@ -1071,6 +1072,8 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, newTlsPort = virDomainGraphicsListenGetTlsPort(dev, 0); oldListenAddr = virDomainGraphicsListenGetAddress(olddev, 0); newListenAddr = virDomainGraphicsListenGetAddress(dev, 0); + oldListenNetwork = virDomainGraphicsListenGetNetwork(olddev, 0); + newListenNetwork = virDomainGraphicsListenGetNetwork(dev, 0); switch (dev->type) { case VIR_DOMAIN_GRAPHICS_TYPE_VNC: @@ -1086,6 +1089,11 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, _("cannot change listen address setting on vnc graphics")); return -1; } + if (STRNEQ_NULLABLE(oldListenNetwork,newListenNetwork)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot change listen network setting on vnc graphics")); + return -1; + } if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot change keymap setting on vnc graphics")); @@ -1132,6 +1140,11 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, _("cannot change listen address setting on spice graphics")); return -1; } + if (STRNEQ_NULLABLE(oldListenNetwork,newListenNetwork)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot change listen network setting on vnc graphics")); + return -1; + } if (STRNEQ_NULLABLE(olddev->data.spice.keymap, dev->data.spice.keymap)) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list