[libvirt] [PATCH v2 6/8] Qemu remote protocol.

Chris Lalancette clalance at redhat.com
Wed Apr 28 20:20:51 UTC 2010


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

Signed-off-by: Chris Lalancette <clalance at redhat.com>
---
 cfg.mk                            |    2 +-
 daemon/Makefile.am                |   32 +++++++++---
 daemon/dispatch.c                 |   45 +++++++++++-----
 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, 494 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 d1f8485..ab21560 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -249,7 +249,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 a82e9a9..089f1aa 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
@@ -76,7 +77,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,21 +168,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 8f55eaa..2b21111 100644
--- a/daemon/dispatch.c
+++ b/daemon/dispatch.c
@@ -23,6 +23,8 @@
 
 #include <config.h>
 
+#include <stdbool.h>
+
 #include "dispatch.h"
 #include "remote.h"
 
@@ -336,10 +338,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);
 
 
 /*
@@ -356,12 +359,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,
@@ -370,22 +374,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
@@ -427,10 +442,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;
@@ -469,7 +485,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 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..e278fa4
--- /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 0000000..e6c83ba
--- /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 0000000..492dcf9
--- /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 0000000..c196a3c
--- /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 98abd33..7b259dc 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,
@@ -6433,6 +6449,35 @@ 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 (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 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/daemon/remote_generate_stubs.pl b/daemon/remote_generate_stubs.pl
index 8b26e3d..a8c4e6d 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 <rjones at redhat.com>
 
@@ -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 c8ab15e..cdc8240 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -153,7 +153,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
 
@@ -434,7 +436,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
@@ -451,6 +453,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..81916ed
--- /dev/null
+++ b/src/remote/qemu_protocol.c
@@ -0,0 +1,41 @@
+#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;
+}
diff --git a/src/remote/qemu_protocol.h b/src/remote/qemu_protocol.h
new file mode 100644
index 0000000..b822187
--- /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 <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;
+
+/* 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 0000000..1d07895
--- /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 <clalance at 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
+};
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a2079ee..d1dc0b0 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -85,6 +85,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"
@@ -207,8 +208,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),
 };
 
 
@@ -8740,9 +8742,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)
@@ -8770,8 +8812,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;
@@ -9118,7 +9166,6 @@ remoteIODecodeMessageLength(struct private_data *priv) {
 
 static int
 processCallDispatchReply(virConnectPtr conn, struct private_data *priv,
-                         int in_open,
                          remote_message_header *hdr,
                          XDR *xdr);
 
@@ -9130,18 +9177,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;
@@ -9155,35 +9203,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:
@@ -9202,7 +9255,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;
@@ -9318,7 +9370,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;
@@ -9424,7 +9475,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
@@ -9451,7 +9502,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
@@ -9474,7 +9525,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];
@@ -9564,7 +9615,7 @@ remoteIOEventLoop(virConnectPtr conn,
         }
 
         if (fds[0].revents & POLLIN) {
-            if (remoteIOHandleInput(conn, priv, in_open) < 0)
+            if (remoteIOHandleInput(conn, priv, flags) < 0)
                 goto error;
         }
 
@@ -9769,9 +9820,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);
@@ -9843,14 +9892,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) {
@@ -10177,7 +10226,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 eb0f9c3..0dadc8d 100644
--- a/src/remote/remote_protocol.c
+++ b/src/remote/remote_protocol.c
@@ -3550,12 +3550,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_u_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_U_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_u_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_U_LONG(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_u_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 92fd6df..fa60244 100644
--- a/src/remote/remote_protocol.h
+++ b/src/remote/remote_protocol.h
@@ -2213,7 +2213,7 @@ typedef enum remote_message_status remote_message_status;
 struct remote_message_header {
         u_int prog;
         u_int vers;
-        remote_procedure proc;
+        u_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 60f93b2..3afdc62 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2091,7 +2091,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 */
+    unsigned proc;      /* REMOTE_PROC_x */
     remote_message_type type;
     unsigned serial;            /* Serial number of message. */
     remote_message_status status;
-- 
1.6.6.1




More information about the libvir-list mailing list