一、 前言

随着 Linux 内核的演进,netkit 作为一种专为 eBPF 优化的新型虚拟网卡设备(Veth 的高性能替代品),在容器网络和云原生领域崭露头角。本文将带大家在最新的 Debian 13 (Trixie) 上,从底层内核编译开始,一步步实现 netkit 的部署与 eBPF tcx 程序的挂载。


二、 环境准备:编译 Kernel 7.1 与开启 BTF

netkit 和 tcx 钩子需要较新的内核支持。我们选择 7.1-rc 内核。

1. 安装内核编译依赖

sudo apt update
sudo apt install -y build-essential libncurses-dev bison flex libssl-dev libelf-dev \
     dwarves bc xz-utils libcap-dev pkg-config

2. 配置内核选项

进入内核源码目录,开启 BPF 和 BTF 支持(这是 eBPF CO-RE 的核心):

make menuconfig

在界面中确保以下选项为 [ * ] 或 [ Y ]:

  • General setup -> BPF subsystem -> BPF_SYSCALL

  • Kernel hacking -> Compile-time checks and compiler options -> Generate BTF typeinfo (CONFIG_DEBUG_INFO_BTF)

  • Device Drivers -> Network device support -> Network core driver support -> Netkit support

3. 编译与安装

make -j$(nproc)
sudo make modules_install
sudo make install
sudo reboot

三、 编译 eBPF 瑞士军刀:bpftool

由于 netkit 使用了全新的 tcx 挂载方式,我们需要编译与之配套的 bpftool。

# 进入内核源码下的工具目录
cd tools/bpf/bpftool
# 安装 LLVM/Clang 开发环境
sudo apt install -y llvm clang llvm-dev libclang-dev
# 编译并安装
make -j$(nproc)
sudo make install

四、 Netkit 驱动详解:L2、L3 与 Policy

netkit 相比传统的 veth,其设计的精妙之处在于模式的可定制化。

1. 工作模式 (Mode)

  • L3 Mode (默认):设备仅处理 IP 数据包,不保留以太网头(Ethernet Header)。适用于高性能容器路由。

  • L2 Mode:保留以太网帧结构,表现得像一个真实的物理网卡,适用于需要网桥 (Bridge) 接入的场景。

2. 策略 (Policy)

netkit 允许在内核层定义默认动作(无需 eBPF 即可生效):

  • forward:正常转发数据包。

  • blackhole:静默丢弃(不发送任何反馈)。

  • drop:丢弃并可能触发错误反馈。


五. 核心原理:eBPF 如何与 Netkit 结合(tcx 机制解析)

在传统的 Linux 网络架构中,虚拟网卡(如 veth)与 eBPF 的结合通常依赖于 tc(Traffic Control)子系统。然而,netkit 的出现彻底改变了这一游戏规则。

1. 为什么 Netkit 选择了 TCX?

传统的 tc 框架存在一些历史包袱(如复杂的 qdisc 队列、分类器等),导致路径较长。netkit 引入了全新的 tcx 钩子:

  • 直接挂载:tcx 是专门为 eBPF 设计的,它跳过了传统 tc 复杂的解析逻辑,直接在驱动层触发。

  • 多程序链式执行:tcx 支持 bpf_link,这意味着多个 eBPF 程序可以按照优先级(Priority)顺序挂载在同一个 netkit 接口上,而不会互相覆盖。

  • 极低开销:由于 netkit 抛弃了以太网头的强制封装(L3 模式下),eBPF 程序可以直接处理 IP 层数据,减少了内存拷贝和头部解析的开销。

2. 数据流向与 eBPF 触发点

在 netkit 架构中,eBPF 程序可以挂载在两个核心位置:

  • tcx/ingress:当数据包“进入”该网卡时触发。如果 nk0 位于 Namespace A,nk1 位于主机,那么从 A 发往主机的包,在主机的 nk1 入口处会被 ingress 程序捕获。

  • tcx/egress:当数据包准备“离开”网卡时触发。

3. 编程接口的演进:__sk_buff

在 netkit 中,eBPF 程序接收的是 struct __sk_buff *skb。

  • 如果你使用的是 L3 模式:skb->data 指向的是 IP 头,没有 ethhdr。

  • 如果你使用的是 L2 模式:skb->data 指向的是以太网头,你需要像我上文的代码示例那样进行边界检查并解析。

4. 高级交互:Policy 与 eBPF 的协作

netkit 的独特之处在于 eBPF 程序可以动态覆盖设备的默认策略(Policy):

  • 如果 eBPF 程序返回 BPF_OK,数据包将遵循网卡预设的 policy(如 forward)。

  • 如果 eBPF 程序返回 BPF_DROP,数据包将被直接丢弃,优先级高于网卡自身的任何设置。

  • 通过 bpf_redirect(),eBPF 甚至可以绕过协议栈,将 netkit 的包直接“重定向”到另一个网卡或 Socket,实现极速转发。

六、 实战:部署 Netkit 与跨 Namespace 验证

1. 创建并激活 Netkit 设备对

我们创建一个工作在 L2 模式 的设备对:

sudo ip link add nk0 type netkit mode l2 peer name nk1
sudo ip link set dev nk0 up
sudo ip link set dev nk1 up

2. 跨网络命名空间 (NetNS) 测试

将 nk0 移入新创建的命名空间 ns0:

sudo ip netns add ns0
sudo ip link set dev nk0 netns ns0

# 配置 IP 地址
sudo ip netns exec ns0 ip addr add 10.0.0.1/24 dev nk0
sudo ip netns exec ns0 ip link set nk0 up
sudo ip addr add 10.0.0.2/24 dev nk1

# 验证连通性
sudo ip netns exec ns0 ping -c 3 10.0.0.2

七、 进阶:编译 eBPF 程序并 Attach 到 Netkit

我们编写一个简单的 eBPF 程序,捕获进入 netkit 的 IP 数据包。

1. 编写 C 程序 (my_netkit_ebpf.c)

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>

SEC("tcx/ingress")
int handle_netkit_ingress(struct __sk_buff *skb) {
    void *data_end = (void *)(long)skb->data_end;
    void *data = (void *)(long)skb->data;
    struct ethhdr *eth = data;

    if (data + sizeof(*eth) > data_end) return BPF_OK;

    if (eth->h_proto == __constant_htons(ETH_P_IP)) {
        bpf_printk("Netkit: Caught IP packet!\n");
    }
    return BPF_OK;
}

char _license[] SEC("license") = "GPL";

2. 编译为 BPF 字节码

clang -O2 -g -target bpf -c my_netkit_ebpf.c -o my_netkit_ebpf.o

3. 使用 bpftool 挂载到 tcx 钩子

netkit 抛弃了传统的 tc 挂载,直接使用 tcx_ingress 路径,速度极快。

# 加载并固定程序
sudo bpftool prog load my_netkit_ebpf.o /sys/fs/bpf/my_prog
# 挂载到 nk1 的入口
sudo bpftool net attach tcx_ingress name handle_netkit_ingress dev nk1

4. 结果展示

再次运行之前的 ping 命令,然后查看内核日志:

sudo cat /sys/kernel/debug/tracing/trace_pipe

输出结果示例:

<...>-1234  [001] .Ns1  123.456: bpf_trace_printk: Netkit: Caught IP packet!

八、 总结

在 Debian 13 与 Kernel 7.1 的加持下,netkit 展现了极其简洁的配置逻辑和强大的 eBPF 扩展性。通过 tcx 钩子,我们可以实现零拷贝的数据包监控和过滤,这正是下一代高性能云原生网络的基础。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