[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v3.2] libxl: Design of an async API to issue QMP commands to QEMU



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.perard@xxxxxxxxxx>
---
 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@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.