qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [RFC PATCH v3 42/49] replay: network packets record/replay


From: Pavel Dovgalyuk
Subject: [Qemu-devel] [RFC PATCH v3 42/49] replay: network packets record/replay
Date: Thu, 31 Jul 2014 16:57:25 +0400
User-agent: StGit/0.16

This patch implements passing network packets to replay module in
record mode. New virtual network adapter is implemented to replay the
packets when they are read from the log file.

Signed-off-by: Pavel Dovgalyuk <address@hidden>
---
 net/Makefile.objs        |    1 
 net/clients.h            |    3 +
 net/dump.c               |    6 +
 net/hub.c                |    1 
 net/net-replay.c         |   68 ++++++++++++++++
 net/net.c                |    7 +-
 net/slirp.c              |   14 +++
 net/socket.c             |   35 ++++++++
 net/tap-win32.c          |   14 +++
 net/tap.c                |   24 +++++-
 net/vde.c                |   14 +++
 qapi-schema.json         |   13 +++
 replay/Makefile.objs     |    1 
 replay/replay-events.c   |   17 ++++
 replay/replay-internal.h |   21 +++++
 replay/replay-net.c      |  191 ++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay.c          |    5 +
 replay/replay.h          |    9 ++
 slirp/slirp.c            |    9 ++
 19 files changed, 439 insertions(+), 14 deletions(-)
 create mode 100755 net/net-replay.c
 create mode 100755 replay/replay-net.c

diff --git a/net/Makefile.objs b/net/Makefile.objs
index ec19cb3..def44e3 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -2,6 +2,7 @@ common-obj-y = net.o queue.o checksum.o util.o hub.o
 common-obj-y += socket.o
 common-obj-y += dump.o
 common-obj-y += eth.o
+common-obj-y += net-replay.o
 common-obj-$(CONFIG_L2TPV3) += l2tpv3.o
 common-obj-$(CONFIG_POSIX) += tap.o vhost-user.o
 common-obj-$(CONFIG_LINUX) += tap-linux.o
