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