]> git.proxmox.com Git - mirror_qemu.git/blame - net/dump.c
net/dump: Rework net-dump init functions
[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 {
4e68f7a0 34 NetClientState nc;
0fa29915 35 int64_t start_ts;
1abecf77
MM
36 int fd;
37 int pcap_caplen;
38} DumpState;
39
40#define PCAP_MAGIC 0xa1b2c3d4
41
42struct pcap_file_hdr {
43 uint32_t magic;
44 uint16_t version_major;
45 uint16_t version_minor;
46 int32_t thiszone;
47 uint32_t sigfigs;
48 uint32_t snaplen;
49 uint32_t linktype;
50};
51
52struct pcap_sf_pkthdr {
53 struct {
54 int32_t tv_sec;
55 int32_t tv_usec;
56 } ts;
57 uint32_t caplen;
58 uint32_t len;
59};
60
43192fcc
TH
61static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov,
62 int cnt)
1abecf77 63{
731d5856 64 DumpState *s = DO_UPCAST(DumpState, nc, nc);
1abecf77
MM
65 struct pcap_sf_pkthdr hdr;
66 int64_t ts;
67 int caplen;
43192fcc
TH
68 size_t size = iov_size(iov, cnt);
69 struct iovec dumpiov[cnt + 1];
1abecf77
MM
70
71 /* Early return in case of previous error. */
72 if (s->fd < 0) {
73 return size;
74 }
75
ab60b748 76 ts = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
1abecf77
MM
77 caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
78
0fa29915 79 hdr.ts.tv_sec = ts / 1000000 + s->start_ts;
1abecf77
MM
80 hdr.ts.tv_usec = ts % 1000000;
81 hdr.caplen = caplen;
82 hdr.len = size;
43192fcc
TH
83
84 dumpiov[0].iov_base = &hdr;
85 dumpiov[0].iov_len = sizeof(hdr);
86 cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
87
88 if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
1abecf77
MM
89 qemu_log("-net dump write error - stop dump\n");
90 close(s->fd);
91 s->fd = -1;
92 }
93
94 return size;
95}
96
43192fcc
TH
97static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
98{
99 struct iovec iov = {
100 .iov_base = (void *)buf,
101 .iov_len = size
102 };
103 return dump_receive_iov(nc, &iov, 1);
104}
105
4e68f7a0 106static void dump_cleanup(NetClientState *nc)
1abecf77 107{
731d5856 108 DumpState *s = DO_UPCAST(DumpState, nc, nc);
1abecf77
MM
109
110 close(s->fd);
1abecf77
MM
111}
112
731d5856 113static NetClientInfo net_dump_info = {
2be64a68 114 .type = NET_CLIENT_OPTIONS_KIND_DUMP,
731d5856
MM
115 .size = sizeof(DumpState),
116 .receive = dump_receive,
43192fcc 117 .receive_iov = dump_receive_iov,
731d5856
MM
118 .cleanup = dump_cleanup,
119};
120
7bc3074c
TH
121static int net_dump_state_init(DumpState *s, const char *filename,
122 int len, Error **errp)
1abecf77
MM
123{
124 struct pcap_file_hdr hdr;
0fa29915 125 struct tm tm;
731d5856 126 int fd;
1abecf77 127
6514ed52 128 fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
731d5856 129 if (fd < 0) {
3791f83c 130 error_setg_errno(errp, errno, "-net dump: can't open %s", filename);
1abecf77
MM
131 return -1;
132 }
133
1abecf77
MM
134 hdr.magic = PCAP_MAGIC;
135 hdr.version_major = 2;
136 hdr.version_minor = 4;
137 hdr.thiszone = 0;
138 hdr.sigfigs = 0;
731d5856 139 hdr.snaplen = len;
1abecf77
MM
140 hdr.linktype = 1;
141
731d5856 142 if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
3791f83c 143 error_setg_errno(errp, errno, "-net dump write error");
731d5856 144 close(fd);
1abecf77
MM
145 return -1;
146 }
147
731d5856
MM
148 s->fd = fd;
149 s->pcap_caplen = len;
150
0fa29915
HP
151 qemu_get_timedate(&tm, 0);
152 s->start_ts = mktime(&tm);
153
1abecf77
MM
154 return 0;
155}
156
1a0c0958 157int net_init_dump(const NetClientOptions *opts, const char *name,
a30ecde6 158 NetClientState *peer, Error **errp)
1abecf77 159{
7bc3074c 160 int len, rc;
1abecf77
MM
161 const char *file;
162 char def_file[128];
848040d1 163 const NetdevDumpOptions *dump;
7bc3074c 164 NetClientState *nc;
848040d1
LE
165
166 assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
167 dump = opts->dump;
1abecf77 168
d33d93b2 169 assert(peer);
1abecf77 170
848040d1
LE
171 if (dump->has_file) {
172 file = dump->file;
173 } else {
d33d93b2
SH
174 int id;
175 int ret;
176
177 ret = net_hub_id_for_client(peer, &id);
178 assert(ret == 0); /* peer must be on a hub */
179
180 snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", id);
1abecf77
MM
181 file = def_file;
182 }
183
848040d1
LE
184 if (dump->has_len) {
185 if (dump->len > INT_MAX) {
3791f83c 186 error_setg(errp, "invalid length: %"PRIu64, dump->len);
848040d1
LE
187 return -1;
188 }
189 len = dump->len;
190 } else {
191 len = 65536;
192 }
1abecf77 193
7bc3074c
TH
194 nc = qemu_new_net_client(&net_dump_info, peer, "dump", name);
195 snprintf(nc->info_str, sizeof(nc->info_str),
196 "dump to %s (len=%d)", file, len);
197
198 rc = net_dump_state_init(DO_UPCAST(DumpState, nc, nc), file, len, errp);
199 if (rc) {
200 qemu_del_net_client(nc);
201 }
202 return rc;
1abecf77 203}