All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent
@ 2010-11-11  1:37 Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 01/11] virtagent: add common rpc transport defs Michael Roth
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

The previous submission was missing the subject, please disregard it.

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

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

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 the Virtproxy guest daemon and aimed at providing this type of functionality.

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.

Currently there are only 2 RPCs implemented for the guest server (getfile and getdmesg), and 0 for the host. Additional RPCs can be added fairly easily, but are dependent on feedback from here and elsewhere. ping/status, shutdown, and reboot are likely candidates (although the latter 2 will likely require asynchronous notifications to the host RPC server to implement reliably).

EXAMPLE USAGE:

The commandline options are a little convoluted right now; this will addressed in later revisions.

 - 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

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.
 - capability negotiation will be needed to handle version/architecture differences.
 - 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.
 - additional host-to-guest RPCs as well as asynchronous notifications via guest-to-host RPCs for events such as shutdown/reboot/agent up/agent down

 Makefile           |    2 +-
 Makefile.target    |    2 +-
 configure          |   25 +++
 hmp-commands.hx    |   32 ++++
 monitor.c          |    1 +
 qemu-char.c        |   24 +++
 qemu-config.c      |    3 +
 qemu-vp.c          |   94 ++++++++++-
 qerror.c           |    4 +
 qerror.h           |    3 +
 qmp-commands.hx    |   68 ++++++++
 roms/seabios       |    2 +-
 virtagent-common.c |  431 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-common.h |   73 +++++++++
 virtagent-daemon.c |  291 +++++++++++++++++++++++++++++++++++
 virtagent-daemon.h |   23 +++
 virtagent.c        |  345 +++++++++++++++++++++++++++++++++++++++++
 virtagent.h        |   33 ++++
 18 files changed, 1444 insertions(+), 12 deletions(-)

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

* [Qemu-devel] [RFC][PATCH v3 01/11] virtagent: add common rpc transport defs
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 02/11] virtagent: base definitions for host/guest RPC server Michael Roth
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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 |  431 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-common.h |   73 +++++++++
 2 files changed, 504 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..cc58938
--- /dev/null
+++ b/virtagent-common.c
@@ -0,0 +1,431 @@
+/*
+ * 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
+         */ 
+        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
+         */
+        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) {
+                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) {
+                    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 send handler for RPC request");
+    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 {
+            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
+         */
+        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) {
+                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) {
+                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] 13+ messages in thread

* [Qemu-devel] [RFC][PATCH v3 02/11] virtagent: base definitions for host/guest RPC server
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 01/11] virtagent: add common rpc transport defs Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 03/11] virtagent: qemu-vp, integrate virtagent server Michael Roth
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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 |  194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-daemon.h |   22 ++++++
 2 files changed, 216 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..0505a81
--- /dev/null
+++ b/virtagent-daemon.c
@@ -0,0 +1,194 @@
+/*
+ * 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 "qemu_socket.h"
+#include "virtagent-daemon.h"
+#include "virtagent-common.h"
+
+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;
+    }
+    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] 13+ messages in thread

* [Qemu-devel] [RFC][PATCH v3 03/11] virtagent: qemu-vp, integrate virtagent server
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 01/11] virtagent: add common rpc transport defs Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 02/11] virtagent: base definitions for host/guest RPC server Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 04/11] virtagent: base RPC client definitions Michael Roth
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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-vp.c |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/qemu-vp.c b/qemu-vp.c
index 3a3762a..fe06e07 100644
--- a/qemu-vp.c
+++ b/qemu-vp.c
@@ -37,6 +37,7 @@
 #include "qemu-option.h"
 #include "qemu_socket.h"
 #include "virtproxy.h"
+#include "virtagent-daemon.h"
 
 static bool verbose_enabled = 0;
 #define DEBUG_ENABLED
@@ -252,14 +253,18 @@ 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"
+"  -p, --host-agent  host rpc server, options of the form:\n"
+"                    [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"
@@ -533,13 +538,44 @@ static int init_iforwards(void) {
     return 0;
 }
 
+static int init_agent(const VPData *agent_iforward, bool is_host) {
+    QemuOpts *opts = agent_iforward->opts;
+    int listen_fd, ret;
+
+    INFO("initializing agent...");
+    if (verbose_enabled) {
+        qemu_opts_print(opts, NULL);
+    }
+
+    /* create unix socket pair that agent http/rpc daemon will listen on */
+    listen_fd = unix_listen_opts(agent_iforward->opts);
+    if (listen_fd < 0) {
+        return -1;
+    }
+
+    /* start RPC server */
+    ret = va_server_start(listen_fd, is_host);
+    if (ret != 0) {
+        warnx("error starting RPC server");
+        goto err;
+    }
+
+    return 0;
+
+err:
+    closesocket(listen_fd);
+    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' },
@@ -549,10 +585,13 @@ int main(int argc, char **argv)
     QTAILQ_INIT(&iforwards);
     QTAILQ_INIT(&oforwards);
     QTAILQ_INIT(&channels);
