diff options
Diffstat (limited to 'replay')
-rw-r--r-- | replay/Makefile.objs | 1 | ||||
-rw-r--r-- | replay/replay-events.c | 11 | ||||
-rw-r--r-- | replay/replay-internal.h | 10 | ||||
-rw-r--r-- | replay/replay-net.c | 102 | ||||
-rw-r--r-- | replay/replay.c | 2 |
5 files changed, 125 insertions, 1 deletions
diff --git a/replay/Makefile.objs b/replay/Makefile.objs index c8ad3ebb89..b2afd4030a 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -5,3 +5,4 @@ common-obj-y += replay-time.o common-obj-y += replay-input.o common-obj-y += replay-char.o common-obj-y += replay-snapshot.o +common-obj-y += replay-net.o diff --git a/replay/replay-events.c b/replay/replay-events.c index c513913671..94a6dcccfc 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 9117e442d0..c26d0795f2 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 }; @@ -161,6 +162,15 @@ 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); + /* VMState-related functions */ /* Registers replay VMState. diff --git a/replay/replay-net.c b/replay/replay-net.c new file mode 100644 index 0000000000..80b7054156 --- /dev/null +++ b/replay/replay-net.c @@ -0,0 +1,102 @@ +/* + * 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)); + 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 = g_new(NetEvent, 1); + event->flags = flags; + event->data = g_malloc(iov_size(iov, iovcnt)); + event->size = iov_size(iov, iovcnt); + event->id = rns->id; + iov_to_buf(iov, iovcnt, 0, event->data, event->size); + + 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 c797aeae8a..7f27cf17b0 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)) |