Saturday, 23 April 2011

How to capture VM network traffic using qemu -net dump

This post describes how to save a packet capture of the network traffic a QEMU
virtual machine sees. This feature is built into QEMU and works with any
emulated network card and any host network device except vhost-net.

It's relatively easy to use tcpdump(8) with tap networking. First the
tap device for the particular VM needs to be identified and then packets can be
captured:
# tcpdump -i vnet0 -s0 -w /tmp/vm0.pcap

The tcpdump(8) approach cannot be easily used with non-tap host network devices, including slirp and socket.

Using the dump net client

Packet capture is built into QEMU and can be done without tcpdump(8). There are some restrictions:
  1. The vhost-net host network device is not supported because traffic does not cross QEMU so interception is not possible.
  2. The old-style -net command-line option must be used instead of -netdev because the dump net client depends on the mis-named "vlan" feature (essentially a virtual network hub).

Without further ado, here is an example invocation:
$ qemu -net nic,model=e1000 -net dump,file=/tmp/vm0.pcap -net user
This presents the VM with an Intel e1000 network card using QEMU's userspace network stack (slirp). The packet capture will be written to /tmp/vm0.pcap. After shutting down the VM, either inspect the packet capture on the command-line:
$ /usr/sbin/tcpdump -nr /tmp/vm0.pcap

Or open the pcap file with Wireshark.

2 comments:

  1. where is the tmp directory

    ReplyDelete
  2. Hi Stephan
    Thanks for the info. Your post seems to be one of the few that pointed me in the right direction. I'm using a setup where a network using Qemu/kvm and Virsh has networking using UDP encap on 127.0.0.1. Most of the traffic I was interested in is not on a vnet interface but is multiplexed on the loopback interface with a UDP header. Initially with tcpdump on lo I got too many packets and it was not decoded by wireshark.

    In order to capture only what I wanted and decode the packets I had to do: virsh dumpxml 3 where 3 was the id of the VM I got from virsh list. Then I looked at the dumpxml output to find interface I wanted (swp1 in my case) to trace and find the corresponding UDP ports.
    eg:
    source address='127.0.0.1' port='20002'
    local address='127.0.0.1' port='21002'
    source
    target dev='swp1'
    model type='virtio'

    Using this info I could now filter the tcpdump by port with:
    sudo tcpdump port 21002 -i lo -s0 -w /tmp/lo.pcap
    where lo is the loopback and finally:

    editcap -C42 lo.pcap newlo.pcap
    to return the output to non UDP encap. (42 is of course the answer to everything and the size of the UDP header!)
    That newlo.pcap is then read correctly by Wireshark.

    ReplyDelete