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:
David Scott authored and Ian Campbell committed 2014-10-20 13:51:29 +01:00
1 parent 8878d01936
commit 0c09b6495e
5 files changed
+194 -8

No files matched your search

+53
View File
@@ -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>
+10
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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;
+5
View File
@@ -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",
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.