Signed-off-by: Chris Lalancette <clalance@xxxxxxxxxx> --- daemon/Makefile.am | 25 +++++- daemon/dispatch.c | 171 +++++++++++++++++++------------------ daemon/libvirtd.h | 1 + daemon/qemu_dispatch_args.h | 5 + daemon/qemu_dispatch_prototypes.h | 12 +++ daemon/qemu_dispatch_ret.h | 5 + daemon/qemu_dispatch_table.h | 14 +++ daemon/qemu_generate_stubs.pl | 170 ++++++++++++++++++++++++++++++++++++ daemon/remote.c | 43 +++++++++ daemon/remote.h | 8 ++ src/Makefile.am | 37 ++++++++- src/remote/qemu_protocol.c | 60 +++++++++++++ src/remote/qemu_protocol.h | 69 +++++++++++++++ src/remote/qemu_protocol.x | 55 ++++++++++++ src/remote/remote_driver.c | 105 +++++++++++++++++------ 15 files changed, 665 insertions(+), 115 deletions(-) create mode 100644 daemon/qemu_dispatch_args.h create mode 100644 daemon/qemu_dispatch_prototypes.h create mode 100644 daemon/qemu_dispatch_ret.h create mode 100644 daemon/qemu_dispatch_table.h create mode 100755 daemon/qemu_generate_stubs.pl create mode 100644 src/remote/qemu_protocol.c create mode 100644 src/remote/qemu_protocol.h create mode 100644 src/remote/qemu_protocol.x diff --git a/daemon/Makefile.am b/daemon/Makefile.am index a82e9a9..17d3eb5 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -10,7 +10,8 @@ DAEMON_SOURCES = \ remote_dispatch_table.h \ remote_dispatch_args.h \ remote_dispatch_ret.h \ - ../src/remote/remote_protocol.c + ../src/remote/remote_protocol.c \ + ../src/remote/qemu_protocol.c AVAHI_SOURCES = \ mdns.c mdns.h @@ -18,6 +19,7 @@ AVAHI_SOURCES = \ DISTCLEANFILES = EXTRA_DIST = \ remote_generate_stubs.pl \ + qemu_generate_stubs.pl \ libvirtd.conf \ libvirtd.init.in \ libvirtd.policy-0 \ @@ -76,7 +78,7 @@ libvirtd_LDADD = \ $(SASL_LIBS) \ $(POLKIT_LIBS) -libvirtd_LDADD += ../src/libvirt_util.la +libvirtd_LDADD += ../src/libvirt_util.la ../src/libvirt_qemu.la if WITH_DRIVER_MODULES libvirtd_LDADD += ../src/libvirt_driver.la @@ -167,9 +169,14 @@ endif remote.c: remote_dispatch_prototypes.h \ remote_dispatch_table.h \ remote_dispatch_args.h \ - remote_dispatch_ret.h + remote_dispatch_ret.h \ + qemu_dispatch_prototypes.h \ + qemu_dispatch_table.h \ + qemu_dispatch_args.h \ + qemu_dispatch_ret.h REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x +QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x remote_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -p $(REMOTE_PROTOCOL) > $@ @@ -183,6 +190,18 @@ remote_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) remote_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -r $(REMOTE_PROTOCOL) > $@ +qemu_dispatch_prototypes.h: $(srcdir)/qemu_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/qemu_generate_stubs.pl -p $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_table.h: $(srcdir)/qemu_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/qemu_generate_stubs.pl -t $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_args.h: $(srcdir)/qemu_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/qemu_generate_stubs.pl -a $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_ret.h: $(srcdir)/qemu_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/qemu_generate_stubs.pl -r $(QEMU_PROTOCOL) > $@ + LOGROTATE_CONFS = libvirtd.qemu.logrotate libvirtd.lxc.logrotate \ libvirtd.uml.logrotate diff --git a/daemon/dispatch.c b/daemon/dispatch.c index f024900..d36d1a1 100644 --- a/daemon/dispatch.c +++ b/daemon/dispatch.c @@ -336,85 +336,6 @@ cleanup: } -int -remoteDispatchClientCall (struct qemud_server *server, - struct qemud_client *client, - struct qemud_client_message *msg); - - -/* - * @server: the unlocked server object - * @client: the locked client object - * @msg: the complete incoming message packet, with header already decoded - * - * This function gets called from qemud when it pulls a incoming - * remote protocol messsage off the dispatch queue for processing. - * - * The @msg parameter must have had its header decoded already by - * calling remoteDecodeClientMessageHeader - * - * Returns 0 if the message was dispatched, -1 upon fatal error - */ -int -remoteDispatchClientRequest (struct qemud_server *server, - struct qemud_client *client, - struct qemud_client_message *msg) -{ - int ret; - remote_error rerr; - - DEBUG("prog=%d ver=%d type=%d satus=%d serial=%d proc=%d", - msg->hdr.prog, msg->hdr.vers, msg->hdr.type, - msg->hdr.status, msg->hdr.serial, msg->hdr.proc); - - memset(&rerr, 0, sizeof rerr); - - /* Check version, etc. */ - if (msg->hdr.prog != REMOTE_PROGRAM) { - remoteDispatchFormatError (&rerr, - _("program mismatch (actual %x, expected %x)"), - msg->hdr.prog, REMOTE_PROGRAM); - goto error; - } - if (msg->hdr.vers != REMOTE_PROTOCOL_VERSION) { - remoteDispatchFormatError (&rerr, - _("version mismatch (actual %x, expected %x)"), - msg->hdr.vers, REMOTE_PROTOCOL_VERSION); - goto error; - } - - switch (msg->hdr.type) { - case REMOTE_CALL: - return remoteDispatchClientCall(server, client, msg); - - case REMOTE_STREAM: - /* Since stream data is non-acked, async, we may continue to received - * stream packets after we closed down a stream. Just drop & ignore - * these. - */ - VIR_INFO("Ignoring unexpected stream data serial=%d proc=%d status=%d", - msg->hdr.serial, msg->hdr.proc, msg->hdr.status); - qemudClientMessageRelease(client, msg); - break; - - default: - remoteDispatchFormatError (&rerr, _("type (%d) != REMOTE_CALL"), - (int) msg->hdr.type); - goto error; - } - - return 0; - -error: - ret = remoteSerializeReplyError(client, &rerr, &msg->hdr); - - if (ret >= 0) - VIR_FREE(msg); - - return ret; -} - - /* * @server: the unlocked server object * @client: the locked client object @@ -427,10 +348,11 @@ error: * * Returns 0 if the reply was sent, or -1 upon fatal error */ -int +static int remoteDispatchClientCall (struct qemud_server *server, struct qemud_client *client, - struct qemud_client_message *msg) + struct qemud_client_message *msg, + int qemu_protocol) { XDR xdr; remote_error rerr; @@ -469,7 +391,10 @@ remoteDispatchClientCall (struct qemud_server *server, } } - data = remoteGetDispatchData(msg->hdr.proc); + if (qemu_protocol) + data = qemuGetDispatchData(msg->hdr.proc); + else + data = remoteGetDispatchData(msg->hdr.proc); if (!data) { remoteDispatchFormatError (&rerr, _("unknown procedure: %d"), @@ -584,6 +509,88 @@ fatal_error: return -1; } +/* + * @server: the unlocked server object + * @client: the locked client object + * @msg: the complete incoming message packet, with header already decoded + * + * This function gets called from qemud when it pulls a incoming + * remote protocol messsage off the dispatch queue for processing. + * + * The @msg parameter must have had its header decoded already by + * calling remoteDecodeClientMessageHeader + * + * Returns 0 if the message was dispatched, -1 upon fatal error + */ +int remoteDispatchClientRequest(struct qemud_server *server, + struct qemud_client *client, + struct qemud_client_message *msg) +{ + int ret; + remote_error rerr; + int qemu_call; + + DEBUG("prog=%d ver=%d type=%d satus=%d serial=%d proc=%d", + msg->hdr.prog, msg->hdr.vers, msg->hdr.type, + msg->hdr.status, msg->hdr.serial, msg->hdr.proc); + + memset(&rerr, 0, sizeof rerr); + + /* Check version, etc. */ + if (msg->hdr.prog == REMOTE_PROGRAM) + qemu_call = 0; + else if (msg->hdr.prog == QEMU_PROGRAM) + qemu_call = 1; + else { + remoteDispatchFormatError (&rerr, + _("program mismatch (actual %x, expected %x or %x)"), + msg->hdr.prog, REMOTE_PROGRAM, QEMU_PROGRAM); + goto error; + } + + if (!qemu_call && msg->hdr.vers != REMOTE_PROTOCOL_VERSION) { + remoteDispatchFormatError (&rerr, + _("version mismatch (actual %x, expected %x)"), + msg->hdr.vers, REMOTE_PROTOCOL_VERSION); + goto error; + } + else if (qemu_call && msg->hdr.vers != QEMU_PROTOCOL_VERSION) { + remoteDispatchFormatError (&rerr, + _("version mismatch (actual %x, expected %x)"), + msg->hdr.vers, QEMU_PROTOCOL_VERSION); + goto error; + } + + switch (msg->hdr.type) { + case REMOTE_CALL: + return remoteDispatchClientCall(server, client, msg, qemu_call); + + case REMOTE_STREAM: + /* Since stream data is non-acked, async, we may continue to received + * stream packets after we closed down a stream. Just drop & ignore + * these. + */ + VIR_INFO("Ignoring unexpected stream data serial=%d proc=%d status=%d", + msg->hdr.serial, msg->hdr.proc, msg->hdr.status); + qemudClientMessageRelease(client, msg); + break; + + default: + remoteDispatchFormatError (&rerr, _("type (%d) != REMOTE_CALL"), + (int) msg->hdr.type); + goto error; + } + + return 0; + +error: + ret = remoteSerializeReplyError(client, &rerr, &msg->hdr); + + if (ret >= 0) + VIR_FREE(msg); + + return ret; +} int remoteSendStreamData(struct qemud_client *client, diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index d292681..56b79d6 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -45,6 +45,7 @@ # include <rpc/types.h> # include <rpc/xdr.h> # include "remote_protocol.h" +# include "qemu_protocol.h" # include "logging.h" # include "threads.h" diff --git a/daemon/qemu_dispatch_args.h b/daemon/qemu_dispatch_args.h new file mode 100644 index 0000000..2eee3bd --- /dev/null +++ b/daemon/qemu_dispatch_args.h @@ -0,0 +1,5 @@ +/* Automatically generated by qemu_generate_stubs.pl. + * Do not edit this file. Any changes you make will be lost. + */ + + qemu_monitor_command_args val_qemu_monitor_command_args; diff --git a/daemon/qemu_dispatch_prototypes.h b/daemon/qemu_dispatch_prototypes.h new file mode 100644 index 0000000..920ad73 --- /dev/null +++ b/daemon/qemu_dispatch_prototypes.h @@ -0,0 +1,12 @@ +/* Automatically generated by qemu_generate_stubs.pl. + * Do not edit this file. Any changes you make will be lost. + */ + +static int qemuDispatchMonitorCommand( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + qemu_monitor_command_args *args, + qemu_monitor_command_ret *ret); diff --git a/daemon/qemu_dispatch_ret.h b/daemon/qemu_dispatch_ret.h new file mode 100644 index 0000000..9feb699 --- /dev/null +++ b/daemon/qemu_dispatch_ret.h @@ -0,0 +1,5 @@ +/* Automatically generated by qemu_generate_stubs.pl. + * Do not edit this file. Any changes you make will be lost. + */ + + qemu_monitor_command_ret val_qemu_monitor_command_ret; diff --git a/daemon/qemu_dispatch_table.h b/daemon/qemu_dispatch_table.h new file mode 100644 index 0000000..e6078de --- /dev/null +++ b/daemon/qemu_dispatch_table.h @@ -0,0 +1,14 @@ +/* Automatically generated by qemu_generate_stubs.pl. + * Do not edit this file. Any changes you make will be lost. + */ + +{ /* (unused) => 0 */ + .fn = NULL, + .args_filter = (xdrproc_t) xdr_void, + .ret_filter = (xdrproc_t) xdr_void, +}, +{ /* MonitorCommand => 1 */ + .fn = (dispatch_fn) qemuDispatchMonitorCommand, + .args_filter = (xdrproc_t) xdr_qemu_monitor_command_args, + .ret_filter = (xdrproc_t) xdr_qemu_monitor_command_ret, +}, diff --git a/daemon/qemu_generate_stubs.pl b/daemon/qemu_generate_stubs.pl new file mode 100755 index 0000000..870b5c5 --- /dev/null +++ b/daemon/qemu_generate_stubs.pl @@ -0,0 +1,170 @@ +#!/usr/bin/perl -w +# +# This script parses remote_protocol.x and produces lots of boilerplate +# code for both ends of the remote connection. +# +# By Richard Jones <rjones@xxxxxxxxxx> + +use strict; + +use Getopt::Std; + +# Command line options. +our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d); +getopts ('ptard'); + +# Convert name_of_call to NameOfCall. +sub name_to_ProcName { + my $name = shift; + my @elems = split /_/, $name; + @elems = map ucfirst, @elems; + join "", @elems +} + +# Read the input file (usually remote_protocol.x) and form an +# opinion about the name, args and return type of each RPC. +my ($name, $ProcName, $id, %calls, @calls); + +while (<>) { + if (/^struct qemu_(.*)_args/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + die "duplicate definition of qemu_${name}_args" + if exists $calls{$name}; + + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + args => "qemu_${name}_args", + ret => "void", + }; + + } elsif (/^struct qemu_(.*)_ret/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + if (exists $calls{$name}) { + $calls{$name}->{ret} = "qemu_${name}_ret"; + } else { + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + args => "void", + ret => "qemu_${name}_ret" + } + } + } elsif (/^struct qemu_(.*)_msg/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + msg => "qemu_${name}_msg" + } + } elsif (/^\s*QEMU_PROC_(.*?)\s+=\s+(\d+),?$/) { + $name = lc $1; + $id = $2; + $ProcName = name_to_ProcName ($name); + + $calls[$id] = $calls{$name}; + } +} + +#---------------------------------------------------------------------- +# Output + +print <<__EOF__; +/* Automatically generated by qemu_generate_stubs.pl. + * Do not edit this file. Any changes you make will be lost. + */ + +__EOF__ + +# Debugging. +if ($opt_d) { + my @keys = sort (keys %calls); + foreach (@keys) { + print "$_:\n"; + print " name $calls{$_}->{name} ($calls{$_}->{ProcName})\n"; + print " $calls{$_}->{args} -> $calls{$_}->{ret}\n"; + } +} + +# Prototypes for dispatch functions ("qemu_dispatch_prototypes.h"). +elsif ($opt_p) { + my @keys = sort (keys %calls); + foreach (@keys) { + # Skip things which are REMOTE_MESSAGE + next if $calls{$_}->{msg}; + + print "static int qemuDispatch$calls{$_}->{ProcName}(\n"; + print " struct qemud_server *server,\n"; + print " struct qemud_client *client,\n"; + print " virConnectPtr conn,\n"; + print " remote_message_header *hdr,\n"; + print " remote_error *err,\n"; + print " $calls{$_}->{args} *args,\n"; + print " $calls{$_}->{ret} *ret);\n"; + } +} + +# Union of all arg types +# ("qemu_dispatch_args.h"). +elsif ($opt_a) { + for ($id = 0 ; $id <= $#calls ; $id++) { + if (defined $calls[$id] && + !$calls[$id]->{msg} && + $calls[$id]->{args} ne "void") { + print " $calls[$id]->{args} val_$calls[$id]->{args};\n"; + } + } +} + +# Union of all arg types +# ("qemu_dispatch_ret.h"). +elsif ($opt_r) { + for ($id = 0 ; $id <= $#calls ; $id++) { + if (defined $calls[$id] && + !$calls[$id]->{msg} && + $calls[$id]->{ret} ne "void") { + print " $calls[$id]->{ret} val_$calls[$id]->{ret};\n"; + } + } +} + +# Inside the switch statement, prepare the 'fn', 'args_filter', etc +# ("qemu_dispatch_table.h"). +elsif ($opt_t) { + for ($id = 0 ; $id <= $#calls ; $id++) { + if (defined $calls[$id] && !$calls[$id]->{msg}) { + print "{ /* $calls[$id]->{ProcName} => $id */\n"; + print " .fn = (dispatch_fn) qemuDispatch$calls[$id]->{ProcName},\n"; + if ($calls[$id]->{args} ne "void") { + print " .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n"; + } else { + print " .args_filter = (xdrproc_t) xdr_void,\n"; + } + if ($calls[$id]->{ret} ne "void") { + print " .ret_filter = (xdrproc_t) xdr_$calls[$id]->{ret},\n"; + } else { + print " .ret_filter = (xdrproc_t) xdr_void,\n"; + } + print "},\n"; + } else { + if ($calls[$id]->{msg}) { + print "{ /* Async event $calls[$id]->{ProcName} => $id */\n"; + } else { + print "{ /* (unused) => $id */\n"; + } + print " .fn = NULL,\n"; + print " .args_filter = (xdrproc_t) xdr_void,\n"; + print " .ret_filter = (xdrproc_t) xdr_void,\n"; + print "},\n"; + } + } +} diff --git a/daemon/remote.c b/daemon/remote.c index 149176f..820f0c5 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -80,11 +80,16 @@ static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapsh #include "remote_dispatch_prototypes.h" +#include "qemu_dispatch_prototypes.h" static const dispatch_data const dispatch_table[] = { #include "remote_dispatch_table.h" }; +static const dispatch_data const qemu_dispatch_table[] = { +#include "qemu_dispatch_table.h" +}; + const dispatch_data const *remoteGetDispatchData(int proc) { if (proc >= ARRAY_CARDINALITY(dispatch_table) || @@ -95,6 +100,16 @@ const dispatch_data const *remoteGetDispatchData(int proc) return &(dispatch_table[proc]); } +const dispatch_data const *qemuGetDispatchData(int proc) +{ + if (proc >= ARRAY_CARDINALITY(qemu_dispatch_table) || + qemu_dispatch_table[proc].fn == NULL) { + return NULL; + } + + return &(qemu_dispatch_table[proc]); +} + /* Prototypes */ static void remoteDispatchDomainEventSend (struct qemud_client *client, @@ -6390,6 +6405,34 @@ remoteDispatchNumOfNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED, return 0; } +static int +qemuDispatchMonitorCommand (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + qemu_monitor_command_args *args, + qemu_monitor_command_ret *ret) +{ + virDomainPtr domain; + + domain = get_nonnull_domain(conn, args->domain); + if (domain == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virQemuMonitorCommand(domain, args->cmd, &ret->result, args->flags) == -1) { + virDomainFree(domain); + remoteDispatchConnError(rerr, conn); + return -1; + } + + virDomainFree(domain); + + return 0; +} + /*----- Helpers. -----*/ diff --git a/daemon/remote.h b/daemon/remote.h index 9db7432..fd8d381 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -35,6 +35,13 @@ typedef union { # include "remote_dispatch_ret.h" } dispatch_ret; +typedef union { +# include "qemu_dispatch_args.h" +} qemu_dispatch_args; + +typedef union { +# include "qemu_dispatch_ret.h" +} qemu_dispatch_ret; @@ -67,6 +74,7 @@ typedef struct { const dispatch_data const *remoteGetDispatchData(int proc); +const dispatch_data const *qemuGetDispatchData(int proc); diff --git a/src/Makefile.am b/src/Makefile.am index c01c94e..a0df9c8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -151,7 +151,9 @@ REMOTE_DRIVER_SOURCES = \ gnutls_1_0_compat.h \ remote/remote_driver.c remote/remote_driver.h \ remote/remote_protocol.c \ - remote/remote_protocol.h + remote/remote_protocol.h \ + remote/qemu_protocol.c \ + remote/qemu_protocol.h EXTRA_DIST += remote/remote_protocol.x remote/rpcgen_fix.pl @@ -429,7 +431,7 @@ if HAVE_RPCGEN # Support for non-GLIB rpcgen is here as a convenience for # non-Linux people needing to test changes during dev. # -rpcgen: +rpcgen-normal: rm -f rp.c-t rp.h-t rp.c-t1 rp.c-t2 rp.h-t1 $(RPCGEN) -h -o rp.h-t $(srcdir)/remote/remote_protocol.x $(RPCGEN) -c -o rp.c-t $(srcdir)/remote/remote_protocol.x @@ -446,6 +448,37 @@ else mv -f rp.h-t $(srcdir)/remote/remote_protocol.h mv -f rp.c-t $(srcdir)/remote/remote_protocol.c endif + +rpcgen-qemu: + rm -f rp_qemu.c-t rp_qemu.h-t rp_qemu.c-t1 rp_qemu.c-t2 rp_qemu.h-t1 + $(RPCGEN) -h -o rp_qemu.h-t $(srcdir)/remote/qemu_protocol.x + $(RPCGEN) -c -o rp_qemu.c-t $(srcdir)/remote/qemu_protocol.x +if HAVE_GLIBC_RPCGEN + perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.h-t > rp_qemu.h-t1 + perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.c-t > rp_qemu.c-t1 + (echo '#include <config.h>'; cat rp_qemu.c-t1) > rp_qemu.c-t2 + chmod 0444 rp_qemu.c-t2 rp_qemu.h-t1 + mv -f rp_qemu.h-t1 $(srcdir)/remote/qemu_protocol.h + mv -f rp_qemu.c-t2 $(srcdir)/remote/qemu_protocol.c + rm -f rp_qemu.c-t rp_qemu.h-t rp_qemu.c-t1 +else + chmod 0444 rp_qemu.c-t rp_qemu.h-t + mv -f rp_qemu.h-t $(srcdir)/remote/qemu_protocol.h + mv -f rp_qemu.c-t $(srcdir)/remote/qemu_protocol.c +endif + +# +# Maintainer-only target for re-generating the derived .c/.h source +# files, which are actually derived from the .x file. +# +# For committing protocol changes to GIT, the GLIBC rpcgen *must* +# be used. +# +# Support for non-GLIB rpcgen is here as a convenience for +# non-Linux people needing to test changes during dev. +# +rpcgen: rpcgen-normal rpcgen-qemu + endif remote/remote_protocol.c: remote/remote_protocol.h diff --git a/src/remote/qemu_protocol.c b/src/remote/qemu_protocol.c new file mode 100644 index 0000000..8592e96 --- /dev/null +++ b/src/remote/qemu_protocol.c @@ -0,0 +1,60 @@ +#include <config.h> +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "./remote/qemu_protocol.h" +#include "internal.h" +#include "remote_protocol.h" +#include <arpa/inet.h> + +bool_t +xdr_qemu_monitor_command_args (XDR *xdrs, qemu_monitor_command_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->domain)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->cmd)) + return FALSE; + if (!xdr_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_qemu_monitor_command_ret (XDR *xdrs, qemu_monitor_command_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->result)) + return FALSE; + return TRUE; +} + +bool_t +xdr_qemu_procedure (XDR *xdrs, qemu_procedure *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_qemu_message_header (XDR *xdrs, qemu_message_header *objp) +{ + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_qemu_procedure (xdrs, &objp->proc)) + return FALSE; + if (!xdr_remote_message_type (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->serial)) + return FALSE; + if (!xdr_remote_message_status (xdrs, &objp->status)) + return FALSE; + return TRUE; +} diff --git a/src/remote/qemu_protocol.h b/src/remote/qemu_protocol.h new file mode 100644 index 0000000..bc2ed4f --- /dev/null +++ b/src/remote/qemu_protocol.h @@ -0,0 +1,69 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _RP_QEMU_H_RPCGEN +#define _RP_QEMU_H_RPCGEN + +#include <rpc/rpc.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "internal.h" +#include "remote_protocol.h" +#include <arpa/inet.h> + +struct qemu_monitor_command_args { + remote_nonnull_domain domain; + remote_nonnull_string cmd; + int flags; +}; +typedef struct qemu_monitor_command_args qemu_monitor_command_args; + +struct qemu_monitor_command_ret { + remote_nonnull_string result; +}; +typedef struct qemu_monitor_command_ret qemu_monitor_command_ret; +#define QEMU_PROGRAM 0x20008087 +#define QEMU_PROTOCOL_VERSION 1 + +enum qemu_procedure { + QEMU_PROC_MONITOR_COMMAND = 1, +}; +typedef enum qemu_procedure qemu_procedure; + +struct qemu_message_header { + u_int prog; + u_int vers; + qemu_procedure proc; + remote_message_type type; + u_int serial; + remote_message_status status; +}; +typedef struct qemu_message_header qemu_message_header; + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_qemu_monitor_command_args (XDR *, qemu_monitor_command_args*); +extern bool_t xdr_qemu_monitor_command_ret (XDR *, qemu_monitor_command_ret*); +extern bool_t xdr_qemu_procedure (XDR *, qemu_procedure*); +extern bool_t xdr_qemu_message_header (XDR *, qemu_message_header*); + +#else /* K&R C */ +extern bool_t xdr_qemu_monitor_command_args (); +extern bool_t xdr_qemu_monitor_command_ret (); +extern bool_t xdr_qemu_procedure (); +extern bool_t xdr_qemu_message_header (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_RP_QEMU_H_RPCGEN */ diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x new file mode 100644 index 0000000..e0593a8 --- /dev/null +++ b/src/remote/qemu_protocol.x @@ -0,0 +1,55 @@ +/* -*- c -*- + * qemu_protocol.x: private protocol for communicating between + * remote_internal driver and libvirtd. This protocol is + * internal and may change at any time. + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Chris Lalancette <clalance@xxxxxxxxxx> + */ + +%#include "internal.h" +%#include "remote_protocol.h" +%#include <arpa/inet.h> + +/*----- Protocol. -----*/ +struct qemu_monitor_command_args { + remote_nonnull_domain domain; + remote_nonnull_string cmd; + int flags; +}; + +struct qemu_monitor_command_ret { + remote_nonnull_string result; +}; + +/* Define the program number, protocol version and procedure numbers here. */ +const QEMU_PROGRAM = 0x20008087; +const QEMU_PROTOCOL_VERSION = 1; + +enum qemu_procedure { + QEMU_PROC_MONITOR_COMMAND = 1 +}; + +struct qemu_message_header { + unsigned prog; /* QEMU_PROGRAM */ + unsigned vers; /* QEMU_PROTOCOL_VERSION */ + qemu_procedure proc; /* QEMU_PROC_x */ + remote_message_type type; + unsigned serial; /* Serial number of message. */ + remote_message_status status; +}; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 408d18d..2342e78 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -84,6 +84,7 @@ #include "qparams.h" #include "remote_driver.h" #include "remote_protocol.h" +#include "qemu_protocol.h" #include "memory.h" #include "util.h" #include "event.h" @@ -206,8 +207,9 @@ struct private_data { }; enum { - REMOTE_CALL_IN_OPEN = 1, - REMOTE_CALL_QUIET_MISSING_RPC = 2, + REMOTE_CALL_IN_OPEN = (1 << 0), + REMOTE_CALL_QUIET_MISSING_RPC = (1 << 1), + REMOTE_QEMU_CALL = (1 << 2), }; @@ -8730,9 +8732,49 @@ done: /*----------------------------------------------------------------------*/ +static int +qemuMonitorCommand (virDomainPtr domain, const char *cmd, char **result, + unsigned int flags) +{ + int rv = -1; + qemu_monitor_command_args args; + qemu_monitor_command_ret ret; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.domain, domain); + args.cmd = (char *)cmd; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, REMOTE_QEMU_CALL, QEMU_PROC_MONITOR_COMMAND, + (xdrproc_t) xdr_qemu_monitor_command_args, (char *) &args, + (xdrproc_t) xdr_qemu_monitor_command_ret, (char *) &ret) == -1) + goto done; + + *result = strdup(ret.result); + if (*result == NULL) { + + virReportOOMError(); + goto cleanup; + } + + rv = 0; + +cleanup: + xdr_free ((xdrproc_t) xdr_qemu_monitor_command_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + +/*----------------------------------------------------------------------*/ static struct remote_thread_call * prepareCall(struct private_data *priv, + int flags, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret) @@ -8760,8 +8802,14 @@ prepareCall(struct private_data *priv, rv->ret = ret; rv->want_reply = 1; - hdr.prog = REMOTE_PROGRAM; - hdr.vers = REMOTE_PROTOCOL_VERSION; + if (flags & REMOTE_QEMU_CALL) { + hdr.prog = QEMU_PROGRAM; + hdr.vers = QEMU_PROTOCOL_VERSION; + } + else { + hdr.prog = REMOTE_PROGRAM; + hdr.vers = REMOTE_PROTOCOL_VERSION; + } hdr.proc = proc_nr; hdr.type = REMOTE_CALL; hdr.serial = rv->serial; @@ -9099,7 +9147,6 @@ remoteIODecodeMessageLength(struct private_data *priv) { static int processCallDispatchReply(virConnectPtr conn, struct private_data *priv, - int in_open, remote_message_header *hdr, XDR *xdr); @@ -9111,18 +9158,19 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, static int processCallDispatchStream(virConnectPtr conn, struct private_data *priv, - int in_open, remote_message_header *hdr, XDR *xdr); static int processCallDispatch(virConnectPtr conn, struct private_data *priv, - int in_open) { + int flags) { XDR xdr; struct remote_message_header hdr; int len = priv->bufferLength - 4; int rv = -1; + int expectedprog; + int expectedvers; /* Length word has already been read */ priv->bufferOffset = 4; @@ -9136,35 +9184,40 @@ processCallDispatch(virConnectPtr conn, struct private_data *priv, priv->bufferOffset += xdr_getpos(&xdr); + expectedprog = REMOTE_PROGRAM; + expectedvers = REMOTE_PROTOCOL_VERSION; + if (flags & REMOTE_QEMU_CALL) { + expectedprog = QEMU_PROGRAM; + expectedvers = QEMU_PROTOCOL_VERSION; + } + /* Check program, version, etc. are what we expect. */ - if (hdr.prog != REMOTE_PROGRAM) { + if (hdr.prog != expectedprog) { remoteError(VIR_ERR_RPC, _("unknown program (received %x, expected %x)"), - hdr.prog, REMOTE_PROGRAM); + hdr.prog, expectedprog); return -1; } - if (hdr.vers != REMOTE_PROTOCOL_VERSION) { + if (hdr.vers != expectedvers) { remoteError(VIR_ERR_RPC, _("unknown protocol version (received %x, expected %x)"), - hdr.vers, REMOTE_PROTOCOL_VERSION); + hdr.vers, expectedvers); return -1; } switch (hdr.type) { case REMOTE_REPLY: /* Normal RPC replies */ - rv = processCallDispatchReply(conn, priv, in_open, - &hdr, &xdr); + rv = processCallDispatchReply(conn, priv, &hdr, &xdr); break; case REMOTE_MESSAGE: /* Async notifications */ - rv = processCallDispatchMessage(conn, priv, in_open, + rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN, &hdr, &xdr); break; case REMOTE_STREAM: /* Stream protocol */ - rv = processCallDispatchStream(conn, priv, in_open, - &hdr, &xdr); + rv = processCallDispatchStream(conn, priv, &hdr, &xdr); break; default: @@ -9183,7 +9236,6 @@ processCallDispatch(virConnectPtr conn, struct private_data *priv, static int processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED, struct private_data *priv, - int in_open ATTRIBUTE_UNUSED, remote_message_header *hdr, XDR *xdr) { struct remote_thread_call *thecall; @@ -9299,7 +9351,6 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, static int processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED, struct private_data *priv, - int in_open ATTRIBUTE_UNUSED, remote_message_header *hdr, XDR *xdr) { struct private_stream_data *privst; @@ -9405,7 +9456,7 @@ processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED, static int remoteIOHandleInput(virConnectPtr conn, struct private_data *priv, - int in_open) + int flags) { /* Read as much data as is available, until we get * EAGAIN @@ -9432,7 +9483,7 @@ remoteIOHandleInput(virConnectPtr conn, struct private_data *priv, * next iteration. */ } else { - ret = processCallDispatch(conn, priv, in_open); + ret = processCallDispatch(conn, priv, flags); priv->bufferOffset = priv->bufferLength = 0; /* * We've completed one call, so return even @@ -9455,7 +9506,7 @@ remoteIOHandleInput(virConnectPtr conn, struct private_data *priv, static int remoteIOEventLoop(virConnectPtr conn, struct private_data *priv, - int in_open, + int flags, struct remote_thread_call *thiscall) { struct pollfd fds[2]; @@ -9535,7 +9586,7 @@ remoteIOEventLoop(virConnectPtr conn, } if (fds[0].revents & POLLIN) { - if (remoteIOHandleInput(conn, priv, in_open) < 0) + if (remoteIOHandleInput(conn, priv, flags) < 0) goto error; } @@ -9726,9 +9777,7 @@ remoteIO(virConnectPtr conn, if (priv->watch >= 0) virEventUpdateHandle(priv->watch, 0); - rv = remoteIOEventLoop(conn, priv, - flags & REMOTE_CALL_IN_OPEN ? 1 : 0, - thiscall); + rv = remoteIOEventLoop(conn, priv, flags, thiscall); if (priv->watch >= 0) virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE); @@ -9800,14 +9849,14 @@ cleanup: */ static int call (virConnectPtr conn, struct private_data *priv, - int flags /* if we are in virConnectOpen */, + int flags, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret) { struct remote_thread_call *thiscall; - thiscall = prepareCall(priv, proc_nr, args_filter, args, + thiscall = prepareCall(priv, flags, proc_nr, args_filter, args, ret_filter, ret); if (!thiscall) { @@ -10134,7 +10183,7 @@ static virDriver remote_driver = { remoteDomainSnapshotCurrent, /* domainSnapshotCurrent */ remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ - NULL, /* qemuMonitorCommand */ + qemuMonitorCommand, /* qemuMonitorCommand */ }; static virNetworkDriver network_driver = { -- 1.6.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list