The Robur cooperative blog.
Back to index

Speeding up MirageVPN and use it in the wild

As we were busy continuing to work on MirageVPN, we got in touch with eduVPN, who are interested about deploying MirageVPN. We got example configuration from their side, and fixed some issues, and also implemented tls-crypt - which was straightforward since we earlier spend time to implement tls-crypt-v2.

In January, they gave MirageVPN another try, and measured the performance -- which was very poor -- MirageVPN (run as a Unix binary) provided a bandwith of 9.3Mb/s, while OpenVPN provided a bandwidth of 360Mb/s (using a VPN tunnel over TCP).

We aim at spending less resources for computing, thus the result was not satisfying for us. We re-read a lot of code, refactored a lot, and are now at ~250Mb/s.

Tooling for performance engineering of OCaml

As a first approach we connected with the MirageVPN unix client & OpenVPN client to a eduVPN server and ran speed tests using This was sufficient to show the initial huge gap in download speeds between MirageVPN and OpenVPN. There is a lot of noise in this approach as there are many computers and routers involved in this setup, and it is hard to reproduce.

To get more reproducible results we set up a local VM with openvpn and iperf3 installed. On the host machine we can then connect to the VM's OpenVPN server and run iperf3 against the VPN ip address. This worked more reliably. However, it was still noisy and not suitable to measure single digit percentage changes in performance. To better guide the performance engineering, we also developed a microbenchmark using OCaml tooling. This will setup a client and server without any input and output, and transfer data in memory.

We also re-read our code and used the Linux utility perf together with Flamegraph to graph its output. This works nicely with OCaml programs (we're using the 4.14.1 compiler and runtime system). We did the performance engineering on Unix binaries, i.e. not on MirageOS unikernels - but the MirageVPN protocol is used in both scenarios - thus the performance improvements described here are also in the MirageVPN unikernels.

Takeaway of performance engineering

The learnings of our performance engineering are in three areas:


To conclude: we already achieved a factor of 25 in performance by adapting the code in various ways. We have ideas to improve the performance even more in the future - we also work on using OCaml string and bytes, instead of off-the-OCaml-heap-allocated bigarrays (see our previous article, which provided some speedups).

Don't hesitate to reach out to us on GitHub, or by mail if you're stuck.

We want to thank NLnet for their funding (via NGI assure), and eduVPN for their interest.

  1. It has come to our attention that the blog post is rather old (2012) and that the implementation has been completely rewritten since then.