[libvirt] [RFC PATCH 3/5] Qemu remote protocol.

Chris Lalancette clalance at redhat.com
Tue Apr 13 18:36:48 UTC 2010


Signed-off-by: Chris Lalancette <clalance at 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 at 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 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
+};
+
+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




More information about the libvir-list mailing list