qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [RFC PATCH 18/22] Network packets record/replay


From: Pavel Dovgaluk
Subject: [Qemu-devel] [RFC PATCH 18/22] Network packets record/replay
Date: Tue, 1 Jul 2014 15:31:03 +0400

These patches implement passing network packets to replay module in
record mode. New virtual network adapter is impelemented to replay the
packets when they are read from the log file.

Signed-off-by: Pavel Dovgalyuk <address@hidden>
---

diff --git a/net/clients.h b/net/clients.h
index 2e8feda..d245a9f 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -49,6 +49,10 @@ int net_init_bridge(const NetClientOptions *opts, const char 
*name,
 
 int net_init_l2tpv3(const NetClientOptions *opts, const char *name,
                     NetClientState *peer);
+                    
+int net_init_replay(const NetClientOptions *opts, const char *name,
+                 NetClientState *peer);
+
 #ifdef CONFIG_VDE
 int net_init_vde(const NetClientOptions *opts, const char *name,
                  NetClientState *peer);
diff --git a/net/dump.c b/net/dump.c
index 9d3a09e..4c8ec1b 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;
@@ -153,6 +154,11 @@ int net_init_dump(const NetClientOptions *opts, const char 
*name,
     char def_file[128];
     const NetdevDumpOptions *dump;
 
+    if (replay_mode == REPLAY_SAVE) {
+        fprintf(stderr, "Interface \"dump\" is not permitted with record\n");
+        exit(1);
+    }
+
     assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
     dump = opts->dump;
 
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 100644
index 0000000..074ee56
--- /dev/null
+++ b/net/net-replay.c
@@ -0,0 +1,56 @@
+#include "net/net.h"
+#include "clients.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.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_SAVE) {
+        printf("Network interface \"replay\" is not permitted with record\n");
+        exit(1);
+    } else if (replay_mode == REPLAY_PLAY) {
+        replay_add_network_client(nc);
+    } else {
+        printf("Network interface \"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 0869c60..ea404f8 100644
--- a/net/net.c
+++ b/net/net.c
@@ -41,6 +41,7 @@
 #include "qapi-visit.h"
 #include "qapi/opts-visitor.h"
 #include "qapi/dealloc-visitor.h"
+#include "replay/replay.h"
 
 /* Net bridge is currently not supported for W32. */
 #if !defined(_WIN32)
@@ -799,6 +800,7 @@ static int (* const 
net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
         [NET_CLIENT_OPTIONS_KIND_NETMAP]    = net_init_netmap,
 #endif
         [NET_CLIENT_OPTIONS_KIND_DUMP]      = net_init_dump,
+        [NET_CLIENT_OPTIONS_KIND_REPLAY]   = net_init_replay,
 #ifdef CONFIG_NET_BRIDGE
         [NET_CLIENT_OPTIONS_KIND_BRIDGE]    = net_init_bridge,
 #endif
@@ -1264,7 +1266,12 @@ 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_PLAY) {
+            qemu_opts_set(net, NULL, "type", "user");
+        }
+        if (replay_mode == REPLAY_PLAY) {
+            qemu_opts_set(net, NULL, "type", "replay");
+        }
 #endif
     }
 
diff --git a/net/slirp.c b/net/slirp.c
index 8fddc03..bb7030d
--- 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_SAVE) {
+        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_PLAY) {
+        printf("Network interface \"user\" is not permitted with replay\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+    
     return 0;
 
 error:
diff --git a/net/socket.c b/net/socket.c
index fb21e20..cfb0dbf
--- 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_SAVE) {
+                    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_SAVE) {
+        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_PLAY) {
+        printf("Network interface \"socket\" is not permitted with replay\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_PLAY) {
+        printf("Network interface \"socket\" is not permitted with replay\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+    
     return s;
 }
 
@@ -549,6 +573,14 @@ static int net_socket_listen_init(NetClientState *peer,
     s->nc.link_down = true;
 
     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
+
+    if (replay_mode == REPLAY_PLAY) {
+        printf("Network interface \"socked\" is not permitted with replay\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+    
     return 0;
 }
 
@@ -599,6 +631,7 @@ static int net_socket_connect_init(NetClientState *peer,
     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
              "socket: connect to %s:%d",
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+
     return 0;
 }
 
@@ -637,8 +670,8 @@ static int net_socket_mcast_init(NetClientState *peer,
     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
              "socket: mcast=%s:%d",
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
-    return 0;
 
+    return 0;
 }
 
 static int net_socket_udp_init(NetClientState *peer,
@@ -688,6 +721,7 @@ static int net_socket_udp_init(NetClientState *peer,
     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
              "socket: udp=%s:%d",
              inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
+
     return 0;
 }
 
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 8aee611..2de43f8 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>
@@ -99,6 +100,7 @@ typedef struct tap_win32_overlapped {
     HANDLE output_queue_semaphore;
     HANDLE free_list_semaphore;
     HANDLE tap_semaphore;
+    HANDLE hThread;
     CRITICAL_SECTION output_queue_cs;
     CRITICAL_SECTION free_list_cs;
     OVERLAPPED read_overlapped;
@@ -625,7 +627,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
 
     *phandle = &tap_overlapped;
 
-    CreateThread(NULL, 0, tap_win32_thread_entry,
+    tap_overlapped.hThread = CreateThread(NULL, 0, tap_win32_thread_entry,
                  (LPVOID)&tap_overlapped, 0, &idThread);
     return 0;
 }
@@ -646,6 +648,8 @@ static void tap_cleanup(NetClientState *nc)
     /* FIXME: need to kill thread and close file handle:
        tap_win32_close(s);
     */
+    TerminateThread(s->handle->hThread, 0);
+    CloseHandle(s->handle->handle);
 }
 
 static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size)
@@ -664,7 +668,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_SAVE) {
+            replay_save_net_packet(&s->nc, buf, size);
+        } else {
+            qemu_send_packet(&s->nc, buf, size);
+        }
         tap_win32_free_buffer(s->handle, buf);
     }
 }
@@ -748,6 +756,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_PLAY) {
+        fprintf(stderr, "Network interface \"tap\" is not permitted with 
replay\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+    
     return 0;
 }
 
diff --git a/net/tap.c b/net/tap.c
index a40f7f0..761e855
--- 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,12 +204,17 @@ 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);
-            break;
-        } else if (size < 0) {
+        if (replay_mode == REPLAY_SAVE) {
+            replay_save_net_packet(&s->nc, buf, size);
             break;
+        } 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;
+            }
         }
     }
 }
