The domain XML now understands an attribute named "listenNetwork" in the <graphics> element, 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 such that when it is starting up a domain, if it finds "listenNetwork" in the XML, it will call the network driver to get an associated IP address, and tell qemu to listen for vnc (or spice) on that address rather than the default (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. listenNetwork can solve this problem in the following manner: 1) on each host, define a libvirt network of the same name, associated with some interface on that host (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' autoport='yes' listenNetwork='example-net'/> (all the above also applies for graphics type='spice'). Since this is the commit that turns on the new functionality, I've included the doc changes here. --- docs/formatdomain.html.in | 22 ++++++++++++++--- src/qemu/qemu_command.c | 55 ++++++++++++++++++++++++++++++++++++++++----- src/qemu/qemu_hotplug.c | 12 +++++++++ 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 8f42ba9..2788190 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1934,8 +1934,15 @@ qemu-kvm -net nic,model=? /dev/null auto-allocated). The <code>autoport</code> attribute is the new preferred syntax for indicating autoallocation of the TCP port to use. The <code>listen</code> attribute is - an IP address for the server to listen - on. The <code>passwd</code> attribute provides a VNC + an IP address for the server to listen on. + Alternately, a <code>listenNetwork</code> attribute can be + specified instead<span class="since">Since 0.9.4</span>; + the named network will be looked up in the list of + networks managed by libvirt and, if found, the VNC server + will listen on the IP address associated with the physical + device used by that network (e.g. the bridge device or the + direct mode forward <code>dev</code>). + The <code>passwd</code> attribute provides a VNC password in clear text. The <code>keymap</code> attribute specifies the keymap to use. It is possible to set a limit on the validity of the password be giving an @@ -1959,8 +1966,15 @@ qemu-kvm -net nic,model=? /dev/null port number. The <code>autoport</code> attribute is the new preferred syntax for indicating autoallocation of both port numbers. The <code>listen</code> attribute is - an IP address for the server to listen - on. The <code>passwd</code> attribute provides a SPICE + an IP address for the server to listen on. + Alternately, a <code>listenNetwork</code> attribute can be + specified instead<span class="since">Since 0.9.4</span>; + the named network will be looked up in the list of + networks managed by libvirt and, if found, the VNC server + will listen on the IP address associated with the physical + device used by that network (e.g. the bridge device or the + direct mode forward <code>dev</code>). + The <code>passwd</code> attribute provides a SPICE password in clear text. The <code>keymap</code> attribute specifies the keymap to use. It is possible to set a limit on the validity of the password be giving an diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 0ae8d67..bccb984 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4116,16 +4116,40 @@ qemuBuildCommandLine(virConnectPtr conn, def->graphics[0]->data.vnc.socket); } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNC_COLON)) { - const char *addr = def->graphics[0]->data.vnc.listenAddr ? - def->graphics[0]->data.vnc.listenAddr : - driver->vncListen; - bool escapeAddr = strchr(addr, ':') != NULL; + int ret; + char *addr; + bool freeAddr = false; + bool escapeAddr; + + if (def->graphics[0]->data.vnc.listenAddr) { + addr = def->graphics[0]->data.vnc.listenAddr; + } else if (def->graphics[0]->data.vnc.listenNetwork) { + ret = networkGetNetworkAddress(def->graphics[0]->data.vnc.listenNetwork, + &addr); + if (ret <= -2) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("listenNetwork not supported, network driver not present")); + } + if (!addr) { + qemuReportError(VIR_ERR_XML_ERROR, + _("listenNetwork '%s' had no usable address"), + def->graphics[0]->data.vnc.listenNetwork); + goto error; + } + freeAddr = true; + } else { + addr = driver->vncListen; + } + + escapeAddr = strchr(addr, ':') != NULL; if (escapeAddr) virBufferAsprintf(&opt, "[%s]", addr); else virBufferAdd(&opt, addr, -1); virBufferAsprintf(&opt, ":%d", def->graphics[0]->data.vnc.port - 5900); + if (freeAddr) + VIR_FREE(addr); } else { virBufferAsprintf(&opt, "%d", @@ -4222,10 +4246,29 @@ qemuBuildCommandLine(virConnectPtr conn, if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1) virBufferAsprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort); - if (def->graphics[0]->data.spice.listenAddr) + if (def->graphics[0]->data.spice.listenAddr) { virBufferAsprintf(&opt, ",addr=%s", def->graphics[0]->data.spice.listenAddr); - else if (driver->spiceListen) + } else if (def->graphics[0]->data.spice.listenNetwork) { + int ret; + char *addr; + + ret = networkGetNetworkAddress(def->graphics[0]->data.spice.listenNetwork, + &addr); + if (ret <= -2) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("listenNetwork not supported, network driver not present")); + } + if (!addr) { + qemuReportError(VIR_ERR_XML_ERROR, + _("listenNetwork '%s' had no usable address"), + def->graphics[0]->data.spice.listenNetwork); + goto error; + } + virBufferAsprintf(&opt, ",addr=%s", addr); + VIR_FREE(addr); + } else if (driver->spiceListen) { virBufferAsprintf(&opt, ",addr=%s", driver->spiceListen); + } /* 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 diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 74ce9be..09023b0 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1075,6 +1075,12 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, _("cannot change listen address setting on vnc graphics")); return -1; } + if (STRNEQ_NULLABLE(olddev->data.vnc.listenNetwork, + dev->data.vnc.listenNetwork)) { + 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")); @@ -1124,6 +1130,12 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, _("cannot change listen address setting on spice graphics")); return -1; } + if (STRNEQ_NULLABLE(olddev->data.spice.listenNetwork, + dev->data.spice.listenNetwork)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot change listen address setting on spice 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@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list