本文介绍了在macOS上开发和测试XDP(eXpress Data Path)程序的解决方案。由于XDP是Linux内核特性,直接在macOS上运行会导致错误。文章探讨了使用Docker的不足,并推荐使用Lima虚拟机来提供一个真正的Linux内核环境,详细说明了Lima的安装、配置,以及如何在Lima虚拟机中构建和运行XDP程序,解决了在macOS上进行XDP开发的难题。
无法在 macOS 上运行 XDP 程序? 那是因为 XDP 需要 Linux 内核。 本指南向你展示了如何使用 Lima(一个轻量级的 Linux 虚拟机)在 macOS 上开发和测试 XDP 程序,而无需 Docker 的复杂性。
我最近尝试按照官方 Aya 文档 使用他们提供的模板运行一个简单的 XDP 程序。 这些步骤看起来很简单:生成项目,构建它,然后运行它。 但是,在 macOS 上尝试这样做很快导致了令人困惑的失败。
这篇文章不是一个全面的教程,而是对失败的内容、失败的原因以及最终有效的内容的实践记录。 如果你尝试在 macOS 上开发 XDP 程序,这可能会节省你的调试时间。
Aya 文档假定使用 Linux 环境。 我使用官方模板和 Rust 工具在 macOS 上执行了相同的步骤。 该项目成功构建,这最初让人感觉一切正常。 真正的问题只有在尝试运行程序并将 XDP 附加到网络接口时才会出现。

在 macOS 上运行 XDP 程序会导致与缺少系统调用和内核接口相关的错误。 诸如 bpf()、perf_event_open() 之类的函数以及与 netlink 相关的符号在 macOS 上根本不存在。 错误消息具有误导性,最初看起来像是依赖问题,但根本原因要深得多。
XDP 是一项 Linux 内核功能。 macOS 使用 Darwin (XNU) 内核,该内核未实现 XDP 所需的 eBPF 子系统。 这些缺失的系统调用和内核Hook无法从用户空间添加。 即使代码成功编译,也没有内核支持在 macOS 上执行 XDP 程序。
简而言之:XDP 需要 Linux。 任何数量的用户空间工具都无法解决这一根本限制。
Docker 是我的下一个尝试。 虽然 Docker 确实在 macOS 上运行了一个 Linux 内核(通过轻量级虚拟机),但它的网络堆栈被严重抽象化了。 由于 XDP 需要在网络驱动程序级别附加并直接与网络接口交互,因此 Docker 的虚拟化网络使调试变得更加困难,而不是更容易。
Docker 在容器化应用程序方面表现出色,但对于像 XDP 这样的底层内核功能,它会引入不必要的复杂性。
此时,几位朋友建议使用 Lima。 这个想法很简单:停止与内核限制作斗争,只需使用真正的 Linux 内核。 Lima 在 macOS 上提供了一个轻量级的 Linux 虚拟机,并且感觉比 Docker 更适合内核级别的开发。
Lima 专门为需要在 macOS 上使用 Linux 环境的开发人员而设计,具有合理的默认设置并且与主机系统集成良好。
我们不需要自定义的 lima.yaml 或复杂的配置。 启动默认的 Ubuntu Lima VM 就足够了。 macOS 主目录会自动挂载在 VM 内部,因此无需任何额外设置即可访问该项目。
## 使用 Homebrew 安装 Lima
brew install lima
## 启动默认的 Ubuntu VM
limactl start
## 进入 VM
lima
进入 Lima VM 后,安装 XDP 和 Aya 开发所需的所有依赖项:
## 更新系统包
sudo apt update && sudo apt upgrade -y
## 安装核心构建和 eBPF 依赖项
sudo apt install -y \
build-essential \
clang \
llvm \
lld \
llvm-dev \
llvm-runtime \
libelf-dev \
linux-headers-$(uname -r) \
iproute2 \
bpftool \
pkg-config \
git \
curl
## 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
## 安装 nightly 工具链 + rust-src(eBPF 所需)
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
rustup default nightly
## 安装 bpf-linker(Aya 链接 eBPF 程序所需)
cargo install bpf-linker
导航到 Lima VM 内部的项目目录。 由于 Lima 默认挂载你的 macOS 主目录,因此你的项目应该可以在同一路径下访问。
Lima 默认将你的 macOS 目录挂载为只读。 这意味着 cargo build 将因权限错误而失败。 最简单的解决方案是将你的项目复制到你具有写入权限的 VM 主目录中:
## 在 Lima VM 内部
mkdir -p ~/work
cp -r ~/documents/networking/xdp-hello ~/work/
cd ~/work/xdp-hello
注意:这使用了我特定的文件路径。 更改 ~/documents/networking/xdp-hello 以匹配你的项目位置
或者,你可以重新配置 Lima 的挂载设置(高级)。
在 macOS 上编辑 Lima 配置:
limactl edit ubuntu
将挂载部分更改为:
mounts:
- location: "~"
writable: true
然后重启 VM:
limactl stop ubuntu
limactl start ubuntu
现在你可以构建而不会出现任何权限问题。
使用此构建命令在内核空间中编译 XDP 程序:
cargo +nightly build -Z build-std=core --target bpfel-unknown-none
现在正常构建用户空间程序:
cargo build
找到 XDP 将附加到的网络接口:
ip link
在 Lima VM 中,这通常是 eth0。
运行 XDP 程序并将其显式附加到接口:
sudo RUST_LOG=info target/debug/xdp-hello --iface eth0
你应该看到类似于以下内容的输出:
Waiting for Ctrl-C...
此输出表明用户空间加载程序正在运行,并且 XDP 程序已附加到该接口。 但是,XDP 程序仅在实际网络流量流经附加的接口时执行。
打开另一个终端,进入 Lima VM,并生成一些网络流量:
## 在新终端中进入 Lima VM
lima
## 在 eth0 上生成流量
ping -I eth0 8.8.8.8
当你 ping 时,你将在主终端中看到输出: 
此输出来自 Aya 文档 中提供的默认 Aya 模板代码。
我一路遇到的失败不是由 Aya 或 Rust 引起的,而是由于尝试在非 Linux 内核上运行 Linux 内核功能。 一旦环境与 Aya 文档所做的假设相匹配,一切都按预期运行。
事实证明,Lima 是在 macOS 上运行 XDP 程序的最简单、最简洁的方法,而无需不必要的抽象或复杂性。 如果你正在 macOS 上进行任何内核级别的 Linux 开发,那么与 Docker 或其他虚拟化解决方案相比,Lima 值得考虑。
如果你在遵循本指南时遇到任何问题或对 XDP 开发有疑问,请随时与我联系。 你还可以查看 Aya 社区 以获取更多帮助。
觉得有帮助? 与其他努力在 macOS 上运行 XDP 程序的开发人员分享它。
- 原文链接: jkrishna.xyz/blog/runnin...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!