From 337d201ef2ab07ecfb5f21352dcdd8cab56e37cd Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 16 Apr 2010 22:09:25 -0400 Subject: [PATCH] Qemu remote protocol. Since we are adding a new "per-hypervisor" protocol, we make it so that the qemu remote protocol uses a new PROTOCOL and PROGRAM number. This allows us to easily distinguish it from the normal REMOTE protocol. This necessitates changing the proc in remote_message_header from a "remote_procedure" to an "unsigned", which should be the same size (and thus preserve the on-wire protocol). Changes since v1: - Fixed up a couple of script problems in remote_generate_stubs.pl - Switch an int flag to a bool in dispatch.c Changes since v2: - None Changes since v3: - Change unsigned proc to signed proc, to conform to spec Signed-off-by: Chris Lalancette --- cfg.mk | 2 +- daemon/Makefile.am | 32 +++++++-- daemon/dispatch.c | 44 +++++++++---- 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/remote.c | 45 +++++++++++++ daemon/remote.h | 8 +++ daemon/remote_generate_stubs.pl | 62 +++++++++++------- src/Makefile.am | 37 ++++++++++- src/remote/qemu_protocol.c | 41 ++++++++++++ src/remote/qemu_protocol.h | 57 ++++++++++++++++ src/remote/qemu_protocol.x | 46 +++++++++++++ src/remote/remote_driver.c | 105 ++++++++++++++++++++++-------- src/remote/remote_protocol.c | 50 +++++++++++++- src/remote/remote_protocol.h | 2 +- src/remote/remote_protocol.x | 2 +- 19 files changed, 493 insertions(+), 77 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 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/cfg.mk b/cfg.mk index aefe34c17a..e12265e2e4 100644 --- a/cfg.mk +++ b/cfg.mk @@ -416,7 +416,7 @@ sc_prohibit_trailing_blank_lines: test $$found = 0 # Regex for grep -E that exempts generated files from style rules. -preprocessor_exempt = (remote_(driver|protocol)\.h)$$ +preprocessor_exempt = ((qemu|remote)_(driver|protocol)\.h)$$ # Enforce recommended preprocessor indentation style. sc_preprocessor_indentation: @if cppi --version >/dev/null 2>&1; then \ diff --git a/daemon/Makefile.am b/daemon/Makefile.am index cf7951d86e..6769bab90a 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 @@ -96,7 +97,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 @@ -187,21 +188,38 @@ 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) > $@ + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -p remote $(REMOTE_PROTOCOL) > $@ remote_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -t $(REMOTE_PROTOCOL) > $@ + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -t remote $(REMOTE_PROTOCOL) > $@ remote_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -a $(REMOTE_PROTOCOL) > $@ + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -a remote $(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) > $@ + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -r remote $(REMOTE_PROTOCOL) > $@ + +qemu_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -p qemu $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -t qemu $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -a qemu $(QEMU_PROTOCOL) > $@ + +qemu_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -r qemu $(QEMU_PROTOCOL) > $@ LOGROTATE_CONFS = libvirtd.qemu.logrotate libvirtd.lxc.logrotate \ libvirtd.uml.logrotate diff --git a/daemon/dispatch.c b/daemon/dispatch.c index 966db71ea4..302829836b 100644 --- a/daemon/dispatch.c +++ b/daemon/dispatch.c @@ -25,6 +25,7 @@ #include #include +#include #include "dispatch.h" #include "remote.h" @@ -339,10 +340,11 @@ cleanup: } -int +static int remoteDispatchClientCall (struct qemud_server *server, struct qemud_client *client, - struct qemud_client_message *msg); + struct qemud_client_message *msg, + bool qemu_protocol); /* @@ -359,12 +361,13 @@ remoteDispatchClientCall (struct qemud_server *server, * 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) +remoteDispatchClientRequest(struct qemud_server *server, + struct qemud_client *client, + struct qemud_client_message *msg) { int ret; remote_error rerr; + bool qemu_call; DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d", msg->hdr.prog, msg->hdr.vers, msg->hdr.type, @@ -373,22 +376,33 @@ remoteDispatchClientRequest (struct qemud_server *server, memset(&rerr, 0, sizeof rerr); /* Check version, etc. */ - if (msg->hdr.prog != REMOTE_PROGRAM) { + if (msg->hdr.prog == REMOTE_PROGRAM) + qemu_call = false; + else if (msg->hdr.prog == QEMU_PROGRAM) + qemu_call = true; + else { remoteDispatchFormatError (&rerr, - _("program mismatch (actual %x, expected %x)"), - msg->hdr.prog, REMOTE_PROGRAM); + _("program mismatch (actual %x, expected %x or %x)"), + msg->hdr.prog, REMOTE_PROGRAM, QEMU_PROGRAM); goto error; } - if (msg->hdr.vers != REMOTE_PROTOCOL_VERSION) { + + 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); + return remoteDispatchClientCall(server, client, msg, qemu_call); case REMOTE_STREAM: /* Since stream data is non-acked, async, we may continue to received @@ -430,10 +444,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, + bool qemu_protocol) { XDR xdr; remote_error rerr; @@ -472,7 +487,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"), diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 4d8e7e2955..3f13fb11a7 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -45,6 +45,7 @@ # include # include # 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 0000000000..e278fa48d5 --- /dev/null +++ b/daemon/qemu_dispatch_args.h @@ -0,0 +1,5 @@ +/* Automatically generated by remote_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 0000000000..e6c83ba909 --- /dev/null +++ b/daemon/qemu_dispatch_prototypes.h @@ -0,0 +1,12 @@ +/* Automatically generated by remote_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 0000000000..492dcf9944 --- /dev/null +++ b/daemon/qemu_dispatch_ret.h @@ -0,0 +1,5 @@ +/* Automatically generated by remote_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 0000000000..c196a3c4f8 --- /dev/null +++ b/daemon/qemu_dispatch_table.h @@ -0,0 +1,14 @@ +/* Automatically generated by remote_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/remote.c b/daemon/remote.c index cb9e83d267..118654c45c 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -57,6 +57,7 @@ #include "memory.h" #include "util.h" #include "stream.h" +#include "libvirt/libvirt-qemu.h" #define VIR_FROM_THIS VIR_FROM_REMOTE #define REMOTE_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__) @@ -81,11 +82,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) || @@ -96,6 +102,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, @@ -6564,6 +6580,35 @@ remoteDispatchDomainGetBlockInfo (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 (virDomainQemuMonitorCommand(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 9db743291c..fd8d3814a8 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/daemon/remote_generate_stubs.pl b/daemon/remote_generate_stubs.pl index 8b26e3deb0..a8c4e6dd38 100755 --- a/daemon/remote_generate_stubs.pl +++ b/daemon/remote_generate_stubs.pl @@ -1,7 +1,16 @@ #!/usr/bin/perl -w # -# This script parses remote_protocol.x and produces lots of boilerplate -# code for both ends of the remote connection. +# This script parses remote_protocol.x or qemu_protocol.x and produces lots of +# boilerplate code for both ends of the remote connection. +# +# The first non-option argument specifies the prefix to be searched for, and +# output to, the boilerplate code. The second non-option argument is the +# file you want to operate on. For instance, to generate the dispatch table +# for both remote_protocol.x and qemu_protocol.x, you would run the +# following: +# +# remote_generate_stubs.pl -c -t remote ../src/remote/remote_protocol.x +# remote_generate_stubs.pl -t qemu ../src/remote/qemu_protocol.x # # By Richard Jones @@ -10,8 +19,12 @@ use strict; use Getopt::Std; # Command line options. -our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d); -getopts ('ptard'); +our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d, $opt_c); +getopts ('ptardc'); + +my $structprefix = $ARGV[0]; +my $procprefix = uc $structprefix; +shift; # Convert name_of_call to NameOfCall. sub name_to_ProcName { @@ -25,47 +38,50 @@ sub name_to_ProcName { # opinion about the name, args and return type of each RPC. my ($name, $ProcName, $id, %calls, @calls); -# REMOTE_PROC_CLOSE has no args or ret. -$calls{close} = { - name => "close", - ProcName => "Close", - UC_NAME => "CLOSE", - args => "void", - ret => "void", -}; +# only generate a close method if -c was passed +if ($opt_c) { + # REMOTE_PROC_CLOSE has no args or ret. + $calls{close} = { + name => "close", + ProcName => "Close", + UC_NAME => "CLOSE", + args => "void", + ret => "void", + }; +} while (<>) { - if (/^struct remote_(.*)_args/) { + if (/^struct ${structprefix}_(.*)_args/) { $name = $1; $ProcName = name_to_ProcName ($name); - die "duplicate definition of remote_${name}_args" + die "duplicate definition of ${structprefix}_${name}_args" if exists $calls{$name}; $calls{$name} = { name => $name, ProcName => $ProcName, UC_NAME => uc $name, - args => "remote_${name}_args", + args => "${structprefix}_${name}_args", ret => "void", }; - } elsif (/^struct remote_(.*)_ret/) { + } elsif (/^struct ${structprefix}_(.*)_ret/) { $name = $1; $ProcName = name_to_ProcName ($name); if (exists $calls{$name}) { - $calls{$name}->{ret} = "remote_${name}_ret"; + $calls{$name}->{ret} = "${structprefix}_${name}_ret"; } else { $calls{$name} = { name => $name, ProcName => $ProcName, UC_NAME => uc $name, args => "void", - ret => "remote_${name}_ret" + ret => "${structprefix}_${name}_ret" } } - } elsif (/^struct remote_(.*)_msg/) { + } elsif (/^struct ${structprefix}_(.*)_msg/) { $name = $1; $ProcName = name_to_ProcName ($name); @@ -73,9 +89,9 @@ while (<>) { name => $name, ProcName => $ProcName, UC_NAME => uc $name, - msg => "remote_${name}_msg" + msg => "${structprefix}_${name}_msg" } - } elsif (/^\s*REMOTE_PROC_(.*?)\s+=\s+(\d+),?$/) { + } elsif (/^\s*${procprefix}_PROC_(.*?)\s+=\s+(\d+),?$/) { $name = lc $1; $id = $2; $ProcName = name_to_ProcName ($name); @@ -111,7 +127,7 @@ elsif ($opt_p) { # Skip things which are REMOTE_MESSAGE next if $calls{$_}->{msg}; - print "static int remoteDispatch$calls{$_}->{ProcName}(\n"; + print "static int ${structprefix}Dispatch$calls{$_}->{ProcName}(\n"; print " struct qemud_server *server,\n"; print " struct qemud_client *client,\n"; print " virConnectPtr conn,\n"; @@ -152,7 +168,7 @@ 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) remoteDispatch$calls[$id]->{ProcName},\n"; + print " .fn = (dispatch_fn) ${structprefix}Dispatch$calls[$id]->{ProcName},\n"; if ($calls[$id]->{args} ne "void") { print " .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n"; } else { diff --git a/src/Makefile.am b/src/Makefile.am index 4150a037df..f71f72c9d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -155,7 +155,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 @@ -489,7 +491,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 @@ -506,6 +508,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 '; 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 0000000000..81916ed0a6 --- /dev/null +++ b/src/remote/qemu_protocol.c @@ -0,0 +1,41 @@ +#include +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "./remote/qemu_protocol.h" +#include "internal.h" +#include "remote_protocol.h" +#include + +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; +} diff --git a/src/remote/qemu_protocol.h b/src/remote/qemu_protocol.h new file mode 100644 index 0000000000..b82218742b --- /dev/null +++ b/src/remote/qemu_protocol.h @@ -0,0 +1,57 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _RP_QEMU_H_RPCGEN +#define _RP_QEMU_H_RPCGEN + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "internal.h" +#include "remote_protocol.h" +#include + +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; + +/* 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*); + +#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 (); + +#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 0000000000..1d078953ae --- /dev/null +++ b/src/remote/qemu_protocol.x @@ -0,0 +1,46 @@ +/* -*- 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 + */ + +%#include "internal.h" +%#include "remote_protocol.h" +%#include + +/*----- 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 +}; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index afa8f11e60..cb0d8e1ed3 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -77,6 +77,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" @@ -199,8 +200,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), }; @@ -8859,9 +8861,49 @@ done: /*----------------------------------------------------------------------*/ +static int +remoteQemuDomainMonitorCommand (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) @@ -8889,8 +8931,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; @@ -9237,7 +9285,6 @@ remoteIODecodeMessageLength(struct private_data *priv) { static int processCallDispatchReply(virConnectPtr conn, struct private_data *priv, - int in_open, remote_message_header *hdr, XDR *xdr); @@ -9249,18 +9296,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; @@ -9274,35 +9322,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: @@ -9321,7 +9374,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; @@ -9441,7 +9493,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; @@ -9547,7 +9598,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 @@ -9574,7 +9625,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 @@ -9597,7 +9648,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]; @@ -9687,7 +9738,7 @@ remoteIOEventLoop(virConnectPtr conn, } if (fds[0].revents & POLLIN) { - if (remoteIOHandleInput(conn, priv, in_open) < 0) + if (remoteIOHandleInput(conn, priv, flags) < 0) goto error; } @@ -9892,9 +9943,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); @@ -9966,14 +10015,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) { @@ -10302,7 +10351,7 @@ static virDriver remote_driver = { remoteDomainSnapshotCurrent, /* domainSnapshotCurrent */ remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */ remoteDomainSnapshotDelete, /* domainSnapshotDelete */ - NULL, /* qemuDomainMonitorCommand */ + remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 33bbac51a6..0a33f0bb2e 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3611,12 +3611,60 @@ xdr_remote_message_status (XDR *xdrs, remote_message_status *objp) bool_t xdr_remote_message_header (XDR *xdrs, remote_message_header *objp) { + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_int (xdrs, &objp->proc)) + return FALSE; + + } else { + (void)IXDR_PUT_U_INT32(buf, objp->prog); + (void)IXDR_PUT_U_INT32(buf, objp->vers); + (void)IXDR_PUT_INT32(buf, objp->proc); + } + 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; + } else if (xdrs->x_op == XDR_DECODE) { + buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_int (xdrs, &objp->proc)) + return FALSE; + + } else { + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->proc = IXDR_GET_INT32(buf); + } + 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; + } if (!xdr_u_int (xdrs, &objp->prog)) return FALSE; if (!xdr_u_int (xdrs, &objp->vers)) return FALSE; - if (!xdr_remote_procedure (xdrs, &objp->proc)) + if (!xdr_int (xdrs, &objp->proc)) return FALSE; if (!xdr_remote_message_type (xdrs, &objp->type)) return FALSE; diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index cf8e2cbd30..4ec0895730 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -2249,7 +2249,7 @@ typedef enum remote_message_status remote_message_status; struct remote_message_header { u_int prog; u_int vers; - remote_procedure proc; + int proc; remote_message_type type; u_int serial; remote_message_status status; diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index db412bed0f..62450c4a77 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2122,7 +2122,7 @@ const REMOTE_MESSAGE_HEADER_XDR_LEN = 4; struct remote_message_header { unsigned prog; /* REMOTE_PROGRAM */ unsigned vers; /* REMOTE_PROTOCOL_VERSION */ - remote_procedure proc; /* REMOTE_PROC_x */ + int proc; /* REMOTE_PROC_x */ remote_message_type type; unsigned serial; /* Serial number of message. */ remote_message_status status;