Project Overview
This project, undertaken as part of Google Summer of Code 2023, sets out to implement a robust TUN/TAP driver for Haiku given the increasing demand from the community for a virtual network kernel interface. This project allows for VPN software and other network-related utilities that work with TUN/TAP driver to operate seamlessly on Haiku. Throughout the project’s duration, I’ve documented the rationale behind key design decisions, and offered insights on the interplay between the TUN/TAP driver and Haiku’s unique networking architecture in my series of seven progress blog posts. For those interested in trying out the TUN/TAP driver on Haiku (when the code is merged, more on that in a different section), you can use the port of OpenVPN that was made on haikuports here. One last thing to say is that I could not get the TUN interface to work properly due to a lack of Point-to-Point being supported by Haiku but TAP works for both the interface and driver.
Where We Last Left Off
Last post, I left off on the problem where the select functionality was working but there are some problems as it works but not well as the average latency is above 2000ms and when using ping it drops more than 60% of packets on average. For two weeks I was working on this issue but I couldn’t figure out what was wrong with select and given that I was coming up on the deadline of my project, I decided to go with a condition variable approach when reading data from the driver for both the application and interface side. For the application side, it does have a timeout on it so that write can also take place since OpenVPN uses select/poll which will check if both read and write can happen at the same time, and since I am blocking one of them, it would just infinitely block both operations until read was fine. While select functionality is something that should be implemented with the driver, timing was not on my side with this issue so for those who want to take more of a crack at finding out what the problem is, here was how I tested it:
Where We Last Left Off
So last time I posted I was able to say that I got the client side for OpenVPN on Haiku working but not the server but I am proud to say that now both the server and client work extremely well now on Haiku :) I was able to get the server from not working to working and was able to get the latency for the entire VPN operation down from 1000ms average to anywhere between 2ms to 9ms (that’s a caveat as that is without blocking which will be discussed later). I had a check in my tun_read() function wrong where I wanted any side that is non-blocking to send a signal to the other side’s condition variable that something is now in their queue but had it backwards with a not
statement in there. The simplest mistakes slip the mind huh :p Anyway, the server also follows suit with the faster latency so now that the read and write functions are basically complete, lets get on with what I was dealing with for the past 2ish weeks.
Tempered Optimism
So great news everyone, OpenVPN and the TUN/TAP driver is working on Haiku! While this is great news for the development of the project, I need to temper it with some problems that the project has encountered now. So first thing that I had to change first was going from TUN to TAP since OpenVPN wanted a Point-to-Point connection for the TUN driver and Point-to-Point isn’t quite a thing on Haiku yet. I had a lot of trouble with routing with TUN, so I moved onto TAP, and that seems to work… sort of. The main thing is that Haiku can be a client fine but it has some trouble being a server as OpenVPN can set the server up, and have a client OpenVPN connect to it (let us say the client is running Linux), but the client cannot ping the Haiku server. When I try to ping the server, ping will just say Destination Host Unreachable
. Looking further into it using tcpdump, I realized that the client is trying to send ARP request to try and find the server and the Haiku server isn’t responding. Checking the Haiku side of things, I noticed that it wasn’t receiving the ARP requests to begin with so I have a hunch it might be the VirtualBox NAT Network I am using but I am not ruling out the possibility of the TAP driver or the TAP interface.
The Weekly Problem
So we are just past the midway point for GSoC and last update I told you guys that I had a working (albeit somewhat buggy) TUN Driver working. I had gotten great feedback from Pulkomandy, Axel, and Korli to help with a more efficient driver and to make it more human-readable because it made no sense the way I had written it. I have very good news to bring to everyone in that all of the 3 main problems that I talked about last time are all solved! I think most of them got solved after I fully understood creating semaphores and imposed execution order by adding a write semaphore. While this new code made the driver much more efficient and less error-prone, there were two new errors that popped up during testing:
Sorry for the late blog post everyone! Personal life and some roadblocks on the project got in the way but I am proud to say that the driver is up and working!
Problems, Problems, and more Problems
I got the semaphore problem settled, but I then ran into a problem where the data that the application on the interface side sends a packet was then not receiving the packet. Through some debugging I found out that the interface, when it goes into device_consumer_thread
for getting the receive function, it fails here. Looking deeper into when that interface->receive_funcs
element gets assigned I found the function here which I realized is never called when I call ifconfig
to set up the interface. I ran into the solution to the problem by just changing the type of datalink frame from loopback to an ethernet frame that the interface will be using from now on. That brought the packet to an interface and I started to get a new problem of course :)
More updates on the TUN Driver development!
So What’s Been Happening?
Thankfully I’ve been able to get a lot more done on the driver this week with finishing the write/sending functionality of the driver and I am currently on the reading/receiving functionality which is getting close to being done. At first I tried to implement a solution in the networking interface (tun.cpp) that didn’t use iovecs but that just caught up to me in the end and it was just significantly easier to copy and paste the code from ethernet.cpp’s send/receive functions as that is something that works a lot better than what I was implementing. Me and my mentors also decided on using the already made BufferQueue data structure for holding the data in the driver itself since it would just be plain easier to make the data parameter, when using read from a interface, a straight up net_buffer packet that it can immediately be read back and just use the net_buffer_module_info
structs read function member to get the byte stream information that any application needs. The main roadblock I have with the read functionality is using semaphores correctly to stop the networking stack from continuously reading data that isn’t there. As of writing this update, I am able to make read blocking but I am testing different ways I can release the semaphore for it to read data properly. Big shoutout to PulkoMandy and Korli for helping me with this issue!
Intro
Hello again everyone! I wanted to write a long overdue update on how everything is going and what I’ve been learning over the past couple of weeks. Due to how my semester didn’t actually end until the 16th, progress has been relatively slow but now that I have more time I can get started on more things with this project.
Understanding the Project Better
(If I get anything wrong about anything I am about to say, please correct me!)
First things first, what are the actual specifics of what a TUN driver is (since I didn’t go over it in detail last time)? TUN drivers are essentially virtual network interfaces and and a driver that is typically used to establish communication between the operating system and user-space applications. For the network interface in specific, it is a virtual point-to-point connection that works at the IP level of the networking stack and routes all outgoing packets on the system through it where these packets are then sent to the driver. Looking at the driver element, you use your normal write and read syscalls on the driver to emulate the sending and receiving behavior respectfully. You can think of a TUN driver as part of the emulation of an IP interface.
About Me
Hello everyone! My name is Sean Brady, and I am currently in my Sophomore year at Oregon State University studying Computer Science. In early January of this year, I decided to become a contributor for a Google Summer of Code (GSoC) project focused on operating systems where I researched Haiku and its projects which interested me and the VPN Support Project in particular. From what I can tell, interest in bringing a VPN to Haiku has been in the works since the BeOS days and more recently the tun.cpp
file about 4 years ago.