+    VPData *guest_agent_iforward = NULL;
+    VPData *host_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);
@@ -584,6 +623,50 @@ 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 'p':
+            /* create pre-baked iforward for host agent */
+            if (host_agent_iforward) {
+                errx(EXIT_FAILURE, "only one --host-agent argument allowed");
+            }
+            opts = qemu_opts_create(&vp_opts, NULL, 0);
+            if (optarg == 0) {
+                sprintf(optarg_tmp, "%s:%s:-", HOST_AGENT_SERVICE_ID,
+                                     HOST_AGENT_PATH);
+            } else {
+                sprintf(optarg_tmp, "%s:%s:-:%d", HOST_AGENT_SERVICE_ID,
+                                     HOST_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);
+            host_agent_iforward = data;
+            break;
         case 'v':
             verbose_enabled = 1;
             break;
@@ -613,6 +696,20 @@ int main(int argc, char **argv)
              "error initializing service mappings for incoming connections");
     }
 
+    if (guest_agent_iforward) {
+        ret = init_agent(guest_agent_iforward, false);
+        if (ret) {
+            errx(EXIT_FAILURE,
+                 "error initializing guest agent");
+        }
+    } else if (host_agent_iforward) {
+        ret = init_agent(host_agent_iforward, true);
+        if (ret) {
+            errx(EXIT_FAILURE,
+                 "error initializing host agent");
+        }
+    }
+
     /* main i/o loop */
     for (;;) {
         DEBUG("entering main_loop_wait()");
-- 
1.7.0.4

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

* [Qemu-devel] [RFC][PATCH v3 04/11] virtagent: base RPC client definitions
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (2 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 03/11] virtagent: qemu-vp, integrate virtagent server Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 05/11] virtagent: add getfile RPC Michael Roth
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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 |  145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h |   27 +++++++++++
 5 files changed, 180 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..cfd279f
--- /dev/null
+++ b/virtagent.c
@@ -0,0 +1,145 @@
+/*
+ * 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;
+} VARPCClientState;
+
+/* only one virtagent client can exist at a time */
+static VARPCClientState *client_state;
+
+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;
+
+    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] 13+ messages in thread

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

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 |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 0505a81..3615e8a 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -15,6 +15,57 @@
 #include "virtagent-daemon.h"
 #include "virtagent-common.h"
 
