qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v4 1/8] record/replay: add network support


From: Pavel Dovgalyuk
Subject: Re: [Qemu-devel] [PATCH v4 1/8] record/replay: add network support
Date: Thu, 13 Oct 2016 11:01:10 +0300

Jason, what about v5 of this patch?

Pavel Dovgalyuk

> -----Original Message-----
> From: Jason Wang [mailto:address@hidden
> Sent: Friday, September 23, 2016 9:07 AM
> To: Pavel Dovgalyuk; address@hidden
> Cc: address@hidden; address@hidden; address@hidden; address@hidden
> Subject: Re: [PATCH v4 1/8] record/replay: add network support
> 
> 
> 
> On 2016年09月21日 19:33, Pavel Dovgalyuk wrote:
> > This patch adds support of recording and replaying network packets in
> > irount rr mode.
> >
> > Record and replay for network interactions is performed with the network 
> > filter.
> > Each backend must have its own instance of the replay filter as follows:
> >   -netdev user,id=net1 -device rtl8139,netdev=net1
> >   -object filter-replay,id=replay,netdev=net1
> >
> > Replay network filter is used to record and replay network packets. While
> > recording the virtual machine this filter puts all packets coming from
> > the outer world into the log. In replay mode packets from the log are
> > injected into the network device. All interactions with network backend
> > in replay mode are disabled.
> >
> > Signed-off-by: Pavel Dovgalyuk <address@hidden>
> 
> Looks good, just few nits, see below.
> 
> Thanks
> 
> > ---
> >   docs/replay.txt          |   14 ++++++
> >   include/sysemu/replay.h  |   12 +++++
> >   net/Makefile.objs        |    1
> >   net/filter-replay.c      |   92 ++++++++++++++++++++++++++++++++++++++
> >   replay/Makefile.objs     |    1
> >   replay/replay-events.c   |   11 +++++
> >   replay/replay-internal.h |   10 ++++
> >   replay/replay-net.c      |  111 
> > ++++++++++++++++++++++++++++++++++++++++++++++
> >   replay/replay.c          |    2 -
> >   vl.c                     |    3 +
> >   10 files changed, 255 insertions(+), 2 deletions(-)
> >   create mode 100644 net/filter-replay.c
> >   create mode 100644 replay/replay-net.c
> >
> > diff --git a/docs/replay.txt b/docs/replay.txt
> > index 779c6c0..347b2ff 100644
> > --- a/docs/replay.txt
> > +++ b/docs/replay.txt
> > @@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about 
> > processed
> requests
> >   is recorded to the log. In replay phase the queue is matched with
> >   events read from the log. Therefore block devices requests are processed
> >   deterministically.
> > +
> > +Network devices
> > +---------------
> > +
> > +Record and replay for network interactions is performed with the network 
> > filter.
> > +Each backend must have its own instance of the replay filter as follows:
> > + -netdev user,id=net1 -device rtl8139,netdev=net1
> > + -object filter-replay,id=replay,netdev=net1
> > +
> > +Replay network filter is used to record and replay network packets. While
> > +recording the virtual machine this filter puts all packets coming from
> > +the outer world into the log. In replay mode packets from the log are
> > +injected into the network device. All interactions with network backend
> > +in replay mode are disabled.
> > diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
> > index 0a88393..a408633 100644
> > --- a/include/sysemu/replay.h
> > +++ b/include/sysemu/replay.h
> > @@ -39,6 +39,8 @@ enum ReplayCheckpoint {
> >   };
> >   typedef enum ReplayCheckpoint ReplayCheckpoint;
> >
> > +typedef struct ReplayNetState ReplayNetState;
> > +
> >   extern ReplayMode replay_mode;
> >
> >   /* Replay process control functions */
> > @@ -133,4 +135,14 @@ void replay_char_read_all_save_error(int res);
> >   /*! Writes character read_all execution result into the replay log. */
> >   void replay_char_read_all_save_buf(uint8_t *buf, int offset);
> >
> > +/* Network */
> > +
> > +/*! Registers replay network filter attached to some backend. */
> > +ReplayNetState *replay_register_net(NetFilterState *nfs);
> > +/*! Unregisters replay network filter. */
> > +void replay_unregister_net(ReplayNetState *rns);
> > +/*! Called to write network packet to the replay log. */
> > +void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
> > +                             const struct iovec *iov, int iovcnt);
> > +
> >   #endif
> > diff --git a/net/Makefile.objs b/net/Makefile.objs
> > index b7c22fd..f787ba4 100644
> > --- a/net/Makefile.objs
> > +++ b/net/Makefile.objs
> > @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o
> >   common-obj-y += filter.o
> >   common-obj-y += filter-buffer.o
> >   common-obj-y += filter-mirror.o
> > +common-obj-y += filter-replay.o
> > diff --git a/net/filter-replay.c b/net/filter-replay.c
> > new file mode 100644
> > index 0000000..cff65f8
> > --- /dev/null
> > +++ b/net/filter-replay.c
> > @@ -0,0 +1,92 @@
> > +/*
> > + * filter-replay.c
> > + *
> > + * Copyright (c) 2010-2016 Institute for System Programming
> > + *                         of the Russian Academy of Sciences.
> > + *
> > + * 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/osdep.h"
> > +#include "clients.h"
> > +#include "qapi/error.h"
> > +#include "qemu-common.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/iov.h"
> > +#include "qemu/log.h"
> > +#include "qemu/timer.h"
> > +#include "qapi/visitor.h"
> > +#include "net/filter.h"
> > +#include "sysemu/replay.h"
> > +
> > +#define TYPE_FILTER_REPLAY "filter-replay"
> > +
> > +#define FILTER_REPLAY(obj) \
> > +    OBJECT_CHECK(NetFilterReplayState, (obj), TYPE_FILTER_REPLAY)
> > +
> > +struct NetFilterReplayState {
> > +    NetFilterState nfs;
> > +    ReplayNetState *rns;
> > +};
> > +typedef struct NetFilterReplayState NetFilterReplayState;
> > +
> > +static ssize_t filter_replay_receive_iov(NetFilterState *nf,
> > +                                         NetClientState *sndr,
> > +                                         unsigned flags,
> > +                                         const struct iovec *iov,
> > +                                         int iovcnt, NetPacketSent 
> > *sent_cb)
> > +{
> > +    NetFilterReplayState *nfrs = FILTER_REPLAY(nf);
> > +    switch (replay_mode) {
> > +    case REPLAY_MODE_RECORD:
> > +        if (nf->netdev == sndr) {
> > +            replay_net_packet_event(nfrs->rns, flags, iov, iovcnt);
> > +            return iov_size(iov, iovcnt);
> > +        }
> > +        return 0;
> > +    case REPLAY_MODE_PLAY:
> > +        /* Drop all packets in replay mode.
> > +           Packets from the log will be injected by the replay module. */
> > +        return iov_size(iov, iovcnt);
> > +    default:
> > +        /* Pass all the packets. */
> > +        return 0;
> > +    }
> > +}
> > +
> > +static void filter_replay_instance_init(Object *obj)
> > +{
> > +    NetFilterReplayState *nfrs = FILTER_REPLAY(obj);
> > +    nfrs->rns = replay_register_net(&nfrs->nfs);
> > +}
> > +
> > +static void filter_replay_instance_finalize(Object *obj)
> > +{
> > +    NetFilterReplayState *nfrs = FILTER_REPLAY(obj);
> > +    replay_unregister_net(nfrs->rns);
> > +}
> > +
> > +static void filter_replay_class_init(ObjectClass *oc, void *data)
> > +{
> > +    NetFilterClass *nfc = NETFILTER_CLASS(oc);
> > +
> > +    nfc->receive_iov = filter_replay_receive_iov;
> > +}
> > +
> > +static const TypeInfo filter_replay_info = {
> > +    .name = TYPE_FILTER_REPLAY,
> > +    .parent = TYPE_NETFILTER,
> > +    .class_init = filter_replay_class_init,
> > +    .instance_init = filter_replay_instance_init,
> > +    .instance_finalize = filter_replay_instance_finalize,
> > +    .instance_size = sizeof(NetFilterReplayState),
> > +};
> > +
> > +static void filter_replay_register_types(void)
> > +{
> > +    type_register_static(&filter_replay_info);
> > +}
> > +
> > +type_init(filter_replay_register_types);
> > diff --git a/replay/Makefile.objs b/replay/Makefile.objs
> > index fcb3f74..f55a6b5 100644
> > --- a/replay/Makefile.objs
> > +++ b/replay/Makefile.objs
> > @@ -4,3 +4,4 @@ common-obj-y += replay-events.o
> >   common-obj-y += replay-time.o
> >   common-obj-y += replay-input.o
> >   common-obj-y += replay-char.o
> > +common-obj-y += replay-net.o
> > diff --git a/replay/replay-events.c b/replay/replay-events.c
> > index 3807245..9ce9e51 100644
> > --- a/replay/replay-events.c
> > +++ b/replay/replay-events.c
> > @@ -54,6 +54,9 @@ static void replay_run_event(Event *event)
> >       case REPLAY_ASYNC_EVENT_BLOCK:
> >           aio_bh_call(event->opaque);
> >           break;
> > +    case REPLAY_ASYNC_EVENT_NET:
> > +        replay_event_net_run(event->opaque);
> > +        break;
> >       default:
> >           error_report("Replay: invalid async event ID (%d) in the queue",
> >                       event->event_kind);
> > @@ -189,6 +192,9 @@ static void replay_save_event(Event *event, int 
> > checkpoint)
> >           case REPLAY_ASYNC_EVENT_BLOCK:
> >               replay_put_qword(event->id);
> >               break;
> > +        case REPLAY_ASYNC_EVENT_NET:
> > +            replay_event_net_save(event->opaque);
> > +            break;
> >           default:
> >               error_report("Unknown ID %" PRId64 " of replay event", 
> > event->id);
> >               exit(1);
> > @@ -252,6 +258,11 @@ static Event *replay_read_event(int checkpoint)
> >               read_id = replay_get_qword();
> >           }
> >           break;
> > +    case REPLAY_ASYNC_EVENT_NET:
> > +        event = g_malloc0(sizeof(Event));
> > +        event->event_kind = read_event_kind;
> > +        event->opaque = replay_event_net_load();
> > +        return event;
> >       default:
> >           error_report("Unknown ID %d of replay event", read_event_kind);
> >           exit(1);
> > diff --git a/replay/replay-internal.h b/replay/replay-internal.h
> > index efbf14c..d28cfb7 100644
> > --- a/replay/replay-internal.h
> > +++ b/replay/replay-internal.h
> > @@ -50,6 +50,7 @@ enum ReplayAsyncEventKind {
> >       REPLAY_ASYNC_EVENT_INPUT_SYNC,
> >       REPLAY_ASYNC_EVENT_CHAR_READ,
> >       REPLAY_ASYNC_EVENT_BLOCK,
> > +    REPLAY_ASYNC_EVENT_NET,
> >       REPLAY_ASYNC_COUNT
> >   };
> >
> > @@ -155,4 +156,13 @@ void replay_event_char_read_save(void *opaque);
> >   /*! Reads char event read from the file. */
> >   void *replay_event_char_read_load(void);
> >
> > +/* Network devices */
> > +
> > +/*! Called to run network event. */
> > +void replay_event_net_run(void *opaque);
> > +/*! Writes network event to the file. */
> > +void replay_event_net_save(void *opaque);
> > +/*! Reads network from the file. */
> > +void *replay_event_net_load(void);
> > +
> >   #endif
> > diff --git a/replay/replay-net.c b/replay/replay-net.c
> > new file mode 100644
> > index 0000000..4f7b995
> > --- /dev/null
> > +++ b/replay/replay-net.c
> > @@ -0,0 +1,111 @@
> > +/*
> > + * replay-net.c
> > + *
> > + * Copyright (c) 2010-2016 Institute for System Programming
> > + *                         of the Russian Academy of Sciences.
> > + *
> > + * 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/osdep.h"
> > +#include "qemu/error-report.h"
> > +#include "sysemu/replay.h"
> > +#include "replay-internal.h"
> > +#include "sysemu/sysemu.h"
> > +#include "net/net.h"
> > +#include "net/filter.h"
> > +#include "qemu/iov.h"
> > +
> > +struct ReplayNetState {
> > +    NetFilterState *nfs;
> > +    int id;
> > +};
> > +
> > +typedef struct NetEvent {
> > +    uint8_t id;
> > +    uint32_t flags;
> > +    uint8_t *data;
> > +    size_t size;
> > +} NetEvent;
> > +
> > +static NetFilterState **network_filters;
> > +static int network_filters_count;
> > +
> > +ReplayNetState *replay_register_net(NetFilterState *nfs)
> > +{
> > +    ReplayNetState *rns = g_new0(ReplayNetState, 1);
> > +    rns->nfs = nfs;
> > +    rns->id = network_filters_count++;
> > +    network_filters = g_realloc(network_filters,
> > +                                network_filters_count
> > +                                    * sizeof(*network_filters));
> 
> Any chance to avoid maintaining such array? E.g by having a pointer to
> NetFilterState in each NetEvent?
> 
> > +    network_filters[network_filters_count - 1] = nfs;
> > +    return rns;
> > +}
> > +
> > +void replay_unregister_net(ReplayNetState *rns)
> > +{
> > +    network_filters[rns->id] = NULL;
> > +    g_free(rns);
> > +}
> > +
> > +void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
> > +                             const struct iovec *iov, int iovcnt)
> > +{
> > +    NetEvent *event;
> > +    int i;
> > +
> > +    event = g_new(NetEvent, 1);
> > +    event->flags = flags;
> > +    event->data = g_malloc(iov_size(iov, iovcnt));
> > +    event->size = 0;
> > +    event->id = rns->id;
> > +
> > +    for (i = 0; i < iovcnt; i++) {
> > +        size_t len = iov[i].iov_len;
> > +
> > +        memcpy(event->data + event->size, iov[i].iov_base, len);
> > +        event->size += len;
> > +    }
> 
> You can use iov_to_buf() instead.
> 
> > +
> > +    replay_add_event(REPLAY_ASYNC_EVENT_NET, event, NULL, 0);
> > +}
> > +
> > +void replay_event_net_run(void *opaque)
> > +{
> > +    NetEvent *event = opaque;
> > +    struct iovec iov = {
> > +        .iov_base = (void *)event->data,
> > +        .iov_len = event->size
> > +    };
> > +
> > +    assert(event->id < network_filters_count);
> > +
> > +    qemu_netfilter_pass_to_next(network_filters[event->id]->netdev,
> > +        event->flags, &iov, 1, network_filters[event->id]);
> > +
> > +    g_free(event->data);
> > +    g_free(event);
> > +}
> > +
> > +void replay_event_net_save(void *opaque)
> > +{
> > +    NetEvent *event = opaque;
> > +
> > +    replay_put_byte(event->id);
> > +    replay_put_dword(event->flags);
> > +    replay_put_array(event->data, event->size);
> > +}
> > +
> > +void *replay_event_net_load(void)
> > +{
> > +    NetEvent *event = g_new(NetEvent, 1);
> > +
> > +    event->id = replay_get_byte();
> > +    event->flags = replay_get_dword();
> > +    replay_get_array_alloc(&event->data, &event->size);
> > +
> > +    return event;
> > +}
> > diff --git a/replay/replay.c b/replay/replay.c
> > index 167fd29..e040f6f 100644
> > --- a/replay/replay.c
> > +++ b/replay/replay.c
> > @@ -21,7 +21,7 @@
> >
> >   /* Current version of the replay mechanism.
> >      Increase it when file format changes. */
> > -#define REPLAY_VERSION              0xe02004
> > +#define REPLAY_VERSION              0xe02005
> >   /* Size of replay log header */
> >   #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
> >
> > diff --git a/vl.c b/vl.c
> > index fca0487..fd7f17e 100644
> > --- a/vl.c
> > +++ b/vl.c
> > @@ -2807,7 +2807,8 @@ static bool object_create_initial(const char *type)
> >       if (g_str_equal(type, "filter-buffer") ||
> >           g_str_equal(type, "filter-dump") ||
> >           g_str_equal(type, "filter-mirror") ||
> > -        g_str_equal(type, "filter-redirector")) {
> > +        g_str_equal(type, "filter-redirector") ||
> > +        g_str_equal(type, "filter-replay")) {
> >           return false;
> >       }
> >
> >





reply via email to

[Prev in Thread] Current Thread [Next in Thread]