VirtualBox NAT Network Performance

December 19, 2020 ~ 3 min read

If you are using virtualbox, and have noticed that network transfer is very slow, then read on, you will get some tips on how to improve the transfer rate.

Are you using VirtualBox to play around with a new OS or to isolate your host OS or for your development environment or for a Kubernetes cluster?

Have you experienced slow network performance through NAT Networks? Let me tell you what I did to improve that.

We were using VirtualBox to develop web applications in Linux. We had a VM as a proxy server sitting before multiple VMs acting as application servers. We used NAT Networking because we need to be able to connect from the host OS and our proxy server needs to connect to application servers for forwarding the requests. And only NAT Networking allows that setup. However, the issue with NAT Networking is that it's super slow 🦥. A mere 200MB file transfer took about 20 minutes. And we needed to regularly transfer this file at two different places. So our ops team was complaining that this process is very slow. They had to carve out an entire hour to complete this process, and that was becoming a problem. We tried bridge networking for a few application servers that were involved in this process. But the issue was that our enterprise networking team was actively blocking the bridge networking whenever they could detect. So we switched to NAT. And we received a much better performance. File transfer went from 30 mins to mere 2 mins.

The problem then was, whenever you'd need to transfer the files, you'd need to update your networking from NAT network to NAT and back again once the process is finished. To solve that issue, VirtualBox allows you to add multiple network connections to your VM, just like joining multiple ethernet cables to your machine. You can also apply different network configuration to these different connections. So my solution is to use NAT Network in the first connection and use NAT on the second connection. Now by default all our applications will use NAT Network from the first connection. To use NAT configuration for the processes that require greater transfer speeds, I am using the following script just before running the main application.

We need to first add a network namespace and assign the interface to it and bring it up. We are doing it once when the system starts.

# Add new namespace
ip netns add perf_ns
# Set namespace to use enp0s8; it will be inaccessible without this namespace
ip link set enp0s8 netns perf_ns
# Bring up the network interface inside namespace
ip netns exec perf_ns ip link set enp0s8 up

Once we have the network namespace set up, we ask the application to use this namespace whenever we need higher network transfer speeds.

# Nudge network namespace to get ipv4
# We can fallback to NATNetwork in case of errors
sudo ip netns exec perf_ns dhclient enp0s8 &> /dev/null

# Your script passed as an argument
SCRIPT_CMD=$1

if [[ $(ip netns) == "perf_ns" ]]; then
    SCRIPT_CMD="sudo ip netns exec perf_ns runuser - $(logname) -c '${SCRIPT_CMD}'"
fi

eval ${SCRIPT_CMD}

Voila, now the host can connect to these VMs, and these VMs can connect to other VMs and we also get good transfer speed whenever it is required. 🚀