A fast eBPF-based router for Linux
This is mostly exploratory code, and not intended for production use.
sudo snap install go --channel=1.24/stable --classic
sudo apt update
sudo apt -y install clang llvm gcc-multilib libbpf-dev# 1. Create namespaces
for ns in hostA router hostB; do
sudo ip netns add $ns
sudo ip netns exec $ns ip link set lo up
done
# 2. Create veths
sudo ip link add vethA type veth peer name vethR1
sudo ip link add vethB type veth peer name vethR2
sudo ip link set vethA netns hostA
sudo ip link set vethR1 netns router
sudo ip link set vethB netns hostB
sudo ip link set vethR2 netns router
# 3. Assign addresses & bring up
sudo ip netns exec hostA ip addr add 10.0.0.1/24 dev vethA
sudo ip netns exec hostA ip link set vethA up
sudo ip netns exec router ip addr add 10.0.0.254/24 dev vethR1
sudo ip netns exec router ip link set vethR1 up
sudo ip netns exec hostB ip addr add 10.1.0.1/24 dev vethB
sudo ip netns exec hostB ip link set vethB up
sudo ip netns exec router ip addr add 10.1.0.254/24 dev vethR2
sudo ip netns exec router ip link set vethR2 up
sudo ip netns exec hostA ip route add 10.1.0.0/24 via 10.0.0.254 dev vethA
sudo ip netns exec hostB ip route add 10.0.0.0/24 via 10.1.0.254 dev vethBgo build cmd/router/main.go
sudo ip netns exec router ./main --config router.yamlCreate three LXD networks:
lxc network create net1 ipv4.address=10.0.0.1/24 ipv4.routing=false
lxc network create net2 ipv4.address=20.0.0.1/24 ipv4.routing=falseCreate three Multipass instances:
multipass launch noble --name=host1 --network net1
multipass launch noble --name=host2 --network net2
multipass launch noble --name=router --network net1 --network net2Validate that the 3 instances have been created:
multipass listYou should see the following output:
Name State IPv4 Image
host1 Running 10.166.86.124 Ubuntu 24.04 LTS
10.0.0.144
host2 Running 10.166.86.61 Ubuntu 24.04 LTS
20.0.0.41
router Running 10.166.86.122 Ubuntu 24.04 LTS
10.0.0.130
20.0.0.12Connect to host1:
multipass shell host1Create a route to host2:
sudo ip route add 20.0.0.0/24 via 10.0.0.130 dev ens4Try to ping host2:
ping -I ens4 20.0.0.41You should see that the ping fails.
Exit the shell:
exitLog into host2:
multipass shell host2Create a route to host1:
sudo ip route add 10.0.0.0/24 via 20.0.0.12 dev ens4Exit the shell:
exitLog into the router:
multipass shell routerBuild the project:
sudo snap install go --channel=1.24/stable --classic
sudo apt update
sudo apt -y install clang llvm gcc-multilib libbpf-dev
git clone https://github.com/gruyaume/router.git
cd router
go build cmd/router/main.goWrite the configuration file:
cat << EOF > router.yaml
interfaces: ["ens4", "ens5"]
routes:
- destination: "10.0.0.144"
prefixlen: 24
interface: "ens4"
gateway: "0.0.0.0"
- destination: "20.0.0.41"
prefixlen: 24
interface: "ens5"
gateway: "0.0.0.0"
neighbors:
- ip: "10.0.0.144"
mac: "52:54:00:e1:7b:38"
- ip: "20.0.0.41"
mac: "52:54:00:86:fe:fd"
log_level: "info"
EOFRun the router:
sudo ./main --config router.yamlRouter is configured using a YAML file.
Start Router with the --config flag to specify the path to the configuration file.
interfaces(list[string]): List of interfaces to be used by the router. The eBPF program will be attached to all of them.routes(list[route]): List of routes to be added to the routing table. Each route is defined by:destination(string): The destination IP address.prefixlen(int): The prefix length of the destination IP address.interface(string): The interface to use for this route.gateway(string): The gateway IP address for this route.
neighbors(list[neighbor]): List of neighbors to be added to the ARP table. Each neighbor is defined by:ip(string): The IP address of the neighbor.mac(string): The MAC address of the neighbor.
interfaces: ["vethR1", "vethR2"]
routes:
- destination: "10.1.0.1"
prefixlen: 32
interface: "vethR2"
gateway: "0.0.0.0"
- destination: "10.0.0.1"
prefixlen: 32
interface: "vethR1"
gateway: "0.0.0.0"
neighbors:
- ip: "10.0.0.1"
mac: "c6:9f:fb:e6:cc:1f"
- ip: "10.1.0.1"
mac: "8a:93:d5:28:9e:35"
log_level: "info"Using the Multipass setup, I am able to achieve over 3 Gbps throughput between host1 and host2, going through the router.
ubuntu@host1:~$ iperf3 -c 20.0.0.41 --bind-dev ens4
Connecting to host 20.0.0.41, port 5201
[ 5] local 10.0.0.144 port 33702 connected to 20.0.0.41 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 403 MBytes 3.37 Gbits/sec 509 520 KBytes
[ 5] 1.00-2.00 sec 404 MBytes 3.39 Gbits/sec 302 457 KBytes
[ 5] 2.00-3.00 sec 404 MBytes 3.39 Gbits/sec 151 687 KBytes
[ 5] 3.00-4.00 sec 435 MBytes 3.65 Gbits/sec 81 940 KBytes
[ 5] 4.00-5.00 sec 417 MBytes 3.50 Gbits/sec 247 433 KBytes
[ 5] 5.00-6.00 sec 403 MBytes 3.38 Gbits/sec 156 496 KBytes
[ 5] 6.00-7.00 sec 416 MBytes 3.49 Gbits/sec 164 550 KBytes
[ 5] 7.00-8.00 sec 403 MBytes 3.38 Gbits/sec 331 369 KBytes
[ 5] 8.00-9.00 sec 420 MBytes 3.53 Gbits/sec 0 882 KBytes
[ 5] 9.00-10.00 sec 394 MBytes 3.31 Gbits/sec 305 393 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 4.00 GBytes 3.44 Gbits/sec 2246 sender
[ 5] 0.00-10.00 sec 4.00 GBytes 3.44 Gbits/sec receiver
iperf Done.