diff --git a/net/clients.h b/net/clients.h
index 2e8feda..f75f43b 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -62,4 +62,7 @@ int net_init_netmap(const NetClientOptions *opts, const char 
*name,
 int net_init_vhost_user(const NetClientOptions *opts, const char *name,
                         NetClientState *peer);
 
+int net_init_replay(const NetClientOptions *opts, const char *name,
+                    NetClientState *peer);
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/dump.c b/net/dump.c
index 9d3a09e..77e2d3f 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -28,6 +28,7 @@
 #include "qemu/log.h"
 #include "qemu/timer.h"
 #include "hub.h"
+#include "replay/replay.h"
 
 typedef struct DumpState {
     NetClientState nc;
@@ -158,6 +159,11 @@ int net_init_dump(const NetClientOptions *opts, const char 
*name,
 
     assert(peer);
 
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        fprintf(stderr, "-net dump is not permitted in replay mode\n");
+        exit(1);
+    }
+
     if (dump->has_file) {
         file = dump->file;
     } else {
diff --git a/net/hub.c b/net/hub.c
index 7e0f2d6..91fdfb6 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -323,6 +323,7 @@ void net_hub_check_clients(void)
             case NET_CLIENT_OPTIONS_KIND_SOCKET:
             case NET_CLIENT_OPTIONS_KIND_VDE:
             case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+            case NET_CLIENT_OPTIONS_KIND_REPLAY:
                 has_host_dev = 1;
                 break;
             default:
diff --git a/net/net-replay.c b/net/net-replay.c
new file mode 100755
index 0000000..01da9ef
--- /dev/null
+++ b/net/net-replay.c
@@ -0,0 +1,68 @@
+/*
+ * net-replay.c
+ *
+ * Copyright (c) 2010-2014 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 "net/net.h"
+#include "clients.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "replay/replay.h"
+
+typedef struct NetReplayState {
+    NetClientState nc;
+} NetReplayState;
+
+static ssize_t net_replay_receive(NetClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    return size;
+}
+
+static void net_replay_cleanup(NetClientState *nc)
+{
+}
+
+static NetClientInfo net_replay_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_REPLAY,
+    .size = sizeof(NetReplayState),
+    .receive = net_replay_receive,
+    .cleanup = net_replay_cleanup,
+};
+
+static int net_replay_init(NetClientState *vlan, const char *device,
+                         const char *name)
+{
+    NetClientState *nc;
+
+    nc = qemu_new_net_client(&net_replay_info, vlan, device, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str), "replayer");
+
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        fprintf(stderr, "-net replay is not permitted in record mode\n");
+        exit(1);
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_add_network_client(nc);
+    } else {
+        fprintf(stderr, "-net replay is not permitted without replay\n");
+        exit(1);
+    }
+
+    return 0;
+}
+
+int net_init_replay(const NetClientOptions *opts, const char *name,
+                    NetClientState *peer)
+{
+    assert(peer);
+    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_REPLAY);
+
+    return net_replay_init(peer, "replay", name);
+}
diff --git a/net/net.c b/net/net.c
index 6d930ea..e837341 100644
--- a/net/net.c
+++ b/net/net.c
@@ -809,6 +809,7 @@ static int (* const 
net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
 #ifdef CONFIG_L2TPV3
         [NET_CLIENT_OPTIONS_KIND_L2TPV3]    = net_init_l2tpv3,
 #endif
+        [NET_CLIENT_OPTIONS_KIND_REPLAY]    = net_init_replay,
 };
 
 
@@ -1264,7 +1265,11 @@ int net_init_clients(void)
         /* if no clients, we use a default config */
         qemu_opts_set(net, NULL, "type", "nic");
 #ifdef CONFIG_SLIRP
-        qemu_opts_set(net, NULL, "type", "user");
+        if (replay_mode != REPLAY_MODE_PLAY) {
+            qemu_opts_set(net, NULL, "type", "user");
+        } else {
+            qemu_opts_set(net, NULL, "type", "replay");
+        }
 #endif
     }
 
diff --git a/net/slirp.c b/net/slirp.c
index 647039e..95abae2 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -36,6 +36,7 @@
 #include "qemu/sockets.h"
 #include "slirp/libslirp.h"
 #include "sysemu/char.h"
+#include "replay/replay.h"
 
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
 {
@@ -103,7 +104,11 @@ void slirp_output(void *opaque, const uint8_t *pkt, int 
pkt_len)
 {
     SlirpState *s = opaque;
 
-    qemu_send_packet(&s->nc, pkt, pkt_len);
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_net_packet(&s->nc, pkt, pkt_len);
+    } else {
+        qemu_send_packet(&s->nc, pkt, pkt_len);
+    }
 }
 
 static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, 
size_t size)
@@ -267,6 +272,13 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
     }
 #endif
 
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        fprintf(stderr, "-net user is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return 0;
 
 error:
diff --git a/net/socket.c b/net/socket.c
index fb21e20..5070d2a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -32,6 +32,7 @@
 #include "qemu/sockets.h"
 #include "qemu/iov.h"
 #include "qemu/main-loop.h"
+#include "replay/replay.h"
 
 typedef struct NetSocketState {
     NetClientState nc;
@@ -211,7 +212,11 @@ static void net_socket_send(void *opaque)
             buf += l;
             size -= l;
             if (s->index >= s->packet_len) {
-                qemu_send_packet(&s->nc, s->buf, s->packet_len);
+                if (replay_mode == REPLAY_MODE_RECORD) {
+                    replay_save_net_packet(&s->nc, s->buf, s->packet_len);
+                } else {
+                    qemu_send_packet(&s->nc, s->buf, s->packet_len);
+                }
                 s->index = 0;
                 s->state = 0;
             }
@@ -234,7 +239,11 @@ static void net_socket_send_dgram(void *opaque)
         net_socket_write_poll(s, false);
         return;
     }
-    qemu_send_packet(&s->nc, s->buf, size);
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_net_packet(&s->nc, s->buf, size);
+    } else {
+        qemu_send_packet(&s->nc, s->buf, size);
+    }
 }
 
 static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct 
