Qemu remote protocol.

Since we are adding a new "per-hypervisor" protocol, we
make it so that the qemu remote protocol uses a new
PROTOCOL and PROGRAM number.  This allows us to easily
distinguish it from the normal REMOTE protocol.

This necessitates changing the proc in remote_message_header
from a "remote_procedure" to an "unsigned", which should
be the same size (and thus preserve the on-wire protocol).

Changes since v1:
 - Fixed up a couple of script problems in remote_generate_stubs.pl
 - Switch an int flag to a bool in dispatch.c

Changes since v2:
 - None

Changes since v3:
 - Change unsigned proc to signed proc, to conform to spec

Signed-off-by: Chris Lalancette <clalance@redhat.com>
This commit is contained in:
Chris Lalancette 2010-04-16 22:09:25 -04:00
parent 057e855324
commit 337d201ef2
19 changed files with 493 additions and 77 deletions

2
cfg.mk
View File

@ -416,7 +416,7 @@ sc_prohibit_trailing_blank_lines:
test $$found = 0
# Regex for grep -E that exempts generated files from style rules.
preprocessor_exempt = (remote_(driver|protocol)\.h)$$
preprocessor_exempt = ((qemu|remote)_(driver|protocol)\.h)$$
# Enforce recommended preprocessor indentation style.
sc_preprocessor_indentation:
@if cppi --version >/dev/null 2>&1; then \

View File

@ -10,7 +10,8 @@ DAEMON_SOURCES = \
remote_dispatch_table.h \
remote_dispatch_args.h \
remote_dispatch_ret.h \
../src/remote/remote_protocol.c
../src/remote/remote_protocol.c \
../src/remote/qemu_protocol.c
AVAHI_SOURCES = \
mdns.c mdns.h
@ -96,7 +97,7 @@ libvirtd_LDADD = \
$(SASL_LIBS) \
$(POLKIT_LIBS)
libvirtd_LDADD += ../src/libvirt_util.la
libvirtd_LDADD += ../src/libvirt_util.la ../src/libvirt-qemu.la
if WITH_DRIVER_MODULES
libvirtd_LDADD += ../src/libvirt_driver.la
@ -187,21 +188,38 @@ endif
remote.c: remote_dispatch_prototypes.h \
remote_dispatch_table.h \
remote_dispatch_args.h \
remote_dispatch_ret.h
remote_dispatch_ret.h \
qemu_dispatch_prototypes.h \
qemu_dispatch_table.h \
qemu_dispatch_args.h \
qemu_dispatch_ret.h
REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x
QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x
remote_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -p $(REMOTE_PROTOCOL) > $@
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -p remote $(REMOTE_PROTOCOL) > $@
remote_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -t $(REMOTE_PROTOCOL) > $@
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -t remote $(REMOTE_PROTOCOL) > $@
remote_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -a $(REMOTE_PROTOCOL) > $@
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -a remote $(REMOTE_PROTOCOL) > $@
remote_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -r $(REMOTE_PROTOCOL) > $@
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -r remote $(REMOTE_PROTOCOL) > $@
qemu_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -p qemu $(QEMU_PROTOCOL) > $@
qemu_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -t qemu $(QEMU_PROTOCOL) > $@
qemu_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -a qemu $(QEMU_PROTOCOL) > $@
qemu_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -r qemu $(QEMU_PROTOCOL) > $@
LOGROTATE_CONFS = libvirtd.qemu.logrotate libvirtd.lxc.logrotate \
libvirtd.uml.logrotate

View File

