From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: David Scott <dave.scott@citrix.com>
Cc: xen-devel@lists.xenproject.org, stefano.stabellini@eu.citrix.com,
ian.jackson@eu.citrix.com, wei.liu2@citrix.com,
ian.campbell@citrix.com
Subject: Re: [PATCH v6 for-4.5 1/5] libxl: add support for 'channels'
Date: Thu, 25 Sep 2014 14:56:25 -0400 [thread overview]
Message-ID: <20140925185625.GA29663@laptop.dumpdata.com> (raw)
In-Reply-To: <1411591685-25308-2-git-send-email-dave.scott@citrix.com>
On Wed, Sep 24, 2014 at 09:48:01PM +0100, David Scott wrote:
> A 'channel':
> - is a low-bandwidth private communication channel that resembles
> a physical serial port.
> - is implemented as a PV console with a well-known string name
> which is used to hook the channel to the appropriate software
> in the guest (i.e. some kind of guest agent).
> - has a backend 'connection' which describes what should happen
> to the data.
>
> The following 'connection' types are defined:
>
> * PTY: the I/O surfaces as a pty in the backend domain
> * SOCKET: a listening Unix domain socket accepts a connection in
> the backend domain and proxies
>
> Channels may be listed but don't currently support hotplug/unplug.
>
> Signed-off-by: David Scott <dave.scott@citrix.com>
> ---
> docs/misc/channel.txt | 95 ++++++++++++
> docs/misc/console.txt | 69 ++++++---
> tools/libxl/libxl.c | 268 +++++++++++++++++++++++++++++++---
> tools/libxl/libxl.h | 20 +++
> tools/libxl/libxl_create.c | 38 +++--
> tools/libxl/libxl_dm.c | 46 +++++-
> tools/libxl/libxl_internal.h | 10 +-
> tools/libxl/libxl_types.idl | 37 +++++
> tools/libxl/libxl_types_internal.idl | 5 +
> 9 files changed, 538 insertions(+), 50 deletions(-)
> create mode 100644 docs/misc/channel.txt
>
> diff --git a/docs/misc/channel.txt b/docs/misc/channel.txt
> new file mode 100644
> index 0000000..1b8e405
> --- /dev/null
> +++ b/docs/misc/channel.txt
> @@ -0,0 +1,95 @@
> +Xen PV Channels
> +===============
> +
> +A channel is a low-bandwidth private byte stream similar to a serial
> +link. Typical uses of channels are
> +
> + 1. to provide initial configuration information to a VM on boot
> + (example use: CloudStack's cloud-early-config service)
> + 2. to signal/query an in-guest agent
> + (example use: oVirt's guest agent)
> +
> +Channels are similar to virtio-serial devices and emulated serial links.
> +Channels are intended to be used in the implementation of libvirt <channel>s
> +when running on Xen.
> +
> +Note: if an application requires a high-bandwidth link then it should use
> +vchan instead.
> +
> +How to use channels: an example
> +-------------------------------
> +
> +Consider a cloud deployment where VMs are cloned from pre-made templates,
> +and customised on first boot by an in-guest agent which sets the IP address,
> +hostname, ssh keys etc. To install the system the cloud administrator would
> +first:
> +
> + 1. Install a guest as normal (no channel configuration necessary)
> + 2. Install the in-guest agent specific to the cloud software. This will
> + prepare the guest to communicate over the channel, and also prepare
> + the guest to be cloned safely (sometimes known as "sysprepping")
> + 3. Shutdown the guest
> + 4. Register the guest as a template with the cloud orchestration software
> + 5. Install the cloud orchestration agent in dom0
> +
> +At runtime, when a cloud tenant requests that a VM is created from the template,
> +the sequence of events would be:
> +
> + 1. A VM is "cloned" from the template
> + 2. A unique Unix domain socket path in dom0 is allocated
> + (e.g. /my/cloud/software/talk/to/domain/<vm uuid>)
> + 3. Domain configuration is created for the VM, listing the channel
> + name expected by the in-guest agent. In xl syntax this would be:
> +
> + channel = [ "connection=socket, name=org.my.cloud.software.agent.version1,
> + path = /my/cloud/software/talk/to/domain/<vm uuid>" ]
> +
> + 4. The VM is started
> + 5. In dom0 the cloud orchestration agent connects to the Unix domain
> + socket, writes a handshake message and waits for a reply
> + 6. In the guest, a udev rule (part of the guest agent package) is activated
> + by the hotplug event, and it starts the in-guest agent.
<scratchies his head> That would mean there must be some form of
a kernel driver to trigger the hotplug event. Which driver is this?
I am not seeing anything obvious in the hvc_console.c ?
> + 7. The in-guest agent completes a handshake with the dom0 agent
> + 8. The dom0 agent transmits the unique VM configuration: hostname, IP
> + address, ssh keys etc etc
> + 9. The in-guest agent receives the configuration and applies it.
> +
> +Using channels avoids having to use a temporary disk device or network
> +connection.
> +
> +Design recommendations and pitfalls
> +-----------------------------------
> +
> +It's necessary to install channel-specific software (an "agent") into the guest
> +before you can use a channel. By default a channel will appear as a device
> +which could be mistaken for a serial port or regular console. It is known
> +that some software will proactively seek out serial ports and issue AT commands
> +at them; make sure such software is disabled!
> +
> +Since channels are identified by names, application authors must ensure their
> +channel names are unique to avoid clashes. We recommend that channel names
> +include parts unique to the application such as a domain names. To assist
> +prevent clashes we recommend authors add their names to our global channel
> +registry at the end of this document.
> +
> +Limitations
> +-----------
> +
> +Hotplug and unplug of channels is not currently implemented.
> +
> +Channel name registry
> +---------------------
> +
> +It is important that channel names are globally unique. To help ensure
> +that no-one's name clashes with yours, please add yours to this list.
> +
> +Key:
> +N: Name
> +C: Contact
> +D: Short description of use, possibly including a URL to your software
> + or API
> +
> +N: org.xenproject.guest.clipboard.0.1
> +C: David Scott <dave.scott@citrix.com>
> +D: Share clipboard data via an in-guest agent. See:
> + http://wiki.xenproject.org/wiki/Clipboard_sharing_protocol
> diff --git a/docs/misc/console.txt b/docs/misc/console.txt
> index 8a53a95..ed7b795 100644
> --- a/docs/misc/console.txt
> +++ b/docs/misc/console.txt
> @@ -9,10 +9,11 @@ relevant information in xenstore under /local/domain/$DOMID/console.
>
> Now many years after the introduction of the pv console we have
> multiple pv consoles support for pv and hvm guests; multiple pv
> -console backends (qemu and xenconsoled) and emulated serial cards too.
> +console backends (qemu and xenconsoled, see limitations below) and
> +emulated serial cards too.
>
> This document tries to describe how the whole system works and how the
> -different components interact with each others.
> +different components interact with each other.
>
> The first PV console path in xenstore remains:
>
> @@ -23,28 +24,63 @@ live in:
>
> /local/domain/$DOMID/device/console/$DEVID.
>
> -The output of a PV console, whether it should be a file, a pty, a
> -socket, or something else, is specified by the toolstack in the xenstore
> -node "output", under the relevant console section.
> -For example:
> +PV consoles have
> +* (optional) string names;
> +* 'connection' information describing to what they should be
> + connected; and
> +* a 'type' indicating which daemon should process the data.
> +
> +We call a PV console with a name a "channel", in reference to the libvirt
> +concept with the same name and purpose. The file "channels.txt" describes
> +how to use channels and includes a registry of well-known channel names.
> +
> +If the PV console has a name (i.e. it is a "channel") then the name
> +is written to the frontend directory:
> +
> +name = <name>
> +
> +If the PV console has no name (i.e. it is a regular console) then the "name"
> +key is omitted.
> +
> +The toolstack writes 'connection' information in the xenstore backend in
> +the keys
> +* connection: either 'pty' or 'socket'
> +* path: only present if connection = 'socket', the path of the socket to
> + glue the channel to
> +
> +An artifact of the current implementation, the toolstack will write an
> +extra backend key
> +* output: an identifier only meaningful for qemu/xenconsoled
>
> -# xenstore-read /local/domain/26/device/console/1/output
> -pty
> +If the toolstack wants the console to be connected to a pty, it will write
> +to the backend:
>
> -The backend chosen for a particular console is specified by the
> -toolstack in the "type" node on xenstore, under the relevant console
> -section.
> +connection = pty
> +output = pty
> +
> +The backend will write the pty device name to the "tty" node in the
> +console frontend.
> +
> +If the toolstack wants a listening Unix domain socket to be created at path
> +<path>, a connection accepted and data proxied to the console, it will write:
> +
> +connection = socket
> +path = <path>
> +output = chardev:<some internal identifier>
> +
> +where chardev:<some internal identifier> matches a qemu character device
> +configured on the qemu command-line.
> +
> +The backend implementation daemon chosen for a particular console is specified
> +by the toolstack in the "type" node in the xenstore frontend.
> For example:
>
> # xenstore-read /local/domain/26/console/1/type
> -xenconsoled
> +ioemu
>
> The supported values are only xenconsoled or ioemu; xenconsoled has
> several limitations: it can only be used for the first PV console and it
> -can only have a pty as output.
> -
> -If the output is a pty, backends write the device name to the "tty" node
> -in xenstore under the relevant console path.
> +can only connect to a pty.
>
> Emulated serials are provided by qemu-dm only to hvm guests; the number
> of emulated serials depends on how many "-serial" command line options
> @@ -54,7 +90,6 @@ xenstore in the following path:
>
> /local/domain/$DOMID/serial/$SERIAL_NUM/tty
>
> -
> xenconsole is the tool to connect to a PV console or an emulated serial
> that has a pty as output. Xenconsole takes a domid as parameter plus an
> optional console type (pv for PV consoles or serial for emulated
> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 77672d0..9ce93d9 100644
> --- a/tools/libxl/libxl.c
> +++ b/tools/libxl/libxl.c
> @@ -21,6 +21,15 @@
> #define PAGE_TO_MEMKB(pages) ((pages) * 4)
> #define BACKEND_STRING_SIZE 5
>
> +/* Utility to read backend xenstore keys */
> +#define READ_BACKEND(tgc, subpath) ({ \
> + rc = libxl__xs_read_checked(tgc, XBT_NULL, \
> + GCSPRINTF("%s/" subpath, be_path), \
> + &tmp); \
> + if (rc) goto out; \
> + (char*)tmp; \
> + });
> +
> int libxl_ctx_alloc(libxl_ctx **pctx, int version,
> unsigned flags, xentoollog_logger * lg)
> {
> @@ -3319,14 +3328,6 @@ static int libxl__device_nic_from_xs_be(libxl__gc *gc,
>
> libxl_device_nic_init(nic);
>
> -#define READ_BACKEND(tgc, subpath) ({ \
> - rc = libxl__xs_read_checked(tgc, XBT_NULL, \
> - GCSPRINTF("%s/" subpath, be_path), \
> - &tmp); \
> - if (rc) goto out; \
> - (char*)tmp; \
> - });
> -
> tmp = READ_BACKEND(gc, "handle");
> if (tmp)
> nic->devid = atoi(tmp);
> @@ -3506,28 +3507,33 @@ const char *libxl__device_nic_devname(libxl__gc *gc,
> /******************************************************************************/
> int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
> libxl__device_console *console,
> - libxl__domain_build_state *state)
> + libxl__domain_build_state *state,
> + libxl__device *device)
> {
> flexarray_t *front, *ro_front;
> flexarray_t *back;
> - libxl__device device;
> int rc;
>
> if (console->devid && state) {
> rc = ERROR_INVAL;
> goto out;
> }
> + if (!console->devid && (console->name || console->path)) {
> + LOG(ERROR, "Primary console has invalid configuration");
> + rc = ERROR_INVAL;
> + goto out;
> + }
>
> front = flexarray_make(gc, 16, 1);
> ro_front = flexarray_make(gc, 16, 1);
> back = flexarray_make(gc, 16, 1);
>
> - device.backend_devid = console->devid;
> - device.backend_domid = console->backend_domid;
> - device.backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
> - device.devid = console->devid;
> - device.domid = domid;
> - device.kind = LIBXL__DEVICE_KIND_CONSOLE;
> + device->backend_devid = console->devid;
> + device->backend_domid = console->backend_domid;
> + device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
> + device->devid = console->devid;
> + device->domid = domid;
> + device->kind = LIBXL__DEVICE_KIND_CONSOLE;
>
> flexarray_append(back, "frontend-id");
> flexarray_append(back, libxl__sprintf(gc, "%d", domid));
> @@ -3540,6 +3546,19 @@ int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
> flexarray_append(back, "protocol");
> flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
>
> + if (console->name) {
> + flexarray_append(ro_front, "name");
> + flexarray_append(ro_front, console->name);
> + }
> + if (console->connection) {
> + flexarray_append(back, "connection");
> + flexarray_append(back, console->connection);
> + }
> + if (console->path) {
> + flexarray_append(back, "path");
> + flexarray_append(back, console->path);
> + }
> +
> flexarray_append(front, "backend-id");
> flexarray_append(front, libxl__sprintf(gc, "%d", console->backend_domid));
>
> @@ -3566,8 +3585,7 @@ int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
> flexarray_append(front, "protocol");
> flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
> }
> -
> - libxl__device_generic_add(gc, XBT_NULL, &device,
> + libxl__device_generic_add(gc, XBT_NULL, device,
> libxl__xs_kvs_of_flexarray(gc, back, back->count),
> libxl__xs_kvs_of_flexarray(gc, front, front->count),
> libxl__xs_kvs_of_flexarray(gc, ro_front, ro_front->count));
> @@ -3578,6 +3596,216 @@ out:
>
> /******************************************************************************/
>
> +int libxl__init_console_from_channel(libxl__gc *gc,
> + libxl__device_console *console,
> + int dev_num,
> + libxl_device_channel *channel)
> +{
> + int rc;
Newline here please.
> + libxl__device_console_init(console);
> + console->devid = dev_num;
> + console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
> + if (!channel->name){
Missing space before '{'
> + LOG(ERROR, "channel %d has no name", channel->devid);
> + return ERROR_INVAL;
> + }
> + console->name = libxl__strdup(NOGC, channel->name);
> +
> + if (channel->backend_domname) {
> + rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
> + &channel->backend_domid);
> + if (rc < 0) return rc;
Don't want to free 'console->name' ? Especially as you used the NOGC variant?
> + }
> +
> + console->backend_domid = channel->backend_domid;
> +
> + /* The xenstore 'output' node tells the backend what to connect the console
> + to. If the channel has "connection = pty" then the "output" node will be
> + set to "pty". If the channel has "connection = socket" then the "output"
> + node will be set to "chardev:libxl-channel%d". This tells the qemu
> + backend to proxy data between the console ring and the character device
> + with id "libxl-channel%d". These character devices are currently defined
> + on the qemu command-line via "-chardev" options in libxl_dm.c */
> +
> + switch (channel->connection) {
> + case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
> + LOG(ERROR, "channel %d has no defined connection; "
> + "to where should it be connected?", channel->devid);
Ditto? Don't want to free the 'console->name'?
> + return ERROR_INVAL;
> + case LIBXL_CHANNEL_CONNECTION_PTY:
> + console->connection = libxl__strdup(NOGC, "pty");
> + console->output = libxl__sprintf(NOGC, "pty");
> + break;
> + case LIBXL_CHANNEL_CONNECTION_SOCKET:
> + console->connection = libxl__strdup(NOGC, "socket");
How about that being done after the 'if (..)' clause below?
> + if (!channel->u.socket.path) {
> + LOG(ERROR, "channel %d has no path", channel->devid);
> + return ERROR_INVAL;
> + }
> + console->path = libxl__strdup(NOGC, channel->u.socket.path);
> + console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
> + channel->devid);
> + break;
> + default:
> + /* We've forgotten to add the clause */
> + LOG(ERROR, "%s: missing implementation for channel connection %d",
> + __func__, channel->connection);
> + abort();
> + }
> +
> + return 0;
> +}
> +
> +static int libxl__device_channel_from_xs_be(libxl__gc *gc,
> + const char *be_path,
> + libxl_device_channel *channel)
> +{
> + const char *tmp;
> + int rc;
> +
> + libxl_device_channel_init(channel);
> +
> + /* READ_BACKEND is from libxl__device_nic_from_xs_be above */
> + channel->name = READ_BACKEND(NOGC, "name");
> + tmp = READ_BACKEND(gc, "connection");
> + if (!strcmp(tmp, "pty")) {
> + channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
> + } else if (!strcmp(tmp, "socket")) {
> + channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
> + channel->u.socket.path = READ_BACKEND(NOGC, "path");
> + } else {
> + rc = ERROR_INVAL;
> + goto out;
> + }
> +
> + rc = 0;
> + out:
> + return rc;
> +}
> +
> +static int libxl__append_channel_list_of_type(libxl__gc *gc,
> + uint32_t domid,
> + const char *type,
> + libxl_device_channel **channels,
> + int *nchannels)
> +{
> + char *fe_path = NULL, *be_path = NULL;
> + char **dir = NULL;
> + unsigned int n = 0, devid = 0;
> + libxl_device_channel *next = NULL;
> + int rc = 0, i;
> +
> + fe_path = GCSPRINTF("%s/device/%s",
> + libxl__xs_get_dompath(gc, domid), type);
> + dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &n);
> + if (!dir || !n)
> + goto out;
> +
> + for (i = 0; i < n; i++) {
> + const char *p, *name;
> + libxl_device_channel *tmp;
Newline missing here.
> + p = libxl__sprintf(gc, "%s/%s", fe_path, dir[i]);
> + name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", p));
> + /* 'channels' are consoles with names, so ignore all consoles
> + without names */
> + if (!name) continue;
> + be_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/backend", p));
> + tmp = realloc(*channels,
> + sizeof(libxl_device_channel) * (*nchannels + devid + 1));
> + if (!tmp) {
> + rc = ERROR_NOMEM;
> + goto out;
> + }
> + *channels = tmp;
> + next = *channels + *nchannels + devid;
> + rc = libxl__device_channel_from_xs_be(gc, be_path, next);
> + if (rc) goto out;
> + next->devid = devid;
> + devid++;
> + }
> + *nchannels += devid;
> + return 0;
> +
> + out:
> + return rc;
> +}
> +
> +libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
> + uint32_t domid,
> + int *num)
> +{
> + GC_INIT(ctx);
> + libxl_device_channel *channels = NULL;
> + int rc;
> +
> + *num = 0;
> +
> + rc = libxl__append_channel_list_of_type(gc, domid, "console", &channels, num);
> + if (rc) goto out_err;
> +
> + GC_FREE;
> + return channels;
> +
> +out_err:
> + LOG(ERROR, "Unable to list channels");
> + while (*num) {
> + (*num)--;
> + libxl_device_channel_dispose(&channels[*num]);
> + }
> + free(channels);
> + return NULL;
> +}
> +
> +int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
> + libxl_device_channel *channel,
> + libxl_channelinfo *channelinfo)
> +{
> + GC_INIT(ctx);
> + char *dompath, *fe_path;
> + char *val;
> +
> + dompath = libxl__xs_get_dompath(gc, domid);
> + channelinfo->devid = channel->devid;
> +
> + fe_path = libxl__sprintf(gc, "%s/device/console/%d", dompath,
> + channelinfo->devid + 1);
> + channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
> + libxl__sprintf(gc, "%s/backend",
> + fe_path), NULL);
> + if (!channelinfo->backend) {
> + GC_FREE;
> + return ERROR_FAIL;
> + }
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/backend-id", fe_path));
> + channelinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
> + channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
> + channelinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
> + GCSPRINTF("%s/frontend",
> + channelinfo->backend), NULL);
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/frontend-id",
> + channelinfo->backend));
> + channelinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
> + channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
> + channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
> +
> + channelinfo->connection = channel->connection;
> + switch (channel->connection) {
> + case LIBXL_CHANNEL_CONNECTION_PTY:
> + val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
> + channelinfo->u.pty.path = strdup(val);
> + break;
> + default:
> + break;
> + }
> + GC_FREE;
> + return 0;
> +}
> +
> +/******************************************************************************/
> +
> int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb)
> {
> int rc;
> @@ -3842,6 +4070,10 @@ DEFINE_DEVICE_REMOVE(vfb, destroy, 1)
> DEFINE_DEVICE_REMOVE(vtpm, remove, 0)
> DEFINE_DEVICE_REMOVE(vtpm, destroy, 1)
>
> +/* channel/console hotunplug is not implemented. There are 2 possibilities:
> + * 1. add support for secondary consoles to xenconsoled
> + * 2. dynamically add/remove qemu chardevs via qmp messages. */
> +
> #undef DEFINE_DEVICE_REMOVE
>
> /******************************************************************************/
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index bc68cac..300e489 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -583,6 +583,15 @@ typedef struct libxl__ctx libxl_ctx;
> */
> #define LIBXL_HAVE_BUILDINFO_KERNEL 1
>
> +/*
> + * LIBXL_HAVE_DEVICE_CHANNEL
> + *
> + * If this is defined, then the libxl_device_channel struct exists
> + * and channels can be attached to a domain. Channels manifest as consoles
> + * with names, see docs/misc/console.txt.
> + */
> +#define LIBXL_HAVE_DEVICE_CHANNEL 1
> +
> /* Functions annotated with LIBXL_EXTERNAL_CALLERS_ONLY may not be
> * called from within libxl itself. Callers outside libxl, who
> * do not #include libxl_internal.h, are fine. */
> @@ -1129,6 +1138,17 @@ libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int *num
> int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid,
> libxl_device_nic *nic, libxl_nicinfo *nicinfo);
>
> +/*
> + * Virtual Channels
> + * Channels manifest as consoles with names, see docs/misc/channels.txt
> + */
> +libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
> + uint32_t domid,
> + int *num);
> +int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
> + libxl_device_channel *channel,
> + libxl_channelinfo *channelinfo);
> +
> /* Virtual TPMs */
> int libxl_device_vtpm_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vtpm *vtpm,
> const libxl_asyncop_how *ao_how)
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 8b82584..4be4c5c 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -387,14 +387,16 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
> return 0;
> }
>
> -static int init_console_info(libxl__device_console *console, int dev_num)
> +static int init_console_info(libxl__gc *gc,
> + libxl__device_console *console,
> + int dev_num)
> {
> - memset(console, 0x00, sizeof(libxl__device_console));
> + libxl__device_console_init(console);
How come?
Should that be a seperate patch - to use 'libxl__device_console_init' ?
> console->devid = dev_num;
> console->consback = LIBXL__CONSOLE_BACKEND_XENCONSOLED;
> - console->output = strdup("pty");
> - if (!console->output)
> - return ERROR_NOMEM;
> + console->output = libxl__strdup(NOGC, "pty");
> + /* console->{name,connection,path} are NULL on normal consoles.
> + Only 'channels' when mapped to consoles have a string name. */
And the 'return ERROR_NOMEM' is gone too?
> return 0;
Why don't you just make this function 'void'?
> }
>
> @@ -1194,17 +1196,31 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
> }
> }
>
> + /* For both HVM and PV the 0th console is a regular console. We
> + map channels to IOEMU consoles starting at 1 */
> + for (i = 0; i < d_config->num_channels; i++) {
> + libxl__device_console console;
> + libxl__device device;
> + ret = libxl__init_console_from_channel(gc, &console, i + 1,
> + &d_config->channels[i]);
> + if ( ret )
> + goto error_out;
And since 'console' is on the stack, and we have potentially allocated
'->name', now we are leaking '->name' when we get to error_out (as we
haven't called 'libxl__device_console_dispose(&console)'.
> + libxl__device_console_add(gc, domid, &console, NULL, &device);
> + libxl__device_console_dispose(&console);
> + }
> +
> switch (d_config->c_info.type) {
> case LIBXL_DOMAIN_TYPE_HVM:
> {
> libxl__device_console console;
> + libxl__device device;
> libxl_device_vkb vkb;
>
> - ret = init_console_info(&console, 0);
> + ret = init_console_info(gc, &console, 0);
> if ( ret )
> goto error_out;
> console.backend_domid = state->console_domid;
> - libxl__device_console_add(gc, domid, &console, state);
> + libxl__device_console_add(gc, domid, &console, state, &device);
> libxl__device_console_dispose(&console);
>
> libxl_device_vkb_init(&vkb);
> @@ -1231,22 +1247,24 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
> {
> int need_qemu = 0;
> libxl__device_console console;
> + libxl__device device;
>
> for (i = 0; i < d_config->num_vfbs; i++) {
> libxl__device_vfb_add(gc, domid, &d_config->vfbs[i]);
> libxl__device_vkb_add(gc, domid, &d_config->vkbs[i]);
> }
>
> - ret = init_console_info(&console, 0);
> + ret = init_console_info(gc, &console, 0);
> if ( ret )
> goto error_out;
>
> need_qemu = libxl__need_xenpv_qemu(gc, 1, &console,
> d_config->num_vfbs, d_config->vfbs,
> - d_config->num_disks, &d_config->disks[0]);
> + d_config->num_disks, &d_config->disks[0],
> + d_config->num_channels, &d_config->channels[0]);
>
> console.backend_domid = state->console_domid;
> - libxl__device_console_add(gc, domid, &console, state);
> + libxl__device_console_add(gc, domid, &console, state, &device);
> libxl__device_console_dispose(&console);
>
> if (need_qemu) {
> diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
> index fbc82fd..dc748be 100644
> --- a/tools/libxl/libxl_dm.c
> +++ b/tools/libxl/libxl_dm.c
> @@ -416,8 +416,9 @@ static char ** libxl__build_device_model_args_new(libxl__gc *gc,
> const libxl_sdl_info *sdl = dm_sdl(guest_config);
> const char *keymap = dm_keymap(guest_config);
> flexarray_t *dm_args;
> - int i;
> + int i, connection, devid;
> uint64_t ram_size;
> + const char *path, *chardev;
>
> dm_args = flexarray_make(gc, 16, 1);
>
> @@ -434,6 +435,28 @@ static char ** libxl__build_device_model_args_new(libxl__gc *gc,
> flexarray_append(dm_args, "-mon");
> flexarray_append(dm_args, "chardev=libxl-cmd,mode=control");
>
> + for (i = 0; i < guest_config->num_channels; i++) {
> + connection = guest_config->channels[i].connection;
> + devid = guest_config->channels[i].devid;
> + switch (connection) {
> + case LIBXL_CHANNEL_CONNECTION_PTY:
> + chardev = GCSPRINTF("pty,id=libxl-channel%d", devid);
> + break;
> + case LIBXL_CHANNEL_CONNECTION_SOCKET:
> + path = guest_config->channels[i].u.socket.path;
> + chardev = GCSPRINTF("socket,id=libxl-channel%d,path=%s,"
> + "server,nowait", devid, path);
> + break;
> + default:
> + /* We've forgotten to add the clause */
> + LOG(ERROR, "%s: unknown channel connection %d",
> + __func__, connection);
> + return NULL;
> + }
> + flexarray_append(dm_args, "-chardev");
> + flexarray_append(dm_args, (void*)chardev);
> + }
> +
> /*
> * Remove default devices created by qemu. Qemu will create only devices
> * defined by xen, since the devices not defined by xen are not usable.
> @@ -1116,6 +1139,7 @@ static void spawn_stub_launch_dm(libxl__egc *egc,
> }
>
> for (i = 0; i < num_console; i++) {
> + libxl__device device;
> console[i].devid = i;
> console[i].consback = LIBXL__CONSOLE_BACKEND_IOEMU;
> /* STUBDOM_CONSOLE_LOGGING (console 0) is for minios logging
> @@ -1146,7 +1170,8 @@ static void spawn_stub_launch_dm(libxl__egc *egc,
> break;
> }
> ret = libxl__device_console_add(gc, dm_domid, &console[i],
> - i == STUBDOM_CONSOLE_LOGGING ? stubdom_state : NULL);
> + i == STUBDOM_CONSOLE_LOGGING ? stubdom_state : NULL,
> + &device);
> if (ret)
> goto out;
> }
> @@ -1566,7 +1591,8 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid)
> int libxl__need_xenpv_qemu(libxl__gc *gc,
> int nr_consoles, libxl__device_console *consoles,
> int nr_vfbs, libxl_device_vfb *vfbs,
> - int nr_disks, libxl_device_disk *disks)
> + int nr_disks, libxl_device_disk *disks,
> + int nr_channels, libxl_device_channel *channels)
> {
> int i, ret = 0;
> uint32_t domid;
> @@ -1606,6 +1632,20 @@ int libxl__need_xenpv_qemu(libxl__gc *gc,
> }
> }
>
> + if (nr_channels > 0) {
> + ret = libxl__get_domid(gc, &domid);
> + if (ret) goto out;
> + for (i = 0; i < nr_channels; i++) {
> + if (channels[i].backend_domid == domid) {
> + /* xenconsoled is limited to the first console only.
> + Until this restriction is removed we must use qemu for
> + secondary consoles which includes all channels. */
> + ret = 1;
> + goto out;
> + }
> + }
> + }
> +
> out:
> return ret;
> }
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index f61673c..151c474 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1033,7 +1033,8 @@ _hidden int libxl__device_disk_dev_number(const char *virtpath,
>
> _hidden int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
> libxl__device_console *console,
> - libxl__domain_build_state *state);
> + libxl__domain_build_state *state,
> + libxl__device *device);
>
> /* Returns 1 if device exists, 0 if not, ERROR_* (<0) on error. */
> _hidden int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
> @@ -1049,6 +1050,10 @@ _hidden int libxl__wait_for_backend(libxl__gc *gc, const char *be_path,
> const char *state);
> _hidden int libxl__nic_type(libxl__gc *gc, libxl__device *dev,
> libxl_nic_type *nictype);
> +_hidden int libxl__init_console_from_channel(libxl__gc *gc,
> + libxl__device_console *console,
> + int dev_num,
> + libxl_device_channel *channel);
>
> /*
> * For each aggregate type which can be used as an input we provide:
> @@ -1468,7 +1473,8 @@ _hidden const char *libxl__domain_device_model(libxl__gc *gc,
> _hidden int libxl__need_xenpv_qemu(libxl__gc *gc,
> int nr_consoles, libxl__device_console *consoles,
> int nr_vfbs, libxl_device_vfb *vfbs,
> - int nr_disks, libxl_device_disk *disks);
> + int nr_disks, libxl_device_disk *disks,
> + int nr_channels, libxl_device_channel *channels);
>
> /*
> * This function will cause the whole libxl process to hang
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index f1fcbc3..59c3d0b 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -69,6 +69,12 @@ libxl_domain_type = Enumeration("domain_type", [
> (2, "PV"),
> ], init_val = "LIBXL_DOMAIN_TYPE_INVALID")
>
> +libxl_channel_connection = Enumeration("channel_connection", [
> + (0, "UNKNOWN"),
> + (1, "PTY"),
> + (2, "SOCKET"), # a listening Unix domain socket
> + ])
> +
> libxl_device_model_version = Enumeration("device_model_version", [
> (0, "UNKNOWN"),
> (1, "QEMU_XEN_TRADITIONAL"), # Historical qemu-xen device model (qemu-dm)
> @@ -269,6 +275,22 @@ libxl_cpupoolinfo = Struct("cpupoolinfo", [
> ("cpumap", libxl_bitmap)
> ], dir=DIR_OUT)
>
> +libxl_channelinfo = Struct("channelinfo", [
> + ("backend", string),
> + ("backend_id", uint32),
> + ("frontend", string),
> + ("frontend_id", uint32),
> + ("devid", libxl_devid),
> + ("state", integer),
> + ("evtch", integer),
> + ("rref", integer),
> + ("u", KeyedUnion(None, libxl_channel_connection, "connection",
> + [("unknown", None),
> + ("pty", Struct(None, [("path", string),])),
> + ("socket", None),
> + ])),
> + ], dir=DIR_OUT)
> +
> libxl_vminfo = Struct("vminfo", [
> ("uuid", libxl_uuid),
> ("domid", libxl_domid),
> @@ -491,6 +513,18 @@ libxl_device_vtpm = Struct("device_vtpm", [
> ("uuid", libxl_uuid),
> ])
>
> +libxl_device_channel = Struct("device_channel", [
> + ("backend_domid", libxl_domid),
> + ("backend_domname", string),
> + ("devid", libxl_devid),
> + ("name", string),
> + ("u", KeyedUnion(None, libxl_channel_connection, "connection",
> + [("unknown", None),
> + ("pty", None),
> + ("socket", Struct(None, [("path", string)])),
> + ])),
> +])
> +
> libxl_domain_config = Struct("domain_config", [
> ("c_info", libxl_domain_create_info),
> ("b_info", libxl_domain_build_info),
> @@ -501,6 +535,9 @@ libxl_domain_config = Struct("domain_config", [
> ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
> ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
> ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
> + # a channel manifests as a console with a name,
> + # see docs/misc/channels.txt
> + ("channels", Array(libxl_device_channel, "num_channels")),
>
> ("on_poweroff", libxl_action_on_shutdown),
> ("on_reboot", libxl_action_on_shutdown),
> diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
> index 800361b..5e55685 100644
> --- a/tools/libxl/libxl_types_internal.idl
> +++ b/tools/libxl/libxl_types_internal.idl
> @@ -34,6 +34,11 @@ libxl__device_console = Struct("device_console", [
> ("devid", integer),
> ("consback", libxl__console_backend),
> ("output", string),
> + # A regular console has no name.
> + # A console with a name is called a 'channel', see docs/misc/channels.txt
> + ("name", string),
> + ("connection", string),
> + ("path", string),
> ])
>
> libxl__device_action = Enumeration("device_action", [
> --
> 1.7.10.4
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2014-09-25 18:56 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-24 20:48 xl, libxl: add support for 'channels' David Scott
2014-09-24 20:48 ` [PATCH v6 for-4.5 1/5] " David Scott
2014-09-25 18:56 ` Konrad Rzeszutek Wilk [this message]
2014-09-26 9:12 ` Wei Liu
2014-09-24 20:48 ` [PATCH v6 for-4.5 2/5] xl: move 'replace_string' further up the file David Scott
2014-09-25 19:06 ` Konrad Rzeszutek Wilk
2014-09-26 9:15 ` Wei Liu
2014-09-24 20:48 ` [PATCH v6 for-4.5 3/5] xl: add 'xstrdup' next to 'xrealloc' David Scott
2014-09-25 19:06 ` Konrad Rzeszutek Wilk
2014-09-26 9:22 ` Wei Liu
2014-09-24 20:48 ` [PATCH v6 for-4.5 4/5] xl: add 'trim' and 'split_string_into_pair' functions David Scott
2014-09-25 19:06 ` Konrad Rzeszutek Wilk
2014-09-26 10:09 ` Wei Liu
2014-09-26 15:45 ` Ian Jackson
2014-09-26 15:51 ` Wei Liu
2014-09-26 15:53 ` Ian Jackson
2014-09-24 20:48 ` [PATCH v6 for-4.5 5/5] xl: add support for 'channels' David Scott
2014-09-25 19:11 ` Konrad Rzeszutek Wilk
2014-09-26 10:22 ` Wei Liu
2014-09-25 19:13 ` xl, libxl: " Konrad Rzeszutek Wilk
2014-09-25 19:37 ` Dave Scott
2014-09-26 15:14 ` Ian Jackson
2014-09-26 19:20 ` Konrad Rzeszutek Wilk
2014-10-07 16:52 ` Dave Scott
2014-10-07 16:59 ` Konrad Rzeszutek Wilk
2014-10-08 11:06 ` Stefano Stabellini
2014-10-08 13:26 ` Ian Campbell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140925185625.GA29663@laptop.dumpdata.com \
--to=konrad.wilk@oracle.com \
--cc=dave.scott@citrix.com \
--cc=ian.campbell@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=stefano.stabellini@eu.citrix.com \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).