[libvirt] [RFC PATCH 3/5] Qemu remote protocol.
Daniel P. Berrange
berrange at redhat.com
Fri Apr 16 11:31:02 UTC 2010
On Tue, Apr 13, 2010 at 02:36:48PM -0400, Chris Lalancette wrote:
> 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/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;
> +}
Can we avoid moving this function down the file - there doesn't appear to
be any compile reason for moving it & I can't see from the diff whether
you changed any code in it
> --- 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"
I'm thinking this is possibly redundant - I feel it should be possible
to just include it in either the remote.c or dispatch.c file where
it is needed. Indeed the same probably applies for remote_protocol.h
too
> 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>
IIUC, the only difference between this script & remote_generate_stubs.pl
is the method name prefix they're matching on. Could we just pass in the
desired method name prfix from the Makefile.am rule, avoiding the need
to duplicate the generator code ?
> +#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;
> +};
I don't think we need, or should have, a separate message header definition
for QEMU. The daemon has to read & look at the complete header before it
can determine that this is the QEMU protocol vs remote protocol. Thus they
must be identical, or bad stuff will happen.
I guess the reason was for the 'qemu_procedure' enum, but could we just
turn that field into a plain 'unsigned' (which is the same byte size).
Despite all the comments, this all looks architecturally sound to me.
Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
More information about the libvir-list
mailing list