mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
net: Add support for capturing VLANs (Jan Kiszka)
This patch is derived from Tristan Gingold's patch. It adds a new VLAN client type that writes all traffic on the VLAN it is attached to into a pcap file. Such a file can then be analyzed offline with Wireshark or tcpdump. Besides rebasing and some minor cleanups, the major differences to the original version are: - support for enabling/disabling via the monitor (host_net_add/remove) - no special ordering of VLAN client list, qemu_send_packet now takes care of properly ordered packets - 64k default capturing limit (I hate tcpdump's default) Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7200 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
1030021681
commit
bb9ea79e7a
3 changed files with 121 additions and 3 deletions
|
@ -1731,7 +1731,7 @@ static const mon_cmd_t mon_cmds[] = {
|
|||
{ "pci_add", "sss", pci_device_hot_add, "pci_addr=auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", "hot-add PCI device" },
|
||||
{ "pci_del", "s", pci_device_hot_remove, "pci_addr=[[<domain>:]<bus>:]<slot>", "hot remove PCI device" },
|
||||
{ "host_net_add", "ss", net_host_device_add,
|
||||
"[tap,user,socket,vde] options", "add host VLAN client" },
|
||||
"[tap,user,socket,vde,dump] options", "add host VLAN client" },
|
||||
{ "host_net_remove", "is", net_host_device_remove,
|
||||
"vlan_id name", "remove host VLAN client" },
|
||||
#endif
|
||||
|
|
115
net.c
115
net.c
|
@ -118,6 +118,7 @@
|
|||
#include "qemu-char.h"
|
||||
#include "audio/audio.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "qemu-log.h"
|
||||
|
||||
#if defined(CONFIG_SLIRP)
|
||||
#include "libslirp.h"
|
||||
|
@ -1558,6 +1559,106 @@ static int net_socket_mcast_init(VLANState *vlan,
|
|||
|
||||
}
|
||||
|
||||
typedef struct DumpState {
|
||||
VLANClientState *pcap_vc;
|
||||
int fd;
|
||||
int pcap_caplen;
|
||||
} DumpState;
|
||||
|
||||
#define PCAP_MAGIC 0xa1b2c3d4
|
||||
|
||||
struct pcap_file_hdr {
|
||||
uint32_t magic;
|
||||
uint16_t version_major;
|
||||
uint16_t version_minor;
|
||||
int32_t thiszone;
|
||||
uint32_t sigfigs;
|
||||
uint32_t snaplen;
|
||||
uint32_t linktype;
|
||||
};
|
||||
|
||||
struct pcap_sf_pkthdr {
|
||||
struct {
|
||||
int32_t tv_sec;
|
||||
int32_t tv_usec;
|
||||
} ts;
|
||||
uint32_t caplen;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
static void dump_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
DumpState *s = opaque;
|
||||
struct pcap_sf_pkthdr hdr;
|
||||
int64_t ts;
|
||||
int caplen;
|
||||
|
||||
/* Early return in case of previous error. */
|
||||
if (s->fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ts = muldiv64 (qemu_get_clock(vm_clock),1000000, ticks_per_sec);
|
||||
caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
|
||||
|
||||
hdr.ts.tv_sec = ts / 1000000000LL;
|
||||
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) {
|
||||
qemu_log("-net dump write error - stop dump\n");
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void net_dump_cleanup(VLANClientState *vc)
|
||||
{
|
||||
DumpState *s = vc->opaque;
|
||||
|
||||
close(s->fd);
|
||||
qemu_free(s);
|
||||
}
|
||||
|
||||
static int net_dump_init(VLANState *vlan, const char *device,
|
||||
const char *name, const char *filename, int len)
|
||||
{
|
||||
struct pcap_file_hdr hdr;
|
||||
DumpState *s;
|
||||
|
||||
s = qemu_malloc(sizeof(DumpState));
|
||||
|
||||
s->fd = open(filename, O_CREAT | O_WRONLY, 0644);
|
||||
if (s->fd < 0) {
|
||||
fprintf(stderr, "-net dump: can't open %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->pcap_caplen = len;
|
||||
|
||||
hdr.magic = PCAP_MAGIC;
|
||||
hdr.version_major = 2;
|
||||
hdr.version_minor = 4;
|
||||
hdr.thiszone = 0;
|
||||
hdr.sigfigs = 0;
|
||||
hdr.snaplen = s->pcap_caplen;
|
||||
hdr.linktype = 1;
|
||||
|
||||
if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
|
||||
perror("-net dump write error");
|
||||
close(s->fd);
|
||||
qemu_free(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->pcap_vc = qemu_new_vlan_client(vlan, device, name, dump_receive, NULL,
|
||||
net_dump_cleanup, s);
|
||||
snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
|
||||
"dump to %s (len=%d)", filename, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find or alloc a new VLAN */
|
||||
VLANState *qemu_find_vlan(int id)
|
||||
{
|
||||
|
@ -1883,7 +1984,17 @@ int net_client_init(const char *device, const char *p)
|
|||
ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!strcmp(device, "dump")) {
|
||||
int len = 65536;
|
||||
|
||||
if (get_param_value(buf, sizeof(buf), "len", p) > 0) {
|
||||
len = strtol(buf, NULL, 0);
|
||||
}
|
||||
if (!get_param_value(buf, sizeof(buf), "file", p)) {
|
||||
snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id);
|
||||
}
|
||||
ret = net_dump_init(vlan, device, name, buf, len);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown network device: %s\n", device);
|
||||
ret = -1;
|
||||
goto out;
|
||||
|
@ -1908,7 +2019,7 @@ void net_client_uninit(NICInfo *nd)
|
|||
static int net_host_check_device(const char *device)
|
||||
{
|
||||
int i;
|
||||
const char *valid_param_list[] = { "tap", "socket"
|
||||
const char *valid_param_list[] = { "tap", "socket", "dump"
|
||||
#ifdef CONFIG_SLIRP
|
||||
,"user"
|
||||
#endif
|
||||
|
|
|
@ -745,6 +745,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, \
|
|||
" Use group 'groupname' and mode 'octalmode' to change default\n"
|
||||
" ownership and permissions for communication port.\n"
|
||||
#endif
|
||||
"-net dump[,vlan=n][,file=f][,len=n]\n"
|
||||
" dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n"
|
||||
"-net none use it alone to have zero network devices; if no -net option\n"
|
||||
" is provided, the default is '-net nic -net user'\n")
|
||||
STEXI
|
||||
|
@ -865,6 +867,11 @@ vde_switch -F -sock /tmp/myswitch
|
|||
qemu linux.img -net nic -net vde,sock=/tmp/myswitch
|
||||
@end example
|
||||
|
||||
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
|
||||
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.
|
||||
|
||||
@item -net none
|
||||
Indicate that no network devices should be configured. It is used to
|
||||
override the default configuration (@option{-net nic -net user}) which
|
||||
|
|
Loading…
Reference in a new issue