mirror of https://gitee.com/openkylin/libvirt.git
qemu: support type=network in domain graphics <listen>
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' port='5922'> <listen type='network'network='example-net'/> </graphics> (all the above also applies for graphics type='spice').
This commit is contained in:
parent
ef79fb5b5f
commit
99e4b30b39
|
@ -4127,10 +4127,43 @@ 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;
|
||||
/* store the address we found in the <graphics> element so it will
|
||||
* show up in status. */
|
||||
if (virDomainGraphicsListenSetAddress(def->graphics[0], 0,
|
||||
listenAddr, -1, false) < 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
|
||||
listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0);
|
||||
if (!listenAddr)
|
||||
listenAddr = driver->vncListen;
|
||||
|
||||
|
@ -4142,6 +4175,7 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||
virBufferAsprintf(&opt, ":%d",
|
||||
def->graphics[0]->data.vnc.port - 5900);
|
||||
|
||||
VIR_FREE(netAddr);
|
||||
} else {
|
||||
virBufferAsprintf(&opt, "%d",
|
||||
def->graphics[0]->data.vnc.port - 5900);
|
||||
|
@ -4225,7 +4259,10 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||
} else if ((def->ngraphics == 1) &&
|
||||
def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
||||
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
||||
const char *listenNetwork;
|
||||
const char *listenAddr = NULL;
|
||||
char *netAddr = NULL;
|
||||
int ret;
|
||||
|
||||
if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SPICE)) {
|
||||
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
|
@ -4238,12 +4275,44 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||
if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1)
|
||||
virBufferAsprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort);
|
||||
|
||||
listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0);
|
||||
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;
|
||||
/* store the address we found in the <graphics> element so it will
|
||||
* show up in status. */
|
||||
if (virDomainGraphicsListenSetAddress(def->graphics[0], 0,
|
||||
listenAddr, -1, false) < 0)
|
||||
goto error;
|
||||
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 */
|
||||
|
|
|
@ -1053,6 +1053,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
|
|||
{
|
||||
virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
|
||||
const char *oldListenAddr, *newListenAddr;
|
||||
const char *oldListenNetwork, *newListenNetwork;
|
||||
int ret = -1;
|
||||
|
||||
if (!olddev) {
|
||||
|
@ -1063,6 +1064,8 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
|
|||
|
||||
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:
|
||||
|
@ -1078,6 +1081,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"));
|
||||
|
@ -1126,6 +1134,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",
|
||||
|
|
Loading…
Reference in New Issue