[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 3/3] xl: add support for 'channels'
This adds support for channel declarations of the form: channel = [ "name=...,connection=...[,path=...][,backend=...]" ] where 'name' is a label to identify the channel to the frontend. If 'connection = pty' then the channel is connected to a pty in the backend domain If 'connection = socket' then the channel is connected to a Unix domain socket given by 'path = ...' in the backend domain. This patch also adds the command: xl channel-list <domain> which allows the state of channels to be queried. In particular if 'connection=pty' this will show the path of the pty slave device. Signed-off-by: David Scott <dave.scott@xxxxxxxxxx> --- docs/man/xl.cfg.pod.5 | 51 +++++++++++ docs/man/xl.pod.1 | 10 +++ tools/libxl/xl.h | 1 + tools/libxl/xl_cmdimpl.c | 207 ++++++++++++++++++++++++++++++++++++++++++--- tools/libxl/xl_cmdtable.c | 5 ++ 5 files changed, 264 insertions(+), 10 deletions(-) diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index ff9ea77..6c43e7da 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -470,6 +470,57 @@ L<qemu(1)> manpage. The default is B<en-us>. =back +=item B<channel=[ "CHANNEL_SPEC_STRING", "CHANNEL_SPEC_STRING", ...]> + +Specifies the virtual channels to be provided to the guest. A +channel is a low-bandwidth, bidirectional byte stream, which resembles +a serial link. Typical uses for channels include transmitting VM +configuration after boot and signalling to in-guest agents. Please see +F<docs/misc/channels.txt> for more details. + +Each B<CHANNEL_SPEC_STRING> is a comma-separated list of C<KEY=VALUE> +settings, from the following list: + +=over 4 + +=item C<backend=DOMAIN> + +Specify the backend domain name or id. This parameter is optional. If +this parameter is omitted then the toolstack domain will be assumed. + +=item C<name=NAME> + +Specify the string name for this device. This parameter is mandatory. +This should be a well-known name for the specific application (e.g. +guest agent) and should be used by the frontend to connect the +application to the right channel device. There is no formal registry +of channel names, so application authors are encouraged to make their +names unique by including domain name and version number in the string +(e.g. org.mydomain.guestagent.1). + +=item C<connection=CONNECTION> + +Specify how the backend will be implemented. This following options are +available: + +=over 4 + +=item B<connection=SOCKET>: + +The backend will bind a Unix domain socket (at the path given by +B<path=PATH>), call listen and accept connections. The backend will proxy +data between the channel and the connected socket. + +=item B<connection=PTY>: + +The backend will create a pty and proxy data between the channel and the +master device. The command B<xl channel-list> can be used to discover the +assigned slave device. + +=back + +=back + =item B<pci=[ "PCI_SPEC_STRING", "PCI_SPEC_STRING", ... ]> Specifies the host PCI devices to passthrough to this guest. Each B<PCI_SPEC_STRING> diff --git a/docs/man/xl.pod.1 b/docs/man/xl.pod.1 index 30bd4bf..827f5a5 100644 --- a/docs/man/xl.pod.1 +++ b/docs/man/xl.pod.1 @@ -1194,6 +1194,16 @@ List virtual network interfaces for a domain. =back +=head2 CHANNEL DEVICES + +=over 4 + +=item B<channel-list> I<domain-id> + +List virtual channel interfaces for a domain. + +=back + =head2 VTPM DEVICES =over 4 diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h index 10a2e66..afc5f8b 100644 --- a/tools/libxl/xl.h +++ b/tools/libxl/xl.h @@ -78,6 +78,7 @@ int main_top(int argc, char **argv); int main_networkattach(int argc, char **argv); int main_networklist(int argc, char **argv); int main_networkdetach(int argc, char **argv); +int main_channellist(int argc, char **argv); int main_blockattach(int argc, char **argv); int main_blocklist(int argc, char **argv); int main_blockdetach(int argc, char **argv); diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 68df548..48e16c0 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -298,6 +298,18 @@ static void *xrealloc(void *ptr, size_t sz) { return r; } +static char *xstrdup(const char *x) +{ + char *r; + r = strdup(x); + if (!r) { + fprintf(stderr, "xl: Unable to strdup a string of length %zu.\n", + strlen(x)); + exit(-ERROR_FAIL); + } + return r; +} + #define ARRAY_EXTEND_INIT(array,count,initfn) \ ({ \ typeof((count)) array_extend_old_count = (count); \ @@ -516,7 +528,7 @@ static void split_string_into_string_list(const char *str, s = strdup(str); if (s == NULL) { - fprintf(stderr, "unable to allocate memory to parse bootloader args\n"); + fprintf(stderr, "unable to allocate memory to split string\n"); exit(-1); } @@ -532,7 +544,7 @@ static void split_string_into_string_list(const char *str, sl = malloc((nr+1) * sizeof (char *)); if (sl == NULL) { - fprintf(stderr, "unable to allocate memory for bootloader args\n"); + fprintf(stderr, "unable to allocate memory to split string\n"); exit(-1); } @@ -549,6 +561,64 @@ static void split_string_into_string_list(const char *str, free(s); } +typedef int (*char_predicate_t)(const int c); + +static void trim(char_predicate_t predicate, const char *input, char **output) +{ + char *p, *q, *tmp; + if (*input == '\000') + return; + /* Input has length >= 1 */ + + p = tmp = xstrdup(input); + /* Skip past the first whitespace */ + while ((*p != '\000') && (predicate(*p))) + p ++; + q = p + strlen(p) - 1; + /* q points to the last non-NULL character */ + while ((q > p) && (predicate(*q))) + q --; + /* q points to the last character we want */ + q ++; + *q = '\000'; + *output = xstrdup(p); + free(tmp); +} + +static int split_string_into_pair(const char *str, + const char *delim, + char **a, + char **b) +{ + char *s, *p, *saveptr, *aa = NULL, *bb = NULL; + int rc = 0; + + s = xstrdup(str); + + p = strtok_r(s, delim, &saveptr); + if (p == NULL) { + rc = ERROR_INVAL; + goto out; + } + aa = xstrdup(p); + p = strtok_r(NULL, delim, &saveptr); + if (p == NULL) { + rc = ERROR_INVAL; + goto out; + } + bb = xstrdup(p); + + *a = aa; + aa = NULL; + *b = bb; + bb = NULL; +out: + free(s); + free(aa); + free(bb); + return rc; +} + static int parse_range(const char *str, unsigned long *a, unsigned long *b) { const char *nstr; @@ -690,6 +760,12 @@ static void parse_top_level_sdl_options(XLU_Config *config, xlu_cfg_replace_string (config, "xauthority", &sdl->xauthority, 0); } +static void replace_string(char **str, const char *val) +{ + free(*str); + *str = strdup(val); +} + static void parse_config_data(const char *config_source, const char *config_data, int config_len, @@ -699,7 +775,7 @@ static void parse_config_data(const char *config_source, long l; XLU_Config *config; XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms; - XLU_ConfigList *ioports, *irqs, *iomem; + XLU_ConfigList *channels, *ioports, *irqs, *iomem; int num_ioports, num_irqs, num_iomem, num_cpus; int pci_power_mgmt = 0; int pci_msitranslate = 0; @@ -1229,6 +1305,79 @@ static void parse_config_data(const char *config_source, } } + if (!xlu_cfg_get_list (config, "channel", &channels, 0, 0)) { + d_config->num_channels = 0; + d_config->channels = NULL; + while ((buf = xlu_cfg_get_listitem (channels, + d_config->num_channels)) != NULL) { + libxl_device_channel *chn; + libxl_string_list pairs; + char *path = NULL; + int len; + + chn = ARRAY_EXTEND_INIT(d_config->channels, d_config->num_channels, + libxl_device_channel_init); + + split_string_into_string_list(buf, ",", &pairs); + len = libxl_string_list_length(&pairs); + for (i = 0; i < len; i++) { + char *key, *key_untrimmed, *value, *value_untrimmed; + int rc; + rc = split_string_into_pair(pairs[i], "=", + &key_untrimmed, + &value_untrimmed); + if (rc != 0) { + fprintf(stderr, "failed to parse channel configuration: %s", + pairs[i]); + exit(1); + } + trim(isspace, key_untrimmed, &key); + trim(isspace, value_untrimmed, &value); + + if (!strcmp(key, "backend")) { + replace_string(&chn->backend_domname, value); + } else if (!strcmp(key, "name")) { + replace_string(&chn->name, value); + } else if (!strcmp(key, "path")) { + replace_string(&path, value); + } else if (!strcmp(key, "connection")) { + if (!strcmp(value, "pty")) { + chn->connection = LIBXL_CHANNEL_CONNECTION_PTY; + } else if (!strcmp(value, "socket")) { + chn->connection = LIBXL_CHANNEL_CONNECTION_SOCKET; + } else { + fprintf(stderr, "unknown channel connection '%s'\n", + value); + exit(1); + } + } else { + fprintf(stderr, "unknown channel parameter '%s'," + " ignoring\n", key); + } + free(key); + free(key_untrimmed); + free(value); + free(value_untrimmed); + } + switch (chn->connection){ + case LIBXL_CHANNEL_CONNECTION_UNKNOWN: + fprintf(stderr, "channel has unknown 'connection'\n"); + exit(1); + case LIBXL_CHANNEL_CONNECTION_SOCKET: + if (!path) { + fprintf(stderr, "channel connection 'socket' requires path=..\n"); + exit(1); + } + chn->u.socket.path = xstrdup(path); + break; + default: + break; + } + libxl_string_list_dispose(&pairs); + free(path); + } + } + if (!xlu_cfg_get_list (config, "vif", &nics, 0, 0)) { d_config->num_nics = 0; d_config->nics = NULL; @@ -1815,13 +1964,6 @@ static int match_option_size(const char *prefix, size_t len, #define MATCH_OPTION(prefix, arg, oparg) \ match_option_size((prefix "="), sizeof((prefix)), (arg), &(oparg)) -static void replace_string(char **str, const char *val) -{ - free(*str); - *str = strdup(val); -} - - /* Preserve a copy of a domain under a new name. Updates *r_domid */ static int preserve_domain(uint32_t *r_domid, libxl_event *event, libxl_domain_config *d_config) @@ -5818,6 +5960,51 @@ int main_networkdetach(int argc, char **argv) return 0; } +int main_channellist(int argc, char **argv) +{ + int opt; + libxl_device_channel *channels; + libxl_channelinfo channelinfo; + int nb, i; + + SWITCH_FOREACH_OPT(opt, "", NULL, "channel-list", 1) { + /* No options */ + } + + /* Idx BE state evt-ch ring-ref connection params*/ + printf("%-3s %-2s %-5s %-6s %8s %-10s %-30s\n", + "Idx", "BE", "state", "evt-ch", "ring-ref", "connection", ""); + for (argv += optind, argc -= optind; argc > 0; --argc, ++argv) { + uint32_t domid = find_domain(*argv); + channels = libxl_device_channel_list(ctx, domid, &nb); + if (!channels) { + continue; + } + for (i = 0; i < nb; ++i) { + if (!libxl_device_channel_getinfo(ctx, domid, &channels[i], + &channelinfo)) { + printf("%-3d %-2d ", channels[i].devid, channelinfo.backend_id); + printf("%-5d ", channelinfo.state); + printf("%-6d %-8d ", channelinfo.evtch, channelinfo.rref); + printf("%-10s ", libxl_channel_connection_to_string( + channels[i].connection)); + switch (channels[i].connection) { + case LIBXL_CHANNEL_CONNECTION_PTY: + printf("%-30s ", channelinfo.u.pty.path); + break; + default: + break; + } + printf("\n"); + libxl_channelinfo_dispose(&channelinfo); + } + libxl_device_channel_dispose(&channels[i]); + } + free(channels); + } + return 0; +} + int main_blockattach(int argc, char **argv) { int opt; diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c index 4279b9f..e8d01ae 100644 --- a/tools/libxl/xl_cmdtable.c +++ b/tools/libxl/xl_cmdtable.c @@ -335,6 +335,11 @@ struct cmd_spec cmd_table[] = { "Destroy a domain's virtual network device", "<Domain> <DevId|mac>", }, + { "channel-list", + &main_channellist, 0, 0, + "List virtual channel devices for a domain", + "<Domain(s)>", + }, { "block-attach", &main_blockattach, 1, 1, "Create a new virtual block device", -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |