[libvirt] [PATCH 01/10] Defines the basics of a generic RPC protocol in XDR

Daniel P. Berrange berrange at redhat.com
Wed May 11 10:18:02 UTC 2011


This patch defines the basics of a generic RPC protocol in XDR.
This is wire ABI compatible with the original remote_protocol.x.
It takes everything except for the RPC calls / events from that
protocol

 - The basic header virNetMessageHeader (aka remote_message_header)
 - The error object virNetMessageError  (aka remote_error)
 - Two dummy objects virNetMessageDomain & virNetMessageNetwork
   sadly needed to keep virNetMessageError ABI compatible with
   the old remote_error

The RPC protocol supports method calls, async events and
bidirectional data streams as before

* src/Makefile.am: Add rules for generating RPC code from
  protocol & define a new libvirt-net-rpc.la helper library
* src/rpc/virnetprotocol.x: New generic RPC protocol
* src/rpc/virnetprotocol.c, src/rpc/virnetprotocol.h: Generated
  from virnetprotocol.x
---
 src/Makefile.am          |   20 ++++-
 src/rpc/virnetprotocol.x |  217 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 233 insertions(+), 4 deletions(-)
 create mode 100644 src/rpc/virnetprotocol.x

diff --git a/src/Makefile.am b/src/Makefile.am
index 75ece49..faf9e63 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -551,13 +551,11 @@ libvirt_driver_remote_la_SOURCES = $(REMOTE_DRIVER_SOURCES)
 
 $(srcdir)/remote/remote_driver.c: $(REMOTE_DRIVER_GENERATED)
 
-$(srcdir)/remote/%_protocol.c: $(srcdir)/remote/%_protocol.x \
-		$(srcdir)/remote/%_protocol.h $(srcdir)/remote/rpcgen_fix.pl
+%protocol.c: %protocol.x %protocol.h $(srcdir)/remote/rpcgen_fix.pl
 	$(AM_V_GEN)perl -w $(srcdir)/remote/rpcgen_fix.pl $(RPCGEN) -c \
 	       $< $@
 
-$(srcdir)/remote/%_protocol.h: $(srcdir)/remote/%_protocol.x \
-		$(srcdir)/remote/rpcgen_fix.pl
+%protocol.h: %protocol.x $(srcdir)/remote/rpcgen_fix.pl
 	$(AM_V_GEN)perl -w $(srcdir)/remote/rpcgen_fix.pl $(RPCGEN) -h \
 	       $< $@
 
@@ -1154,6 +1152,20 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
 libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
 EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
 
+
+noinst_LTLIBRARIES += libvirt-net-rpc.la
+
+libvirt_net_rpc_la_SOURCES = \
+	rpc/virnetprotocol.h rpc/virnetprotocol.c
+libvirt_net_rpc_la_CFLAGS = \
+			$(AM_CFLAGS)
+libvirt_net_rpc_la_LDFLAGS = \
+			$(AM_LDFLAGS) \
+			$(CYGWIN_EXTRA_LDFLAGS) \
+			$(MINGW_EXTRA_LDFLAGS)
+libvirt_net_rpc_la_LIBADD = \
+			$(CYGWIN_EXTRA_LIBADD)
+
 libexec_PROGRAMS =
 
 if WITH_LIBVIRTD
