[libvirt] [PATCH V2] add console support in libxl

this patch introduce the console api in libxl driver for both pv and hvm guest. and import and update the libxlMakeChrdevStr function which was deleted in commit dfa1e1dd. Signed-off-by: Bamvor Jian Zhang <bjzhang@suse.com> --- changes since V1: 1), add virDomainOpenConsoleEnsureACL 3), remove virReportOOMErrorFull when virAsprintf fail. 4), change size_t for non-nagetive number in libxlDomainOpenConsole size_t i; size_t num = 0; 5), fix for make check (1), replace virAsprintf with VIR_STRDUP in two places (2), delete space. src/libxl/libxl_conf.c | 88 ++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 3 ++ src/libxl/libxl_driver.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 4a0fba9..5b3a535 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -331,6 +331,90 @@ error: } static int +libxlMakeChrdevStr(virDomainChrDefPtr def, char **buf) +{ + const char *type = virDomainChrTypeToString(def->source.type); + int ret; + + if (!type) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unexpected chr device type")); + return -1; + } + + switch (def->source.type) { + case VIR_DOMAIN_CHR_TYPE_NULL: + case VIR_DOMAIN_CHR_TYPE_STDIO: + case VIR_DOMAIN_CHR_TYPE_VC: + case VIR_DOMAIN_CHR_TYPE_PTY: + if (VIR_STRDUP(*buf, type) < 0) + return -1; + break; + + case VIR_DOMAIN_CHR_TYPE_FILE: + case VIR_DOMAIN_CHR_TYPE_PIPE: + if (virAsprintf(buf, "%s:%s", type, + def->source.data.file.path) < 0) + return -1; + break; + + case VIR_DOMAIN_CHR_TYPE_DEV: + if (VIR_STRDUP(*buf, def->source.data.file.path) < 0) + return -1; + break; + + case VIR_DOMAIN_CHR_TYPE_UDP: { + const char *connectHost = def->source.data.udp.connectHost; + const char *bindHost = def->source.data.udp.bindHost; + const char *bindService = def->source.data.udp.bindService; + + if (connectHost == NULL) + connectHost = ""; + if (bindHost == NULL) + bindHost = ""; + if (bindService == NULL) + bindService = "0"; + + ret = virAsprintf(buf, "udp:%s:%s@%s:%s", + connectHost, + def->source.data.udp.connectService, + bindHost, + bindService); + if (ret < 0) + return -1; + break; + + } + case VIR_DOMAIN_CHR_TYPE_TCP: + if (def->source.data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) + ret = virAsprintf(buf, "telnet:%s:%s%s", + def->source.data.tcp.host, + def->source.data.tcp.service, + def->source.data.tcp.listen ? ",server,nowait" : ""); + else + ret = virAsprintf(buf, "tcp:%s:%s%s", + def->source.data.tcp.host, + def->source.data.tcp.service, + def->source.data.tcp.listen ? ",server,nowait" : ""); + + if (ret < 0) + return -1; + break; + + case VIR_DOMAIN_CHR_TYPE_UNIX: + ret = virAsprintf(buf, "unix:%s%s", + def->source.data.nix.path, + def->source.data.nix.listen ? ",server,nowait" : ""); + if (ret < 0) + return -1; + break; + + } + + return 0; +} + +static int libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) { libxl_domain_build_info *b_info = &d_config->b_info; @@ -403,6 +487,10 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) if (VIR_STRDUP(b_info->u.hvm.boot, bootorder) < 0) goto error; + if (def->nserials && + (libxlMakeChrdevStr(def->serials[0], &b_info->u.hvm.serial) < 0)) + goto error; + /* * The following comment and calculation were taken directly from * libxenlight's internal function libxl_get_required_shadow_memory(): diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index 2b4a281..861d689 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -34,6 +34,7 @@ # include "configmake.h" # include "virportallocator.h" # include "virobject.h" +# include "virchrdev.h" # define LIBXL_VNC_PORT_MIN 5900 @@ -94,6 +95,8 @@ struct _libxlDomainObjPrivate { /* per domain libxl ctx */ libxl_ctx *ctx; + /* console */ + virChrdevsPtr devs; libxl_evgen_domain_death *deathW; /* list of libxl timeout registrations */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 358d387..c1b9e20 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -417,6 +417,9 @@ libxlDomainObjPrivateAlloc(void) libxl_osevent_register_hooks(priv->ctx, &libxl_event_callbacks, priv); + if (!(priv->devs = virChrdevAlloc())) + return NULL; + return priv; } @@ -429,6 +432,7 @@ libxlDomainObjPrivateDispose(void *obj) libxl_evdisable_domain_death(priv->ctx, priv->deathW); libxl_ctx_free(priv->ctx); + virChrdevFree(priv->devs); } static void @@ -4493,6 +4497,123 @@ cleanup: return ret; } + +static int +libxlDomainOpenConsole(virDomainPtr dom, + const char *dev_name, + virStreamPtr st, + unsigned int flags) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + size_t i; + virDomainChrDefPtr chr = NULL; + libxlDomainObjPrivatePtr priv; + char *console = NULL; + size_t num = 0; + libxl_console_type type; + + virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE | + VIR_DOMAIN_CONSOLE_FORCE, -1); + + libxlDriverLock(driver); + vm = virDomainObjListFindByUUID(driver->domains, dom->uuid); + libxlDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (dev_name) { + for (i = 0; !chr && i < vm->def->nconsoles; i++) { + if (vm->def->consoles[i]->info.alias && + STREQ(dev_name, vm->def->consoles[i]->info.alias)) { + chr = vm->def->consoles[i]; + num = i; + } + } + for (i = 0; !chr && i < vm->def->nserials; i++) { + if (STREQ(dev_name, vm->def->serials[i]->info.alias)) { + chr = vm->def->serials[i]; + num = i; + } + } + for (i = 0; !chr && i < vm->def->nparallels; i++) { + if (STREQ(dev_name, vm->def->parallels[i]->info.alias)) { + chr = vm->def->parallels[i]; + num = i; + } + } + } else { + if (vm->def->nconsoles) + chr = vm->def->consoles[0]; + else if (vm->def->nserials) + chr = vm->def->serials[0]; + } + + if (!chr) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find character device %s"), + NULLSTR(dev_name)); + goto cleanup; + } + + if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("character device %s is not using a PTY"), + NULLSTR(dev_name)); + goto cleanup; + } + + if (dev_name) { + if (STREQ(vm->def->os.type, "hvm")) + type = LIBXL_CONSOLE_TYPE_SERIAL; + else + type = LIBXL_CONSOLE_TYPE_PV; + ret = libxl_console_get_tty(priv->ctx, vm->def->id, num, type, &console); + } else { + ret = libxl_primary_console_get_tty(priv->ctx, vm->def->id, &console); + } + if (ret) + goto cleanup; + + if (VIR_STRDUP(chr->source.data.file.path, console) < 0) + goto cleanup; + + /* handle mutually exclusive access to console devices */ + ret = virChrdevOpen(priv->devs, + &chr->source, + st, + (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0); + + if (ret == 1) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Active console session exists for this domain")); + ret = -1; + } + +cleanup: + VIR_FREE(console); + if (vm) + virObjectUnlock(vm); + return ret; +} + static int libxlDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params, int nparams) @@ -4875,6 +4996,7 @@ static virDriver libxlDriver = { .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */ .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */ + .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.1 */ .domainIsActive = libxlDomainIsActive, /* 0.9.0 */ .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */ .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */ -- 1.8.1.4

On Thu, Jul 18, 2013 at 08:14:17PM +0800, Bamvor Jian Zhang wrote:
this patch introduce the console api in libxl driver for both pv and hvm guest. and import and update the libxlMakeChrdevStr function which was deleted in commit dfa1e1dd.
Signed-off-by: Bamvor Jian Zhang <bjzhang@suse.com> --- changes since V1: 1), add virDomainOpenConsoleEnsureACL 3), remove virReportOOMErrorFull when virAsprintf fail. 4), change size_t for non-nagetive number in libxlDomainOpenConsole size_t i; size_t num = 0; 5), fix for make check (1), replace virAsprintf with VIR_STRDUP in two places (2), delete space.
src/libxl/libxl_conf.c | 88 ++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 3 ++ src/libxl/libxl_driver.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+)
+static int libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) { libxl_domain_build_info *b_info = &d_config->b_info; @@ -403,6 +487,10 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) if (VIR_STRDUP(b_info->u.hvm.boot, bootorder) < 0) goto error;
+ if (def->nserials && + (libxlMakeChrdevStr(def->serials[0], &b_info->u.hvm.serial) < 0)) + goto error;
If you're going to hardcode def->serials[0], then you should explicitly report an error if 'def->nserials > 1'. Also you should probably report an error if def->nparallels != 0, since you don't support that at all.
+static int +libxlDomainOpenConsole(virDomainPtr dom, + const char *dev_name, + virStreamPtr st, + unsigned int flags) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + size_t i; + virDomainChrDefPtr chr = NULL; + libxlDomainObjPrivatePtr priv; + char *console = NULL; + size_t num = 0; + libxl_console_type type; + + virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE | + VIR_DOMAIN_CONSOLE_FORCE, -1); + + libxlDriverLock(driver); + vm = virDomainObjListFindByUUID(driver->domains, dom->uuid); + libxlDriverUnlock(driver); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (dev_name) { + for (i = 0; !chr && i < vm->def->nconsoles; i++) { + if (vm->def->consoles[i]->info.alias && + STREQ(dev_name, vm->def->consoles[i]->info.alias)) { + chr = vm->def->consoles[i]; + num = i; + } + } + for (i = 0; !chr && i < vm->def->nserials; i++) { + if (STREQ(dev_name, vm->def->serials[i]->info.alias)) { + chr = vm->def->serials[i]; + num = i; + } + } + for (i = 0; !chr && i < vm->def->nparallels; i++) { + if (STREQ(dev_name, vm->def->parallels[i]->info.alias)) { + chr = vm->def->parallels[i]; + num = i; + } + }
Nothing in the libxl driver appears to ever set the info.alias string names. So this code will crash on a NULL pointer. You should either ensure the alias is set, or use STREQ_NULLABLE to handle NULL pointers.
+ } else { + if (vm->def->nconsoles) + chr = vm->def->consoles[0]; + else if (vm->def->nserials) + chr = vm->def->serials[0]; + }
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Daniel P. Berrange wrote:
On Thu, Jul 18, 2013 at 08:14:17PM +0800, Bamvor Jian Zhang wrote:
this patch introduce the console api in libxl driver for both pv and hvm guest. and import and update the libxlMakeChrdevStr function which was deleted in commit dfa1e1dd.
Signed-off-by: Bamvor Jian Zhang <bjzhang@suse.com> --- changes since V1: 1), add virDomainOpenConsoleEnsureACL 3), remove virReportOOMErrorFull when virAsprintf fail. 4), change size_t for non-nagetive number in libxlDomainOpenConsole size_t i; size_t num = 0; 5), fix for make check (1), replace virAsprintf with VIR_STRDUP in two places (2), delete space.
src/libxl/libxl_conf.c | 88 ++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 3 ++ src/libxl/libxl_driver.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+)
+static int libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) { libxl_domain_build_info *b_info = &d_config->b_info; @@ -403,6 +487,10 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config) if (VIR_STRDUP(b_info->u.hvm.boot, bootorder) < 0) goto error;
+ if (def->nserials && + (libxlMakeChrdevStr(def->serials[0], &b_info->u.hvm.serial) < 0)) + goto error;
If you're going to hardcode def->serials[0], then you should explicitly report an error if 'def->nserials > 1'.
Yes, good point. Currently libxl only supports defining one serial port, so we should enforce that here.
Also you should probably report an error if def->nparallels != 0, since you don't support that at all.
Right. Maybe that should be a separate patch. Poking around a bit, I'm not even sure how to map libvirt's parallel device config to libxl's 'num_ioports' and 'ioports' fields in libxl_domain_build_info struct. xl.cfg(5) contains this info about the 'ioports' setting ioports=[ "IOPORT_RANGE", "IOPORT_RANGE", ... ] Allow guest to access specific legacy I/O ports. Each IOPORT_RANGE is given in hexadecimal and may either a span e.g. "2f8-2ff" (inclusive) or a single I/O port "2f8". It is recommended to use this option only for trusted VMs under administrator control. Regards, Jim
participants (3)
-
Bamvor Jian Zhang
-
Daniel P. Berrange
-
Jim Fehlig