]> git.proxmox.com Git - mirror_qemu.git/blame - net/dump.c
net/dump: Separate the NetClientState from the DumpState
[mirror_qemu.git] / net / dump.c
CommitLineData
1abecf77
MM
1/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
a245fc18 25#include "clients.h"
1abecf77 26#include "qemu-common.h"
1de7afc9 27#include "qemu/error-report.h"
43192fcc 28#include "qemu/iov.h"
1de7afc9
PB
29#include "qemu/log.h"
30#include "qemu/timer.h"
d33d93b2 31#include "hub.h"
1abecf77
MM
32
33typedef struct DumpState {
0fa29915 34 int64_t start_ts;
1abecf77
MM
35 int fd;
36 int pcap_caplen;
37} DumpState;
38
39#define PCAP_MAGIC 0xa1b2c3d4
40
41struct pcap_file_hdr {
42 uint32_t magic;
43 uint16_t version_major;
44 uint16_t version_minor;
45 int32_t thiszone;
46 uint32_t sigfigs;
47 uint32_t snaplen;
48 uint32_t linktype;
49};
50
51struct pcap_sf_pkthdr {
52 struct {
53 int32_t tv_sec;
54 int32_t tv_usec;
55 } ts;
56 uint32_t caplen;
57 uint32_t len;
58};
59
75310e34 60static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt)
1abecf77 61{
1abecf77
MM
62 struct pcap_sf_pkthdr hdr;
63 int64_t ts;
64 int caplen;
43192fcc
TH
65 size_t size = iov_size(iov, cnt);
66 struct iovec dumpiov[cnt + 1];
1abecf77
MM
67
68 /* Early return in case of previous error. */
69 if (s->fd < 0) {
70 return size;
71 }
72
ab60b748 73 ts = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
1abecf77
MM
74 caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
75
0fa29915 76 hdr.ts.tv_sec = ts / 1000000 + s->start_ts;
1abecf77
MM
77 hdr.ts.tv_usec = ts % 1000000;
78 hdr.caplen = caplen;
79 hdr.len = size;
43192fcc
TH
80
81 dumpiov[0].iov_base = &hdr;
82 dumpiov[0].iov_len = sizeof(hdr);
83 cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
84
85 if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
1abecf77
MM
86 qemu_log("-net dump write error - stop dump\n");
87 close(s->fd);
88 s->fd = -1;
89 }
90
91 return size;
92}
93
75310e34 94static void dump_cleanup(DumpState *s)
1abecf77 95{
1abecf77 96 close(s->fd);
75310e34 97 s->fd = -1;
1abecf77
MM
98}
99
7bc3074c
TH
100static int net_dump_state_init(DumpState *s, const char *filename,
101 int len, Error **errp)
1abecf77
MM
102{
103 struct pcap_file_hdr hdr;
0fa29915 104 struct tm tm;
731d5856 105 int fd;
1abecf77 106
6514ed52 107 fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
731d5856 108 if (fd < 0) {
3791f83c 109 error_setg_errno(errp, errno, "-net dump: can't open %s", filename);
1abecf77
MM
110 return -1;
111 }
112
1abecf77
MM
113 hdr.magic = PCAP_MAGIC;
114 hdr.version_major = 2;
115 hdr.version_minor = 4;
116 hdr.thiszone = 0;
117 hdr.sigfigs = 0;
731d5856 118 hdr.snaplen = len;
1abecf77
MM
119 hdr.linktype = 1;
120
731d5856 121 if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
3791f83c 122 error_setg_errno(errp, errno, "-net dump write error");
731d5856 123 close(fd);
1abecf77
MM
124 return -1;
125 }
126
731d5856
MM
127 s->fd = fd;
128 s->pcap_caplen = len;
129
0fa29915
HP
130 qemu_get_timedate(&tm, 0);
131 s->start_ts = mktime(&tm);
132
1abecf77
MM
133 return 0;
134}
135
75310e34
TH
136/* Dumping via VLAN netclient */
137
138struct DumpNetClient {
139 NetClientState nc;
140 DumpState ds;
141};
142typedef struct DumpNetClient DumpNetClient;
143
144static ssize_t dumpclient_receive(NetClientState *nc, const uint8_t *buf,
145 size_t size)
146{
147 DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
148 struct iovec iov = {
149 .iov_base = (void *)buf,
150 .iov_len = size
151 };
152
153 return dump_receive_iov(&dc->ds, &iov, 1);
154}
155
156static ssize_t dumpclient_receive_iov(NetClientState *nc,
157 const struct iovec *iov, int cnt)
158{
159 DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
160
161 return dump_receive_iov(&dc->ds, iov, cnt);
162}
163
164static void dumpclient_cleanup(NetClientState *nc)
165{
166 DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
167
168 dump_cleanup(&dc->ds);
169}
170
171static NetClientInfo net_dump_info = {
172 .type = NET_CLIENT_OPTIONS_KIND_DUMP,
173 .size = sizeof(DumpNetClient),
174 .receive = dumpclient_receive,
175 .receive_iov = dumpclient_receive_iov,
176 .cleanup = dumpclient_cleanup,
177};
178
1a0c0958 179int net_init_dump(const NetClientOptions *opts, const char *name,
a30ecde6 180 NetClientState *peer, Error **errp)
1abecf77 181{
7bc3074c 182 int len, rc;
1abecf77
MM
183 const char *file;
184 char def_file[128];
848040d1 185 const NetdevDumpOptions *dump;
7bc3074c 186 NetClientState *nc;
75310e34 187 DumpNetClient *dnc;
848040d1
LE
188
189 assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
190 dump = opts->dump;
1abecf77 191
d33d93b2 192 assert(peer);
1abecf77 193
848040d1
LE
194 if (dump->has_file) {
195 file = dump->file;
196 } else {
d33d93b2
SH
197 int id;
198 int ret;
199
200 ret = net_hub_id_for_client(peer, &id);
201 assert(ret == 0); /* peer must be on a hub */
202
203 snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", id);
1abecf77
MM
204 file = def_file;
205 }
206
848040d1
LE
207 if (dump->has_len) {
208 if (dump->len > INT_MAX) {
3791f83c 209 error_setg(errp, "invalid length: %"PRIu64, dump->len);
848040d1
LE
210 return -1;
211 }
212 len = dump->len;
213 } else {
214 len = 65536;
215 }
1abecf77 216
7bc3074c
TH
217 nc = qemu_new_net_client(&net_dump_info, peer, "dump", name);
218 snprintf(nc->info_str, sizeof(nc->info_str),
219 "dump to %s (len=%d)", file, len);
220
75310e34
TH
221 dnc = DO_UPCAST(DumpNetClient, nc, nc);
222 rc = net_dump_state_init(&dnc->ds, file, len, errp);
7bc3074c
TH
223 if (rc) {
224 qemu_del_net_client(nc);
225 }
226 return rc;
1abecf77 227}