in_addr *localaddr)
@@ -406,6 +415,13 @@ static NetSocketState 
*net_socket_fd_init_dgram(NetClientState *peer,
         s->dgram_dst = saddr;
     }
 
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        fprintf(stderr, "-net socket is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return s;
 
 err:
@@ -452,6 +468,14 @@ static NetSocketState 
*net_socket_fd_init_stream(NetClientState *peer,
     } else {
         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
     }
+
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        printf("-net socket is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return s;
 }
 
@@ -548,6 +572,13 @@ static int net_socket_listen_init(NetClientState *peer,
     s->listen_fd = fd;
     s->nc.link_down = true;
 
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        printf("-net socket is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
     return 0;
 }
diff --git a/net/tap-win32.c b/net/tap-win32.c
index efd1c75..c0b8339 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -34,6 +34,7 @@
 #include "net/tap.h"            /* tap_has_ufo, ... */
 #include "sysemu/sysemu.h"
 #include "qemu/error-report.h"
+#include "replay/replay.h"
 #include <stdio.h>
 #include <windows.h>
 #include <winioctl.h>
@@ -665,7 +666,11 @@ static void tap_win32_send(void *opaque)
 
     size = tap_win32_read(s->handle, &buf, max_size);
     if (size > 0) {
-        qemu_send_packet(&s->nc, buf, size);
+        if (replay_mode == REPLAY_MODE_RECORD) {
+            replay_save_net_packet(&s->nc, buf, size);
+        } else {
+            qemu_send_packet(&s->nc, buf, size);
+        }
         tap_win32_free_buffer(s->handle, buf);
     }
 }
@@ -749,6 +754,13 @@ static int tap_win32_init(NetClientState *peer, const char 
*model,
 
     qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
 
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        fprintf(stderr, "-net tap is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return 0;
 }
 
diff --git a/net/tap.c b/net/tap.c
index a40f7f0..16380fb 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -39,6 +39,7 @@
 #include "sysemu/sysemu.h"
 #include "qemu-common.h"
 #include "qemu/error-report.h"
+#include "replay/replay.h"
 
 #include "net/tap.h"
 
@@ -203,11 +204,18 @@ static void tap_send(void *opaque)
             size -= s->host_vnet_hdr_len;
         }
 
-        size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
-        if (size == 0) {
-            tap_read_poll(s, false);
+        if (replay_mode == REPLAY_MODE_RECORD) {
+            replay_save_net_packet(&s->nc, buf, size);
             break;
-        } else if (size < 0) {
+        } else {
+            size = qemu_send_packet_async(&s->nc, buf, size,
+                                          tap_send_completed);
+            if (size == 0) {
+                tap_read_poll(s, false);
+                break;
+            } else if (size < 0) {
+                break;
+            }
             break;
         }
     }
@@ -353,6 +361,14 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
     }
     tap_read_poll(s, true);
     s->vhost_net = NULL;
+
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        fprintf(stderr, "-net tap is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return s;
 }
 
diff --git a/net/vde.c b/net/vde.c
index 2a619fb..ca34c4b 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -30,6 +30,7 @@
 #include "qemu-common.h"
 #include "qemu/option.h"
 #include "qemu/main-loop.h"
+#include "replay/replay.h"
 
 typedef struct VDEState {
     NetClientState nc;
@@ -44,7 +45,11 @@ static void vde_to_qemu(void *opaque)
 
     size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
     if (size > 0) {
-        qemu_send_packet(&s->nc, buf, size);
+        if (replay_mode == REPLAY_SAVE) {
+            replay_save_net_packet(&s->nc, buf, size);
+        } else {
+            qemu_send_packet(&s->nc, buf, size);
+        }
     }
 }
 
@@ -106,6 +111,13 @@ static int net_vde_init(NetClientState *peer, const char 
*model,
 
     qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
 
+    if (replay_mode == REPLAY_PLAY) {
+        fprintf(stderr, "-net vde is not permitted in replay mode\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return 0;
 }
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 2de14c4..3f2dab4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2211,6 +2211,16 @@
     '*vhostforce':    'bool' } }
 
 ##
+# @NetdevReplayOptions
+#
+# Reads network traffic from the log in replay mode.
+#
+# Since: 2.2
+##
+{ 'type': 'NetdevReplayOptions',
+  'data': { } }
+
+##
 # @NetClientOptions
 #
 # A discriminated record of network device traits.
