5

I have a qemu VM started by an orchestration script, which creates transient tap interfaces. When I inspect the command line arguments of the qemu-system-x86_64 process, then I can see, that the process connects to already opened tap interface with the file descriptor 27:

-netdev tap,fd=27,id=hostnet1,vhost=on,vhostfd=28

According to ls -l /proc/<qemu-system-x86_64_PID>/fd/27 it points to /dev/net/tun.

Does it work somehow in a way that tap interface name (for example vnet99) is passed to /dev/net/tun with ioctl() and this returns the correct fd? Or in general, how can I find out which tap interface in my host machine has file descriptor 27?

2

2 Answers 2

3

The iff: entry which could have given an answer was added in kernel 3.14 with the commit tun: add device name(iff) field to proc fdinfo entry, so is not available on kernel 3.13 or before, eg with Ubuntu 14.04LTS.

In this case, while it's not possible to ask the kernel to give the information, it's still possible to ask the actual process to give this information, by tracing it with a debugger.

There's an ioctl available since Linux 2.6.27 to ask informations about a configured tuntap interface: TUNGETIFF. Its use is for a process inheriting an fd to be able to query the fd to receive interface's name and type (ifr_name and ifr_flags) or to know the tuntap device was not configured yet (EBADFD) and that it should do it.

So while it's possible using gdb, it's a bit tricky because if no development environment is available, a few needed parameter and values have to be known or adjusted (and might change in the future or with architectures). These informations and adjustments where needed here:

  • defining $malloc for 64bits systems to handle the correct size for the returned memory address: credit goes to this comment from SO.
  • $malloc(64): struct ifreq appears to be 40 bytes on 64bits, let's use 64 to stay safe.
  • 0x800454d2 == TUNGETIFF.
  • result ifr_name is at offset 0.

Here are a shell script preparing the way for each tuntap fd found to call gdb, along with gdb's own script:

tungetiff.sh:

#!/bin/sh

[ $# -gt 0 ] || exit 1
SCRIPTGDB="$1"; shift

for pid in "$@"; do
    for procfd in /proc/$pid/fd/*; do
        if [ "$(readlink $procfd)" = "/dev/net/tun" ]; then
            fd=$(basename $procfd)
            printf 'pid=%d fd=%d ifname=' $pid $fd
            gdb -batch-silent --pid=$pid -ex 'set $fd'=$fd -x "$SCRIPTGDB"
        fi
    done
done

tungetiff.gdb:

set $malloc=(void *(*)(long long)) malloc
p $malloc(64)
p ioctl($fd, 0x800454d2, $1)
set *((char *)($1+16))=0
set logging file /dev/stdout
set logging on
printf "%s\n",$1
set logging off
call free($1)
quit

Typical example of execution (will probably only work as root, even user libvirt-qemu doesn't appear to be able to ptrace qemu-system):

# ./tungetiff.sh tungetiff.gdb $(pgrep qemu-system-)
pid=22281 fd=26 ifname=vnet1
pid=22281 fd=30 ifname=vnet2
pid=27109 fd=26 ifname=vnet0
3

With the file descriptor 27 known you'd walk the /proc under the QEMU's process:

 $ ls /proc/<qemu-system-x86_64_PID>/fd/27

At the same level as the fd directory is another directory fdinfo which contains details such as this:

$ cat /proc/<qemu-system-x86_64_PID>/fdinfo/27
pos:    0
flags:  0104002
mnt_id: 18
iff:    tap0123acdc-66

The iff entry in this file is the tap device.

References

2
  • At least in Linux 3.13.0-32-generic the fd file in fdinfo does not contain the mnt_id and iff fields.
    – Martin
    Commented Aug 13, 2018 at 8:59
  • @Martin - interesting, what's the distro?
    – slm
    Commented Aug 13, 2018 at 11:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .