mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 11:23:43 +08:00
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJWLw/wAAoJEO8Ells5jWIRdfsIAIJyeCC5Ad84mj/6/Pc+occN udXPrWGNnGz0QGS8fPHt7bWGGjN6ROAOMBhzRE0R2rve3r3obAbhu2tbt7OMTmAy ATjVKGMdWK08KXszvmaIqo0KfmfF17j4BB4EPNCN35EREGdZ3AWGabfwVWrEfbJZ Qvw7dQ5Vwsw7bwCEQ3ywg65WHtl9S52iIF3RikNmVNC0a1332Cj+DOtybZrEf+Nh NSAJrZK/3BduyCMMpK0M+Wib7l4L5VDtyN2WzvvZAPStEhf9LJ/Emvt49bldAVAj gpui5itoANn4LGP3oye8NyzdINS8hJ1fLUHQQVYS7qeUQRW3JuxPyoSLD2PKsQM= =0Bna -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging # gpg: Signature made Tue 27 Oct 2015 05:47:28 GMT using RSA key ID 398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: net: free the string returned by object_get_canonical_path_component net: make iov_to_buf take right size argument in nc_sendv_compat() net: Remove duplicate data from query-rx-filter on multiqueue net devices vmxnet3: Do not fill stats if device is inactive options: Add documentation for filter-dump net/dump: Provide the dumping facility as a net-filter net/dump: Separate the NetClientState from the DumpState net/dump: Rework net-dump init functions net/dump: Add support for receive_iov function net: cadence_gem: Set initial MAC address Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7e038b94e7
@ -964,6 +964,7 @@ static void gem_reset(DeviceState *d)
|
||||
{
|
||||
int i;
|
||||
CadenceGEMState *s = CADENCE_GEM(d);
|
||||
const uint8_t *a;
|
||||
|
||||
DB_PRINT("\n");
|
||||
|
||||
@ -982,6 +983,11 @@ static void gem_reset(DeviceState *d)
|
||||
s->regs[GEM_DESCONF5] = 0x002f2145;
|
||||
s->regs[GEM_DESCONF6] = 0x00000200;
|
||||
|
||||
/* Set MAC address */
|
||||
a = &s->conf.macaddr.a[0];
|
||||
s->regs[GEM_SPADDR1LO] = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
|
||||
s->regs[GEM_SPADDR1HI] = a[4] | (a[5] << 8);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
s->sar_active[i] = false;
|
||||
}
|
||||
|
@ -1289,6 +1289,10 @@ static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
|
||||
static void vmxnet3_fill_stats(VMXNET3State *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!s->device_active)
|
||||
return;
|
||||
|
||||
for (i = 0; i < s->txq_num; i++) {
|
||||
cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
|
||||
&s->txq_descr[i].txq_stats,
|
||||
|
228
net/dump.c
228
net/dump.c
@ -25,12 +25,13 @@
|
||||
#include "clients.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hub.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "net/filter.h"
|
||||
|
||||
typedef struct DumpState {
|
||||
NetClientState nc;
|
||||
int64_t start_ts;
|
||||
int fd;
|
||||
int pcap_caplen;
|
||||
@ -57,12 +58,13 @@ struct pcap_sf_pkthdr {
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt)
|
||||
{
|
||||
DumpState *s = DO_UPCAST(DumpState, nc, nc);
|
||||
struct pcap_sf_pkthdr hdr;
|
||||
int64_t ts;
|
||||
int caplen;
|
||||
size_t size = iov_size(iov, cnt);
|
||||
struct iovec dumpiov[cnt + 1];
|
||||
|
||||
/* Early return in case of previous error. */
|
||||
if (s->fd < 0) {
|
||||
@ -76,8 +78,12 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
hdr.ts.tv_usec = ts % 1000000;
|
||||
hdr.caplen = caplen;
|
||||
hdr.len = size;
|
||||
if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
|
||||
write(s->fd, buf, caplen) != caplen) {
|
||||
|
||||
dumpiov[0].iov_base = &hdr;
|
||||
dumpiov[0].iov_len = sizeof(hdr);
|
||||
cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
|
||||
|
||||
if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
|
||||
qemu_log("-net dump write error - stop dump\n");
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
@ -86,27 +92,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
return size;
|
||||
}
|
||||
|
||||
static void dump_cleanup(NetClientState *nc)
|
||||
static void dump_cleanup(DumpState *s)
|
||||
{
|
||||
DumpState *s = DO_UPCAST(DumpState, nc, nc);
|
||||
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
|
||||
static NetClientInfo net_dump_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_DUMP,
|
||||
.size = sizeof(DumpState),
|
||||
.receive = dump_receive,
|
||||
.cleanup = dump_cleanup,
|
||||
};
|
||||
|
||||
static int net_dump_init(NetClientState *peer, const char *device,
|
||||
const char *name, const char *filename, int len,
|
||||
Error **errp)
|
||||
static int net_dump_state_init(DumpState *s, const char *filename,
|
||||
int len, Error **errp)
|
||||
{
|
||||
struct pcap_file_hdr hdr;
|
||||
NetClientState *nc;
|
||||
DumpState *s;
|
||||
struct tm tm;
|
||||
int fd;
|
||||
|
||||
@ -130,13 +125,6 @@ static int net_dump_init(NetClientState *peer, const char *device,
|
||||
return -1;
|
||||
}
|
||||
|
||||
nc = qemu_new_net_client(&net_dump_info, peer, device, name);
|
||||
|
||||
snprintf(nc->info_str, sizeof(nc->info_str),
|
||||
"dump to %s (len=%d)", filename, len);
|
||||
|
||||
s = DO_UPCAST(DumpState, nc, nc);
|
||||
|
||||
s->fd = fd;
|
||||
s->pcap_caplen = len;
|
||||
|
||||
@ -146,13 +134,58 @@ static int net_dump_init(NetClientState *peer, const char *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dumping via VLAN netclient */
|
||||
|
||||
struct DumpNetClient {
|
||||
NetClientState nc;
|
||||
DumpState ds;
|
||||
};
|
||||
typedef struct DumpNetClient DumpNetClient;
|
||||
|
||||
static ssize_t dumpclient_receive(NetClientState *nc, const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = size
|
||||
};
|
||||
|
||||
return dump_receive_iov(&dc->ds, &iov, 1);
|
||||
}
|
||||
|
||||
static ssize_t dumpclient_receive_iov(NetClientState *nc,
|
||||
const struct iovec *iov, int cnt)
|
||||
{
|
||||
DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
|
||||
|
||||
return dump_receive_iov(&dc->ds, iov, cnt);
|
||||
}
|
||||
|
||||
static void dumpclient_cleanup(NetClientState *nc)
|
||||
{
|
||||
DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc);
|
||||
|
||||
dump_cleanup(&dc->ds);
|
||||
}
|
||||
|
||||
static NetClientInfo net_dump_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_DUMP,
|
||||
.size = sizeof(DumpNetClient),
|
||||
.receive = dumpclient_receive,
|
||||
.receive_iov = dumpclient_receive_iov,
|
||||
.cleanup = dumpclient_cleanup,
|
||||
};
|
||||
|
||||
int net_init_dump(const NetClientOptions *opts, const char *name,
|
||||
NetClientState *peer, Error **errp)
|
||||
{
|
||||
int len;
|
||||
int len, rc;
|
||||
const char *file;
|
||||
char def_file[128];
|
||||
const NetdevDumpOptions *dump;
|
||||
NetClientState *nc;
|
||||
DumpNetClient *dnc;
|
||||
|
||||
assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
|
||||
dump = opts->dump;
|
||||
@ -182,5 +215,140 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
|
||||
len = 65536;
|
||||
}
|
||||
|
||||
return net_dump_init(peer, "dump", name, file, len, errp);
|
||||
nc = qemu_new_net_client(&net_dump_info, peer, "dump", name);
|
||||
snprintf(nc->info_str, sizeof(nc->info_str),
|
||||
"dump to %s (len=%d)", file, len);
|
||||
|
||||
dnc = DO_UPCAST(DumpNetClient, nc, nc);
|
||||
rc = net_dump_state_init(&dnc->ds, file, len, errp);
|
||||
if (rc) {
|
||||
qemu_del_net_client(nc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Dumping via filter */
|
||||
|
||||
#define TYPE_FILTER_DUMP "filter-dump"
|
||||
|
||||
#define FILTER_DUMP(obj) \
|
||||
OBJECT_CHECK(NetFilterDumpState, (obj), TYPE_FILTER_DUMP)
|
||||
|
||||
struct NetFilterDumpState {
|
||||
NetFilterState nfs;
|
||||
DumpState ds;
|
||||
char *filename;
|
||||
uint32_t maxlen;
|
||||
};
|
||||
typedef struct NetFilterDumpState NetFilterDumpState;
|
||||
|
||||
static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr,
|
||||
unsigned flags, const struct iovec *iov,
|
||||
int iovcnt, NetPacketSent *sent_cb)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(nf);
|
||||
|
||||
dump_receive_iov(&nfds->ds, iov, iovcnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void filter_dump_cleanup(NetFilterState *nf)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(nf);
|
||||
|
||||
dump_cleanup(&nfds->ds);
|
||||
}
|
||||
|
||||
static void filter_dump_setup(NetFilterState *nf, Error **errp)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(nf);
|
||||
|
||||
if (!nfds->filename) {
|
||||
error_setg(errp, "dump filter needs 'file' property set!");
|
||||
return;
|
||||
}
|
||||
|
||||
net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp);
|
||||
}
|
||||
|
||||
static void filter_dump_get_maxlen(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
uint32_t value = nfds->maxlen;
|
||||
|
||||
visit_type_uint32(v, &value, name, errp);
|
||||
}
|
||||
|
||||
static void filter_dump_set_maxlen(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
Error *local_err = NULL;
|
||||
uint32_t value;
|
||||
|
||||
visit_type_uint32(v, &value, name, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (value == 0) {
|
||||
error_setg(&local_err, "Property '%s.%s' doesn't take value '%u'",
|
||||
object_get_typename(obj), name, value);
|
||||
goto out;
|
||||
}
|
||||
nfds->maxlen = value;
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static char *file_dump_get_filename(Object *obj, Error **errp)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
|
||||
return g_strdup(nfds->filename);
|
||||
}
|
||||
|
||||
static void file_dump_set_filename(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
|
||||
g_free(nfds->filename);
|
||||
nfds->filename = g_strdup(value);
|
||||
}
|
||||
|
||||
static void filter_dump_instance_init(Object *obj)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
|
||||
nfds->maxlen = 65536;
|
||||
|
||||
object_property_add(obj, "maxlen", "int", filter_dump_get_maxlen,
|
||||
filter_dump_set_maxlen, NULL, NULL, NULL);
|
||||
object_property_add_str(obj, "file", file_dump_get_filename,
|
||||
file_dump_set_filename, NULL);
|
||||
}
|
||||
|
||||
static void filter_dump_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
NetFilterClass *nfc = NETFILTER_CLASS(oc);
|
||||
|
||||
nfc->setup = filter_dump_setup;
|
||||
nfc->cleanup = filter_dump_cleanup;
|
||||
nfc->receive_iov = filter_dump_receive_iov;
|
||||
}
|
||||
|
||||
static const TypeInfo filter_dump_info = {
|
||||
.name = TYPE_FILTER_DUMP,
|
||||
.parent = TYPE_NETFILTER,
|
||||
.class_init = filter_dump_class_init,
|
||||
.instance_init = filter_dump_instance_init,
|
||||
.instance_size = sizeof(NetFilterDumpState),
|
||||
};
|
||||
|
||||
static void filter_dump_register_types(void)
|
||||
{
|
||||
type_register_static(&filter_dump_info);
|
||||
}
|
||||
|
||||
type_init(filter_dump_register_types);
|
||||
|
13
net/net.c
13
net/net.c
@ -708,7 +708,7 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
|
||||
offset = iov[0].iov_len;
|
||||
} else {
|
||||
buffer = buf;
|
||||
offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer));
|
||||
offset = iov_to_buf(iov, iovcnt, 0, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
|
||||
@ -1197,10 +1197,11 @@ void print_net_client(Monitor *mon, NetClientState *nc)
|
||||
monitor_printf(mon, "filters:\n");
|
||||
}
|
||||
QTAILQ_FOREACH(nf, &nc->filters, next) {
|
||||
monitor_printf(mon, " - %s: type=%s%s\n",
|
||||
object_get_canonical_path_component(OBJECT(nf)),
|
||||
char *path = object_get_canonical_path_component(OBJECT(nf));
|
||||
monitor_printf(mon, " - %s: type=%s%s\n", path,
|
||||
object_get_typename(OBJECT(nf)),
|
||||
nf->info_str);
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1227,6 +1228,12 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only query information on queue 0 since the info is per nic,
|
||||
* not per queue
|
||||
*/
|
||||
if (nc->queue_index != 0)
|
||||
continue;
|
||||
|
||||
if (nc->info->query_rx_filter) {
|
||||
info = nc->info->query_rx_filter(nc);
|
||||
entry = g_malloc0(sizeof(*entry));
|
||||
|
@ -2012,6 +2012,7 @@ qemu -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,sha
|
||||
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
|
||||
At most @var{len} bytes (64k by default) per packet are stored. The file format is
|
||||
libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
|
||||
Note: For devices created with '-netdev', use '-object filter-dump,...' instead.
|
||||
|
||||
@item -net none
|
||||
Indicate that no network devices should be configured. It is used to
|
||||
@ -3665,6 +3666,13 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter.
|
||||
@option{tx}: the filter is attached to the transmit queue of the netdev,
|
||||
where it will receive packets sent by the netdev.
|
||||
|
||||
@item -object filter-dump,id=@var{id},netdev=@var{dev},file=@var{filename}][,maxlen=@var{len}]
|
||||
|
||||
Dump the network traffic on netdev @var{dev} to the file specified by
|
||||
@var{filename}. At most @var{len} bytes (64k by default) per packet are stored.
|
||||
The file format is libpcap, so it can be analyzed with tools such as tcpdump
|
||||
or Wireshark.
|
||||
|
||||
@end table
|
||||
|
||||
ETEXI
|
||||
|
7
vl.c
7
vl.c
@ -2769,7 +2769,12 @@ static bool object_create_initial(const char *type)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_str_equal(type, "filter-buffer")) {
|
||||
/*
|
||||
* return false for concrete netfilters since
|
||||
* they depend on netdevs already existing
|
||||
*/
|
||||
if (g_str_equal(type, "filter-buffer") ||
|
||||
g_str_equal(type, "filter-dump")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user