@@ -2233,7 +2243,8 @@
     'bridge':   'NetdevBridgeOptions',
     'hubport':  'NetdevHubPortOptions',
     'netmap':   'NetdevNetmapOptions',
-    'vhost-user': 'NetdevVhostUserOptions' } }
+    'vhost-user': 'NetdevVhostUserOptions',
+    'replay':   'NetdevReplayOptions' } }
 
 ##
 # @NetLegacy
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index 59c3602..ad262d0 100755
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -4,3 +4,4 @@ obj-y += replay-events.o
 obj-y += replay-time.o
 obj-y += replay-icount.o
 obj-y += replay-input.o
+obj-y += replay-net.o
diff --git a/replay/replay-events.c b/replay/replay-events.c
index f8e58ea..9dacb52 100755
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -53,6 +53,9 @@ static void replay_run_event(Event *event)
     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
         qemu_input_event_sync_impl();
         break;
+    case REPLAY_ASYNC_EVENT_NETWORK:
+        replay_net_send_packet(event->opaque);
+        break;
     default:
         fprintf(stderr, "Replay: invalid async event ID (%d) in the queue\n",
                 event->event_kind);
@@ -180,6 +183,9 @@ void replay_save_events(int opt)
             case REPLAY_ASYNC_EVENT_INPUT:
                 replay_save_input_event(event->opaque);
                 break;
+            case REPLAY_ASYNC_EVENT_NETWORK:
+                replay_net_save_packet(event->opaque);
+                break;
             }
         }
 
@@ -240,6 +246,17 @@ void replay_read_events(int opt)
             replay_fetch_data_kind();
             /* continue with the next event */
             continue;
+        case REPLAY_ASYNC_EVENT_NETWORK:
+            e.opaque = replay_net_read_packet();
+            e.event_kind = read_event_kind;
+            replay_run_event(&e);
+
+            replay_has_unread_data = 0;
+            read_event_kind = -1;
+            read_opt = -1;
+            replay_fetch_data_kind();
+            /* continue with the next event */
+            continue;
         default:
             fprintf(stderr, "Unknown ID %d of replay event\n", 
read_event_kind);
             exit(1);
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 5d0aa71..eb469f0 100755
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -51,7 +51,8 @@
 #define REPLAY_ASYNC_EVENT_THREAD      1
 #define REPLAY_ASYNC_EVENT_INPUT       2
 #define REPLAY_ASYNC_EVENT_INPUT_SYNC  3
