2

I want to read IP packets from a non-blocking tun/tap file descriptor tunfd I set the tunfd as non-blocking and register a READ_EV event for it in libevent.

when the event is triggered, I read the first 20 bytes first to get the IP header, and then read the rest.

nr_bytes = read(tunfd, buf, 20);
...
ip_len = .... // here I get the IP length
....
nr_bytes = read(tunfd, buf+20, ip_len-20);

but for the read(tunfd, buf+20, ip_len-20) I got EAGAIN error, actually there should be a full packet, so there should be some bytes, why I get such an error?

tunfd is not compatible with non-blocking mode or libevent?

thanks!

misteryes
  • 2,167
  • 4
  • 32
  • 58

1 Answers1

6

Reads and writes with TUN/TAP, much like reads and writes on datagram sockets, must be for complete packets. If you read into a buffer that is too small to fit a full packet, the buffer will be filled up and the rest of the packet will be discarded. For writes, if you write a partial packet, the driver will think it's a full packet and deliver the truncated packet through the tunnel device.

Therefore, when you read a TUN/TAP device, you must supply a buffer that is at least as large as the configured MTU on the tun or tap interface.

Celada
  • 21,627
  • 4
  • 64
  • 78
  • so you meant, every time the read() can only return exactly 1 packet? not multiple packets? besides, if I write to tun fd too often and there is not enough buffer, what will happen? for example, if there are only 200 bytes buffer, but I want to write a packet with 500 bytes. will 200 bytes be written or none of the 500 bytes is written? thanks! – misteryes Jun 17 '13 at 08:18
  • Yes, `read()` can only return 1 (complete) packet at a time. If you `write()` too much then `write()` will probably eventually block, but it will still only write complete packets. – Celada Jun 17 '13 at 12:45
  • write() will be blocked? isn't it that it returns a EAGAIN error if the socket is non-blocking? – misteryes Jun 17 '13 at 12:52
  • Oh, yes, of course. If you are in non-blocking mode it will return `EAGAIN` instead of blocking. – Celada Jun 17 '13 at 14:52
  • Does this also mean that it is not possible to use buffered readers/writers with TUN/TAP interfaces? I would like to cut down on my reads and redeuce GC overhead (Android) but I can't seem to find a solution. – Simon Langhoff Oct 13 '14 at 23:52
  • 1
    That's correct, @SimonLanghoff. One of the reasons to use buffered readers and writers is to batch up more data and reduce the number of `read()`/`write()`/`recv()`/`send()` system calls. But with TUN/TAP, one system call = one packet is a requirement of the interface so you can't make that optimization. – Celada Oct 14 '14 at 02:23