OpenVPN Data Channel Offload (aka OVPN-DCO)


The expression Data Channel Offload refers to any technique implemented with the goal of moving the processing of data packets from the OpenVPN userspace program to a separate entity.

Given that OpenVPN spends a considerable amount of time passing data packets back and forth from kernel-land to user-land, where decryption and re-routing happens, it was decided to offload the data processing directly to the kernel. As direct consequence, data packets are not required to leave the kernelspace anymore, thus boosting the performance of active VPN connections.

Antonio's speech about DCO, held at Netdev 0x16 (Lisbon, October 2022), is online here

Before DCO

The picture below depicts how data packets flow on a generic OpenVPN server:

From the application, packets enter the kernel networking stack through tun0, but then they are immediately sent back to userspace, so that the OpenVPN process can decide where they are headed to and then encrypt them. At this point packets are sent back to the networking stack of the kernel and finally to the Internet. On the way back the sequence of events is the same but in the opposite direction.

There are two main disadvantages with this approach:

  1. data packets enter and leave the kernel twice;
  2. all client traffic is handled by the single-threaded OpenVPN process.

Both have been known limiting factors for OpenVPN2.x performance. Running OpenVPN on a beefy CPU has often been the answer in the past in order to push the throughput as high as possible, but due to continuously increasing line rates this approach is simply not feasible anymore.

Introducing DCO

To overcome the limitations described in the section above we have developed ovpn-dco, a Linux kernel module designed to work back-to-back with the OpenVPN userspace software. When a VPN connection is established, being it on a client, on a server or on a p2p instance, the userspace process will first perform the usual handshake and will then pass the data channel parameters to ovpn-dco using its NetLink? interface, so that it can take over from there. At this point, data packets are all handled in kernelspace and are never sent up to the userspace process.

The picture below helps to visualize the difference with to the basic scenario shown above:

Context switches are therefore reduced to the minimum and packet processing can take advantage of the kernel concurrency model. The two main OpenVPN functions, crypto and routing, are now implemented in kernel using the provided API. For what concerns routing, the system routing table is directly used to understand if packets have to be re-routed directly to another peer (i.e. client-to-client mode), without the need to ask the userspace process at all.

OpenVPN in userspace is still in charge of handling the control channel, where all the complex and less throughput-critical operations take place. This is considered an advantage as it allowed to keep the complexity of the ovpn-dco kernel module to the minimum and thus reduce the attack surface. This means that the TLS handshake, data channel key (re-)negotiations and parameters exchange is still performed in userspace.

It should be noted that embedded devices, like small routers, will probably benefit considerably from DCO.

The ovpn-dco source code for Linux is currently available at the following repository:

Please note that OpenVPN 2.6 or greater is required in order to use ovpn-dco.

DCO on Windows

A kernel module has also been developed for Windows, namely ovpn-dco-win. It is a device driver implemented in kernelspace that substitutes all previous drivers used by OpenVPN (i.e. tap-windows6, wintun, etc..). Differently from the other drivers, ovpn-dco-win uses the Windows Kernel API to also implement crypto operations, thus allowing the driver to process data packets entirely in kernelspace, similarly to ovpn-dco for Linux. The main limitation of ovpn-dco-win is that it only supports client/p2p mode, while server mode is not available. This decision was made due to the fact that there is less and less demand for running OpenVPN server on Windows.

The ovpn-dco-win source code is currently available at the following repository:

DCO on FreeBSD

The FreeBSD community has shown great interest for the DCO model and so they also implemented a FreeBSD kernel module. It is expected to be a drop-in replacement for ovpn-dco on Linux, thus implementing the same feature set.

The source code can be found at:

Expected limitations

Not all functionalities available in OpenVPN have been implemented in ovpn-dco(-win). The reasons for this decision are mainly:

  1. avoid unneeded complexity in a critical component like a kernel module;
  2. take the chance to give a clear cut with legacy features that OpenVPN has carried around for a while.

In particular, this is a list (may not be complete) of features that are not available when using ovpn-dco:

  • ciphers other than AES-GCM and CHACHA20-POLY1305;
    • due to the above, when using ovpn-dco peers must use OpenVPN 2.4 or greater (AEAD ciphers are not supported in earlier versions);
  • compression or compression framing;
  • fragmentation;
  • TAP/Ethernet mode;
  • topologies other than subnet;
  • traffic shaping or any other sort of data packets manipulation (system tools should be used when available).

supported features, by plattform (work in progress, so subject to change)

Feature Windows Linux FreeBSD Remark
TUN mode (L3) yes yes yes
TAP mode (L2) no no no not planned
OpenVPN over UDP yes yes yes
OpenVPN over TCP yes yes no
Ciphers AES-GCM, ChaCha20-Poly1305 (Win11 only) AES-GCM, ChaCha20-Poly1305AES-GCM, ChaCha20-Poly1305
Client, P2MP-Server? client client+server client+server
--iroute handling -standard routes ?
outside fragment (inside MTU 1500) yes! handled by kernel (to be tested) yes (to be tested)
OpenVPN fragmentation (--fragment) no no no maybe?
--mssfix yes(?) no* no* desirable
compression no no no not planned
OCC packets in data channel ? ? ? mtu-test, others?
RPF check - (client only) yes ?
--inactive no no no

Using ovpn-dco

If OpenVPN has DCO support compiled-in it will always try to use ovpn-dco (note that Windows builds have DCO support always enabled), unless an incompatible option has been specified. In this case OpenVPN will fall-back to another driver (i.e. tun on Linux). If using DCO is not desirable, it can be deactivated at startup by passing the --disable-dco option.

Last modified 5 weeks ago Last modified on 02/20/23 23:55:10

Attachments (3)

Download all attachments as: .zip