-#define REPLAY_ASYNC_COUNT             4
+#define REPLAY_ASYNC_EVENT_NETWORK     4
+#define REPLAY_ASYNC_COUNT             5
 
 typedef struct ReplayState {
     /*! Cached clock values. */
@@ -150,4 +151,22 @@ void replay_save_input_event(InputEvent *evt);
 /*! Reads input event from the log */
 InputEvent *replay_read_input_event(void);
 
+/* Network events */
+
+/*! Initializes network data structures. */
+void replay_net_init(void);
+/*! Cleans up network data structures. */
+void replay_net_free(void);
+/*! Reads packets offsets array from the log. */
+void replay_net_read_packets_data(void);
+/*! Writes packets offsets array to the log. */
+void replay_net_write_packets_data(void);
+/*! Saves network packet into the log. */
+void replay_net_save_packet(void *opaque);
+/*! Reads network packet from the log. */
+void *replay_net_read_packet(void);
+/*! Called to send packet that was read or received from external input
+    to the net queue. */
+void replay_net_send_packet(void *opaque);
+
 #endif
diff --git a/replay/replay-net.c b/replay/replay-net.c
new file mode 100755
index 0000000..0dc891a
--- /dev/null
+++ b/replay/replay-net.c
@@ -0,0 +1,191 @@
+/*
+ * replay-net.c
+ *
+ * Copyright (c) 2010-2014 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-common.h"
+#include "exec/cpu-common.h"
+#include "net/net.h"
+#include "replay.h"
+#include "replay-internal.h"
+
+/* limited by Ethernet frame size */
+#define MAX_NET_PACKET_SIZE             1560
+
+/* Network data */
+NetClientState **vlan_states = NULL;
+size_t vlan_states_count = 0;
+size_t vlan_states_capacity = 0;
+
+/* Structure for storing information about the network packet */
+typedef struct {
+    /* Offset in the replay log file where packet is saved. */
+    uint64_t file_offset;
+    /* Number of step when packet came. */
+    uint64_t step;
+} QEMU_PACKED NetPacketInfo;
+
+typedef struct NetPacketQueue {
+    /* ID of the packet */
+    uint64_t id;
+    /* ID of the network client */
+    int32_t nc_id;
+    size_t size;
+    uint8_t buf[MAX_NET_PACKET_SIZE];
+    uint64_t offset;
+} NetPacketQueue;
+
+/* Network packets count. */
+static uint64_t net_packets_count;
+/* Capacity of the array for packets parameters. */
+static uint64_t net_packets_capacity;
+/* Array for storing network packets parameters. */
+static NetPacketInfo *net_packets;
+
+
+void replay_net_init(void)
+{
+    net_packets_count = 0;
+}
+
+void replay_net_read_packets_data(void)
+{
+    net_packets_count = replay_get_qword();
+    net_packets_capacity = net_packets_count;
+    if (net_packets_count) {
+        net_packets = (NetPacketInfo *)g_malloc(sizeof(NetPacketInfo)
+                                                * net_packets_count);
+        if (fread(net_packets, sizeof(NetPacketInfo),
+                  net_packets_count, replay_file) != net_packets_count) {
+            fprintf(stderr, "Internal error in 
replay_net_read_packets_data\n");
+            exit(1);
+        }
+    }
+}
+
+void replay_net_write_packets_data(void)
+{
+    replay_put_qword(net_packets_count);
+    if (net_packets && net_packets_count) {
+        fwrite(net_packets, sizeof(NetPacketInfo),
+               net_packets_count, replay_file);
+    }
+}
+
+void replay_add_network_client(NetClientState *nc)
+{
+    if (vlan_states_count == 0) {
+        vlan_states = (NetClientState **)g_malloc(sizeof(*vlan_states));
+        vlan_states_count = 0;
+        vlan_states_capacity = 1;
+    } else if (vlan_states_count == vlan_states_capacity) {
+        vlan_states_capacity *= 2;
+        vlan_states = (NetClientState **)g_realloc(vlan_states,
+                                                   sizeof(*vlan_states)
+                                                   * vlan_states_capacity);
+    }
+
+    vlan_states[vlan_states_count++] = nc;
+}
+
+void replay_net_free(void)
+{
+    if (vlan_states) {
+        g_free(vlan_states);
+        vlan_states = NULL;
+    }
+}
+
+void replay_save_net_packet(struct NetClientState *nc, const uint8_t *buf,
+                            size_t size)
+{
+    if (replay_file) {
+        if (net_packets_capacity == net_packets_count) {
+            if (net_packets_capacity == 0) {
+                net_packets_capacity = 1;
+            } else {
+                net_packets_capacity *= 2;
+            }
+            net_packets = (NetPacketInfo *)g_realloc(net_packets,
+                                                     net_packets_capacity
+                                                     * sizeof(NetPacketInfo));
+        }
+
+        /* add packet processing event to the queue */
+        NetPacketQueue *p = (NetPacketQueue *)
+                                g_malloc0(sizeof(NetPacketQueue));
+        p->id = net_packets_count;
+        p->size = size;
+        if (net_hub_id_for_client(nc, &p->nc_id) < 0) {
+            fprintf(stderr, "Replay: Cannot determine net client id\n");
+            exit(1);
+        }
+        memcpy(p->buf, buf, size);
+        replay_add_event(REPLAY_ASYNC_EVENT_NETWORK, p);
+
+        ++net_packets_count;
+    }
+}
+
+static NetClientState *replay_net_find_vlan(NetPacketQueue *packet)
+{
+    int i;
+    for (i = 0 ; i < vlan_states_count ; ++i) {
+        int id = 0;
+        if (net_hub_id_for_client(vlan_states[i], &id) < 0) {
+            fprintf(stderr, "Replay: Cannot determine net client id\n");
+            exit(1);
+        }
+        if (id == packet->nc_id) {
+            return vlan_states[i];
+        }
+    }
+
+    fprintf(stderr, "Replay: please specify -net replay command-line 
option\n");
+    exit(1);
+
+    return NULL;
+}
+
+void replay_net_send_packet(void *opaque)
+{
+    NetPacketQueue *packet = (NetPacketQueue *)opaque;
+    NetClientState *vlan_state = replay_net_find_vlan(packet);
+
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        net_packets[packet->id].file_offset = packet->offset;
+        net_packets[packet->id].step = replay_get_current_step();
+
+        qemu_send_packet(vlan_state, packet->buf, packet->size);
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        qemu_send_packet(vlan_state, packet->buf, packet->size);
+    }
+
+    g_free(packet);
+}
+
+void replay_net_save_packet(void *opaque)
+{
+    NetPacketQueue *p = (NetPacketQueue *)opaque;
+    p->offset = ftello64(replay_file);
+    replay_put_qword(p->id);
+    replay_put_dword(p->nc_id);
+    replay_put_array(p->buf, p->size);
+}
+
+void *replay_net_read_packet(void)
+{
+    NetPacketQueue *p = g_malloc0(sizeof(NetPacketQueue));;
+    p->id = replay_get_qword();
+    p->nc_id = replay_get_dword();
+    replay_get_array(p->buf, &p->size);
+    replay_check_error();
+
+    return p;
+}
diff --git a/replay/replay.c b/replay/replay.c
index a9268db..bcd8864 100755
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -462,6 +462,8 @@ static void replay_enable(const char *fname, int mode)
     replay_state.current_step = 0;
     current_saved_state = 0;
 
+    replay_net_init();
+
     /* skip file header for RECORD and check it for PLAY */
     if (replay_mode == REPLAY_MODE_RECORD) {
         fseek(replay_file, HEADER_SIZE, SEEK_SET);
@@ -482,6 +484,7 @@ static void replay_enable(const char *fname, int mode)
             fread(saved_states, sizeof(SavedStateInfo), saved_states_count,
                   replay_file);
         }
+        replay_net_read_packets_data();
         /* go to the beginning */
         fseek(replay_file, 12, SEEK_SET);
     }
@@ -565,6 +568,7 @@ void replay_finish(void)
                 fwrite(saved_states, sizeof(SavedStateInfo),
                        saved_states_count, replay_file);
             }
