net/dump: Add support for receive_iov function
[qemu/rayw.git] / net / dump.c
blobaa0d45ddc039e3de1c7aac4837534000b71e9d2d
1 /*
2 * QEMU System Emulator
4 * Copyright (c) 2003-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
25 #include "clients.h"
26 #include "qemu-common.h"
27 #include "qemu/error-report.h"
28 #include "qemu/iov.h"
29 #include "qemu/log.h"
30 #include "qemu/timer.h"
31 #include "hub.h"
33 typedef struct DumpState {
34 NetClientState nc;
35 int64_t start_ts;
36 int fd;
37 int pcap_caplen;
38 } DumpState;
40 #define PCAP_MAGIC 0xa1b2c3d4
42 struct 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;
52 struct 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;
61 static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov,
62 int cnt)
64 DumpState *s = DO_UPCAST(DumpState, nc, nc);
65 struct pcap_sf_pkthdr hdr;
66 int64_t ts;
67 int caplen;
68 size_t size = iov_size(iov, cnt);
69 struct iovec dumpiov[cnt + 1];
71 /* Early return in case of previous error. */
72 if (s->fd < 0) {
73 return size;
76 ts = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
77 caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
79 hdr.ts.tv_sec = ts / 1000000 + s->start_ts;
80 hdr.ts.tv_usec = ts % 1000000;
81 hdr.caplen = caplen;
82 hdr.len = size;
84 dumpiov[0].iov_base = &hdr;
85 dumpiov[0].iov_len = sizeof(hdr);
86 cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
88 if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
89 qemu_log("-net dump write error - stop dump\n");
90 close(s->fd);
91 s->fd = -1;
94 return size;
97 static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
99 struct iovec iov = {
100 .iov_base = (void *)buf,
101 .iov_len = size
103 return dump_receive_iov(nc, &iov, 1);
106 static void dump_cleanup(NetClientState *nc)
108 DumpState *s = DO_UPCAST(DumpState, nc, nc);
110 close(s->fd);
113 static NetClientInfo net_dump_info = {
114 .type = NET_CLIENT_OPTIONS_KIND_DUMP,
115 .size = sizeof(DumpState),
116 .receive = dump_receive,
117 .receive_iov = dump_receive_iov,
118 .cleanup = dump_cleanup,
121 static int net_dump_init(NetClientState *peer, const char *device,
122 const char *name, const char *filename, int len,
123 Error **errp)
125 struct pcap_file_hdr hdr;
126 NetClientState *nc;
127 DumpState *s;
128 struct tm tm;
129 int fd;
131 fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
132 if (fd < 0) {
133 error_setg_errno(errp, errno, "-net dump: can't open %s", filename);
134 return -1;
137 hdr.magic = PCAP_MAGIC;
138 hdr.version_major = 2;
139 hdr.version_minor = 4;
140 hdr.thiszone = 0;
141 hdr.sigfigs = 0;
142 hdr.snaplen = len;
143 hdr.linktype = 1;
145 if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
146 error_setg_errno(errp, errno, "-net dump write error");
147 close(fd);
148 return -1;
151 nc = qemu_new_net_client(&net_dump_info, peer, device, name);
153 snprintf(nc->info_str, sizeof(nc->info_str),
154 "dump to %s (len=%d)", filename, len);
156 s = DO_UPCAST(DumpState, nc, nc);
158 s->fd = fd;
159 s->pcap_caplen = len;
161 qemu_get_timedate(&tm, 0);
162 s->start_ts = mktime(&tm);
164 return 0;
167 int net_init_dump(const NetClientOptions *opts, const char *name,
168 NetClientState *peer, Error **errp)
170 int len;
171 const char *file;
172 char def_file[128];
173 const NetdevDumpOptions *dump;
175 assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
176 dump = opts->dump;
178 assert(peer);
180 if (dump->has_file) {
181 file = dump->file;
182 } else {
183 int id;
184 int ret;
186 ret = net_hub_id_for_client(peer, &id);
187 assert(ret == 0); /* peer must be on a hub */
189 snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", id);
190 file = def_file;
193 if (dump->has_len) {
194 if (dump->len > INT_MAX) {
195 error_setg(errp, "invalid length: %"PRIu64, dump->len);
196 return -1;
198 len = dump->len;
199 } else {
200 len = 65536;
203 return net_dump_init(peer, "dump", name, file, len, errp);