In this article I’ll explain how to aggregate internet access bandwidth using mlvpn software. I struggled a lot to set this up so I wanted to share a how-to.
mlvpn is meant to be used with DSL / fiber links, not wireless or 4G links with variable bandwidth or packet loss.
mlvpn requires to be run on a server which will be the public internet access and on the client on which you want to aggregate the links, this is like doing multiples VPN to the same remote server with a VPN per link, and aggregate them.
Multi-wan roundrobin / load balancer doesn’t allow to stack bandwidth but doesn’t require a remote server, depend on what you want to do, this may be enough and mlvpn may not be required.
mlvpn should be OS agnostic between client / server but I only tried between two OpenBSD hosts, your setup may differ.
Some network diagram
Here is a simple network, the client has access to 2 ISP through two ethernet interfaces.
em0 and em1 will have to be on different rdomains (it’s a feature to separate routing tables).
Let’s say the public ip of the server is 18.104.22.168.
[internet] ↑ | (public ip on em0) #-------------# | | | Server | | | #-------------# | | | | | | | | (internet) | | (internet) #-------------# #-------------# | | | | | ISP 1 | | ISP 2 | | | | | (you certainly don't control those) #-------------# #-------------# | | | | (dsl1 via em0)| | (dsl1 via em1) #-------------# | | | Client | | | #-------------#
As said previously, em0 and em1 must be on different rdomains, it can easily be
done by adding
rdomain 1 and
rdomain 2 to the interfaces configuration.
Example in /etc/hostname.em0
rdomain 1 dhcp
On OpenBSD the installation is as easy as
pkg_add mlvpn (should work starting
from 6.7 because it required patching).
Once the network configuration is done on the client, there are 3 steps to do to get aggregation working:
- mlvpn configuration on the server
- mlvpn configuration on the client
- activating NAT on the client
On the server we will use the UDP ports 5080 et 5081.
Connections speed must be defined in bytes to allow mlvpn to correctly balance the traffic over the links, this is really important.
bandwidth_upload = 1468006 is the maximum download bandwidth of the
client on the specified link in bytes. If you have a download speed of 1.4 MB/s
then you can choose a value of 1.4*1024*1024 => 1468006.
bandwidth_download = 102400 is the maximum upload bandwidth of the
client on the specified link in bytes. If you have an upload speed of 100 kB/s
then you can choose a value of 100*1024 => 102400.
The password line must be a very long random string, it’s a shared secret between the client and the server.
# config you don't need to change [general] statuscommand = "/etc/mlvpn/mlvpn_updown.sh" protocol = "tcp" loglevel = 4 mode = "server" tuntap = "tun" interface_name = "tun0" cleartext_data = 0 ip4 = "10.44.43.2/30" ip4_gateway = "10.44.43.1" # things you need to change password = "apoziecxjvpoxkvpzeoirjdskpoezroizepzdlpojfoiezjrzanzaoinzoi" [dsl1] bindhost = "22.214.171.124" bindport = 5080 bandwidth_upload = 1468006 bandwidth_download = 102400 [dsl2] bindhost = "126.96.36.199" bindport = 5081 bandwidth_upload = 1468006 bandwidth_download = 102400
password value must match the one on the server, the values of
ip4_gateway must be reversed compared to the server configuration (this is so
in the following example).
bindfib lines must correspond to the according rdomain values of your
# config you don't need to change [general] statuscommand = "/etc/mlvpn/mlvpn_updown.sh" loglevel = 4 mode = "client" tuntap = "tun" interface_name = "tun0" ip4 = "10.44.43.1/30" ip4_gateway = "10.44.43.2" timeout = 30 cleartext_data = 0 password = "apoziecxjvpoxkvpzeoirjdskpoezroizepzdlpojfoiezjrzanzaoinzoi" [dsl1] remotehost = "188.8.131.52" remoteport = 5080 bindfib = 1 [dsl2] remotehost = "184.108.40.206" remoteport = 5081 bindfib = 2
NAT configuration (server side)
As with every VPN you must enable packet forwarding and create a pf rule for the NAT.
Add this line in /etc/sysctl.conf:
You can enable it now with
sysctl net.inet.ip.forwarding=1 instead of waiting
for a reboot.
In pf.conf you must allow the UDP ports 5080 and 5081 on the public interface and enable nat, this can be done with the following lines in pf.conf but you should obviously adapt to your configuration.
# allow NAT on VPN pass in on tun0 pass out quick on em0 from 10.44.43.0/30 to any nat-to em0 # allow mlvpn to be reachable pass in on egress inet proto udp from any to (egress) port 5080:5081
On both server and client you can run mlvpn with rcctl:
rcctl enable mlvpn rcctl start mlvpn
You should see a new tun0 device on both systems and being able to ping them through tun0.
Now, on the client you have to add a default gateway through the mlvpn
tunnel with the command
route add -net default 10.44.43.2 (adapt if you
use others addresses). I still didn’t find how to automatize it properly.
Your client should now use both WAN links and being visible with the remote server public IP address.
mlvpn can be used for more links, you only need to add new sections.
mlvpn also support IPv6 but I didn’t take time to find how to make it work,
si if you are comfortable with ipv6 it may be easy to set up IPv6 with the
ip6_gateway in mlvpn.conf.