+/* 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;
+    }
+
+    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;
@@ -42,6 +93,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] 13+ messages in thread

* [Qemu-devel] [RFC][PATCH v3 06/11] virtagent: add agent_viewfile command
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (4 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 05/11] virtagent: add getfile RPC Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 07/11] virtagent: add getdmesg RPC Michael Roth
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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     |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent.h     |    3 ++
 4 files changed, 152 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 cfd279f..2e496f9 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -143,3 +143,103 @@ out_callxml:
 out:
     return ret;
 }
+
+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] 13+ messages in thread

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

Add RPC to view guest dmesg output.

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

diff --git a/virtagent-daemon.c b/virtagent-daemon.c
index 3615e8a..51e4e0f 100644
--- a/virtagent-daemon.c
+++ b/virtagent-daemon.c
@@ -66,6 +66,48 @@ 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;
+
+    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;
@@ -95,6 +137,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] 13+ messages in thread

* [Qemu-devel] [RFC][PATCH v3 08/11] virtagent: add agent_viewdmesg command
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (6 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 07/11] virtagent: add getdmesg RPC Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 09/11] virtagent: qemu-vp integration, use virtagent init functions Michael Roth
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah

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 2e496f9..7d04cd6 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -205,6 +205,7 @@ out:
     xmlrpc_DECREF(resp);
 out_no_resp:
     rpc_data->mon_cb(rpc_data->mon_data, QOBJECT(qdict));
+    qobject_decref(QOBJECT(qdict));
 }
 
 /*
@@ -243,3 +244,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] 13+ messages in thread

* [Qemu-devel] [RFC][PATCH v3 09/11] virtagent: qemu-vp integration, use virtagent init functions
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (7 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 08/11] virtagent: add agent_viewdmesg command Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 10/11] virtagent: qemu integration, add va invocation via virtproxy chardev Michael Roth
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, root, aliguori, ryanh, amit.shah

From: root <root@arsenal.linuxperf9025.net>

Invoke virtagent client/server instances via their init functions.

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

diff --git a/qemu-vp.c b/qemu-vp.c
index fe06e07..2fde670 100644
--- a/qemu-vp.c
+++ b/qemu-vp.c
@@ -37,6 +37,7 @@
 #include "qemu-option.h"
 #include "qemu_socket.h"
 #include "virtproxy.h"
+#include "virtagent.h"
 #include "virtagent-daemon.h"
 
 static bool verbose_enabled = 0;
@@ -255,8 +256,6 @@ static void usage(const char *cmd)
 "\n"
 "  -c, --channel     channel options of the form:\n"
 "                    <method>:<addr>:<port>[:channel_id]\n"
-"  -p, --host-agent  host rpc server, options of the form:\n"
-"                    [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"
@@ -538,23 +537,32 @@ static int init_iforwards(void) {
     return 0;
 }
 
-static int init_agent(const VPData *agent_iforward, bool is_host) {
+static int init_agent(const VPData *agent_iforward) {
     QemuOpts *opts = agent_iforward->opts;
-    int listen_fd, ret;
+    VPDriver *drv;
+    int ret, index;
 
     INFO("initializing agent...");
     if (verbose_enabled) {
         qemu_opts_print(opts, NULL);
     }
 
-    /* create unix socket pair that agent http/rpc daemon will listen on */
-    listen_fd = unix_listen_opts(agent_iforward->opts);
-    if (listen_fd < 0) {
-        return -1;
+    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;
     }
 
-    /* start RPC server */
-    ret = va_server_start(listen_fd, is_host);
+    /* 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;
@@ -563,7 +571,6 @@ static int init_agent(const VPData *agent_iforward, bool is_host) {
     return 0;
 
 err:
-    closesocket(listen_fd);
     return -1;
 }
 
@@ -586,7 +593,6 @@ int main(int argc, char **argv)
     QTAILQ_INIT(&oforwards);
     QTAILQ_INIT(&channels);
     VPData *guest_agent_iforward = NULL;
-    VPData *host_agent_iforward = NULL;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         QemuOpts *opts;
@@ -645,28 +651,6 @@ int main(int argc, char **argv)
             QTAILQ_INSERT_TAIL(&iforwards, data, next);
             guest_agent_iforward = data;
             break;
-        case 'p':
-            /* create pre-baked iforward for host agent */
-            if (host_agent_iforward) {
-                errx(EXIT_FAILURE, "only one --host-agent argument allowed");
-            }
-            opts = qemu_opts_create(&vp_opts, NULL, 0);
-            if (optarg == 0) {
-                sprintf(optarg_tmp, "%s:%s:-", HOST_AGENT_SERVICE_ID,
-                                     HOST_AGENT_PATH);
-            } else {
-                sprintf(optarg_tmp, "%s:%s:-:%d", HOST_AGENT_SERVICE_ID,
-                                     HOST_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);
-            host_agent_iforward = data;
-            break;
         case 'v':
             verbose_enabled = 1;
             break;
@@ -696,18 +680,13 @@ int main(int argc, char **argv)
              "error initializing service mappings for incoming connections");
     }
 