@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include "dispatch.h"
#include "remote.h"
@ -339,10 +340,11 @@ cleanup:
}
int
static int
remoteDispatchClientCall (struct qemud_server *server,
struct qemud_client *client,
struct qemud_client_message *msg);
struct qemud_client_message *msg,
bool qemu_protocol);
/*
@ -359,12 +361,13 @@ remoteDispatchClientCall (struct qemud_server *server,
* Returns 0 if the message was dispatched, -1 upon fatal error
*/
int
remoteDispatchClientRequest (struct qemud_server *server,
struct qemud_client *client,
struct qemud_client_message *msg)
remoteDispatchClientRequest(struct qemud_server *server,
struct qemud_client *client,
struct qemud_client_message *msg)
{
int ret;
remote_error rerr;
bool qemu_call;
DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d",
msg->hdr.prog, msg->hdr.vers, msg->hdr.type,
@ -373,22 +376,33 @@ remoteDispatchClientRequest (struct qemud_server *server,
memset(&rerr, 0, sizeof rerr);
/* Check version, etc. */
if (msg->hdr.prog != REMOTE_PROGRAM) {
if (msg->hdr.prog == REMOTE_PROGRAM)
qemu_call = false;
else if (msg->hdr.prog == QEMU_PROGRAM)
qemu_call = true;
else {
remoteDispatchFormatError (&rerr,
_("program mismatch (actual %x, expected %x)"),
msg->hdr.prog, REMOTE_PROGRAM);
_("program mismatch (actual %x, expected %x or %x)"),
msg->hdr.prog, REMOTE_PROGRAM, QEMU_PROGRAM);
goto error;
}
if (msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
if (!qemu_call && msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
remoteDispatchFormatError (&rerr,
_("version mismatch (actual %x, expected %x)"),
msg->hdr.vers, REMOTE_PROTOCOL_VERSION);
goto error;
}
else if (qemu_call && msg->hdr.vers != QEMU_PROTOCOL_VERSION) {
remoteDispatchFormatError (&rerr,
_("version mismatch (actual %x, expected %x)"),
msg->hdr.vers, QEMU_PROTOCOL_VERSION);
goto error;
}
switch (msg->hdr.type) {
case REMOTE_CALL:
return remoteDispatchClientCall(server, client, msg);
return remoteDispatchClientCall(server, client, msg, qemu_call);
case REMOTE_STREAM:
/* Since stream data is non-acked, async, we may continue to received
@ -430,10 +444,11 @@ error:
*
* Returns 0 if the reply was sent, or -1 upon fatal error
*/
int
static int
remoteDispatchClientCall (struct qemud_server *server,
struct qemud_client *client,
struct qemud_client_message *msg)
struct qemud_client_message *msg,
bool qemu_protocol)
{
XDR xdr;
remote_error rerr;
@ -472,7 +487,10 @@ remoteDispatchClientCall (struct qemud_server *server,
}
}
data = remoteGetDispatchData(msg->hdr.proc);
if (qemu_protocol)
data = qemuGetDispatchData(msg->hdr.proc);
else
data = remoteGetDispatchData(msg->hdr.proc);
if (!data) {
remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),

View File

@ -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"

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,
},

View File

@ -57,6 +57,7 @@
#include "memory.h"
#include "util.h"
#include "stream.h"
#include "libvirt/libvirt-qemu.h"
#define VIR_FROM_THIS VIR_FROM_REMOTE
#define REMOTE_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__)
@ -81,11 +82,16 @@ static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapsh
#include "remote_dispatch_prototypes.h"
#include "qemu_dispatch_prototypes.h"
static const dispatch_data const dispatch_table[] = {
#include "remote_dispatch_table.h"
};
static const dispatch_data const qemu_dispatch_table[] = {
#include "qemu_dispatch_table.h"
};
const dispatch_data const *remoteGetDispatchData(int proc)
{
if (proc >= ARRAY_CARDINALITY(dispatch_table) ||
@ -96,6 +102,16 @@ const dispatch_data const *remoteGetDispatchData(int proc)
return &(dispatch_table[proc]);
}
const dispatch_data const *qemuGetDispatchData(int proc)
{
if (proc >= ARRAY_CARDINALITY(qemu_dispatch_table) ||
qemu_dispatch_table[proc].fn == NULL) {
return NULL;
}
return &(qemu_dispatch_table[proc]);
}
/* Prototypes */
static void
remoteDispatchDomainEventSend (struct qemud_client *client,
@ -6564,6 +6580,35 @@ remoteDispatchDomainGetBlockInfo (struct qemud_server *server ATTRIBUTE_UNUSED,
return 0;
}
static int
qemuDispatchMonitorCommand (struct qemud_server *server ATTRIBUTE_UNUSED,
struct qemud_client *client ATTRIBUTE_UNUSED,
virConnectPtr conn,
remote_message_header *hdr ATTRIBUTE_UNUSED,
remote_error *rerr,
qemu_monitor_command_args *args,
qemu_monitor_command_ret *ret)
{
virDomainPtr domain;
domain = get_nonnull_domain(conn, args->domain);
if (domain == NULL) {
remoteDispatchConnError(rerr, conn);
return -1;
}
if (virDomainQemuMonitorCommand(domain, args->cmd, &ret->result,
args->flags) == -1) {
virDomainFree(domain);
remoteDispatchConnError(rerr, conn);
return -1;
}
virDomainFree(domain);
return 0;
}
/*----- Helpers. -----*/

View File

@ -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);

View File

@ -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@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 {

View File

@ -155,7 +155,9 @@ REMOTE_DRIVER_SOURCES = \
gnutls_1_0_compat.h \
remote/remote_driver.c remote/remote_driver.h \
remote/remote_protocol.c \
remote/remote_protocol.h
remote/remote_protocol.h \
remote/qemu_protocol.c \
remote/qemu_protocol.h
EXTRA_DIST += remote/remote_protocol.x remote/rpcgen_fix.pl
@ -489,7 +491,7 @@ if HAVE_RPCGEN
# Support for non-GLIB rpcgen is here as a convenience for
# non-Linux people needing to test changes during dev.
#
rpcgen:
rpcgen-normal:
rm -f rp.c-t rp.h-t rp.c-t1 rp.c-t2 rp.h-t1
$(RPCGEN) -h -o rp.h-t $(srcdir)/remote/remote_protocol.x
$(RPCGEN) -c -o rp.c-t $(srcdir)/remote/remote_protocol.x
@ -506,6 +508,37 @@ else
mv -f rp.h-t $(srcdir)/remote/remote_protocol.h
mv -f rp.c-t $(srcdir)/remote/remote_protocol.c
endif
rpcgen-qemu:
rm -f rp_qemu.c-t rp_qemu.h-t rp_qemu.c-t1 rp_qemu.c-t2 rp_qemu.h-t1
$(RPCGEN) -h -o rp_qemu.h-t $(srcdir)/remote/qemu_protocol.x
$(RPCGEN) -c -o rp_qemu.c-t $(srcdir)/remote/qemu_protocol.x
if HAVE_GLIBC_RPCGEN
perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.h-t > rp_qemu.h-t1
perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.c-t > rp_qemu.c-t1
(echo '#include <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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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@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
};

View File

@ -77,6 +77,7 @@
#include "qparams.h"
#include "remote_driver.h"
#include "remote_protocol.h"
#include "qemu_protocol.h"
#include "memory.h"
#include "util.h"
#include "event.h"
@ -199,8 +200,9 @@ struct private_data {
};
enum {
REMOTE_CALL_IN_OPEN = 1,
REMOTE_CALL_QUIET_MISSING_RPC = 2,
REMOTE_CALL_IN_OPEN = (1 << 0),
REMOTE_CALL_QUIET_MISSING_RPC = (1 << 1),
REMOTE_QEMU_CALL = (1 << 2),
};
@ -8859,9 +8861,49 @@ done:
/*----------------------------------------------------------------------*/
static int
remoteQemuDomainMonitorCommand (virDomainPtr domain, const char *cmd,
char **result, unsigned int flags)
{
int rv = -1;
qemu_monitor_command_args args;
qemu_monitor_command_ret ret;
struct private_data *priv = domain->conn->privateData;
remoteDriverLock(priv);
make_nonnull_domain(&args.domain, domain);
args.cmd = (char *)cmd;
args.flags = flags;
memset (&ret, 0, sizeof ret);
if (call (domain->conn, priv, REMOTE_QEMU_CALL, QEMU_PROC_MONITOR_COMMAND,
(xdrproc_t) xdr_qemu_monitor_command_args, (char *) &args,
(xdrproc_t) xdr_qemu_monitor_command_ret, (char *) &ret) == -1)
goto done;
*result = strdup(ret.result);
if (*result == NULL) {
virReportOOMError();
goto cleanup;
}
rv = 0;
cleanup:
xdr_free ((xdrproc_t) xdr_qemu_monitor_command_ret, (char *) &ret);
done:
remoteDriverUnlock(priv);
return rv;
}
/*----------------------------------------------------------------------*/
static struct remote_thread_call *
prepareCall(struct private_data *priv,
int flags,
int proc_nr,
xdrproc_t args_filter, char *args,
xdrproc_t ret_filter, char *ret)
@ -8889,8 +8931,14 @@ prepareCall(struct private_data *priv,
rv->ret = ret;
rv->want_reply = 1;
hdr.prog = REMOTE_PROGRAM;
hdr.vers = REMOTE_PROTOCOL_VERSION;
if (flags & REMOTE_QEMU_CALL) {
hdr.prog = QEMU_PROGRAM;
hdr.vers = QEMU_PROTOCOL_VERSION;
}
else {
hdr.prog = REMOTE_PROGRAM;
hdr.vers = REMOTE_PROTOCOL_VERSION;
}
hdr.proc = proc_nr;
hdr.type = REMOTE_CALL;
hdr.serial = rv->serial;
@ -9237,7 +9285,6 @@ remoteIODecodeMessageLength(struct private_data *priv) {
static int
processCallDispatchReply(virConnectPtr conn, struct private_data *priv,
int in_open,
remote_message_header *hdr,
XDR *xdr);
@ -9249,18 +9296,19 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
static int
processCallDispatchStream(virConnectPtr conn, struct private_data *priv,
int in_open,
remote_message_header *hdr,
XDR *xdr);
static int
processCallDispatch(virConnectPtr conn, struct private_data *priv,
int in_open) {
int flags) {
XDR xdr;
struct remote_message_header hdr;
int len = priv->bufferLength - 4;
int rv = -1;
int expectedprog;
int expectedvers;
/* Length word has already been read */
priv->bufferOffset = 4;
@ -9274,35 +9322,40 @@ processCallDispatch(virConnectPtr conn, struct private_data *priv,
priv->bufferOffset += xdr_getpos(&xdr);
expectedprog = REMOTE_PROGRAM;
expectedvers = REMOTE_PROTOCOL_VERSION;
if (flags & REMOTE_QEMU_CALL) {
expectedprog = QEMU_PROGRAM;
expectedvers = QEMU_PROTOCOL_VERSION;
}
/* Check program, version, etc. are what we expect. */
if (hdr.prog != REMOTE_PROGRAM) {
if (hdr.prog != expectedprog) {
remoteError(VIR_ERR_RPC,
_("unknown program (received %x, expected %x)"),
hdr.prog, REMOTE_PROGRAM);
hdr.prog, expectedprog);
return -1;
}
if (hdr.vers != REMOTE_PROTOCOL_VERSION) {
if (hdr.vers != expectedvers) {
remoteError(VIR_ERR_RPC,
_("unknown protocol version (received %x, expected %x)"),
hdr.vers, REMOTE_PROTOCOL_VERSION);
hdr.vers, expectedvers);
return -1;
}
switch (hdr.type) {
case REMOTE_REPLY: /* Normal RPC replies */
rv = processCallDispatchReply(conn, priv, in_open,
&hdr, &xdr);
rv = processCallDispatchReply(conn, priv, &hdr, &xdr);
break;
case REMOTE_MESSAGE: /* Async notifications */
rv = processCallDispatchMessage(conn, priv, in_open,
rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN,
&hdr, &xdr);
break;
case REMOTE_STREAM: /* Stream protocol */
rv = processCallDispatchStream(conn, priv, in_open,
&hdr, &xdr);
rv = processCallDispatchStream(conn, priv, &hdr, &xdr);
break;
default:
@ -9321,7 +9374,6 @@ processCallDispatch(virConnectPtr conn, struct private_data *priv,
static int
processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED,
struct private_data *priv,
int in_open ATTRIBUTE_UNUSED,
remote_message_header *hdr,
XDR *xdr) {
struct remote_thread_call *thecall;
@ -9441,7 +9493,6 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
static int
processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
struct private_data *priv,
int in_open ATTRIBUTE_UNUSED,
remote_message_header *hdr,
XDR *xdr) {
struct private_stream_data *privst;
@ -9547,7 +9598,7 @@ processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
static int
remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
int in_open)
int flags)
{
/* Read as much data as is available, until we get
* EAGAIN
@ -9574,7 +9625,7 @@ remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
* next iteration.
*/
} else {
ret = processCallDispatch(conn, priv, in_open);
ret = processCallDispatch(conn, priv, flags);
priv->bufferOffset = priv->bufferLength = 0;
/*
* We've completed one call, so return even
@ -9597,7 +9648,7 @@ remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
static int
remoteIOEventLoop(virConnectPtr conn,
struct private_data *priv,
int in_open,
int flags,
struct remote_thread_call *thiscall)
{
struct pollfd fds[2];
@ -9687,7 +9738,7 @@ remoteIOEventLoop(virConnectPtr conn,
}
if (fds[0].revents & POLLIN) {
if (remoteIOHandleInput(conn, priv, in_open) < 0)
if (remoteIOHandleInput(conn, priv, flags) < 0)
goto error;
}
@ -9892,9 +9943,7 @@ remoteIO(virConnectPtr conn,
if (priv->watch >= 0)
virEventUpdateHandle(priv->watch, 0);
rv = remoteIOEventLoop(conn, priv,
flags & REMOTE_CALL_IN_OPEN ? 1 : 0,
thiscall);
rv = remoteIOEventLoop(conn, priv, flags, thiscall);
if (priv->watch >= 0)
virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE);
@ -9966,14 +10015,14 @@ cleanup:
*/
static int
call (virConnectPtr conn, struct private_data *priv,
int flags /* if we are in virConnectOpen */,
int flags,
int proc_nr,
xdrproc_t args_filter, char *args,
xdrproc_t ret_filter, char *ret)
{
struct remote_thread_call *thiscall;
thiscall = prepareCall(priv, proc_nr, args_filter, args,
thiscall = prepareCall(priv, flags, proc_nr, args_filter, args,
ret_filter, ret);
if (!thiscall) {
@ -10302,7 +10351,7 @@ static virDriver remote_driver = {
remoteDomainSnapshotCurrent, /* domainSnapshotCurrent */
remoteDomainRevertToSnapshot, /* domainRevertToSnapshot */
remoteDomainSnapshotDelete, /* domainSnapshotDelete */
NULL, /* qemuDomainMonitorCommand */
remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
};
static virNetworkDriver network_driver = {

View File

@ -3611,12 +3611,60 @@ xdr_remote_message_status (XDR *xdrs, remote_message_status *objp)
bool_t
xdr_remote_message_header (XDR *xdrs, remote_message_header *objp)
{
register int32_t *buf;
if (xdrs->x_op == XDR_ENCODE) {
buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (!xdr_u_int (xdrs, &objp->prog))
return FALSE;
if (!xdr_u_int (xdrs, &objp->vers))
return FALSE;
if (!xdr_int (xdrs, &objp->proc))
return FALSE;
} else {
(void)IXDR_PUT_U_INT32(buf, objp->prog);
(void)IXDR_PUT_U_INT32(buf, objp->vers);
(void)IXDR_PUT_INT32(buf, objp->proc);
}
if (!xdr_remote_message_type (xdrs, &objp->type))
return FALSE;
if (!xdr_u_int (xdrs, &objp->serial))
return FALSE;
if (!xdr_remote_message_status (xdrs, &objp->status))
return FALSE;
return TRUE;
} else if (xdrs->x_op == XDR_DECODE) {
buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (!xdr_u_int (xdrs, &objp->prog))
return FALSE;
if (!xdr_u_int (xdrs, &objp->vers))
return FALSE;
if (!xdr_int (xdrs, &objp->proc))
return FALSE;
} else {
objp->prog = IXDR_GET_U_LONG(buf);
objp->vers = IXDR_GET_U_LONG(buf);
objp->proc = IXDR_GET_INT32(buf);
}
if (!xdr_remote_message_type (xdrs, &objp->type))
return FALSE;
if (!xdr_u_int (xdrs, &objp->serial))
return FALSE;
if (!xdr_remote_message_status (xdrs, &objp->status))
return FALSE;
return TRUE;
}
if (!xdr_u_int (xdrs, &objp->prog))
return FALSE;
if (!xdr_u_int (xdrs, &objp->vers))
return FALSE;
if (!xdr_remote_procedure (xdrs, &objp->proc))
if (!xdr_int (xdrs, &objp->proc))
return FALSE;
if (!xdr_remote_message_type (xdrs, &objp->type))
return FALSE;

View File

@ -2249,7 +2249,7 @@ typedef enum remote_message_status remote_message_status;
struct remote_message_header {
u_int prog;
u_int vers;
remote_procedure proc;
int proc;
remote_message_type type;
u_int serial;
remote_message_status status;

View File

@ -2122,7 +2122,7 @@ const REMOTE_MESSAGE_HEADER_XDR_LEN = 4;
struct remote_message_header {
unsigned prog; /* REMOTE_PROGRAM */
unsigned vers; /* REMOTE_PROTOCOL_VERSION */
remote_procedure proc; /* REMOTE_PROC_x */
int proc; /* REMOTE_PROC_x */
remote_message_type type;
unsigned serial; /* Serial number of message. */
remote_message_status status;