How to know if a process is attached to a tap interface?

Each file descriptor has a /proc/pid/fdinfo/num entry, like:

# cat /proc/24332/fdinfo/28
pos:    0
flags:  0104002
mnt_id: 18
iff:    tap0123acdc-66

So, with the interface name, you can get the pid with:

# egrep -l iff:.*tap0123acdc-66 /proc/*/fdinfo/* 2>/dev/null|cut -d/ -f3
24332

This got me wondering and I had a look at the Linux kernel source (I'm assuming your question is about Linux).

It appears the answer's more difficult than you'd expect. This TUN/TAP API tutorial page offers some insight. Basically, your program allocates a new TUN/TAP device by opening /dev/net/tun and sending it the TUNSETIFF ioctl. If all goes well, an interface is created, the kernel gives you its name and a file descriptor, and that's how you manage it.

There are two catches here:

  1. The kernel doesn't store the PID of the process that sent the ioctl in struct tun_struct (TUN and TAP largely share the same data structures).
  2. A process may mark an interface as persistent, close its file descriptor and thereafter use it as a normal network interface.

In practice, I suspect 2 doesn't happen much. Checking out an openvpn process with lsof reveals it's still got its file descriptor to the TAP device open and obviously using it, but since /dev/net/tun is a sort of multiplexing device like /dev/ptmx, you can use lsof to find out what processes are currently using a TUN/TAP device, but you can't know what process is using what device.

There are oblique ways of solving the underlying problem. For OpenVPN, I use a tunnel setup script that names the tunX/tapX devices with a more descriptive name that includes the basename of the OpenVPN config file. So, /etc/openvpn/foo.conf leads to a vpn-foo device. Then I can correlate the OpenvVPN process with the interface it's using. Haven't had to do this with QEmu/KVM yet, though.