mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
This commit is contained in:
1 parent
8878d01936
commit
0c09b6495e
5 files changed
+194
-8
No files matched your search
@@ -530,6 +530,59 @@ 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>
|
||||
seettings. Leading and trailing whitespace is ignored in both KEY and
|
||||
VALUE. Neither KEY nor VALUE may contain ',', '=' or '"'. Defined values
|
||||
are:
|
||||
|
||||
=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>
|
||||
|
||||
@@ -1268,6 +1268,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
|
||||
|
||||
@@ -79,6 +79,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);
|
||||
|
||||
+125
-8
@@ -554,7 +554,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);
|
||||
}
|
||||
|
||||
@@ -570,7 +570,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);
|
||||
}
|
||||
|
||||
@@ -591,7 +591,6 @@ static void split_string_into_string_list(const char *str,
|
||||
and look for CTYPE in libxl_internal.h */
|
||||
typedef int (*char_predicate_t)(const int c);
|
||||
|
||||
static void trim(char_predicate_t predicate, const char *input, char **output) __attribute__ ((unused));
|
||||
static void trim(char_predicate_t predicate, const char *input, char **output)
|
||||
{
|
||||
char *p, *q, *tmp;
|
||||
@@ -616,10 +615,6 @@ static void trim(char_predicate_t predicate, const char *input, char **output)
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static int split_string_into_pair(const char *str,
|
||||
const char *delim,
|
||||
char **a,
|
||||
char **b) __attribute__ ((unused));
|
||||
static int split_string_into_pair(const char *str,
|
||||
const char *delim,
|
||||
char **a,
|
||||
@@ -917,7 +912,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, *viridian;
|
||||
XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian;
|
||||
int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
|
||||
int pci_power_mgmt = 0;
|
||||
int pci_msitranslate = 0;
|
||||
@@ -1451,6 +1446,84 @@ 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;
|
||||
case LIBXL_CHANNEL_CONNECTION_PTY:
|
||||
/* Nothing to do since PTY has no arguments */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown channel connection: %d",
|
||||
chn->connection);
|
||||
exit(1);
|
||||
}
|
||||
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;
|
||||
@@ -6225,6 +6298,50 @@ 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;
|
||||
|
||||
@@ -345,6 +345,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",
|
||||
|
||||