不建议用 netfilter 模块开发高性能防火墙,因其 hook 串行回调、协议栈开销大、多核扩展差;应优先选用 ebpf/xdp 方案,实现零拷贝、驱动层过滤。

直接回答:不建议用 Netfilter 模块开发“高性能防火墙”
除非你已深度参与 Linux 内核网络子系统维护,否则在 2024 年仍基于 nf_register_hook 或 nf_register_net_hook 写内核态防火墙模块,大概率会陷入性能瓶颈、维护成本爆炸、兼容性断裂三重困境。Netfilter 的 hook 点(如 NF_INET_PRE_ROUTING)本质是串行回调链,单核吞吐受制于规则遍历+内存访问模式,且无法绕过协议栈开销(skb 分配、校验和检查、conntrack 初始化等)。真正追求高性能的场景,应优先评估 eBPF/XDP 或内核旁路方案。
为什么 nf_hook_ops 在高并发下容易卡住
常见现象是:pps 超过 50k 后延迟陡增、CPU 单核跑满、softirq 时间占比持续高于 70%。根本原因不是代码写得差,而是 Netfilter hook 的设计约束:
-
nf_hook_ops回调运行在 softirq 上下文,不可睡眠,所有逻辑必须原子完成; - 每个包必须顺序经过全部注册的 hook(即使你的模块只关心 TCP SYN),无法跳过无关协议处理;
- skb 数据可能未线性化(
skb_is_nonlinear()为真),访问 payload 前需skb_linearize()—— 这会触发内存拷贝,在 XDP 层本可避免; - conntrack 查找(
nf_conntrack_invert_tuple())涉及哈希表加锁,多核扩展性差; - 内核版本升级常导致
struct nf_hook_ops字段变更(如 5.10+ 新增hook_thresh),模块需同步适配。
如果非要用 Netfilter,关键避坑点
仅当满足以下条件时才考虑:目标设备是嵌入式网关(单核 ARM,流量
- 用
nf_register_net_hook(&init_net, &my_hook)替代旧式nf_register_hook(),避免命名空间污染; - 在 hook 函数开头快速判断协议/端口(用
ip_hdr(skb)->protocol和tcp_hdr(skb)->dest),不匹配立即返回NF_ACCEPT; - 禁用 conntrack:在模块 init 中调用
nf_ct_untrack(skb),否则每个包都会被塞进 conntrack 表; - 规则存储不用链表,改用 RCU + 预分配数组(
struct rule_entry rules[MAX_RULES]),避免遍历时 cache miss; - 日志用
pr_debug()并关闭动态调试(echo 0 > /sys/module/nf_log_common/parameters/debug),否则 printk 会锁住整个 softirq。
XDP 替代方案比 Netfilter 更实际
如果你的真实诉求是“在网卡驱动层丢弃恶意包”,XDP 是更合理的选择。它运行在驱动收包中断之后、协议栈之前,零拷贝、无 skb 构造开销。C++ 不能直接写 XDP,但可用 C 编写 eBPF 程序,再用 libbpf + C++ 用户态控制(如加载规则、读取统计):
// xdp_firewall.c(编译为 .o 后用 libbpf 加载)
SEC("xdp")
int xdp_drop_bad_packets(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end) return XDP_PASS;
if (eth->h_proto == htons(ETH_P_IP)) {
struct iphdr *ip = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*ip) protocol == IPPROTO_TCP) {
struct tcphdr *tcp = (void *)ip + (ip->ihl ihl dest == htons(65535)) // 示例:封禁端口 65535
return XDP_DROP;
}
}
return XDP_PASS;
}
这种写法在 10G 网卡上轻松达到 8M pps,而同等逻辑的 Netfilter 模块通常卡在 200k pps 左右。真正的复杂点在于:XDP 不支持修改包内容(如 NAT)、不能访问 socket 层信息、部分网卡驱动不支持 offload 模式。这些限制恰恰说明——所谓“高性能防火墙”,从来不是靠在 Netfilter 里堆优化技巧实现的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











