qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent
@ 2010-11-16 16:01 Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs Michael Roth
                   ` (18 more replies)
  0 siblings, 19 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

This set of patches is meant to be applied on top of the recently submitted Virtproxy v3 patchset. It can also be obtained at:

git://repo.or.cz/qemu/mdroth.git virtproxy_v3

OVERVIEW:

There are a wide range of use cases motivating the need for a guest agent of some sort to extend the functionality/usability/control offered by QEMU. Some examples include graceful guest shutdown/reboot and notifications thereof, copy/paste syncing between host/guest, guest statistics gathering, file access, etc.

Ideally these would all be served by a single, easilly extensible agent that can be deployed in a wide range of guests. Virtagent is an XMLRPC server, integrated into QEMU and the Virtproxy guest daemon, aimed at providing this type of functionality.

NOTE: The guest agent can potentially be implemented independently of virtproxy depending on the feedback, we simply make use of it to provide an abstraction from the actual transport layer (ISA vs. Virtio serial) and use it's multiplexing capabilities to avoid having to dedicate 2 isa/virtio serial ports to the virtagent service. Please evaluate these patches as being seperate from virtproxy.

CHANGES IN V4:

 - Added guest agent capabilities negotiation
 - Added RPC/monitor command to invoke guest shutdown/reboot/powerdown
 - Added RPC/monitor command to the guest agent
 - Added guest startup notification ("hello")
 - Added syslog()'ing of guest agent RPCs
 - Various cleanups

CHANGES IN V3:

 - Integrated virtagent server into virtproxy chardev. Usage examples below.
 - Consolidated RPC server/client setup into a pair of init routines
 - Fixed buffer overflow in agent_viewfile() and various memory leaks

CHANGES IN V2:

 - All RPC communication is now done using asynchronous/non-blocking read/write handlers
 - Previously fork()'d RPC server loop is now integrated into qemu-vp/virtproxy i/o loop
 - Cleanups/suggestions from previous RFC

DESIGN:

There are actually 2 RPC servers:

1) a server in the guest integrated into qemu-vp, the Virtproxy guest daemon, which handles RPC requests from QEMU
2) a server in the host, integrated into the virtproxy chardev, to handle RPC requests sent by the guest agent (mainly for handling asynchronous events reported by the agent).

At the Virtagent level, communication is done via standard RPCs (HTTP between host and guest). Virtproxy transparently handles transport over a network or isa/virtio serial channel, allowing the agent to be deployed on older guests which may not support virtio-serial.

EXAMPLE USAGE:

 - Configure guest agent to talk to host via virtio-serial
    # start guest with virtio-serial/virtproxy/virtagent. for example (RHEL6rc1):
    qemu \
    -chardev virtproxy,id=test0,virtagent=on \
    -device virtio-serial \
    -device virtserialport,chardev=test0,name=virtagent0 \
    -monitor stdio
    ...
    # in the guest:
    ./qemu-vp -c virtserial-open:/dev/virtio-ports/virtagent0:- -g
    ...
    # monitor commands
    (qemu) agent_viewdmesg
    [139311.710326] wlan0: deauthenticating from 00:30:bd:f7:12:d5 by local choice (reason=3)
    [139323.469857] wlan0: deauthenticating from 00:21:29:cd:41:ee by local choice (reason=3)
    ...
    [257683.375646] wlan0: authenticated
    [257683.375684] wlan0: associate with AP 00:30:bd:f7:12:d5 (try 1)
    [257683.377932] wlan0: RX AssocResp from 00:30:bd:f7:12:d5 (capab=0x411 status=0 aid=4)
    [257683.377940] wlan0: associated
    
    (qemu) agent_viewfile /proc/meminfo
    MemTotal:        3985488 kB
    MemFree:          400524 kB
    Buffers:          220556 kB
    Cached:          2073160 kB
    SwapCached:            0 kB
    ...
    Hugepagesize:       2048 kB
    DirectMap4k:        8896 kB
    DirectMap2M:     4110336 kB
    (qemu) agent_shutdown powerdown
    (qemu)

KNOWN ISSUES/PLANS:
 - the client socket that qemu connects to send RPCs is a hardcoded filepath. This is unacceptable as the socket is channel/process specific and things will break when multiple guests are started.
 - proper channel negotiation is needed to avoid hung monitors and such when a guest reboots or the guest agent is stopped for whatever reason. additionally, a timeout may need to be imposed on the amount of time the http read handler can block the monitor.

[RFC][PATCH v4 01/18] virtagent: add common rpc transport defs
[RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server
[RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server
[RFC][PATCH v4 04/18] virtagent: base RPC client definitions
[RFC][PATCH v4 05/18] virtagent: add getfile RPC
[RFC][PATCH v4 06/18] virtagent: add agent_viewfile command
[RFC][PATCH v4 07/18] virtagent: add getdmesg RPC
[RFC][PATCH v4 08/18] virtagent: add agent_viewdmesg command
[RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC
[RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command
[RFC][PATCH v4 11/18] virtagent: add va_ping RPC
[RFC][PATCH v4 12/18] virtagent: add agent_ping monitor command
[RFC][PATCH v4 13/18] virtagent: add agent_capabilities monitor function
[RFC][PATCH v4 14/18] virtagent: add client capabilities init function
[RFC][PATCH v4 15/18] virtagent: add va_hello RPC function
[RFC][PATCH v4 16/18] virtagent: add va_send_hello() client function
[RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup
[RFC][PATCH v4 18/18] virtagent: Makefile/configure changes to build virtagent bits

 Makefile           |    2 +-
 Makefile.target    |    2 +-
 configure          |   25 ++
 hmp-commands.hx    |   80 ++++++
 monitor.c          |    1 +
 qemu-char.c        |   26 ++
 qemu-config.c      |    3 +
 qemu-vp.c          |   96 ++++++-
 qerror.c           |    4 +
 qerror.h           |    3 +
 qmp-commands.hx    |  164 +++++++++++
 roms/seabios       |    2 +-
 virtagent-common.c |  440 +++++++++++++++++++++++++++++
 virtagent-common.h |   73 +++++
 virtagent-daemon.c |  404 +++++++++++++++++++++++++++
 virtagent-daemon.h |   23 ++
 virtagent.c        |  785 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h        |   43 +++
 18 files changed, 2164 insertions(+), 12 deletions(-)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 13:53   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server Michael Roth
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Common code for sending/recieving RPCs via http over virtproxy channel.
All communication is done via asynchronous read/write handlers and using
non-blocking reads/writes

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-common.c |  440 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-common.h |   73 +++++++++
 2 files changed, 513 insertions(+), 0 deletions(-)
 create mode 100644 virtagent-common.c
 create mode 100644 virtagent-common.h

diff --git a/virtagent-common.c b/virtagent-common.c
new file mode 100644
index 0000000..8c4dcd4
--- /dev/null
+++ b/virtagent-common.c
@@ -0,0 +1,440 @@
+/*
+ * virt-agent - common host/guest RPC functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtagent-common.h"
+
+#define VA_READ true
+#define VA_SEND false
+
+enum va_rpc_type {
+    VA_RPC_REQUEST,
+    VA_RPC_RESPONSE,
+};
+
+typedef struct VARPCState {
+    char hdr[VA_HDR_LEN_MAX];
+    int fd;
+    size_t hdr_len;
+    size_t hdr_pos;
+    enum {
+        VA_READ_START,
+        VA_READ_HDR,
+        VA_READ_BODY,
+        VA_SEND_START,
+        VA_SEND_HDR,
+        VA_SEND_BODY,
+    } state;
+    enum va_rpc_type rpc_type;
+    char *content;
+    size_t content_len;
+    size_t content_pos;
+    VARPCData *data;
+} VARPCState;
+
+static void va_rpc_read_handler(void *opaque);
+static void va_rpc_send_handler(void *opaque);
+
+static int end_of_header(char *buf, int end_pos)
+{
+    return !strncmp(buf+(end_pos-2), "\n\r\n", 3);
+}
+
+static void va_rpc_hdr_init(VARPCState *s) {
+    const char *preamble;
+
+    TRACE("called");
+    /* essentially ignored in the context of virtagent, but might as well */
+    if (s->rpc_type == VA_RPC_REQUEST) {
+        preamble = "POST /RPC2 HTTP/1.1";
+    } else if (s->rpc_type == VA_RPC_RESPONSE) {
+        preamble = "HTTP/1.1 200 OK";
+    } else {
+        s->hdr_len = 0;
+        return;
+    }
+
+    s->hdr_len = sprintf(s->hdr,
+                         "%s" EOL
+                         "Content-Type: text/xml" EOL
+                         "Content-Length: %u" EOL EOL,
+                         preamble,
+                         (uint32_t)s->content_len);
+}
+
+static void va_rpc_parse_hdr(VARPCState *s)
+{
+    int i, line_pos = 0;
+    char line_buf[4096];
+
+    for (i = 0; i < VA_HDR_LEN_MAX; ++i) {
+        if (s->hdr[i] != '\n') {
+            /* read line */
+            line_buf[line_pos++] = s->hdr[i];
+        } else {
+            /* process line */
+            if (strncmp(line_buf, "Content-Length: ", 16) == 0) {
+                s->content_len = atoi(&line_buf[16]);
+                return;
+            }
+            line_pos = 0;
+        }
+    }
+}
+
+static VARPCState *va_rpc_state_new(VARPCData *data, int fd,
+                                    enum va_rpc_type rpc_type, bool read)
+{
+    VARPCState *s = qemu_mallocz(sizeof(VARPCState));
+
+    s->rpc_type = rpc_type;
+    s->fd = fd;
+    s->data = data;
+    if (s->data == NULL) {
+        goto EXIT_BAD;
+    }
+
+    if (read) {
+        s->state = VA_READ_START;
+        s->content = NULL;
+    } else {
+        s->state = VA_SEND_START;
+        if (rpc_type == VA_RPC_REQUEST) {
+            s->content = XMLRPC_MEMBLOCK_CONTENTS(char, s->data->send_req_xml);
+            s->content_len = XMLRPC_MEMBLOCK_SIZE(char, s->data->send_req_xml);
+        } else if (rpc_type == VA_RPC_RESPONSE) {
+            s->content = XMLRPC_MEMBLOCK_CONTENTS(char, s->data->send_resp_xml);
+            s->content_len = XMLRPC_MEMBLOCK_SIZE(char, s->data->send_resp_xml);
+        } else {
+            LOG("unknown rcp type");
+            goto EXIT_BAD;
+        }
+        va_rpc_hdr_init(s);
+        if (s->hdr_len == 0) {
+            LOG("failed to initialize http header");
+            goto EXIT_BAD;
+        }
+    }
+
+    return s;
+EXIT_BAD:
+    qemu_free(s);
+    return NULL;
+}
+
+/* called by va_rpc_read_handler after reading requests */
+static int va_rpc_send_response(VARPCData *data, int fd)
+{
+    VARPCState *s = va_rpc_state_new(data, fd, VA_RPC_RESPONSE, VA_SEND);
+
+    TRACE("called");
+    if (s == NULL) {
+        LOG("failed to set up RPC state");
+        return -1;
+    }
+    TRACE("setting up send handler for RPC request");
+    vp_set_fd_handler(fd, NULL, va_rpc_send_handler, s);
+
+    return 0;
+}
+
+static void va_rpc_read_handler_completion(VARPCState *s) {
+    int ret;
+
+    if (s->rpc_type == VA_RPC_REQUEST) {
+        /* server read request, call it's cb function then set up
+         * a send handler for the rpc response if there weren't any
+         * communication errors
+         */ 
+        if (s->data->cb) {
+            s->data->cb(s->data);
+        }
+        if (s->data->status == VA_RPC_STATUS_OK) {
+            ret = va_rpc_send_response(s->data, s->fd);
+            if (ret != 0) {
+                LOG("error setting up send handler for rpc response");
+            }
+        } else {
+            LOG("error reading rpc request, skipping response");
+            vp_set_fd_handler(s->fd, NULL, NULL, NULL);
+            closesocket(s->fd);
+            qemu_free(s->data);
+        }
+    } else if (s->rpc_type == VA_RPC_RESPONSE) {
+        /* client read response, call it's cb function and complete
+         * the RPC
+         */
+        if (s->data->cb) {
+            s->data->cb(s->data);
+        }
+        vp_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        qemu_free(s->data);
+    } else {
+        LOG("unknown rpc_type");
+    }
+    if (s->content != NULL) {
+        qemu_free(s->content);
+    }
+    qemu_free(s);
+}
+
+static void va_rpc_read_handler(void *opaque)
+{
+    VARPCState *s = opaque;
+    int ret;
+
+    TRACE("called with opaque: %p", opaque);
+
+    switch (s->state) {
+    case VA_READ_START:
+        s->state = VA_READ_HDR;
+    case VA_READ_HDR:
+        while((ret = read(s->fd, s->hdr + s->hdr_pos, 1)) > 0
+              && s->hdr_pos < VA_HDR_LEN_MAX) {
+            s->hdr_pos += ret;
+            if (end_of_header(s->hdr, s->hdr_pos - 1)) {
+                break;
+            }
+        }
+        if (ret == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+                return;
+            } else {
+                LOG("error reading connection: %s", strerror(errno));
+                goto out_bad;
+            }
+        } else if (ret == 0) {
+            LOG("connected closed unexpectedly");
+            goto out_bad;
+        } else if (s->hdr_pos >= VA_HDR_LEN_MAX) {
+            LOG("http header too long");
+            goto out_bad;
+        } else {
+            s->content_len = -1;
+            va_rpc_parse_hdr(s);
+            if (s->content_len == -1) {
+                LOG("malformed http header");
+                goto out_bad;
+            } else if (s->content_len > VA_CONTENT_LEN_MAX) {
+                LOG("http content length too long");
+                goto out_bad;
+            }
+            s->content = qemu_mallocz(s->content_len);
+            s->state = VA_READ_BODY;
+        }
+    case VA_READ_BODY:
+        while(s->content_pos < s->content_len) {
+            ret = read(s->fd, s->content + s->content_pos,
+                       s->content_len - s->content_pos);
+            if (ret == -1) {
+                if (errno == EAGAIN || errno == EWOULDBLOCK
+                    || errno == EINTR) {
+                    return;
+                } else {
+                    LOG("error reading connection: %s", strerror(errno));
+                    goto out_bad;
+                }
+            } else if (ret == 0) {
+                LOG("connection closed unexpectedly:"
+                    " read %u bytes, expected %u bytes",
+                    (unsigned int)s->content_pos, (unsigned int)s->content_len);
+                goto out_bad;
+            }
+            s->content_pos += ret;
+        }
+
+        if (s->rpc_type == VA_RPC_REQUEST) {
+            s->data->req_xml = s->content;
+            s->data->req_xml_len = s->content_len;
+        } else if (s->rpc_type == VA_RPC_RESPONSE) {
+            s->data->resp_xml = s->content;
+            s->data->resp_xml_len = s->content_len;
+        }
+        s->data->status = VA_RPC_STATUS_OK;
+        goto out;
+    default:
+        LOG("unknown state");
+        goto out_bad;
+    }
+
+out_bad:
+    s->data->status = VA_RPC_STATUS_ERR;
+out:
+    va_rpc_read_handler_completion(s);
+}
+
+/* called by va_rpc_send_handler after sending requests */
+static int va_rpc_read_response(VARPCData *data, int fd)
+{
+    VARPCState *s = va_rpc_state_new(data, fd, VA_RPC_RESPONSE, VA_READ);
+
+    TRACE("called");
+    if (s == NULL) {
+        LOG("failed to set up RPC state");
+        return -1;
+    }
+    TRACE("setting up read handler for RPC response");
+    vp_set_fd_handler(fd, NULL, va_rpc_read_handler, s);
+
+    return 0;
+}
+
+static void va_rpc_send_handler_completion(VARPCState *s) {
+    int ret;
+
+    if (s->rpc_type == VA_RPC_REQUEST) {
+        /* client sent request. free request's memblock, and set up read
+         * handler for server response if there weren't any communication
+         * errors
+         */
+        XMLRPC_MEMBLOCK_FREE(char, s->data->send_req_xml);
+        if (s->data->status == VA_RPC_STATUS_OK) {
+            ret = va_rpc_read_response(s->data, s->fd);
+            if (ret != 0) {
+                LOG("error setting up read handler for rpc response");
+            }
+        } else {
+            if (s->data->cb) {
+                s->data->cb(s->data);
+            }
+            LOG("error sending rpc request, skipping response");
+            vp_set_fd_handler(s->fd, NULL, NULL, NULL);
+            closesocket(s->fd);
+            qemu_free(s->data);
+        }
+    } else if (s->rpc_type == VA_RPC_RESPONSE) {
+        /* server sent response. call it's cb once more, then free
+         * response's memblock and complete the RPC
+         */
+        if (s->data->cb) {
+            s->data->cb(s->data);
+        }
+        XMLRPC_MEMBLOCK_FREE(char, s->data->send_resp_xml);
+        vp_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        qemu_free(s->data);
+    } else {
+        LOG("unknown rpc_type");
+    }
+    qemu_free(s);
+}
+
+static void va_rpc_send_handler(void *opaque)
+{
+    VARPCState *s = opaque;
+    int ret;
+
+    TRACE("called with opaque: %p", opaque);
+
+    switch (s->state) {
+    case VA_SEND_START:
+        s->state = VA_SEND_HDR;
+    case VA_SEND_HDR:
+        do {
+            ret = write(s->fd, s->hdr + s->hdr_pos, s->hdr_len - s->hdr_pos);
+            if (ret <= 0) {
+                break;
+            }
+            s->hdr_pos += ret;
+        } while (s->hdr_pos < s->hdr_len);
+        if (ret == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+                return;
+            } else {
+                LOG("error reading connection: %s", strerror(errno));
+                goto out_bad;
+            }
+        } else if (ret == 0) {
+            LOG("connected closed unexpectedly");
+            goto out_bad;
+        } else {
+            s->state = VA_SEND_BODY;
+        }
+    case VA_SEND_BODY:
+        do {
+            ret = write(s->fd, s->content + s->content_pos,
+                        s->content_len - s->content_pos);
+            if (ret <= 0) {
+                break;
+            }
+            s->content_pos += ret;
+        } while (s->content_pos < s->content_len);
+        if (ret == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+                return;
+            } else {
+                LOG("error reading connection: %s", strerror(errno));
+                goto out_bad;
+            }
+        } else if (ret == 0) {
+            LOG("connected closed unexpectedly");
+            goto out_bad;
+        } else {
+            s->data->status = VA_RPC_STATUS_OK;
+            goto out;
+        }
+    default:
+        LOG("unknown state");
+        goto out_bad;
+    }
+
+out_bad:
+    s->data->status = VA_RPC_STATUS_ERR;
+out:
+    va_rpc_send_handler_completion(s);
+}
+
+/* called by rpc client
+ * one callback to data->cb after response is read.
+ * data and data->send_req_xml should be allocated by caller,
+ * callee will de-allocate these after calling data->cb(data)
+ *
+ * if non-zero returned however, caller should free data and hanging refs
+ */ 
+int va_rpc_send_request(VARPCData *data, int fd)
+{
+    VARPCState *s = va_rpc_state_new(data, fd, VA_RPC_REQUEST, VA_SEND);
+
+    TRACE("called");
+    if (s == NULL) {
+        LOG("failed to set up RPC state");
+        return -1;
+    }
+    TRACE("setting up send handler for RPC request");
+    vp_set_fd_handler(fd, NULL, va_rpc_send_handler, s);
+
+    return 0;
+}
+
+/* called by rpc server
+ * one callback to current data->cb after read, one callback after send.
+ * data should be allocated by caller, data->send_resp_xml should be
+ * allocated by first data->cb(data) callback, "callee" will de-allocate
+ * data and data->send_resp_xml after sending rpc response
+ *
+ * if non-zero returned however, caller should free data and hanging refs
+ */
+int va_rpc_read_request(VARPCData *data, int fd)
+{
+    VARPCState *s = va_rpc_state_new(data, fd, VA_RPC_REQUEST, VA_READ);
+
+    TRACE("called");
+    if (s == NULL) {
+        LOG("failed to set up RPC state");
+        return -1;
+    }
+    TRACE("setting up read handler for RPC request");
+    vp_set_fd_handler(fd, va_rpc_read_handler, NULL, s);
+    return 0;
+}
diff --git a/virtagent-common.h b/virtagent-common.h
new file mode 100644
index 0000000..6a58bcd
--- /dev/null
+++ b/virtagent-common.h
@@ -0,0 +1,73 @@
+/*
+ * virt-agent - host/guest RPC client functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef VIRTAGENT_COMMON_H
+#define VIRTAGENT_COMMON_H
+
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
+#include <xmlrpc-c/server.h>
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "monitor.h"
+#include "virtproxy.h"
+
+#define DEBUG_VA
+
+#ifdef DEBUG_VA
+#define TRACE(msg, ...) do { \
+    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
+            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+} while(0)
+#else
+#define TRACE(msg, ...) \
+    do { } while (0)
+#endif
+
+#define LOG(msg, ...) do { \
+    fprintf(stderr, "%s:%s(): " msg "\n", \
+            __FILE__, __FUNCTION__, ## __VA_ARGS__); \
+} while(0)
+
+#define TADDR "127.0.0.1:8080"
+#define URL "http://localhost:8080/RPC2"
+#define NAME "QEMU virt-agent host client"
+#define VERSION "1.0"
+#define EOL "\r\n"
+
+#define VA_RPC_STATUS_OK 0
+#define VA_RPC_STATUS_ERR 1
+#define VA_HDR_LEN_MAX 4096 /* http header limit */
+#define VA_CONTENT_LEN_MAX 2*1024*1024 /* rpc/http send limit */
+
+typedef void (VARPCDataCallback)(void *rpc_data);
+typedef struct VARPCData {
+    VARPCDataCallback *cb;
+    int status;
+    void *opaque;
+    /* provided/allocated by caller for sending as memblocks */
+    xmlrpc_mem_block *send_req_xml;
+    xmlrpc_mem_block *send_resp_xml;
+    /* recieved, and passed to cb func, as char arrays */
+    char *req_xml;
+    int req_xml_len;
+    char *resp_xml;
+    int resp_xml_len;
+    /* for use by QMP functions */
+    MonitorCompletion *mon_cb;
+    void *mon_data;
+} VARPCData;
+
+int va_rpc_send_request(VARPCData *data, int fd);
+int va_rpc_read_request(VARPCData *data, int fd);
+#endif /* VIRTAGENT_COMMON_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 13:57   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server Michael Roth
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Basic skeleton code for RPC server. This is shared by both the
guest-side RPC server as well as the host-side one (the advertised RPCs
for each by guest/host-specific arrays).

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-daemon.h |   22 ++++++
 2 files changed, 231 insertions(+), 0 deletions(-)
 create mode 100644 virtagent-daemon.c
 create mode 100644 virtagent-daemon.h

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
new file mode 100644
index 0000000..78d550f
--- /dev/null
+++ b/virtagent-daemon.c
@@ -0,0 +1,209 @@
+/*
+ * virt-agent - host/guest RPC daemon functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <syslog.h>
+#include "qemu_socket.h"
+#include "virtagent-daemon.h"
+#include "virtagent-common.h"
+#include "virtagent.h"
+
+static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */
+
+#define SLOG(msg, ...) do { \
+    char msg_buf[1024]; \
+    if (!va_enable_syslog) { \
+        break; \
+    } \
+    sprintf(msg_buf, msg, ## __VA_ARGS__); \
+    syslog(LOG_INFO, "virtagent, %s", msg_buf); \
+} while(0)
+
+static int va_accept(int listen_fd) {
+    struct sockaddr_in saddr;
+    struct sockaddr *addr;
+    socklen_t len;
+    int fd;
+
+    while (1) {
+        len = sizeof(saddr);
+        addr = (struct sockaddr *)&saddr;
+        fd = qemu_accept(listen_fd, addr, &len);
+        if (fd < 0 && errno != EINTR) {
+            LOG("accept() failed");
+            break;
+        } else if (fd >= 0) {
+            TRACE("accepted connection");
+            break;
+        }
+    }
+    return fd;
+}
+
+typedef struct RPCFunction {
+    xmlrpc_value *(*func)(xmlrpc_env *env, xmlrpc_value *param, void *unused);
+    const char *func_name;
+} RPCFunction;
+
+static RPCFunction guest_functions[] = {
+    { NULL, NULL }
+};
+static RPCFunction host_functions[] = {
+    { NULL, NULL }
+};
+
+static void va_register_functions(xmlrpc_env *env, xmlrpc_registry *registry,
+                                  RPCFunction *list)
+{
+    int i;
+    for (i = 0; list[i].func != NULL; ++i) {
+        TRACE("adding func: %s", list[i].func_name);
+        xmlrpc_registry_add_method(env, registry, NULL, list[i].func_name,
+                                   list[i].func, NULL);
+    }
+}
+
+typedef struct VARPCServerState {
+    VPDriver *vp;
+    int listen_fd;
+    xmlrpc_env env;
+    xmlrpc_registry *registry;
+} VARPCServerState;
+
+/* only one virtagent server instance can exist at a time */
+static VARPCServerState *server_state = NULL;
+
+static void va_accept_handler(void *opaque);
+
+static void va_rpc_send_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    VARPCServerState *s = server_state;
+
+    TRACE("called");
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error sending RPC response");
+    } else {
+        TRACE("RPC completed");
+    }
+
+    TRACE("waiting for RPC request...");
+    vp_set_fd_handler(s->listen_fd, va_accept_handler, NULL, s);
+}
+
+static void va_rpc_read_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    VARPCServerState *s = server_state;
+
+    TRACE("called");
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error reading RPC request");
+        goto out_bad;
+    }
+
+    rpc_data->send_resp_xml =
+        xmlrpc_registry_process_call(&s->env, s->registry, NULL,
+                                     rpc_data->req_xml, rpc_data->req_xml_len);
+    if (rpc_data->send_resp_xml == NULL) {
+        LOG("error handling RPC request");
+        goto out_bad;
+    }
+
+    rpc_data->cb = va_rpc_send_cb;
+    return;
+
+out_bad:
+    TRACE("waiting for RPC request...");
+    vp_set_fd_handler(s->listen_fd, va_accept_handler, NULL, s);
+}
+
+static void va_accept_handler(void *opaque)
+{
+    VARPCData *rpc_data;
+    int ret, fd;
+
+    TRACE("called");
+    fd = va_accept(server_state->listen_fd);
+    if (fd < 0) {
+        TRACE("connection error: %s", strerror(errno));
+        return;
+    }
+    ret = fcntl(fd, F_GETFL);
+    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
+
+    TRACE("RPC client connected, reading RPC request...");
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = va_rpc_read_cb;
+    ret = va_rpc_read_request(rpc_data, fd);
+    if (ret != 0) {
+        LOG("error setting up read handler");
+        qemu_free(rpc_data);
+        return;
+    }
+    vp_set_fd_handler(server_state->listen_fd, NULL, NULL, NULL);
+}
+
+int va_server_init(VPDriver *vp_drv, bool is_host)
+{
+    RPCFunction *func_list = is_host ? host_functions : guest_functions;
+    QemuOpts *opts;
+    int ret, fd;
+    const char *path, *service_id;
+
+    if (server_state) {
+        LOG("virtagent server already initialized");
+        return -1;
+    }
+    va_enable_syslog = !is_host; /* enable logging for guest agent */
+
+    server_state = qemu_mallocz(sizeof(VARPCServerState));
+    service_id = is_host ? HOST_AGENT_SERVICE_ID : GUEST_AGENT_SERVICE_ID;
+    /* TODO: host agent path needs to be made unique amongst multiple
+     * qemu instances
+     */
+    path = is_host ? HOST_AGENT_PATH : GUEST_AGENT_PATH;
+
+    /* setup listening socket for server */
+    opts = qemu_opts_create(qemu_find_opts("net"), "va_server_opts", 0);
+    qemu_opt_set(opts, "path", path);
+    fd = unix_listen_opts(opts);
+    qemu_opts_del(opts);
+    if (fd < 0) {
+        LOG("error setting up listening socket");
+        goto out_bad;
+    }
+
+    /* tell virtproxy to forward incoming virtagent connections to the socket */
+    ret = vp_set_iforward(vp_drv, service_id, path, NULL, false);
+    if (ret < 0) {
+        LOG("error setting up virtproxy iforward");
+        goto out_bad;
+    }
+
+    server_state->vp = vp_drv;
+    server_state->listen_fd = fd;
+    xmlrpc_env_init(&server_state->env);
+    server_state->registry = xmlrpc_registry_new(&server_state->env);
+    va_register_functions(&server_state->env, server_state->registry, func_list);
+
+    TRACE("waiting for RPC request...");
+    vp_set_fd_handler(server_state->listen_fd, va_accept_handler, NULL,
+                      server_state);
+
+    return 0;
+
+out_bad:
+    qemu_free(server_state);
+    server_state = NULL;
+    return -1;
+}
diff --git a/virtagent-daemon.h b/virtagent-daemon.h
new file mode 100644
index 0000000..6c3436a
--- /dev/null
+++ b/virtagent-daemon.h
@@ -0,0 +1,22 @@
+/*
+ * virt-agent - host/guest RPC daemon functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "virtproxy.h"
+
+#define GUEST_AGENT_SERVICE_ID "virtagent"
+#define GUEST_AGENT_PATH "/tmp/virtagent-guest.sock"
+#define HOST_AGENT_SERVICE_ID "virtagent-host"
+#define HOST_AGENT_PATH "/tmp/virtagent-host.sock"
+#define VA_GETFILE_MAX 1 << 30
+#define VA_FILEBUF_LEN 16384
+
+int va_server_init(VPDriver *vp_drv, bool is_host);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:02   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions Michael Roth
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

This allows the guest RPC server to be integrated into the
qemu-vp/virtproxy i/o loop

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qemu-char.c   |   26 ++++++++++++++++
 qemu-config.c |    3 ++
 qemu-vp.c     |   94 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 114 insertions(+), 9 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index bc7925c..fd02640 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1905,6 +1905,8 @@ return_err:
 /* Virtproxy chardev driver */
 
 #include "virtproxy.h"
+#include "virtagent.h"
+#include "virtagent-daemon.h"
 
 static int vp_init_oforward(VPDriver *drv, QemuOpts *opts)
 {
@@ -2016,6 +2018,8 @@ static CharDriverState *qemu_chr_open_virtproxy(QemuOpts *opts)
 {
     CharDriverState *chr = qemu_mallocz(sizeof(CharDriverState));
     VPDriver *drv = vp_new(VP_CTX_CHARDEV, chr, 0, 0);
+    int ret;
+    bool enable_virtagent;
 
     chr->opaque = drv;
     chr->chr_write = vp_chr_write;
@@ -2025,9 +2029,31 @@ static CharDriverState *qemu_chr_open_virtproxy(QemuOpts *opts)
     /* parse socket forwarding options */
     qemu_opt_foreach(opts, vp_init_forwards, drv, 1);
 
+    /* add forwarding options to enable virtagent server */
+    enable_virtagent = qemu_opt_get_bool(opts, "virtagent", 0);
+    if (enable_virtagent) {
+        /* outbound RPCs */
+        ret = va_client_init(drv, true);
+        if (ret) {
+            fprintf(stderr, "error enabling virtagent client");
+            goto fail;
+        }
+        /* inbound RPCs */
+        ret = va_server_init(drv, true);
+        if (ret) {
+            fprintf(stderr, "error enabling virtagent server");
+            goto fail;
+        }
+    }
+
     /* for "info chardev" monitor command */
     chr->filename = NULL;
     return chr;
+
+fail:
+    qemu_free(drv);
+    qemu_free(chr);
+    return NULL;
 }
 
 /***********************************************************/
diff --git a/qemu-config.c b/qemu-config.c
index 400e61a..41ba54d 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -152,6 +152,9 @@ static QemuOptsList qemu_chardev_opts = {
         },{
             .name = "iforward",
             .type = QEMU_OPT_STRING,
+        },{
+            .name = "virtagent",
+            .type = QEMU_OPT_BOOL,
         },
         { /* end of list */ }
     },
diff --git a/qemu-vp.c b/qemu-vp.c
index cfd2a69..38959e5 100644
--- a/qemu-vp.c
+++ b/qemu-vp.c
@@ -37,6 +37,8 @@
 #include "qemu-option.h"
 #include "qemu_socket.h"
 #include "virtproxy.h"
+#include "virtagent.h"
+#include "virtagent-daemon.h"
 
 static bool verbose_enabled = 0;
 #define DEBUG_ENABLED
@@ -219,14 +221,16 @@ static void usage(const char *cmd)
 "[-o <oforward_opts> ...]\n"
 "QEMU virt-proxy communication channel\n"
 "\n"
-"  -c, --channel    channel options of the form:\n"
-"                   <method>:<addr>:<port>[:channel_id]\n"
-"  -o, --oforward   oforward options of the form:\n"
-"                   <service_id>:<addr>:<port>[:channel_id]\n"
-"  -i, --iforward   iforward options of the form:\n"
-"                   <service_id>:<addr>:<port>[:channel_id]\n"
-"  -v, --verbose    display extra debugging information\n"
-"  -h, --help       display this help and exit\n"
+"  -c, --channel     channel options of the form:\n"
+"                    <method>:<addr>:<port>[:channel_id]\n"
+"  -g, --guest-agent guest rpc server, options of the form:\n"
+"                    [channel_id]\n"
+"  -o, --oforward    oforward options of the form:\n"
+"                    <service_id>:<addr>:<port>[:channel_id]\n"
+"  -i, --iforward    iforward options of the form:\n"
+"                    <service_id>:<addr>:<port>[:channel_id]\n"
+"  -v, --verbose     display extra debugging information\n"
+"  -h, --help        display this help and exit\n"
 "\n"
 "  channels are used to establish a data connection between 2 end-points in\n"
 "  the host or the guest (connection method specified by <method>).\n"
@@ -426,13 +430,52 @@ static int init_iforwards(void) {
     return 0;
 }
 
+static int init_agent(const VPData *agent_iforward) {
+    QemuOpts *opts = agent_iforward->opts;
+    VPDriver *drv;
+    int ret, index;
+
+    INFO("initializing agent...");
+    if (verbose_enabled) {
+        qemu_opts_print(opts, NULL);
+    }
+
+    index = qemu_opt_get_number(agent_iforward->opts, "index", 0);
+    drv = get_channel_drv(index);
+    if (drv == NULL) {
+        warnx("unable to find channel with index: %d", index);
+        goto err;
+    }
+
+    /* outbound RPCs */
+    ret = va_client_init(drv, false);
+    if (ret) {
+        warnx("error starting RPC server");
+        goto err;
+    }
+
+    /* start guest RPC server */
+    ret = va_server_init(drv, false);
+    if (ret != 0) {
+        warnx("error starting RPC server");
+        goto err;
+    }
+
+    return 0;
+
+err:
+    return -1;
+}
+
 int main(int argc, char **argv)
 {
-    const char *sopt = "hVvi:o:c:";
+    const char *sopt = "hVvi:o:c:g::p::";
     struct option lopt[] = {
         { "help", 0, NULL, 'h' },
         { "version", 0, NULL, 'V' },
         { "verbose", 0, NULL, 'v' },
+        { "host-agent", 0, NULL, 'p' },
+        { "guest-agent", 0, NULL, 'g' },
         { "iforward", 0, NULL, 'i' },
         { "oforward", 0, NULL, 'o' },
         { "channel", 0, NULL, 'c' },
@@ -442,10 +485,12 @@ int main(int argc, char **argv)
     QTAILQ_INIT(&iforwards);
     QTAILQ_INIT(&oforwards);
     QTAILQ_INIT(&channels);
+    VPData *guest_agent_iforward = NULL;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         QemuOpts *opts;
         VPData *data;
+        char optarg_tmp[VP_ARG_LEN];
         switch (ch) {
         case 'i':
             opts = qemu_opts_create(&vp_opts, NULL, 0);
@@ -477,6 +522,28 @@ int main(int argc, char **argv)
             data->opts = opts;
             QTAILQ_INSERT_TAIL(&channels, data, next);
             break;
+        case 'g':
+            /* create pre-baked iforward for guest agent */
+            if (guest_agent_iforward) {
+                errx(EXIT_FAILURE, "only one --guest-agent argument allowed");
+            }
+            opts = qemu_opts_create(&vp_opts, NULL, 0);
+            if (optarg == 0) {
+                sprintf(optarg_tmp, "%s:%s:-", GUEST_AGENT_SERVICE_ID,
+                                     GUEST_AGENT_PATH);
+            } else {
+                sprintf(optarg_tmp, "%s:%s:-:%d", GUEST_AGENT_SERVICE_ID,
+                                     GUEST_AGENT_PATH, atoi(optarg));
+            }
+            ret = vp_parse(opts, optarg_tmp, 0);
+            if (ret) {
+                errx(EXIT_FAILURE, "error parsing arg: %s", optarg);
+            }
+            data = qemu_mallocz(sizeof(VPData));
+            data->opts = opts;
+            QTAILQ_INSERT_TAIL(&iforwards, data, next);
+            guest_agent_iforward = data;
+            break;
         case 'v':
             verbose_enabled = 1;
             break;
@@ -506,6 +573,15 @@ int main(int argc, char **argv)
              "error initializing service mappings for incoming connections");
     }
 
+
+    if (guest_agent_iforward) {
+        ret = init_agent(guest_agent_iforward);
+        if (ret) {
+            errx(EXIT_FAILURE,
+                 "error initializing guest agent");
+        }
+    }
+
     /* main i/o loop */
     for (;;) {
         DEBUG("entering main_loop_wait()");
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (2 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:10   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 05/18] virtagent: add getfile RPC Michael Roth
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Base skeleton and helpers for executing RPC commands. Monitor commands
will result in a connect() being issued to the virtagent service socket,
which will then be transported to the listening RPC server in the guest
via the virtproxy layer, RPC requests are then sent/recieved via http
over the resulting connection.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 monitor.c   |    1 +
 qerror.c    |    4 +
 qerror.h    |    3 +
 virtagent.c |  237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h |   27 +++++++
 5 files changed, 272 insertions(+), 0 deletions(-)
 create mode 100644 virtagent.c
 create mode 100644 virtagent.h

diff --git a/monitor.c b/monitor.c
index 8cee35d..cb81cd7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -42,6 +42,7 @@
 #include "audio/audio.h"
 #include "disas.h"
 #include "balloon.h"
+#include "virtagent.h"
 #include "qemu-timer.h"
 #include "migration.h"
 #include "kvm.h"
diff --git a/qerror.c b/qerror.c
index ac2cdaf..2f111a9 100644
--- a/qerror.c
+++ b/qerror.c
@@ -200,6 +200,10 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_VNC_SERVER_FAILED,
         .desc      = "Could not start VNC server on %(target)",
     },
+    {
+        .error_fmt = QERR_RPC_FAILED,
+        .desc      = "An RPC error has occurred",
+    },
     {}
 };
 
diff --git a/qerror.h b/qerror.h
index 943a24b..43cce4a 100644
--- a/qerror.h
+++ b/qerror.h
@@ -165,4 +165,7 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_VNC_SERVER_FAILED \
     "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
+#define QERR_RPC_FAILED \
+    "{ 'class': 'RPCFailed', 'data': { 'code': %i, 'message': %s } }"
+
 #endif /* QERROR_H */
diff --git a/virtagent.c b/virtagent.c
new file mode 100644
index 0000000..750c167
--- /dev/null
+++ b/virtagent.c
@@ -0,0 +1,237 @@
+/*
+ * virt-agent - host/guest RPC client functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu_socket.h"
+#include "virtagent-daemon.h"
+#include "virtagent-common.h"
+#include "virtagent.h"
+
+typedef struct VARPCClientState {
+    VPDriver *vp;
+    const char *socket_path;
+    QList *supported_methods;
+} VARPCClientState;
+
+/* only one virtagent client can exist at a time */
+static VARPCClientState *client_state;
+
+static int va_client_ready(void)
+{
+    if (client_state != NULL && client_state->vp != NULL
+        && client_state->socket_path != NULL) {
+        return 0;
+    }
+
+    return -1;
+}
+
+static void va_set_capabilities(QList *qlist)
+{
+    TRACE("called");
+
+    if (client_state == NULL) {
+        LOG("client is uninitialized, unable to set capabilities");
+        return;
+    }
+
+    if (client_state->supported_methods != NULL) {
+        qobject_decref(QOBJECT(client_state->supported_methods));
+        client_state->supported_methods = NULL;
+        TRACE("capabilities reset");
+    }
+
+    if (qlist != NULL) {
+        client_state->supported_methods = qlist_copy(qlist);
+        TRACE("capabilities set");
+    }
+}
+
+typedef struct VACmpState {
+    const char *method;
+    bool found;
+} VACmpState;
+
+static void va_cmp_capability_iter(QObject *obj, void *opaque)
+{
+    QString *method = qobject_to_qstring(obj);
+    const char *method_str = NULL;
+    VACmpState *cmp_state = opaque;
+
+    if (method) {
+        method_str = qstring_get_str(method);
+    }
+
+    if (method_str && opaque) {
+        if (strcmp(method_str, cmp_state->method) == 0) {
+            cmp_state->found = 1;
+        }
+    }
+}
+
+static bool va_has_capability(const char *method)
+{
+    VACmpState cmp_state;
+
+    if (method == NULL) {
+        return false;
+    }
+
+    /* we can assume method introspection is available */
+    if (strcmp(method, "system.listMethods") == 0) {
+        return true;
+    }
+
+    /* compare method against the last retrieved supported method list */
+    cmp_state.method = method;
+    cmp_state.found = false;
+    if (client_state->supported_methods) {
+        qlist_iter(client_state->supported_methods,
+                   va_cmp_capability_iter,
+                   (void *)&cmp_state);
+    }
+
+    return cmp_state.found;
+}
+
+int va_client_init(VPDriver *vp_drv, bool is_host)
+{
+    const char *service_id, *path;
+    QemuOpts *opts;
+    int fd, ret;
+
+    if (client_state) {
+        LOG("virtagent client already initialized");
+        return -1;
+    }
+    client_state = qemu_mallocz(sizeof(VARPCClientState));
+    client_state->vp = vp_drv;
+
+    /* setup oforwards to connect to to send RPCs. if we're the host, we
+     * want to connect to the guest agent service using the guest agent
+     * client path, and vice-versa */
+    service_id = !is_host ? HOST_AGENT_SERVICE_ID : GUEST_AGENT_SERVICE_ID;
+    /* TODO: host agent path needs to be made unique amongst multiple
+     * qemu instances
+     */
+    path = !is_host ? HOST_AGENT_PATH_CLIENT : GUEST_AGENT_PATH_CLIENT;
+    client_state->socket_path = path;
+
+    /* setup listening socket to forward connections over */
+    opts = qemu_opts_create(qemu_find_opts("net"), "va_client_opts", 0);
+    qemu_opt_set(opts, "path", path);
+    fd = unix_listen_opts(opts);
+    qemu_opts_del(opts);
+    if (fd < 0) {
+        LOG("error setting up listening socket");
+        goto out_bad;
+    }
+
+    /* tell virtproxy to forward connections to this socket to
+     * virtagent service on other end
+     */
+    ret = vp_set_oforward(vp_drv, fd, service_id);
+    if (ret < 0) {
+        LOG("error setting up virtproxy iforward");
+        goto out_bad;
+    }
+
+    return 0;
+out_bad:
+    qemu_free(client_state);
+    client_state = NULL;
+    return -1;
+}
+
+static int rpc_has_error(xmlrpc_env *env)
+{
+    if (env->fault_occurred) {
+        LOG("An RPC error has occurred (%i): %s\n", env->fault_code, env->fault_string);
+        //qerror_report(QERR_RPC_FAILED, env->fault_code, env->fault_string);
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Get a connected socket that can be used to make an RPC call
+ * This interface will eventually return the connected virtproxy socket for the
+ * virt-agent channel
+ */
+static int get_transport_fd(void)
+{
+    /* TODO: eventually this will need a path that is unique to other
+     * instances of qemu-vp/qemu. for the integrated qemu-vp we should
+     * explore the possiblity of not requiring a unix socket under the
+     * covers, as well as having client init code set up the oforward
+     * for the service rather than qemu-vp
+     */
+    int ret;
+    int fd = unix_connect(client_state->socket_path);
+    if (fd < 0) {
+        LOG("failed to connect to virtagent service");
+    }
+    ret = fcntl(fd, F_GETFL);
+    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
+    return fd;
+}
+
+static int rpc_execute(xmlrpc_env *const env, const char *function,
+                       xmlrpc_value *params, VARPCData *rpc_data)
+{
+    xmlrpc_mem_block *call_xml;
+    int fd, ret;
+
+    ret = va_client_ready();
+    if (ret < 0) {
+        LOG("client in uninitialized state, unable to execute RPC");
+        ret = -1;
+        goto out;
+    }
+
+    if (!va_has_capability(function)) {
+        LOG("guest agent does not have required capability");
+        ret = -1;
+        goto out;
+    }
+
+    fd = get_transport_fd();
+    if (fd < 0) {
+        LOG("invalid fd");
+        ret = -1;
+        goto out;
+    }
+
+    call_xml = XMLRPC_MEMBLOCK_NEW(char, env, 0);
+    xmlrpc_serialize_call(env, call_xml, function, params);
+    if (rpc_has_error(env)) {
+        ret = -EREMOTE;
+        goto out_callxml;
+    }
+
+    rpc_data->send_req_xml = call_xml;
+
+    ret = va_rpc_send_request(rpc_data, fd);
+    if (ret != 0) {
+        ret = -1;
+        goto out_callxml;
+    } else {
+        ret = 0;
+        goto out;
+    }
+
+out_callxml:
+    XMLRPC_MEMBLOCK_FREE(char, call_xml);
+out:
+    return ret;
+}
diff --git a/virtagent.h b/virtagent.h
new file mode 100644
index 0000000..53efa29
--- /dev/null
+++ b/virtagent.h
@@ -0,0 +1,27 @@
+/*
+ * virt-agent - host/guest RPC client functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef VIRTAGENT_H
+#define VIRTAGENT_H
+
+#include "monitor.h"
+#include "virtagent-common.h"
+
+#define GUEST_AGENT_PATH_CLIENT "/tmp/virtagent-guest-client.sock"
+#define HOST_AGENT_PATH_CLIENT "/tmp/virtagent-host-client.sock"
+#define VA_MAX_CHUNK_SIZE 4096 /* max bytes at a time for get/send file */
+
+int va_client_init(VPDriver *vp_drv, bool is_host);
+
+#endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 05/18] virtagent: add getfile RPC
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (3 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command Michael Roth
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Add RPC to retrieve a guest file. A size limit of some sort will
eventually be needed else we can block the monitor for arbitrarily long
periods of time. This interface is intended for smaller reads like
peeking at logs and /proc and such.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 78d550f..44c0754 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -28,6 +28,59 @@ static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */
     syslog(LOG_INFO, "virtagent, %s", msg_buf); \
 } while(0)
 
+/* RPC functions common to guest/host daemons */
+
+static xmlrpc_value *getfile(xmlrpc_env *env,
+                                xmlrpc_value *param,
+                                void *user_data)
+{
+    const char *path;
+    char *file_contents = NULL;
+    char buf[VA_FILEBUF_LEN];
+    int fd, ret, count = 0;
+    xmlrpc_value *result = NULL;
+
+    /* parse argument array */
+    xmlrpc_decompose_value(env, param, "(s)", &path);
+    if (env->fault_occurred) {
+        return NULL;
+    }
+
+    SLOG("getfile(), path:%s", path);
+
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        LOG("open failed: %s", strerror(errno));
+        xmlrpc_faultf(env, "open failed: %s", strerror(errno));
+        return NULL;
+    }
+
+    while ((ret = read(fd, buf, VA_FILEBUF_LEN)) > 0) {
+        file_contents = qemu_realloc(file_contents, count + VA_FILEBUF_LEN);
+        memcpy(file_contents + count, buf, ret);
+        count += ret;
+        if (count > VA_GETFILE_MAX) {
+            xmlrpc_faultf(env, "max file size (%d bytes) exceeded",
+                          VA_GETFILE_MAX);
+            goto EXIT_CLOSE_BAD;
+        }
+    }
+    if (ret == -1) {
+        LOG("read failed: %s", strerror(errno));
+        xmlrpc_faultf(env, "read failed: %s", strerror(errno));
+        goto EXIT_CLOSE_BAD;
+    }
+
+    result = xmlrpc_build_value(env, "6", file_contents, count);
+
+EXIT_CLOSE_BAD:
+    if (file_contents) {
+        qemu_free(file_contents);
+    }
+    close(fd);
+    return result;
+}
+
 static int va_accept(int listen_fd) {
     struct sockaddr_in saddr;
     struct sockaddr *addr;
@@ -55,6 +108,8 @@ typedef struct RPCFunction {
 } RPCFunction;
 
 static RPCFunction guest_functions[] = {
+    { .func = getfile,
+      .func_name = "getfile" },
     { NULL, NULL }
 };
 static RPCFunction host_functions[] = {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (4 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 05/18] virtagent: add getfile RPC Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:13   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 07/18] virtagent: add getdmesg RPC Michael Roth
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Utilize the getfile RPC to provide a means to view text files in the
guest. Getfile can handle binary files as well but we don't advertise
that here due to the special handling requiring to store it and provide
it back to the user (base64 encoding it for instance). Hence the
potentially confusing "viewfile" as opposed to "getfile".

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hmp-commands.hx |   16 +++++++++
 qmp-commands.hx |   33 ++++++++++++++++++
 virtagent.c     |  102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    3 ++
 4 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index e5585ba..423c752 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1212,6 +1212,22 @@ show available trace events and their state
 ETEXI
 #endif
 
+    {
+        .name       = "agent_viewfile",
+        .args_type  = "filepath:s",
+        .params     = "filepath",
+        .help       = "Echo a file from the guest filesystem",
+        .user_print = do_agent_viewfile_print,
+        .mhandler.cmd_async = do_agent_viewfile,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_viewfile @var{filepath}
+@findex agent_viewfile
+Echo the file identified by @var{filepath} on the guest filesystem
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 793cf1c..efa2137 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -738,6 +738,39 @@ Example:
 EQMP
 
     {
+        .name       = "agent_viewfile",
+        .args_type  = "filepath:s",
+        .params     = "filepath",
+        .help       = "Echo a file from the guest filesystem",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = do_agent_viewfile,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_viewfile @var{filepath}
+@findex agent_viewfile
+Echo the file identified by @var{filepath} on the guest filesystem
+ETEXI
+SQMP
+agent_viewfile
+--------
+
+Echo the file identified by @var{filepath} from the guest filesystem.
+
+Arguments:
+
+- "filepath": Full guest path of the desired file
+
+Example:
+
+-> { "execute": "agent_viewfile",
+                "arguments": { "filepath": "/sys/kernel/kexec_loaded" } }
+<- { "return": { "contents": "0" } }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/virtagent.c b/virtagent.c
index 750c167..3fe0a7b 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -235,3 +235,105 @@ out_callxml:
 out:
     return ret;
 }
+
+/* QMP/HMP RPC client functions */
+
+void do_agent_viewfile_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+    const char *contents = NULL;
+    int i;
+
+    qdict = qobject_to_qdict(data);
+    if (!qdict_haskey(qdict, "contents")) {
+        return;
+    }
+
+    contents = qdict_get_str(qdict, "contents");
+    if (contents != NULL) {
+         /* monitor_printf truncates so do it in chunks. also, file_contents
+          * may not be null-termed at proper location so explicitly calc
+          * last chunk sizes */
+        for (i = 0; i < strlen(contents); i += 1024) {
+            monitor_printf(mon, "%.1024s", contents + i);
+        }
+    }
+    monitor_printf(mon, "\n");
+}
+
+static void do_agent_viewfile_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    char *file_contents = NULL;
+    size_t file_size;
+    int ret;
+    xmlrpc_env env;
+    QDict *qdict = qdict_new();
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        goto out_no_resp;
+    }
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        ret = -1;
+        goto out_no_resp;
+    }
+
+    xmlrpc_parse_value(&env, resp, "6", &file_contents, &file_size);
+    if (rpc_has_error(&env)) {
+        ret = -1;
+        goto out;
+    }
+
+    if (file_contents != NULL) {
+        qdict_put(qdict, "contents",
+                  qstring_from_substr(file_contents, 0, file_size-1));
+    }
+
+out:
+    xmlrpc_DECREF(resp);
+out_no_resp:
+    rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qdict));
+}
+
+/*
+ * do_agent_viewfile(): View a text file in the guest
+ */
+int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    const char *filepath;
+    int ret;
+
+    filepath = qdict_get_str(mon_params, "filepath");
+    xmlrpc_env_init(&env);
+    params = xmlrpc_build_value(&env, "(s)", filepath);
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_viewfile_cb;
+    rpc_data->mon_cb = cb;
+    rpc_data->mon_data = opaque;
+
+    ret = rpc_execute(&env, "getfile", params, rpc_data);
+    if (ret == -EREMOTE) {
+        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
+                       env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        monitor_printf(mon, "RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index 53efa29..63d77c2 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -23,5 +23,8 @@
 #define VA_MAX_CHUNK_SIZE 4096 /* max bytes at a time for get/send file */
 
 int va_client_init(VPDriver *vp_drv, bool is_host);
+void do_agent_viewfile_print(Monitor *mon, const QObject *qobject);
+int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 07/18] virtagent: add getdmesg RPC
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (5 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 08/18] virtagent: add agent_viewdmesg command Michael Roth
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Add RPC to view guest dmesg output.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-daemon.h |    1 +
 2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 44c0754..0dd72c0 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -81,6 +81,50 @@ EXIT_CLOSE_BAD:
     return result;
 }
 
+/* getdmesg(): return dmesg output
+ * rpc return values:
+ *   - dmesg output as a string
+ */
+static xmlrpc_value *getdmesg(xmlrpc_env *env,
+                              xmlrpc_value *param,
+                              void *user_data)
+{
+    char *dmesg_buf = NULL, cmd[256];
+    int ret;
+    xmlrpc_value *result = NULL;
+    FILE *pipe;
+
+    SLOG("getdmesg()");
+
+    dmesg_buf = qemu_mallocz(VA_DMESG_LEN + 2048);
+    sprintf(cmd, "dmesg -s %d", VA_DMESG_LEN);
+
+    pipe = popen(cmd, "r");
+    if (pipe == NULL) {
+        LOG("popen failed: %s", strerror(errno));
+        xmlrpc_faultf(env, "popen failed: %s", strerror(errno));
+        goto EXIT_NOCLOSE;
+    }
+
+    ret = fread(dmesg_buf, sizeof(char), VA_DMESG_LEN, pipe);
+    if (!ferror(pipe)) {
+        dmesg_buf[ret] = '\0';
+        TRACE("dmesg:\n%s", dmesg_buf);
+        result = xmlrpc_build_value(env, "s", dmesg_buf);
+    } else {
+        LOG("fread failed");
+        xmlrpc_faultf(env, "popen failed: %s", strerror(errno));
+    }
+
+    pclose(pipe);
+EXIT_NOCLOSE:
+    if (dmesg_buf) {
+        qemu_free(dmesg_buf);
+    }
+
+    return result;
+}
+
 static int va_accept(int listen_fd) {
     struct sockaddr_in saddr;
     struct sockaddr *addr;
@@ -110,6 +154,8 @@ typedef struct RPCFunction {
 static RPCFunction guest_functions[] = {
     { .func = getfile,
       .func_name = "getfile" },
+    { .func = getdmesg,
+      .func_name = "getdmesg" },
     { NULL, NULL }
 };
 static RPCFunction host_functions[] = {
diff --git a/virtagent-daemon.h b/virtagent-daemon.h
index 6c3436a..09b0097 100644
--- a/virtagent-daemon.h
+++ b/virtagent-daemon.h
@@ -18,5 +18,6 @@
 #define HOST_AGENT_PATH "/tmp/virtagent-host.sock"
 #define VA_GETFILE_MAX 1 << 30
 #define VA_FILEBUF_LEN 16384
+#define VA_DMESG_LEN 16384
 
 int va_server_init(VPDriver *vp_drv, bool is_host);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 08/18] virtagent: add agent_viewdmesg command
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (6 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 07/18] virtagent: add getdmesg RPC Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC Michael Roth
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Add commands to view guest dmesg output. Currently it is a 16K buffer.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hmp-commands.hx |   16 +++++++++
 qmp-commands.hx |   35 +++++++++++++++++++
 virtagent.c     |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    3 ++
 4 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 423c752..5b9db62 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1228,6 +1228,22 @@ STEXI
 Echo the file identified by @var{filepath} on the guest filesystem
 ETEXI
 
+    {
+        .name       = "agent_viewdmesg",
+        .args_type  = "",
+        .params     = "",
+        .help       = "View guest dmesg output",
+        .user_print = do_agent_viewdmesg_print,
+        .mhandler.cmd_async = do_agent_viewdmesg,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_viewdmesg
+@findex agent_viewdmesg
+View guest dmesg output
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index efa2137..dc319b7 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -771,6 +771,41 @@ Example:
 EQMP
 
     {
+        .name       = "agent_viewdmesg",
+        .args_type  = "",
+        .params     = "",
+        .help       = "View guest dmesg output",
+        .user_print = do_agent_viewdmesg_print,
+        .mhandler.cmd_async = do_agent_viewdmesg,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_viewdmesg
+@findex agent_viewdmesg
+View guest dmesg output
+ETEXI
+SQMP
+agent_viewdmesg
+--------
+
+View guest dmesg output
+
+Arguments:
+
+(none)
+
+Example:
+
+-> { "execute": "agent_viewdmesg" }
+<- { "return": {
+       "contents": "[353487.942215] usb 1-4: USB disconnect, address 9\n..."
+     }
+   }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/virtagent.c b/virtagent.c
index 3fe0a7b..e0298b9 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -299,6 +299,7 @@ out:
     xmlrpc_DECREF(resp);
 out_no_resp:
     rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qdict));
+    qobject_decref(QOBJECT(qdict));
 }
 
 /*
@@ -337,3 +338,102 @@ int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
 
     return 0;
 }
+
+void do_agent_viewdmesg_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+    const char *contents = NULL;
+    int i;
+
+    qdict = qobject_to_qdict(data);
+    if (!qdict_haskey(qdict, "contents")) {
+        goto out;
+    }
+
+    contents = qdict_get_str(qdict, "contents");
+    if (contents != NULL) {
+         /* monitor_printf truncates so do it in chunks. also, file_contents
+          * may not be null-termed at proper location so explicitly calc
+          * last chunk sizes */
+        for (i = 0; i < strlen(contents); i += 1024) {
+            monitor_printf(mon, "%.1024s", contents + i);
+        }
+    }
+
+out:
+    monitor_printf(mon, "\n");
+}
+
+static void do_agent_viewdmesg_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    char *dmesg = NULL;
+    int ret;
+    xmlrpc_env env;
+    QDict *qdict = qdict_new();
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        goto out_no_resp;
+    }
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        ret = -1;
+        goto out_no_resp;
+    }
+
+    xmlrpc_parse_value(&env, resp, "s", &dmesg);
+    if (rpc_has_error(&env)) {
+        ret = -1;
+        goto out;
+    }
+
+    if (dmesg != NULL) {
+        qdict_put(qdict, "contents", qstring_from_str(dmesg));
+    }
+
+out:
+    xmlrpc_DECREF(resp);
+out_no_resp:
+    rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qdict));
+}
+
+/*
+ * do_agent_viewdmesg(): View guest dmesg output
+ */
+int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    int ret;
+
+    xmlrpc_env_init(&env);
+
+    params = xmlrpc_build_value(&env, "(n)");
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_viewdmesg_cb;
+    rpc_data->mon_cb = cb;
+    rpc_data->mon_data = opaque;
+
+    ret = rpc_execute(&env, "getdmesg", params, rpc_data);
+    if (ret == -EREMOTE) {
+        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
+                       env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        monitor_printf(mon, "RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index 63d77c2..c077582 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -26,5 +26,8 @@ int va_client_init(VPDriver *vp_drv, bool is_host);
 void do_agent_viewfile_print(Monitor *mon, const QObject *qobject);
 int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
                       MonitorCompletion cb, void *opaque);
+void do_agent_viewdmesg_print(Monitor *mon, const QObject *qobject);
+int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (7 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 08/18] virtagent: add agent_viewdmesg command Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:17   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command Michael Roth
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

RPC to initiate guest shutdown/reboot/powerdown

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 0dd72c0..18992dd 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -125,6 +125,62 @@ EXIT_NOCLOSE:
     return result;
 }
 
+/* va_shutdown(): initiate guest shutdown
+ * rpc return values: none
+ */
+static xmlrpc_value *va_shutdown(xmlrpc_env *env,
+                                    xmlrpc_value *param,
+                                    void *user_data)
+{
+    int ret;
+    const char *shutdown_type, *shutdown_flag;
+    xmlrpc_value *result = xmlrpc_build_value(env, "s", "dummy"); 
+
+    TRACE("called");
+    xmlrpc_decompose_value(env, param, "(s)", &shutdown_type);
+    if (env->fault_occurred) {
+        goto out_bad;
+    }
+
+    if (strcmp(shutdown_type, "halt") == 0) {
+        shutdown_flag = "-H";
+    } else if (strcmp(shutdown_type, "powerdown") == 0) {
+        shutdown_flag = "-P";
+    } else if (strcmp(shutdown_type, "reboot") == 0) {
+        shutdown_flag = "-r";
+    } else {
+        xmlrpc_faultf(env, "invalid shutdown type: %s", shutdown_type);
+        goto out_bad;
+    }
+
+    SLOG("va_shutdown(), shutdown_type:%s", shutdown_type);
+
+    ret = fork();
+    if (ret == 0) {
+        /* child, start the shutdown */
+        setsid();
+        fclose(stdin);
+        fclose(stdout);
+        fclose(stderr);
+
+        sleep(5);
+        ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
+                    "hypervisor initiated shutdown", (char*)NULL);
+        if (ret < 0) {
+            LOG("execl() failed: %s", strerror(errno));
+            exit(1);
+        }
+        TRACE("shouldn't be here");
+        exit(0);
+    } else if (ret < 0) {
+        xmlrpc_faultf(env, "fork() failed: %s", strerror(errno));
+    }
+
+    return result;
+out_bad:
+    return NULL;
+}
+
 static int va_accept(int listen_fd) {
     struct sockaddr_in saddr;
     struct sockaddr *addr;
@@ -156,6 +212,8 @@ static RPCFunction guest_functions[] = {
       .func_name = "getfile" },
     { .func = getdmesg,
       .func_name = "getdmesg" },
+    { .func = va_shutdown,
+      .func_name = "va_shutdown" },
     { NULL, NULL }
 };
 static RPCFunction host_functions[] = {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (8 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:19   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 11/18] virtagent: add va_ping RPC Michael Roth
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Provide monitor command to initiate guest shutdown/reboot/powerdown

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hmp-commands.hx |   16 +++++++++++++
 qmp-commands.hx |   32 ++++++++++++++++++++++++++
 virtagent.c     |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    2 +
 4 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 5b9db62..3250e41 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1244,6 +1244,22 @@ STEXI
 View guest dmesg output
 ETEXI
 
+    {
+        .name       = "agent_shutdown",
+        .args_type  = "shutdown_type:s",
+        .params     = "[reboot|shutdown|poweroff]",
+        .help       = "Shutdown/reboot a guest locally",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = do_agent_shutdown,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_shutdown
+@findex agent_shutdown
+Shutdown/reboot a guest locally
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index dc319b7..0f983cc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -806,6 +806,38 @@ Example:
 EQMP
 
     {
+        .name       = "agent_shutdown",
+        .args_type  = "shutdown_type:s",
+        .params     = "[reboot|shutdown|poweroff]",
+        .help       = "Shutdown/reboot the guest locally",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = do_agent_shutdown,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_shutdown
+@findex agent_shutdown
+Shutdown/reboot the guest locally
+ETEXI
+SQMP
+agent_shutdown
+--------
+
+Shutdown the guest locally
+
+Arguments:
+
+(none)
+
+Example:
+
+-> { "execute": "agent_shutdown" }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/virtagent.c b/virtagent.c
index e0298b9..a56aeac 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -437,3 +437,69 @@ int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
 
     return 0;
 }
+
+static void do_agent_shutdown_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    xmlrpc_env env;
+
+    TRACE("called");
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        goto out_no_resp;
+    }
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        LOG("RPC Failed (%i): %s\n", env.fault_code,
+            env.fault_string);
+        goto out_no_resp;
+    }
+
+    xmlrpc_DECREF(resp);
+out_no_resp:
+    rpc_data->mon_cb(rpc_data->mon_data, NULL);
+}
+
+/*
+ * do_agent_shutdown(): Shutdown a guest
+ */
+int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    const char *shutdown_type;
+    int ret;
+
+    TRACE("called");
+
+    xmlrpc_env_init(&env);
+    shutdown_type = qdict_get_str(mon_params, "shutdown_type");
+    params = xmlrpc_build_value(&env, "(s)", shutdown_type);
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_shutdown_cb;
+    rpc_data->mon_cb = cb;
+    rpc_data->mon_data = opaque;
+
+    ret = rpc_execute(&env, "va_shutdown", params, rpc_data);
+    if (ret == -EREMOTE) {
+        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
+                       env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        monitor_printf(mon, "RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index c077582..96c6260 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -29,5 +29,7 @@ int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
 void do_agent_viewdmesg_print(Monitor *mon, const QObject *qobject);
 int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
                       MonitorCompletion cb, void *opaque);
+int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 11/18] virtagent: add va_ping RPC
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (9 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 12/18] virtagent: add agent_ping monitor command Michael Roth
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Do nothing RPC that simply replies to client

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 18992dd..137641d 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -181,6 +181,19 @@ out_bad:
     return NULL;
 }
 
+/* va_ping(): respond to client. response without error in env
+ *   variable indicates successful response
+ * rpc return values: none
+ */
+static xmlrpc_value *va_ping(xmlrpc_env *env,
+                             xmlrpc_value *param,
+                             void *user_data)
+{
+    xmlrpc_value *result = xmlrpc_build_value(env, "s", "dummy");
+    SLOG("va_ping()");
+    return result;
+}
+
 static int va_accept(int listen_fd) {
     struct sockaddr_in saddr;
     struct sockaddr *addr;
@@ -214,9 +227,13 @@ static RPCFunction guest_functions[] = {
       .func_name = "getdmesg" },
     { .func = va_shutdown,
       .func_name = "va_shutdown" },
+    { .func = va_ping,
+      .func_name = "va_ping" },
     { NULL, NULL }
 };
 static RPCFunction host_functions[] = {
+    { .func = va_ping,
+      .func_name = "va_ping" },
     { NULL, NULL }
 };
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 12/18] virtagent: add agent_ping monitor command
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (10 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 11/18] virtagent: add va_ping RPC Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 13/18] virtagent: add agent_capabilities monitor function Michael Roth
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Monitor command to ping the RPC server.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hmp-commands.hx |   16 ++++++++++
 qmp-commands.hx |   32 +++++++++++++++++++++
 virtagent.c     |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    3 ++
 4 files changed, 135 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3250e41..d3f642f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1260,6 +1260,22 @@ STEXI
 Shutdown/reboot a guest locally
 ETEXI
 
+    {
+        .name       = "agent_ping",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Ping a guest",
+        .user_print = do_agent_ping_print,
+        .mhandler.cmd_async = do_agent_ping,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_ping
+@findex agent_ping
+Ping a guest
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0f983cc..1e798f5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -838,6 +838,38 @@ Example:
 EQMP
 
     {
+        .name       = "agent_ping",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Ping a guest",
+        .user_print = do_agent_ping_print,
+        .mhandler.cmd_async = do_agent_ping,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_ping
+@findex agent_ping
+Ping a guest
+ETEXI
+SQMP
+agent_ping
+--------
+
+Ping a guest
+
+Arguments:
+
+(none)
+
+Example:
+
+-> { "execute": "agent_ping" }
+<- { "return": { "response":"ok" } }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/virtagent.c b/virtagent.c
index a56aeac..9071131 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -503,3 +503,87 @@ int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
 
     return 0;
 }
+
+void do_agent_ping_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+    const char *response;
+
+    TRACE("called");
+
+    qdict = qobject_to_qdict(data);
+    response = qdict_get_str(qdict, "response");
+    if (qdict_haskey(qdict, "response")) {
+        monitor_printf(mon, "%s", response);
+    }
+
+    monitor_printf(mon, "\n");
+}
+
+static void do_agent_ping_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    xmlrpc_env env;
+    QDict *qdict = qdict_new();
+
+    TRACE("called");
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        qdict_put(qdict, "response", qstring_from_str("error"));
+        goto out_no_resp;
+    }
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        qdict_put(qdict, "response", qstring_from_str("error"));
+        goto out_no_resp;
+    }
+    qdict_put(qdict, "response", qstring_from_str("ok"));
+
+    xmlrpc_DECREF(resp);
+out_no_resp:
+    if (rpc_data->mon_cb) {
+        rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qdict));
+    }
+    qobject_decref(QOBJECT(qdict));
+}
+
+/*
+ * do_agent_ping(): Ping a guest
+ */
+int do_agent_ping(Monitor *mon, const QDict *mon_params,
+                      MonitorCompletion cb, void *opaque)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    int ret;
+
+    xmlrpc_env_init(&env);
+
+    params = xmlrpc_build_value(&env, "(n)");
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_ping_cb;
+    rpc_data->mon_cb = cb;
+    rpc_data->mon_data = opaque;
+
+    ret = rpc_execute(&env, "va_ping", params, rpc_data);
+    if (ret == -EREMOTE) {
+        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
+                       env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        monitor_printf(mon, "RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index 96c6260..071530c 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -31,5 +31,8 @@ int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
                       MonitorCompletion cb, void *opaque);
 int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
                       MonitorCompletion cb, void *opaque);
+void do_agent_ping_print(Monitor *mon, const QObject *qobject);
+int do_agent_ping(Monitor *mon, const QDict *mon_params,
+                  MonitorCompletion cb, void *opaque);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 13/18] virtagent: add agent_capabilities monitor function
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (11 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 12/18] virtagent: add agent_ping monitor command Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function Michael Roth
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Call guest agent's built-in introspection functions to get a list of
supported RPCs, and re-negotiate guest agent capabilities to determine
what agent_* commands are supported.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hmp-commands.hx |   16 ++++++++
 qmp-commands.hx |   32 ++++++++++++++++
 virtagent.c     |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    3 ++
 4 files changed, 158 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index d3f642f..d68c1ba 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1276,6 +1276,22 @@ STEXI
 Ping a guest
 ETEXI
 
+    {
+        .name       = "agent_capabilities",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Fetch and re-negotiate guest agent capabilities",
+        .user_print = do_agent_capabilities_print,
+        .mhandler.cmd_async = do_agent_capabilities,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_capabilities
+@findex agent_capabilities
+Fetch and re-negotiate guest agent capabilties
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1e798f5..4ae0890 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -870,6 +870,38 @@ Example:
 EQMP
 
     {
+        .name       = "agent_capabilities",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Fetch and re-negotiate guest agent capabilities",
+        .user_print = do_agent_capabilities_print,
+        .mhandler.cmd_async = do_agent_capabilities,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+@item agent_capabilities
+@findex agent_capabilities
+Fetch and re-negotiate guest agent capabilties
+ETEXI
+SQMP
+agent_capabilities
+--------
+
+Fetch and re-negotiate guest agent capabilities
+
+Arguments:
+
+(none)
+
+Example:
+
+-> { "execute": "agent_capabilities" }
+<- { "return":["va.shutdown", "va.getdmesg", "va.getfile", ... ] }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/virtagent.c b/virtagent.c
index 9071131..e0f7f99 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -587,3 +587,110 @@ int do_agent_ping(Monitor *mon, const QDict *mon_params,
 
     return 0;
 }
+
+static void va_print_capability_iter(QObject *obj, void *opaque)
+{
+    Monitor *mon = opaque;
+    QString *method = qobject_to_qstring(obj);
+    const char *method_str;
+
+    if (method) {
+        method_str = qstring_get_str(method);
+        monitor_printf(mon, "%s\n", method_str); 
+    }
+}
+
+void do_agent_capabilities_print(Monitor *mon, const QObject *data)
+{
+    QList *qlist;
+
+    TRACE("called");
+
+    monitor_printf(mon, "the following RPC methods are supported by the guest agent:\n");
+    qlist = qobject_to_qlist(data);
+    qlist_iter(qlist, va_print_capability_iter, mon);
+}
+
+static void do_agent_capabilities_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    xmlrpc_value *cur_val = NULL;
+    const char *cur_method = NULL;
+    xmlrpc_env env;
+    QList *qlist = qlist_new();
+    int i;
+
+    TRACE("called");
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        goto out_no_resp;
+    }
+
+    TRACE("resp = %s\n", rpc_data->resp_xml);
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        goto out_no_resp;
+    }
+
+    /* extract the list of supported RPCs */
+    for (i = 0; i < xmlrpc_array_size(&env, resp); i++) {
+        xmlrpc_array_read_item(&env, resp, i, &cur_val);
+        xmlrpc_read_string(&env, cur_val, &cur_method);
+        if (cur_method) {
+            TRACE("cur_method: %s", cur_method);
+            qlist_append_obj(qlist, QOBJECT(qstring_from_str(cur_method)));
+        }
+        xmlrpc_DECREF(cur_val);
+    }
+
+    /* set our client capabilities accordingly */
+    va_set_capabilities(qlist);
+
+    xmlrpc_DECREF(resp);
+out_no_resp:
+    if (rpc_data->mon_cb) {
+        rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qlist));
+    }
+    qobject_decref(QOBJECT(qlist));
+}
+
+/*
+ * do_agent_capabilities(): Fetch/re-negotiate guest agent capabilities
+ */
+int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
+                          MonitorCompletion cb, void *opaque)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    int ret;
+
+    xmlrpc_env_init(&env);
+
+    params = xmlrpc_build_value(&env, "()");
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_capabilities_cb;
+    rpc_data->mon_cb = cb;
+    rpc_data->mon_data = opaque;
+
+    ret = rpc_execute(&env, "system.listMethods", params, rpc_data);
+    if (ret == -EREMOTE) {
+        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
+                       env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        monitor_printf(mon, "RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index 071530c..c10ee35 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -34,5 +34,8 @@ int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
 void do_agent_ping_print(Monitor *mon, const QObject *qobject);
 int do_agent_ping(Monitor *mon, const QDict *mon_params,
                   MonitorCompletion cb, void *opaque);
+void do_agent_capabilities_print(Monitor *mon, const QObject *qobject);
+int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
+                  MonitorCompletion cb, void *opaque);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (12 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 13/18] virtagent: add agent_capabilities monitor function Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:22   ` Jes Sorensen
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 15/18] virtagent: add va_hello RPC function Michael Roth
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Non-monitor version of agent_capabilities monitor function. This is
called by the local RPC server when it gets a "hello" from the guest
agent to re-negotiate guest agent capabilities.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent.c |   34 ++++++++++++++++++++++++++++++++++
 virtagent.h |    1 +
 2 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/virtagent.c b/virtagent.c
