Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
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(a)redhat.com>
+
+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(a)redhat.com>
+ */
+
+%#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