+
     if (guest_agent_iforward) {
-        ret = init_agent(guest_agent_iforward, false);
+        ret = init_agent(guest_agent_iforward);
         if (ret) {
             errx(EXIT_FAILURE,
                  "error initializing guest agent");
         }
-    } else if (host_agent_iforward) {
-        ret = init_agent(host_agent_iforward, true);
-        if (ret) {
-            errx(EXIT_FAILURE,
-                 "error initializing host agent");
-        }
     }
 
     /* main i/o loop */
-- 
1.7.0.4

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

* [Qemu-devel] [RFC][PATCH v3 10/11] virtagent: qemu integration, add va invocation via virtproxy chardev
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (8 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 09/11] virtagent: qemu-vp integration, use virtagent init functions Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 11/11] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
  2010-11-25  9:39 ` [Qemu-devel] Re: [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Amit Shah
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, root, aliguori, ryanh, amit.shah

From: root <root@arsenal.linuxperf9025.net>

With these modifications we can now start virtagent via a bool option to
the virtproxy chardev. For example:

qemu -chardev virtproxy,id=va_id,virtagent=on

and then passing the chardev id to whatever device we're using for the
transport (virtio/isa serial)

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

diff --git a/qemu-char.c b/qemu-char.c
index e318acb..9f5efac 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_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -1925,6 +1927,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;
@@ -1937,10 +1941,30 @@ static CharDriverState *qemu_chr_open_virtproxy(QemuOpts *opts)
      * client/server, which will add it's oforwards/iforwards
      * using using virtproxy API calls directly
      */
+    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 52f18be..374182b 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -146,6 +146,9 @@ static QemuOptsList qemu_chardev_opts = {
         },{
             .name = "signal",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "virtagent",
+            .type = QEMU_OPT_BOOL,
         },
         { /* end of list */ }
     },
-- 
1.7.0.4

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

* [Qemu-devel] [RFC][PATCH v3 11/11] virtagent: Makefile/configure changes to build virtagent bits
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (9 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 10/11] virtagent: qemu integration, add va invocation via virtproxy chardev Michael Roth
@ 2010-11-11  1:37 ` Michael Roth
  2010-11-25  9:39 ` [Qemu-devel] Re: [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Amit Shah
  11 siblings, 0 replies; 13+ messages in thread
From: Michael Roth @ 2010-11-11  1:37 UTC (permalink / raw
  To: qemu-devel; +Cc: agl, abeekhof, mdroth, aliguori, ryanh, amit.shah


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 a435ae1..ed67ad1 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] 13+ messages in thread

* [Qemu-devel] Re: [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent
  2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
                   ` (10 preceding siblings ...)
  2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 11/11] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
@ 2010-11-25  9:39 ` Amit Shah
  11 siblings, 0 replies; 13+ messages in thread
From: Amit Shah @ 2010-11-25  9:39 UTC (permalink / raw
  To: Michael Roth; +Cc: aliguori, ryanh, agl, qemu-devel, abeekhof

Hi,

On (Wed) Nov 10 2010 [19:37:19], Michael Roth wrote:
> EXAMPLE USAGE:
> 
> The commandline options are a little convoluted right now; this will addressed in later revisions.
> 
>  - 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

It would be better to have a command and sub-commands rather than
different commands for viewing different kinds of files:

(qemu) agent view dmesg
(qemu) agent view /proc/meminfo

		Amit

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

end of thread, other threads:[~2010-11-25  9:39 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-11  1:37 [Qemu-devel] [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 01/11] virtagent: add common rpc transport defs Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 02/11] virtagent: base definitions for host/guest RPC server Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 03/11] virtagent: qemu-vp, integrate virtagent server Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 04/11] virtagent: base RPC client definitions Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 05/11] virtagent: add getfile RPC Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 06/11] virtagent: add agent_viewfile command Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 07/11] virtagent: add getdmesg RPC Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 08/11] virtagent: add agent_viewdmesg command Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 09/11] virtagent: qemu-vp integration, use virtagent init functions Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 10/11] virtagent: qemu integration, add va invocation via virtproxy chardev Michael Roth
2010-11-11  1:37 ` [Qemu-devel] [RFC][PATCH v3 11/11] virtagent: Makefile/configure changes to build virtagent bits Michael Roth
2010-11-25  9:39 ` [Qemu-devel] Re: [RFC][PATCH v3 00/11] virtagent: host/guest RPC communication agent Amit Shah

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.