diff --git a/src/rpc/virnetprotocol.x b/src/rpc/virnetprotocol.x
new file mode 100644
index 0000000..15066b8
--- /dev/null
+++ b/src/rpc/virnetprotocol.x
@@ -0,0 +1,217 @@
+/* -*- c -*-
+ * virnetprotocol.x: basic protocol for all RPC services.
+ *
+ * Copyright (C) 2006-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: Richard Jones <rjones at redhat.com>
+ */
+
+%#include "internal.h"
+%#include <arpa/inet.h>
+
+/* cygwin's xdr implementation defines xdr_u_int64_t instead of xdr_uint64_t
+ * and lacks IXDR_PUT_INT32 and IXDR_GET_INT32
+ */
+%#ifdef HAVE_XDR_U_INT64_T
+%# define xdr_uint64_t xdr_u_int64_t
+%#endif
+%#ifndef IXDR_PUT_INT32
+%# define IXDR_PUT_INT32 IXDR_PUT_LONG
+%#endif
+%#ifndef IXDR_GET_INT32
+%# define IXDR_GET_INT32 IXDR_GET_LONG
+%#endif
+%#ifndef IXDR_PUT_U_INT32
+%# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG
+%#endif
+%#ifndef IXDR_GET_U_INT32
+%# define IXDR_GET_U_INT32 IXDR_GET_U_LONG
+%#endif
+
+/*----- Data types. -----*/
+
+/* Maximum total message size (serialised). */
+const VIR_NET_MESSAGE_MAX = 262144;
+
+/* Size of struct virNetMessageHeader (serialised)*/
+const VIR_NET_MESSAGE_HEADER_MAX = 24;
+
+/* Size of message payload */
+const VIR_NET_MESSAGE_PAYLOAD_MAX = 262120;
+
+/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */
+const VIR_NET_MESSAGE_LEN_MAX = 4;
+
+/* Length of long, but not unbounded, strings.
+ * This is an arbitrary limit designed to stop the decoder from trying
+ * to allocate unbounded amounts of memory when fed with a bad message.
+ */
+const VIR_NET_MESSAGE_STRING_MAX = 65536;
+
+/*
+ * RPC wire format
+ *
+ * Each message consists of:
+ *
+ *    Name    | Type                  | Description
+ * -----------+-----------------------+------------------
+ *    Length  | int                   | Total number of bytes in message _including_ length.
+ *    Header  | virNetMessageHeader   | Control information about procedure call
+ *    Payload | -                     | Variable payload data per procedure
+ *
+ * In header, the 'serial' field varies according to:
+ *
+ *  - type == VIR_NET_CALL
+ *      * serial is set by client, incrementing by 1 each time
+ *
+ *  - type == VIR_NET_REPLY
+ *      * serial matches that from the corresponding VIR_NET_CALL
+ *
+ *  - type == VIR_NET_MESSAGE
+ *      * serial is always zero
+ *
+ *  - type == VIR_NET_STREAM
+ *      * serial matches that from the corresponding VIR_NET_CALL
+ *
+ * and the 'status' field varies according to:
+ *
+ *  - type == VIR_NET_CALL
+ *     * VIR_NET_OK always
+ *
+ *  - type == VIR_NET_REPLY
+ *     * VIR_NET_OK if RPC finished successfully
+ *     * VIR_NET_ERROR if something failed
+ *
+ *  - type == VIR_NET_MESSAGE
+ *     * VIR_NET_OK always
+ *
+ *  - type == VIR_NET_STREAM
+ *     * VIR_NET_CONTINUE if more data is following
+ *     * VIR_NET_OK if stream is complete
+ *     * VIR_NET_ERROR if stream had an error
+ *
+ * Payload varies according to type and status:
+ *
+ *  - type == VIR_NET_CALL
+ *          XXX_args  for procedure
+ *
+ *  - type == VIR_NET_REPLY
+ *     * status == VIR_NET_OK
+ *          XXX_ret         for procedure
+ *     * status == VIR_NET_ERROR
+ *          remote_error    Error information
+ *
+ *  - type == VIR_NET_MESSAGE
+ *     * status == VIR_NET_OK
+ *          XXX_msg        for event information
+ *
+ *  - type == VIR_NET_STREAM
+ *     * status == VIR_NET_CONTINUE
+ *          byte[]       raw stream data
+ *     * status == VIR_NET_ERROR
+ *          remote_error error information
+ *     * status == VIR_NET_OK
+ *          <empty>
+ */
+enum virNetMessageType {
+    /* client -> server. args from a method call */
+    VIR_NET_CALL = 0,
+    /* server -> client. reply/error from a method call */
+    VIR_NET_REPLY = 1,
+    /* either direction. async notification */
+    VIR_NET_MESSAGE = 2,
+    /* either direction. stream data packet */
+    VIR_NET_STREAM = 3
+};
+
+enum virNetMessageStatus {
+    /* Status is always VIR_NET_OK for calls.
+     * For replies, indicates no error.
+     */
+    VIR_NET_OK = 0,
+
+    /* For replies, indicates that an error happened, and a struct
+     * remote_error follows.
+     */
+    VIR_NET_ERROR = 1,
+
+    /* For streams, indicates that more data is still expected
+     */
+    VIR_NET_CONTINUE = 2
+};
+
+/* 4 byte length word per header */
+const VIR_NET_MESSAGE_HEADER_XDR_LEN = 4;
+
+struct virNetMessageHeader {
+    unsigned prog;              /* Unique ID for the program */
+    unsigned vers;              /* Program version number */
+    int proc;                   /* Unique ID for the procedure within the program */
+    virNetMessageType type;     /* Type of message */
+    unsigned serial;            /* Serial number of message. */
+    virNetMessageStatus status;
+};
+
+/* Error message. See <virterror.h> for explanation of fields. */
+
+/* Most of these don't really belong here. There are sadly needed
+ * for wire ABI backwards compatibility with the rather crazy
+ * error struct we previously defined :-(
+ */
+
+typedef opaque virNetMessageUUID[VIR_UUID_BUFLEN];
+typedef string virNetMessageNonnullString<VIR_NET_MESSAGE_STRING_MAX>;
+
+/* A long string, which may be NULL. */
+typedef virNetMessageNonnullString *virNetMessageString;
+
+/* A domain which may not be NULL. */
+struct virNetMessageNonnullDomain {
+    virNetMessageNonnullString name;
+    virNetMessageUUID uuid;
+    int id;
+};
+
+/* A network which may not be NULL. */
+struct virNetMessageNonnullNetwork {
+    virNetMessageNonnullString name;
+    virNetMessageUUID uuid;
+};
+
+
+typedef virNetMessageNonnullDomain *virNetMessageDomain;
+typedef virNetMessageNonnullNetwork *virNetMessageNetwork;
+
+/* NB. Fields "code", "domain" and "level" are really enums.  The
+ * numeric value should remain compatible between libvirt and
+ * libvirtd.  This means, no changing or reordering the enums as
+ * defined in <virterror.h> (but we don't do that anyway, for separate
+ * ABI reasons).
+ */
+struct virNetMessageError {
+    int code;
+    int domain;
+    virNetMessageString message;
+    int level;
+    virNetMessageDomain dom; /* unused */
+    virNetMessageString str1;
+    virNetMessageString str2;
+    virNetMessageString str3;
+    int int1;
+    int int2;
+    virNetMessageNetwork net; /* unused */
+};
-- 
1.7.4.4




More information about the libvir-list mailing list