一、 前言

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


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

netkittcx 钩子需要较新的内核支持。我们选择 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编程工具,助力开发者即刻编程。

更多推荐