All the functions will be implemented in later patches.

This patch includes the API that libxl can use to send QMP commands to
QEMU.

This patch also include a description of the internal states of the QMP
client in charge of connecting to QEMU, sending command and handling
responces.

Signed-off-by: Anthony PERARD <anthony.per...@citrix.com>
---
 tools/libxl/libxl_internal.h |  58 ++++++++++++++++++++
 tools/libxl/libxl_qmp.c      | 102 +++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_types.idl  |   4 ++
 3 files changed, 164 insertions(+)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2a1fb784ec..7c88f4c3b5 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -357,6 +357,64 @@ struct libxl__ev_child {
 };
 
 
+/*
+ * QMP asynchronous calls
+ */
+
+/*
+ * This facility allows a command to be sent to QEMU, and the response to be
+ * handed to a callback function.  Each libxl__ev_qmp handles zero or one
+ * outstanding command; if multiple commands are to be sent concurrently,
+ * multiple libxl__ev_qmp's must be used.
+ *
+ * Possible states:
+ *  Undefined
+ *    Might contain anything.
+ *  Idle
+ *    Struct contents are defined enough to pass to any libxl__ev_qmp_*
+ *    functions.
+ *    The struct does not contain references to any allocated private resources
+ *    so can be thrown away.
+ *  Active
+ *    Currently waiting for the callback to be called.
+ *    _dispose must be called to reclaim resources (or wait for the callback to
+ *    be called).
+ *
+ * libxl__ev_qmp_init: Undefined/Idle -> Idle
+ *
+ * libxl__ev_qmp_send: Idle -> Active (on error: Idle)
+ *    Sends a command to QEMU.
+ *
+ * libxl__ev_qmp_dispose: Active/Idle -> Idle
+ *
+ * callback:
+ *    When called, ev is Idle, so can be reused or thrown away.
+ *    When an error occured, it is called with response == NULL and the error
+ *    code in rc.
+ */
+typedef struct libxl__ev_qmp libxl__ev_qmp;
+typedef libxl__ev_qmp_callback(libxl__gc *gc, libxl__ev_qmp *ev,
+                               const libxl__json_object *response,
+                               int rc);
+
+_hidden void libxl__ev_qmp_init(libxl__ev_qmp *ev);
+_hidden int libxl__ev_qmp_send(libxl__gc *gc, libxl__ev_qmp *ev,
+                               const char *cmd, libxl__json_object *args);
+_hidden void libxl__ev_qmp_dispose(libxl__gc *gc, libxl__ev_qmp *ev);
+
+struct libxl__ev_qmp {
+    /* caller should include this in their own struct */
+    /* caller must fill these in, and they must all remain valid */
+    uint32_t domid;
+    libxl__ev_qmp_callback *callback;
+    libxl__carefd *efd; /* set to send a fd with the command, NULL otherwise */
+
+    /* remaining fields are private to libxl_ev_qmp_* */
+    int id;
+    LIBXL_TAILQ_ENTRY(libxl__ev_qmp) entry;
+};
+
+
 /*
  * evgen structures, which are the state we use for generating
  * events for the caller.
diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index 760f2798c7..1e6fbb64a5 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -1237,6 +1237,108 @@ int libxl__qmp_initializations(libxl__gc *gc, uint32_t 
domid,
     return ret;
 }
 
+/* ------------ Implementation of asynchronous QMP calls ------------ */
+
+/*
+ * Implementation of the QMP client.
+ *
+ * This are different state possible in which the client can be in, with the
+ * list of possible transition listed after.
+ *
+ * States:
+ *   Disconnected
+ *      Nothing, no allocated ressources.
+ *   Connecting
+ *      Have allocated ressources, including a connection to a QMP socket.
+ *      Waiting for server greeting.
+ *   Capability Negociation
+ *      QMP server is in Capabilities Negotiation mode.
+ *      Waiting for a response to the "qmp_capabilities" command.
+ *   Connected
+ *      QMP server is in command mode, commands can be issued.
+ *      There is outstanding command to be sent and/or there are in-flight
+ *      libxl_ev_qmp with callback.
+ *   Within A Callback
+ *      The QMP client enter this state when a callback is called.
+ *      The connection to QEMU is kept open until at least the callback
+ *      return.
+ *
+ * Here is the transition from one state to the next:
+ *    Disconnected -> Connecting
+ *      Connect to the QMP socket.
+ *    Connecting -> Capability Negociation
+ *      Server greeting received
+ *      Send "qmp_capabilities"
+ *    Capability Negociation -> Connected
+ *      Response to "qmp_capabilities" received"
+ *
+ *    Connected -> Within A Callback
+ *      When a response is received, if there's a callback associated to it,
+ *      it is called.
+ *    Connected -> Disconnected
+ *      When both list of in-flight event and command to send are empty.
+ *
+ *    Within A Callback -> Connected
+ *      On return from a libxl__ev_qmp callback, there are more command to send
+ *      or there are other in-flight event.
+ *    Within A Callback -> Disconnected
+ *      On return from a libxl__ev_qmp callback, both list of command to send
+ *      and list of in-flight event are empty.
+ *      QMP socket connection is closed, all ressources are deallocated.
+ *
+ *   * -> Disconnected
+ *      Whenever a error occure with the QMP socket, all outstanding callback
+ *      will be called with an error, all ressource will be deallocated.
+ *
+ *
+ * checkout qemu.git:docs/interop/qmp-spec.txt for more information on the
+ * qmp protocol.
+ */
+
+typedef enum qmp_states {
+    qmp_state_disconnected = 1,
+    qmp_state_connecting,
+    qmp_state_capability_negociation,
+    qmp_state_connected,
+    qmp_state_within_callback,
+} qmp_states;
+
+typedef struct qmp_tx_buf qmp_tx_buf;
+struct qmp_tx_buf {
+    char *buf;
+    size_t len;
+    /* File descriptor to send along the command */
+    libxl__carefd *efd;
+    LIBXL_TAILQ_ENTRY(qmp_tx_buf) entry;
+};
+
+struct qmp_state {
+    libxl__carefd *cfd;
+    libxl__ev_fd efd;
+    uint32_t domid;
+
+    /* Current state */
+    qmp_states state;
+
+    /* id associated with the last generated command */
+    unsigned int last_id_used;
+
+    /* receive buffer, with:
+     * buf_size: current allocated size,
+     * buf_used: actual data in the buffer,
+     * buf_consumed: data already parsed.  */
+    char *rx_buf;
+    size_t buf_size;
+    size_t buf_used;
+    size_t buf_consumed;
+
+    /* List of buffers to send */
+    LIBXL_TAILQ_HEAD(qmp_tx_bufs, qmp_tx_buf) tx_buf;
+
+    /* List of in-flight events */
+    LIBXL_SLIST_HEAD(libxl__ev_qmps, libxl__ev_qmp) qmp_events;
+};
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 01ec1d1afa..bb2ea253f6 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -69,6 +69,10 @@ libxl_error = Enumeration("error", [
     (-23, "NOTFOUND"),
     (-24, "DOMAIN_DESTROYED"), # Target domain ceased to exist during op
     (-25, "FEATURE_REMOVED"), # For functionality that has been removed
+    (-26, "QMP_GENERIC_ERROR"), # unspecified qmp error
+    (-27, "QMP_COMMAND_NOT_FOUND"), # the requested command has not been found
+    (-28, "QMP_DEVICE_NOT_ACTIVE"), # a device has failed to be become active
+    (-29, "QMP_DEVICE_NOT_FOUND"), # the requested device has not been found
     ], value_namespace = "")
 
 libxl_domain_type = Enumeration("domain_type", [
-- 
Anthony PERARD


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

Reply via email to