The eBPF (Extended Berkeley Packet Filter) is a powerful Linux kernel technology that allows developers to run sandboxed programs directly within the kernel, extending its functionality safely and efficiently without changing source code or loading modules.
On macOS, we need a virtual machine to test and run eBPF programs. There are several choices, including Docker, Lima, QEMU, VirtualBox, VMWare, etc. Some of them do not support all kinds of eBPF programs. For example, if you want to run XDP programs, you need to use a VM that supports full networking features. In this tutorial, we will set up an eBPF development environment using VirtualBox on an M1 macOS machine.
Before the Apple M1 (ARM architecture), I used VirtualBox on Intel macOS to run an Ubuntu VM for eBPF development. Back then, I was using the redbpf library, which has been deprecated, to write eBPF programs in Rust. After switching to M1 macOS, VirtualBox was not available for a long time. Recently, I found that VirtualBox now supports ARM architecture and can run ARM-based Linux distributions. This makes it possible to set up an eBPF development environment on M1 macOS using VirtualBox.
Prerequisites
brew install filosottile/musl-cross/musl-cross
By default, it will install full cross compiler toolchains targeting musl Linux amd64, arm64, and arm.
which x86_64-linux-musl-gcc
which aarch64-linux-musl-gcc
Install VirtualBox for Apple Silicon hosts from here.
Install rustup and Rust toolchain if you haven’t already:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target install aarch64-unknown-linux-musl
rustup target install x86_64-unknown-linux-musl
Install vagrant via homebrew:
brew tap hashicorp/tap
brew install hashicorp/tap/hashicorp-vagrant
Install the vagrant-reload plugin to allow reloading the VM without destroying it:
vagrant plugin install vagrant-reload
Set up the VM
Create a Vagrantfile with the following content in your project directory:
Vagrant.configure("2") do |config|
config.vm.box = "cloud-image/debian-13"
config.vm.box_version = "20260112.2355.0"
# Disable synced folder
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/home/vagrant/aya-hello", automount: true
config.vm.network "private_network", type: "dhcp"
config.vm.box_check_update = false
config.vagrant.plugins = ["vagrant-reload"]
config.vm.provider "virtualbox" do |virtualbox|
virtualbox.memory = 4096
virtualbox.cpus = 2
end
# Eventually use cloud-init to execute jobs
config.vm.cloud_init do |cloud_init|
cloud_init.content_type = "text/cloud-config"
cloud_init.inline = <<-EOF
apt:
## Use mirrors if needed
# primary:
# - arches: [default]
# uri: https://mirrors.ustc.edu.cn/debian
# security:
# - arches: [default]
# uri: https://mirrors.ustc.edu.cn/debian-security
package_update: true
packages:
- build-essential
- linux-headers-arm64
- dkms
- bpfcc-tools
- bpftool
runcmd:
- wget http://download.virtualbox.org/virtualbox/7.2.4/VBoxGuestAdditions_7.2.4.iso
- mkdir /media/VBoxGuestAdditions
- mount -o loop,ro VBoxGuestAdditions_7.2.4.iso /media/VBoxGuestAdditions
- sh /media/VBoxGuestAdditions/VBoxLinuxAdditions-arm64.run
- rm VBoxGuestAdditions_7.2.4.iso
- umount /media/VBoxGuestAdditions
- rmdir /media/VBoxGuestAdditions
- sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
- echo 'LANG="en_US.UTF-8"' > /etc/default/locale
- dpkg-reconfigure --frontend=noninteractive locales
- update-locale LANG=en_US.UTF-8
- chsh -s /bin/bash vagrant
EOF
end
endVagrantfile
Cross-compile and run eBPF program
To cross-compile the eBPF program for the VM, run the following command on your macOS host:
cargo build --release --target=aarch64-unknown-linux-musl
Start the VM:
vagrant up
Wait for the VM to be fully set up. This may take some time as it installs the necessary packages.
SSH into the VM:
vagrant ssh
Navigate to the shared folder where your project is located:
cd /home/vagrant/aya-hello
Run the eBPF program inside the VM:
sudo RUST_LOG=debug target/aarch64-unknown-linux-musl/release/aya-hello
Conclusion
You have successfully set up an eBPF development and test environment on M1 macOS using VirtualBox. VirtualBox provides a full-featured VM with networking support, making it suitable for testing various types of eBPF programs, including XDP.
If you are not developing eBPF programs for network devices, you can also consider other VM solutions such as Docker, Lima, or QEMU, based on your requirements.
You can find the complete code for this tutorial in the aya-hello repository.