When developing the tap library, I ran into the problem that you cannot destroy an interface (ex. tap0) while the application is running (via SIOCIFDESTROY). The ioctl(SIOCIFDESTROY) call will simply hang until the application using this descriptor finishes (see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242841#c0). Opening "/dev/tap" does not check if existing interfaces are being used and creates tap(N+1) every time. It would be nice to make a parameter that will control the automatic destruction of the interface when the descriptor is closed. For example: if (ioctl(fd, TAPSIFDCLOSE, 1) < 0) { printf("error: ioctl(TAPSIFDCLOSE)\n"); } close(fd); This mechanism is implemented by default in the Linux driver for tuntap: "A network device will appear as tunXX or tapXX, depending on the options chosen. When the program closes the file descriptor, the network device and all corresponding routes will disappear." Source: https://docs.kernel.org/networking/tuntap.html
This is from tap(4). How is it different from what you are proposing? On the last close of the data device, the interface is brought down (as if with “ifconfig tapN down”) and has all of its configured addresses deleted unless the device is a VMnet device, or has IFF_LINK0 flag set. All queued frames are thrown away. If the interface is up when the data device is not open, output frames are thrown away rather than letting them pile up.
(In reply to Alan Somers from comment #1) > On the last close of the data device, the interface is brought down (as if with “ifconfig tapN down”) It's completely different. What I am suggesting refers to the automatic "ifconfig tapN destroy" when closing the descriptor. If you use tap/tun via open("/dev/tap") without a number you will get a new device each time (tap0, tap1, tap2, etc.) which cannot be destroyed during the lifetime of the application. Doing this manually is inconvenient for the user, so we need to make the application delete the interface when it closes the descriptor. Fortunately, the Linux driver equivalent does this by default.
I agree that this would be neat (though you can destroy it, you just have to close it first).
(In reply to Kyle Evans from comment #3) > though you can destroy it, you just have to close it first You can't. If you try to do this via SIOCIFDESTROY inside an application which uses the descriptor, the application will hang, even if you do ioctl after close(fd) The sample code from my application: JFUNC(void, close) { close(getFd(env, this)); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, "tap0"); int sock = socket(PF_INET, SOCK_STREAM, 0); ioctl(sock, SIOCIFDESTROY, &ifr); // hangs } After that, you can only terminate the application via kill -9 <pid>.
(In reply to Nikolay Borodin from comment #4) That is a bug, then, unless you have a dangling reference that you didn't expect.
(In reply to Kyle Evans from comment #5) https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242841#c0(In reply to Kyle Evans from comment #5) I understand, in any case it doesn't apply to the automatic interface destruction functionality. The ioctl should have most likely returned an error in that code sample.
(In reply to Nikolay Borodin from comment #6) Right, but the automatic destroy functionality wouldn't work until the process closes anyways if you leaked an fd to the tap device somewhere, which may or may not be OK.
Something like this should do the trick: https://reviews.freebsd.org/D44200 (tun(4)/tap(4): allow devices to be configured as transient)
(In reply to Kyle Evans from comment #8) After this option is set, the system hangs when the application is closed. i = 1; if (ioctl(fd, TAPSTRANSIENT, &i) < 0) { printf("error: ioctl(TAPSTRANSIENT)\n"); // hangs return 1; } with a 100% CPU load: > 1503846 monster+ 20 0 3583480 610420 494700 S 100,0 1,9 1:21.39 VirtualBoxVM
(In reply to Kyle Evans from comment #8) (In reply to Nikolay Borodin from comment #9) To clarify, it's not the ioctl call that hangs, it's the code in the kernel.
(In reply to Nikolay Borodin from comment #10) That's fascinating. Can you tell us a little more about your application? Is it doing some fork or fork/exec? Any fd passing or anything funky? Interface renaming?
(In reply to Kyle Evans from comment #11) > Is it doing some fork or fork/exec? Any fd passing or anything funky? I doubt it. > Interface renaming? Not yet. :) Here's the code (minus TAPSTRANSIENT) for the library I'm working on. Nothing out of the ordinary. https://gitlab.com/Monsterovich/lanemu/-/blob/4e4c5012c8838b7780c2d96efcc622170839a6e3/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.c
(In reply to Kyle Evans from comment #11) After applying these changes, everything works as it should. https://reviews.freebsd.org/D44199
(In reply to Kyle Evans from comment #11) If I set net.link.tap.user_open to 1 and try to open tap device (e.g. "/dev/tap"), open returns -1, but the tapN interface still exists. It also creates devices and doesn't destroy them. I think this behavior could be fixed as well.