[libvirt] [PATCHv2 4/4] qemu: support the listenNetwork attribute in <graphics>

Laine Stump laine at laine.org
Wed Jul 20 08:11:15 UTC 2011


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




More information about the libvir-list mailing list