@@ -353,6 +359,14 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
     }
     tap_read_poll(s, true);
     s->vhost_net = NULL;
+
+    if (replay_mode == REPLAY_PLAY) {
+        fprintf(stderr, "Using network interface \"tap\" is not permitted with 
replay option\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+
     return s;
 }
 
diff --git a/net/vde.c b/net/vde.c
index 2a619fb..41d48af 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) {
+        printf("Network interface \"vde\" is not permitted with replay\n");
+        exit(1);
+    } else {
+        replay_add_network_client(nc);
+    }
+    
     return 0;
 }
 
diff --git a/qapi-schema.json b/qapi-schema.json
index b11aad2..c5c5082 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2145,6 +2145,15 @@
     '*file': 'str' } }
 
 ##
+# @NetdevReplayOptions
+#
+# Dump network traffic to the log in replay mode.
+#
+##
+{ 'type': 'NetdevReplayOptions',
+  'data': { } }
+
+##
 # @NetdevBridgeOptions
 #
 # Connect a host TAP network interface to a host bridge device.
@@ -2230,6 +2239,7 @@
     'socket':   'NetdevSocketOptions',
     'vde':      'NetdevVdeOptions',
     'dump':     'NetdevDumpOptions',
+    'replay':   'NetdevReplayOptions',
     'bridge':   'NetdevBridgeOptions',
     'hubport':  'NetdevHubPortOptions',
     'netmap':   'NetdevNetmapOptions',

diff --git a/slirp/slirp.c b/slirp/slirp.c
index 35f819a..f6b1440 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,10 @@ 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);
+    if (replay_mode == REPLAY_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]