index e0f7f99..4ec1b42 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -694,3 +694,37 @@ int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
 
     return 0;
 }
+
+/* non-HMP/QMP RPC client functions */
+
+int va_client_init_capabilities(void)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    int ret;
+
+    xmlrpc_env_init(&env);
+
+    params = xmlrpc_build_value(&env, "()");
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = do_agent_capabilities_cb;
+    rpc_data->mon_cb = NULL;
+    rpc_data->mon_data = NULL;
+
+    ret = rpc_execute(&env, "system.listMethods", params, rpc_data);
+    if (ret == -EREMOTE) {
+        LOG("RPC Failed (%i): %s\n", env.fault_code,
+            env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        LOG("RPC communication error\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index c10ee35..da4be60 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -23,6 +23,7 @@
 #define VA_MAX_CHUNK_SIZE 4096 /* max bytes at a time for get/send file */
 
 int va_client_init(VPDriver *vp_drv, bool is_host);
+int va_client_init_capabilities(void);
 void do_agent_viewfile_print(Monitor *mon, const QObject *qobject);
 int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
                       MonitorCompletion cb, void *opaque);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 15/18] virtagent: add va_hello RPC function
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (13 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 16/18] virtagent: add va_send_hello() client function Michael Roth
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

This RPC tells us the guest agent is up and ready, and invokes guest
agent capability negotiation

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent-daemon.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 137641d..ae306b9 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -194,6 +194,23 @@ static xmlrpc_value *va_ping(xmlrpc_env *env,
     return result;
 }
 
+/* va_hello(): handle client startup notification
+ * rpc return values: none
+ */
+
+static xmlrpc_value *va_hello(xmlrpc_env *env,
+                                   xmlrpc_value *param,
+                                   void *user_data)
+{
+    int ret = va_client_init_capabilities();
+    TRACE("called");
+    SLOG("va_hello()");
+    if (ret < 0) {
+        LOG("error setting initializing client capabilities");
+    }
+    return NULL;
+}
+
 static int va_accept(int listen_fd) {
     struct sockaddr_in saddr;
     struct sockaddr *addr;
@@ -234,6 +251,8 @@ static RPCFunction guest_functions[] = {
 static RPCFunction host_functions[] = {
     { .func = va_ping,
       .func_name = "va_ping" },
+    { .func = va_hello,
+      .func_name = "va_hello" },
     { NULL, NULL }
 };
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 16/18] virtagent: add va_send_hello() client function
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (14 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 15/18] virtagent: add va_hello RPC function Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup Michael Roth
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

This tells the host RPC server (QEMU) that we're up and running

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 virtagent.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h |    1 +
 2 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/virtagent.c b/virtagent.c
index 4ec1b42..3be9082 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -728,3 +728,58 @@ int va_client_init_capabilities(void)
 
     return 0;
 }
+
+static void va_send_hello_cb(void *opaque)
+{
+    VARPCData *rpc_data = opaque;
+    xmlrpc_value *resp = NULL;
+    xmlrpc_env env;
+
+    TRACE("called");
+
+    if (rpc_data->status != VA_RPC_STATUS_OK) {
+        LOG("error handling RPC request");
+        return;
+    }
+
+    xmlrpc_env_init(&env);
+    resp = xmlrpc_parse_response(&env, rpc_data->resp_xml,
+                                 rpc_data->resp_xml_len);
+    if (rpc_has_error(&env)) {
+        LOG("error parsing RPC response");
+        return;
+    }
+
+    xmlrpc_DECREF(resp);
+}
+
+int va_send_hello(void)
+{
+    xmlrpc_env env;
+    xmlrpc_value *params;
+    VARPCData *rpc_data;
+    int ret;
+
+    TRACE("called");
+
+    xmlrpc_env_init(&env);
+    params = xmlrpc_build_value(&env, "(s)", "dummy");
+    if (rpc_has_error(&env)) {
+        return -1;
+    }
+
+    rpc_data = qemu_mallocz(sizeof(VARPCData));
+    rpc_data->cb = va_send_hello_cb;
+
+    ret = rpc_execute(&env, "va_hello", params, rpc_data);
+    if (ret == -EREMOTE) {
+        LOG("RPC Failed (%i): %s", env.fault_code,
+            env.fault_string);
+        return -1;
+    } else if (ret == -1) {
+        LOG("RPC communication error");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/virtagent.h b/virtagent.h
index da4be60..83033e3 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -38,5 +38,6 @@ int do_agent_ping(Monitor *mon, const QDict *mon_params,
 void do_agent_capabilities_print(Monitor *mon, const QObject *qobject);
 int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
                   MonitorCompletion cb, void *opaque);
+int va_send_hello(void);
 
 #endif /* VIRTAGENT_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (15 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 16/18] virtagent: add va_send_hello() client function Michael Roth
@ 2010-11-16 16:01 ` Michael Roth
  2010-11-18 14:22   ` Jes Sorensen
  2010-11-16 16:02 ` [Qemu-devel] [RFC][PATCH v4 18/18] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
  2010-11-18 13:50 ` [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Jes Sorensen
  18 siblings, 1 reply; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof

Make the hello call on guest agent startup so QEMU can do whatever init
it needs (currently, capabilities negotiation). Temporarilly commented
due to this tending to induce a virtio bug in RHEL 6.0. As a result
capabilities negotiation must be invoked manually from QEMU via the
agent_capabilities monitor command.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qemu-vp.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/qemu-vp.c b/qemu-vp.c
index 38959e5..b8af513 100644
--- a/qemu-vp.c
+++ b/qemu-vp.c
@@ -580,6 +580,8 @@ int main(int argc, char **argv)
             errx(EXIT_FAILURE,
                  "error initializing guest agent");
         }
+        /* tell the host the agent is running */
+        //va_send_hello();
     }
 
     /* main i/o loop */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [RFC][PATCH v4 18/18] virtagent: Makefile/configure changes to build virtagent bits
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (16 preceding siblings ...)
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup Michael Roth
@ 2010-11-16 16:02 ` Michael Roth
  2010-11-18 13:50 ` [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Jes Sorensen
  18 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-16 16:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, ryanh, agl, mdroth, abeekhof


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile        |    2 +-
 Makefile.target |    2 +-
 configure       |   25 +++++++++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index b4f93eb..f20032f 100644
--- a/Makefile
+++ b/Makefile
@@ -137,7 +137,7 @@ qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-ob
 
 qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
-qemu-vp$(EXESUF): qemu-vp.o virtproxy.o qemu-tool.o qemu-error.o qemu-sockets.c $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+qemu-vp$(EXESUF): qemu-vp.o virtproxy.o virtagent.o virtagent-daemon.o virtagent-common.o qemu-tool.o qemu-error.o qemu-sockets.c $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
diff --git a/Makefile.target b/Makefile.target
index f08c435..829332c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -164,7 +164,7 @@ endif #CONFIG_BSD_USER
 # System emulator target
 ifdef CONFIG_SOFTMMU
 
-obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o virtproxy.o virtproxy-builtin.o
+obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o virtproxy.o virtproxy-builtin.o virtagent.o virtagent-daemon.o virtagent-common.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
diff --git a/configure b/configure
index 01bde83..67f5ed2 100755
--- a/configure
+++ b/configure
@@ -1264,6 +1264,31 @@ EOF
 fi
 
 ##########################################
+# xmlrpc-c probe
+
+# Look for the xmlrpc-c config program
+if test -n "$cross_prefix" && has ${cross_prefix}xmlrpc-c-config; then
+  xmlrpccconfig=${cross_prefix}xmlrpc-c-config
+elif has xmlrpc-c-config; then
+  xmlrpccconfig=xmlrpc-c-config
+else
+  feature_not_found "xmlrpc-c"
+fi
+
+cat > $TMPC << EOF
+#include <xmlrpc.h>
+int main(void) { xmlrpc_env env; xmlrpc_env_init(&env); return 0; }
+EOF
+xmlrpc_cflags=`$xmlrpccconfig --cflags 2> /dev/null`
+xmlrpc_libs=`$xmlrpccconfig client server-util --libs 2> /dev/null`
+if compile_prog "$xmlrpc_cflags" "$xmlrpc_libs"; then
+  libs_softmmu="$xmlrpc_libs $libs_softmmu"
+  libs_tools="$xmlrpc_libs $libs_tools"
+else
+  feature_not_found "xmlrpc-c"
+fi
+
+##########################################
 # VNC TLS detection
 if test "$vnc_tls" != "no" ; then
   cat > $TMPC <<EOF
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent
  2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
                   ` (17 preceding siblings ...)
  2010-11-16 16:02 ` [Qemu-devel] [RFC][PATCH v4 18/18] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
@ 2010-11-18 13:50 ` Jes Sorensen
  18 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 13:50 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> This set of patches is meant to be applied on top of the recently submitted Virtproxy v3 patchset. It can also be obtained at:
> 
> git://repo.or.cz/qemu/mdroth.git virtproxy_v3
> 
> OVERVIEW:
> 
> There are a wide range of use cases motivating the need for a guest agent of some sort to extend the functionality/usability/control offered by QEMU. Some examples include graceful guest shutdown/reboot and notifications thereof, copy/paste syncing between host/guest, guest statistics gathering, file access, etc.
> 
> Ideally these would all be served by a single, easilly extensible agent that can be deployed in a wide range of guests. Virtagent is an XMLRPC server, integrated into QEMU and the Virtproxy guest daemon, aimed at providing this type of functionality.
> 
> NOTE: The guest agent can potentially be implemented independently of virtproxy depending on the feedback, we simply make use of it to provide an abstraction from the actual transport layer (ISA vs. Virtio serial) and use it's multiplexing capabilities to avoid having to dedicate 2 isa/virtio serial ports to the virtagent service. Please evaluate these patches as being seperate from virtproxy.
> 


Michael,

On a general note, while the protocol stuff probably should go into
QEMU, then I don't see the actual agent belonging in the QEMU tree. If
you put it all together, you are less likely other agents are willing to
adopt virtproxy.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs Michael Roth
@ 2010-11-18 13:53   ` Jes Sorensen
  2010-11-18 16:33     ` Michael Roth
  0 siblings, 1 reply; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 13:53 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> +#define DEBUG_VA
> +
> +#ifdef DEBUG_VA
> +#define TRACE(msg, ...) do { \
> +    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
> +            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
> +} while(0)
> +#else
> +#define TRACE(msg, ...) \
> +    do { } while (0)
> +#endif
> +
> +#define LOG(msg, ...) do { \
> +    fprintf(stderr, "%s:%s(): " msg "\n", \
> +            __FILE__, __FUNCTION__, ## __VA_ARGS__); \
> +} while(0)

I am sure I saw those macros in a couple of other places in the tree
recently :)

> +#define TADDR "127.0.0.1:8080"
> +#define URL "http://localhost:8080/RPC2"

Rather than relying on hard coded addresses for this, how about moving
it to a config file?

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server Michael Roth
@ 2010-11-18 13:57   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 13:57 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> +#include <syslog.h>
> +#include "qemu_socket.h"
> +#include "virtagent-daemon.h"
> +#include "virtagent-common.h"
> +#include "virtagent.h"
> +
> +static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */
> +
> +#define SLOG(msg, ...) do { \
> +    char msg_buf[1024]; \
> +    if (!va_enable_syslog) { \
> +        break; \
> +    } \
> +    sprintf(msg_buf, msg, ## __VA_ARGS__); \
> +    syslog(LOG_INFO, "virtagent, %s", msg_buf); \
> +} while(0)

You have a potential buffer overflow here, s/sprintf/snprintf/

> +#include "virtproxy.h"
> +
> +#define GUEST_AGENT_SERVICE_ID "virtagent"
> +#define GUEST_AGENT_PATH "/tmp/virtagent-guest.sock"
> +#define HOST_AGENT_SERVICE_ID "virtagent-host"
> +#define HOST_AGENT_PATH "/tmp/virtagent-host.sock"
> +#define VA_GETFILE_MAX 1 << 30
> +#define VA_FILEBUF_LEN 16384
> +
> +int va_server_init(VPDriver *vp_drv, bool is_host);

More stuff which I think should go into a config file.

Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server Michael Roth
@ 2010-11-18 14:02   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:02 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> +    bool enable_virtagent;
>  
>      chr->opaque = drv;
>      chr->chr_write = vp_chr_write;
> @@ -2025,9 +2029,31 @@ static CharDriverState *qemu_chr_open_virtproxy(QemuOpts *opts)
>      /* parse socket forwarding options */
>      qemu_opt_foreach(opts, vp_init_forwards, drv, 1);
>  
> +    /* add forwarding options to enable virtagent server */
> +    enable_virtagent = qemu_opt_get_bool(opts, "virtagent", 0);

int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)

Sorry qemu_opt_get_bool() actually returns an int.

> diff --git a/qemu-vp.c b/qemu-vp.c
> index cfd2a69..38959e5 100644
> --- a/qemu-vp.c
> +++ b/qemu-vp.c
> @@ -37,6 +37,8 @@
>  #include "qemu-option.h"
>  #include "qemu_socket.h"
>  #include "virtproxy.h"
> +#include "virtagent.h"
> +#include "virtagent-daemon.h"
>  
>  static bool verbose_enabled = 0;

You don't need to initialize global variables to zero, the compiler does
that.


> +static int init_agent(const VPData *agent_iforward) {
> +    QemuOpts *opts = agent_iforward->opts;
> +    VPDriver *drv;
> +    int ret, index;
> +
> +    INFO("initializing agent...");
> +    if (verbose_enabled) {
> +        qemu_opts_print(opts, NULL);
> +    }
> +
> +    index = qemu_opt_get_number(agent_iforward->opts, "index", 0);
> +    drv = get_channel_drv(index);
> +    if (drv == NULL) {
> +        warnx("unable to find channel with index: %d", index);
> +        goto err;
> +    }
> +
> +    /* outbound RPCs */
> +    ret = va_client_init(drv, false);
> +    if (ret) {
> +        warnx("error starting RPC server");
> +        goto err;
> +    }
> +
> +    /* start guest RPC server */
> +    ret = va_server_init(drv, false);
> +    if (ret != 0) {
> +        warnx("error starting RPC server");
> +        goto err;
> +    }
> +
> +    return 0;
> +
> +err:
> +    return -1;
> +}

Please set appropriate error codes and return something meaningful
instead of just -1.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions Michael Roth
@ 2010-11-18 14:10   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:10 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> diff --git a/monitor.c b/monitor.c
> index 8cee35d..cb81cd7 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -42,6 +42,7 @@
>  #include "audio/audio.h"
>  #include "disas.h"
>  #include "balloon.h"
> +#include "virtagent.h"
>  #include "qemu-timer.h"
>  #include "migration.h"
>  #include "kvm.h"

You are adding an include here without modifying any code to actually
use something from this file.

> +static int va_client_ready(void)
> +{
> +    if (client_state != NULL && client_state->vp != NULL
> +        && client_state->socket_path != NULL) {

Please put the && up on the previous line, makes it easier for a reader
to notice that the next line is part of the first portion.

> +        return 0;
> +    }
> +
> +    return -1;
> +}

-EAGAIN? -EBUSY?

> +static void va_set_capabilities(QList *qlist)
> +{
> +    TRACE("called");
> +
> +    if (client_state == NULL) {
> +        LOG("client is uninitialized, unable to set capabilities");
> +        return;
> +    }

Why no error value returned here?

> +int va_client_init(VPDriver *vp_drv, bool is_host)
> +{
> +    const char *service_id, *path;
> +    QemuOpts *opts;
> +    int fd, ret;
> +
> +    if (client_state) {
> +        LOG("virtagent client already initialized");
> +        return -1;
> +    }

-1 again :(

> +    /* setup listening socket to forward connections over */
> +    opts = qemu_opts_create(qemu_find_opts("net"), "va_client_opts", 0);
> +    qemu_opt_set(opts, "path", path);
> +    fd = unix_listen_opts(opts);
> +    qemu_opts_del(opts);
> +    if (fd < 0) {
> +        LOG("error setting up listening socket");
> +        goto out_bad;
> +    }
> +
> +    /* tell virtproxy to forward connections to this socket to
> +     * virtagent service on other end
> +     */
> +    ret = vp_set_oforward(vp_drv, fd, service_id);
> +    if (ret < 0) {
> +        LOG("error setting up virtproxy iforward");
> +        goto out_bad;
> +    }
> +
> +    return 0;
> +out_bad:
> +    qemu_free(client_state);
> +    client_state = NULL;
> +    return -1;
> +}

You know why you ended up here, please pass that information up the stack.

> +static int rpc_has_error(xmlrpc_env *env)
> +{
> +    if (env->fault_occurred) {
> +        LOG("An RPC error has occurred (%i): %s\n", env->fault_code, env->fault_string);
> +        //qerror_report(QERR_RPC_FAILED, env->fault_code, env->fault_string);
> +        return -1;
> +    }
> +    return 0;
> +}

-1 again

> +/*
> + * Get a connected socket that can be used to make an RPC call
> + * This interface will eventually return the connected virtproxy socket for the
> + * virt-agent channel
> + */
> +static int get_transport_fd(void)
> +{
> +    /* TODO: eventually this will need a path that is unique to other
> +     * instances of qemu-vp/qemu. for the integrated qemu-vp we should
> +     * explore the possiblity of not requiring a unix socket under the
> +     * covers, as well as having client init code set up the oforward
> +     * for the service rather than qemu-vp
> +     */
> +    int ret;
> +    int fd = unix_connect(client_state->socket_path);
> +    if (fd < 0) {
> +        LOG("failed to connect to virtagent service");
> +    }
> +    ret = fcntl(fd, F_GETFL);
> +    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
> +    return fd;
> +}

You are forgetting to check the return from fcntl() for errors.

> +static int rpc_execute(xmlrpc_env *const env, const char *function,
> +                       xmlrpc_value *params, VARPCData *rpc_data)
> +{
> +    xmlrpc_mem_block *call_xml;
> +    int fd, ret;
> +
> +    ret = va_client_ready();
> +    if (ret < 0) {
> +        LOG("client in uninitialized state, unable to execute RPC");
> +        ret = -1;
> +        goto out;
> +    }
> +
> +    if (!va_has_capability(function)) {
> +        LOG("guest agent does not have required capability");
> +        ret = -1;
> +        goto out;
> +    }
> +
> +    fd = get_transport_fd();
> +    if (fd < 0) {
> +        LOG("invalid fd");
> +        ret = -1;
> +        goto out;
> +    }

You just got a proper error value back, why replace it with -1? It is
all over this function.

> diff --git a/virtagent.h b/virtagent.h
> new file mode 100644
> index 0000000..53efa29
> --- /dev/null
> +++ b/virtagent.h
> +#define GUEST_AGENT_PATH_CLIENT "/tmp/virtagent-guest-client.sock"
> +#define HOST_AGENT_PATH_CLIENT "/tmp/virtagent-host-client.sock"
> +#define VA_MAX_CHUNK_SIZE 4096 /* max bytes at a time for get/send file */

Config file please!

Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command Michael Roth
@ 2010-11-18 14:13   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:13 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> Utilize the getfile RPC to provide a means to view text files in the
> guest. Getfile can handle binary files as well but we don't advertise
> that here due to the special handling requiring to store it and provide
> it back to the user (base64 encoding it for instance). Hence the
> potentially confusing "viewfile" as opposed to "getfile".
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> 

This one is full of -1 returns again :(

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC Michael Roth
@ 2010-11-18 14:17   ` Jes Sorensen
  2010-11-18 15:35     ` Anthony Liguori
  0 siblings, 1 reply; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:17 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> RPC to initiate guest shutdown/reboot/powerdown

Do we really need this? After all those events can be passed down via ACPI?

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command Michael Roth
@ 2010-11-18 14:19   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:19 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> Provide monitor command to initiate guest shutdown/reboot/powerdown

> +int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
> +                      MonitorCompletion cb, void *opaque)
> +{
> +    xmlrpc_env env;
> +    xmlrpc_value *params;
> +    VARPCData *rpc_data;
> +    const char *shutdown_type;
> +    int ret;
> +
> +    TRACE("called");
> +
> +    xmlrpc_env_init(&env);
> +    shutdown_type = qdict_get_str(mon_params, "shutdown_type");
> +    params = xmlrpc_build_value(&env, "(s)", shutdown_type);
> +    if (rpc_has_error(&env)) {
> +        return -1;
> +    }
> +
> +    rpc_data = qemu_mallocz(sizeof(VARPCData));
> +    rpc_data->cb = do_agent_shutdown_cb;
> +    rpc_data->mon_cb = cb;
> +    rpc_data->mon_data = opaque;
> +
> +    ret = rpc_execute(&env, "va_shutdown", params, rpc_data);
> +    if (ret == -EREMOTE) {
> +        monitor_printf(mon, "RPC Failed (%i): %s\n", env.fault_code,
> +                       env.fault_string);
> +        return -1;
> +    } else if (ret == -1) {
> +        monitor_printf(mon, "RPC communication error\n");
> +        return -1;
> +    }

I would think you could put a lot of this into a utility function
instead of having it open coded for each command you want to support?

Cheers,
Jes


> +
> +    return 0;
> +}
> diff --git a/virtagent.h b/virtagent.h
> index c077582..96c6260 100644
> --- a/virtagent.h
> +++ b/virtagent.h
> @@ -29,5 +29,7 @@ int do_agent_viewfile(Monitor *mon, const QDict *mon_params,
>  void do_agent_viewdmesg_print(Monitor *mon, const QObject *qobject);
>  int do_agent_viewdmesg(Monitor *mon, const QDict *mon_params,
>                        MonitorCompletion cb, void *opaque);
> +int do_agent_shutdown(Monitor *mon, const QDict *mon_params,
> +                      MonitorCompletion cb, void *opaque);
>  
>  #endif /* VIRTAGENT_H */

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function Michael Roth
@ 2010-11-18 14:22   ` Jes Sorensen
  2010-11-18 16:43     ` Michael Roth
  0 siblings, 1 reply; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:22 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> Non-monitor version of agent_capabilities monitor function. This is
> called by the local RPC server when it gets a "hello" from the guest
> agent to re-negotiate guest agent capabilities.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  virtagent.c |   34 ++++++++++++++++++++++++++++++++++
>  virtagent.h |    1 +
>  2 files changed, 35 insertions(+), 0 deletions(-)
> 
> diff --git a/virtagent.c b/virtagent.c
> index e0f7f99..4ec1b42 100644
> --- a/virtagent.c
> +++ b/virtagent.c
> @@ -694,3 +694,37 @@ int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
>  
>      return 0;
>  }
> +
> +/* non-HMP/QMP RPC client functions */
> +
> +int va_client_init_capabilities(void)
> +{
> +    xmlrpc_env env;
> +    xmlrpc_value *params;
> +    VARPCData *rpc_data;
> +    int ret;
> +
> +    xmlrpc_env_init(&env);
> +
> +    params = xmlrpc_build_value(&env, "()");
> +    if (rpc_has_error(&env)) {
> +        return -1;
> +    }
> +
> +    rpc_data = qemu_mallocz(sizeof(VARPCData));
> +    rpc_data->cb = do_agent_capabilities_cb;
> +    rpc_data->mon_cb = NULL;
> +    rpc_data->mon_data = NULL;
> +
> +    ret = rpc_execute(&env, "system.listMethods", params, rpc_data);
> +    if (ret == -EREMOTE) {
> +        LOG("RPC Failed (%i): %s\n", env.fault_code,
> +            env.fault_string);
> +        return -1;
> +    } else if (ret == -1) {
> +        LOG("RPC communication error\n");
> +        return -1;
> +    }

One of many examples that would have benefited from having a utility
function doing most of the work here.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup
  2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup Michael Roth
@ 2010-11-18 14:22   ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 14:22 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/16/10 17:01, Michael Roth wrote:
> Make the hello call on guest agent startup so QEMU can do whatever init
> it needs (currently, capabilities negotiation). Temporarilly commented
> due to this tending to induce a virtio bug in RHEL 6.0. As a result
> capabilities negotiation must be invoked manually from QEMU via the
> agent_capabilities monitor command.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qemu-vp.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/qemu-vp.c b/qemu-vp.c
> index 38959e5..b8af513 100644
> --- a/qemu-vp.c
> +++ b/qemu-vp.c
> @@ -580,6 +580,8 @@ int main(int argc, char **argv)
>              errx(EXIT_FAILURE,
>                   "error initializing guest agent");
>          }
> +        /* tell the host the agent is running */
> +        //va_send_hello();

Ehm, not much point adding a call that is commented out :)

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC
  2010-11-18 14:17   ` Jes Sorensen
@ 2010-11-18 15:35     ` Anthony Liguori
  2010-11-18 15:41       ` Jes Sorensen
  0 siblings, 1 reply; 33+ messages in thread
From: Anthony Liguori @ 2010-11-18 15:35 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: abeekhof, ryanh, agl, Michael Roth, qemu-devel

On 11/18/2010 08:17 AM, Jes Sorensen wrote:
> On 11/16/10 17:01, Michael Roth wrote:
>    
>> RPC to initiate guest shutdown/reboot/powerdown
>>      
> Do we really need this? After all those events can be passed down via ACPI?
>    

Reboot can't be passed by ACPI.  This is why virDomainReboot is still 
not functional in KVM.  Every other hypervisor does something identical 
to this series.

And a hypervisor initiated shutdown ought to be treated differently than 
an ACPI shutdown.  Namely, it should correspond to an immediate shut 
down vs. prompting the user.

Not all OSes response to ACPI shutdown either FWIW.

Regards,

Anthony Liguori

> Cheers,
> Jes
>
>    

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC
  2010-11-18 15:35     ` Anthony Liguori
@ 2010-11-18 15:41       ` Jes Sorensen
  0 siblings, 0 replies; 33+ messages in thread
From: Jes Sorensen @ 2010-11-18 15:41 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: abeekhof, ryanh, agl, Michael Roth, qemu-devel

On 11/18/10 16:35, Anthony Liguori wrote:
> On 11/18/2010 08:17 AM, Jes Sorensen wrote:
>> On 11/16/10 17:01, Michael Roth wrote:
>>   
>>> RPC to initiate guest shutdown/reboot/powerdown
>>>      
>> Do we really need this? After all those events can be passed down via
>> ACPI?
>>    
> 
> Reboot can't be passed by ACPI.  This is why virDomainReboot is still
> not functional in KVM.  Every other hypervisor does something identical
> to this series.
> 
> And a hypervisor initiated shutdown ought to be treated differently than
> an ACPI shutdown.  Namely, it should correspond to an immediate shut
> down vs. prompting the user.
> 
> Not all OSes response to ACPI shutdown either FWIW.

Ok, fair enough.

I just would like to avoid duplicating functionality if we don't have to.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs
  2010-11-18 13:53   ` Jes Sorensen
@ 2010-11-18 16:33     ` Michael Roth
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-18 16:33 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/18/2010 07:53 AM, Jes Sorensen wrote:
> On 11/16/10 17:01, Michael Roth wrote:
>> +#define DEBUG_VA
>> +
>> +#ifdef DEBUG_VA
>> +#define TRACE(msg, ...) do { \
>> +    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
>> +            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
>> +} while(0)
>> +#else
>> +#define TRACE(msg, ...) \
>> +    do { } while (0)
>> +#endif
>> +
>> +#define LOG(msg, ...) do { \
>> +    fprintf(stderr, "%s:%s(): " msg "\n", \
>> +            __FILE__, __FUNCTION__, ## __VA_ARGS__); \
>> +} while(0)
>
> I am sure I saw those macros in a couple of other places in the tree
> recently :)
>

Hehe, too much compartmentalization.

I do plan on moving to QEMU tracing statements instead of a macro...

I only just now noticed qemu_log(), I take it this is the preferred route?

>> +#define TADDR "127.0.0.1:8080"
>> +#define URL "http://localhost:8080/RPC2"
>
> Rather than relying on hard coded addresses for this, how about moving
> it to a config file?
>
> Cheers,
> Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function
  2010-11-18 14:22   ` Jes Sorensen
@ 2010-11-18 16:43     ` Michael Roth
  0 siblings, 0 replies; 33+ messages in thread
From: Michael Roth @ 2010-11-18 16:43 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

On 11/18/2010 08:22 AM, Jes Sorensen wrote:
> On 11/16/10 17:01, Michael Roth wrote:
>> Non-monitor version of agent_capabilities monitor function. This is
>> called by the local RPC server when it gets a "hello" from the guest
>> agent to re-negotiate guest agent capabilities.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>>   virtagent.c |   34 ++++++++++++++++++++++++++++++++++
>>   virtagent.h |    1 +
>>   2 files changed, 35 insertions(+), 0 deletions(-)
>>
>> diff --git a/virtagent.c b/virtagent.c
>> index e0f7f99..4ec1b42 100644
>> --- a/virtagent.c
>> +++ b/virtagent.c
>> @@ -694,3 +694,37 @@ int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
>>
>>       return 0;
>>   }
>> +
>> +/* non-HMP/QMP RPC client functions */
>> +
>> +int va_client_init_capabilities(void)
>> +{
>> +    xmlrpc_env env;
>> +    xmlrpc_value *params;
>> +    VARPCData *rpc_data;
>> +    int ret;
>> +
>> +    xmlrpc_env_init(&env);
>> +
>> +    params = xmlrpc_build_value(&env, "()");
>> +    if (rpc_has_error(&env)) {
>> +        return -1;
>> +    }
>> +
>> +    rpc_data = qemu_mallocz(sizeof(VARPCData));
>> +    rpc_data->cb = do_agent_capabilities_cb;
>> +    rpc_data->mon_cb = NULL;
>> +    rpc_data->mon_data = NULL;
>> +
>> +    ret = rpc_execute(&env, "system.listMethods", params, rpc_data);
>> +    if (ret == -EREMOTE) {
>> +        LOG("RPC Failed (%i): %s\n", env.fault_code,
>> +            env.fault_string);
>> +        return -1;
>> +    } else if (ret == -1) {
>> +        LOG("RPC communication error\n");
>> +        return -1;
>> +    }
>
> One of many examples that would have benefited from having a utility
> function doing most of the work here.
>

Agreed, I should be able to trim quite a few lines out of virtagent.c 
with a bit more code re-use.

> Cheers,
> Jes

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2010-11-18 16:43 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-16 16:01 [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 01/18] virtagent: add common rpc transport defs Michael Roth
2010-11-18 13:53   ` Jes Sorensen
2010-11-18 16:33     ` Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 02/18] virtagent: base definitions for host/guest RPC server Michael Roth
2010-11-18 13:57   ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 03/18] virtagent: qemu-vp, integrate virtagent server Michael Roth
2010-11-18 14:02   ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 04/18] virtagent: base RPC client definitions Michael Roth
2010-11-18 14:10   ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 05/18] virtagent: add getfile RPC Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 06/18] virtagent: add agent_viewfile command Michael Roth
2010-11-18 14:13   ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 07/18] virtagent: add getdmesg RPC Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 08/18] virtagent: add agent_viewdmesg command Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 09/18] virtagent: add va_shutdown RPC Michael Roth
2010-11-18 14:17   ` Jes Sorensen
2010-11-18 15:35     ` Anthony Liguori
2010-11-18 15:41       ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 10/18] virtagent: add agent_shutdown monitor command Michael Roth
2010-11-18 14:19   ` Jes Sorensen
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 11/18] virtagent: add va_ping RPC Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 12/18] virtagent: add agent_ping monitor command Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 13/18] virtagent: add agent_capabilities monitor function Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 14/18] virtagent: add client capabilities init function Michael Roth
2010-11-18 14:22   ` Jes Sorensen
2010-11-18 16:43     ` Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 15/18] virtagent: add va_hello RPC function Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 16/18] virtagent: add va_send_hello() client function Michael Roth
2010-11-16 16:01 ` [Qemu-devel] [RFC][PATCH v4 17/18] virtagent: qemu-vp, va_send_hello() on startup Michael Roth
2010-11-18 14:22   ` Jes Sorensen
2010-11-16 16:02 ` [Qemu-devel] [RFC][PATCH v4 18/18] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
2010-11-18 13:50 ` [Qemu-devel] [RFC][PATCH v4 00/18] virtagent: host/guest RPC communication agent Jes Sorensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).