-----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:
Peter Maydell 2015-10-27 10:10:46 +00:00
commit 7e038b94e7
6 changed files with 232 additions and 34 deletions

View file

@ -964,6 +964,7 @@ static void gem_reset(DeviceState *d)
{ {
int i; int i;
CadenceGEMState *s = CADENCE_GEM(d); CadenceGEMState *s = CADENCE_GEM(d);
const uint8_t *a;
DB_PRINT("\n"); DB_PRINT("\n");
@ -982,6 +983,11 @@ static void gem_reset(DeviceState *d)
s->regs[GEM_DESCONF5] = 0x002f2145; s->regs[GEM_DESCONF5] = 0x002f2145;
s->regs[GEM_DESCONF6] = 0x00000200; 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++) { for (i = 0; i < 4; i++) {
s->sar_active[i] = false; s->sar_active[i] = false;
} }

View file

@ -1289,6 +1289,10 @@ static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
static void vmxnet3_fill_stats(VMXNET3State *s) static void vmxnet3_fill_stats(VMXNET3State *s)
{ {
int i; int i;
if (!s->device_active)
return;
for (i = 0; i < s->txq_num; i++) { for (i = 0; i < s->txq_num; i++) {
cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa, cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
&s->txq_descr[i].txq_stats, &s->txq_descr[i].txq_stats,

View file

@ -25,12 +25,13 @@
#include "clients.h" #include "clients.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/iov.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hub.h" #include "qapi/visitor.h"
#include "net/filter.h"
typedef struct DumpState { typedef struct DumpState {
NetClientState nc;
int64_t start_ts; int64_t start_ts;
int fd; int fd;
int pcap_caplen; int pcap_caplen;
@ -57,12 +58,13 @@ struct pcap_sf_pkthdr {
uint32_t len; 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; struct pcap_sf_pkthdr hdr;
int64_t ts; int64_t ts;
int caplen; int caplen;
size_t size = iov_size(iov, cnt);
struct iovec dumpiov[cnt + 1];
/* Early return in case of previous error. */ /* Early return in case of previous error. */
if (s->fd < 0) { 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.ts.tv_usec = ts % 1000000;
hdr.caplen = caplen; hdr.caplen = caplen;
hdr.len = size; 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"); qemu_log("-net dump write error - stop dump\n");
close(s->fd); close(s->fd);
s->fd = -1; s->fd = -1;
@ -86,27 +92,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return 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); close(s->fd);
s->fd = -1;
} }
static NetClientInfo net_dump_info = { static int net_dump_state_init(DumpState *s, const char *filename,
.type = NET_CLIENT_OPTIONS_KIND_DUMP, int len, Error **errp)
.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)
{ {
struct pcap_file_hdr hdr; struct pcap_file_hdr hdr;
NetClientState *nc;
DumpState *s;
struct tm tm; struct tm tm;
int fd; int fd;
@ -130,13 +125,6 @@ static int net_dump_init(NetClientState *peer, const char *device,
return -1; 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->fd = fd;
s->pcap_caplen = len; s->pcap_caplen = len;
@ -146,13 +134,58 @@ static int net_dump_init(NetClientState *peer, const char *device,
return 0; 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, int net_init_dump(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp) NetClientState *peer, Error **errp)
{ {
int len; int len, rc;
const char *file; const char *file;
char def_file[128]; char def_file[128];
const NetdevDumpOptions *dump; const NetdevDumpOptions *dump;
NetClientState *nc;
DumpNetClient *dnc;
assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP); assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
dump = opts->dump; dump = opts->dump;
@ -182,5 +215,140 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
len = 65536; 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);

View file

@ -708,7 +708,7 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
offset = iov[0].iov_len; offset = iov[0].iov_len;
} else { } else {
buffer = buf; 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) { 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"); monitor_printf(mon, "filters:\n");
} }
QTAILQ_FOREACH(nf, &nc->filters, next) { QTAILQ_FOREACH(nf, &nc->filters, next) {
monitor_printf(mon, " - %s: type=%s%s\n", char *path = object_get_canonical_path_component(OBJECT(nf));
object_get_canonical_path_component(OBJECT(nf)), monitor_printf(mon, " - %s: type=%s%s\n", path,
object_get_typename(OBJECT(nf)), object_get_typename(OBJECT(nf)),
nf->info_str); nf->info_str);
g_free(path);
} }
} }
@ -1227,6 +1228,12 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
continue; 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) { if (nc->info->query_rx_filter) {
info = nc->info->query_rx_filter(nc); info = nc->info->query_rx_filter(nc);
entry = g_malloc0(sizeof(*entry)); entry = g_malloc0(sizeof(*entry));

View file

@ -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). 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 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. 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 @item -net none
Indicate that no network devices should be configured. It is used to 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, @option{tx}: the filter is attached to the transmit queue of the netdev,
where it will receive packets sent by 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 @end table
ETEXI ETEXI

7
vl.c
View file

@ -2769,7 +2769,12 @@ static bool object_create_initial(const char *type)
return false; 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; return false;
} }