+            replay_net_write_packets_data();
 
             /* write header */
             fseek(replay_file, 0, SEEK_SET);
@@ -593,5 +597,6 @@ void replay_finish(void)
         replay_image_suffix = NULL;
     }
 
+    replay_net_free();
     replay_finish_events();
 }
diff --git a/replay/replay.h b/replay/replay.h
index 31c02ba..419dec9 100755
--- a/replay/replay.h
+++ b/replay/replay.h
@@ -19,6 +19,7 @@
 
 struct QemuOpts;
 struct InputEvent;
+struct NetClientState;
 
 /* replay clock kinds */
 /* rdtsc */
@@ -119,4 +120,12 @@ void replay_init_icount(void);
 int64_t replay_get_icount(void);
 void replay_clock_warp(void);
 
+/* Network */
+
+/*! Registers net client in the replay module. */
+void replay_add_network_client(struct NetClientState *nc);
+/*! Saves incoming network packet in the replay log. */
+void replay_save_net_packet(struct NetClientState *nc, const uint8_t *buf,
+                            size_t size);
+
 #endif
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 35f819a..877e1b2 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -26,6 +26,7 @@
 #include "sysemu/char.h"
 #include "slirp.h"
 #include "hw/hw.h"
+#include "replay/replay.h"
 
 /* host loopback address */
 struct in_addr loopback_addr;
@@ -234,8 +235,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
 
     slirp->opaque = opaque;
 
-    register_savevm(NULL, "slirp", 0, 3,
-                    slirp_state_save, slirp_state_load, slirp);
+    /* Do not save slirp state in record mode, because slirp device
+       will not be created in replay mode */
+    if (replay_mode == REPLAY_MODE_NONE) {
+        register_savevm(NULL, "slirp", 0, 3,
+                        slirp_state_save, slirp_state_load, slirp);
+    }
 
     QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
 




reply via email to

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