Polycube是一个基于 eBPF 和 XDP 技术的开源软件框架,用于在Linux内核中构建快速、灵活的网络功能。
介绍
Polycube 是一个基于 Linux 的开源软件框架,提供快速且轻量级的网络功能,比如网桥(bridge)、路由器(router)、网络地址转换(NAT)、负载均衡器(load balancer)、防火墙(firewall)、DDoS 缓解器等。
架构:
- 交互方式:
- polycubectl,命令行工具,用于人工交互
- polycubed,REST API 守护进程,接收 polycubectl 或其他外部指令,用于自动交互
- 架构
- 应用层:应用程序,如 pcn-k8s, pcn-iptables,通过调用 polycubed 或 CLI 来驱动底层 cubes
- 控制与管理层:polycubectl/polycubed,人工/自动控制工具
- 功能模块层:各种可用的 “Cubes” (具体的网络功能模块)
- 底层:基于 BPF/XDP 的 Linux 内核支撑

eBPF
eBPF 程序可以加载到指定的内核代码路径(如 tc、XDP 等)中,当执行该代码路径时,则会执行对应的 eBPF 程序。

PolyCube 主要利用的 XDP 和 tc 挂载 eBPF 程序
XDP (eXpress Data Path) BPF
- 位置: 挂载在网卡驱动层,是数据包进入的最早阶段
- 能力: 性能极高,主要用于高速过滤、DDoS 防护和简单的负载均衡
- 方向: 作用于 Ingress 方向
- 返回值: 程序可以返回
XDP_DROP (丢弃)、XDP_PASS (放行到协议栈)、XDP_TX (原路返回)、XDP_REDIRECT (重定向到其他接口)
TC (Traffic Control) BPF
- 位置: 挂载在内核网络协议栈的 TC 层,位于网络驱动层
- 能力: 可以访问更丰富的数据包元数据,适合进行复杂的流量控制、分类、整形(QoS)、策略执行等
- 方向: 同时支持 Ingress 和 Egress 两个方向
- 返回值: 程序可以返回
TC_ACT_OK (放行)、TC_ACT_SHOT (丢弃)、TC_ACT_REDIRECT (重定向) 等动作

开发
以 pcn-iptables 为例
函数注册
CMake 构建时,将 datapaths 下的代码内容加载成变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
load_file_as_variable(pcn-iptables datapaths/Iptables_ActionLookup_dp.c iptables_code_actionlookup) load_file_as_variable(pcn-iptables datapaths/Iptables_BitScan_dp.c iptables_code_bitscan) load_file_as_variable(pcn-iptables datapaths/Iptables_ChainForwarder_dp.c iptables_code_chainforwarder) load_file_as_variable(pcn-iptables datapaths/Iptables_ChainSelector_dp.c iptables_code_chainselector) load_file_as_variable(pcn-iptables datapaths/Iptables_ConntrackLabel_dp.c iptables_code_conntracklabel) load_file_as_variable(pcn-iptables datapaths/Iptables_ConntrackMatch_dp.c iptables_code_conntrackmatch) load_file_as_variable(pcn-iptables datapaths/Iptables_ConntrackTableUpdate_dp.c iptables_code_conntracktableupdate) load_file_as_variable(pcn-iptables datapaths/Iptables_Horus_dp.c iptables_code_horus) load_file_as_variable(pcn-iptables datapaths/Iptables_IpLookup_dp.c iptables_code_iplookup) load_file_as_variable(pcn-iptables datapaths/Iptables_L4PortLookup_dp.c iptables_code_l4portlookup) load_file_as_variable(pcn-iptables datapaths/Iptables_InterfaceLookup_dp.c iptables_code_interfacelookup) load_file_as_variable(pcn-iptables datapaths/Iptables_L4ProtocolLookup_dp.c iptables_code_l4protolookup) load_file_as_variable(pcn-iptables datapaths/Iptables_Parser_dp.c iptables_code_parser) load_file_as_variable(pcn-iptables datapaths/Iptables_TcpFlagsLookup_dp.c iptables_code_tcpflagslookup)
|
pcn-iptables
Ingress 数据包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| Packet in (TC/XDP ingress) ↓ ┌────────────────────┐ │ Parser_ingress │ │ Iptables_Parser_dp │ └─────────┬──────────┘ ↓ _HORUS_ENABLED? ├── YES ─────┐ ↓ ↓ ┌──────────────┐ ┌──────────────────┐ │ Horus_dp │ │ ChainSelector_dp │ └───────┬──────┘ └───────┬──────────┘ ↓ ↓ ┌────────────────────────────────────┐ │ ConntrackLabel_dp (ingress) │ └──────────────┬─────────────────────┘ ↓ ┌───────────────────────────┐ │ ChainForwarder_dp │ └──────────────┬────────────┘ ↓ _NEXT_HOP_INPUT_1 / _NEXT_HOP_FORWARD_1 ↓ ┌────────────────────────────────────┐ │ Rule chain subprograms │ │ BitScan → IpLookup → InterfaceLookup │ │ → ConntrackMatch → L4ProtocolLookup │ │ → L4PortLookup → TcpFlagsLookup │ │ → ActionLookup │ └──────────────┬─────────────────────┘ ↓ _CONNTRACKTABLEUPDATE_INGRESS ↓ RX_OK / RX_DROP
|
1. 整体架构
1.1 系统分层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ┌─────────────────────────────────────────────────┐ │ 用户态 (Userspace API) │ │ REST API / CLI 接口 │ │ ├─ 添加/删除规则 │ │ ├─ 配置链(INPUT/FORWARD/OUTPUT) │ │ ├─ 查询统计信息 │ │ └─ 启用/禁用功能(Horus, Conntrack) │ └────────────────┬────────────────────────────────┘ │ ┌───────┴────────┐ ↓ ↓ Control Plane Data Plane (Iptables.cpp) (BPF Programs) │ │ ┌────┴─────────┐ ┌───┴──────────────────┐ │ Chain │ │ Kernel (eBPF) │ │ Manager │ │ Parser/Lookup/... │ │ │ │ AttackPoint Hook │ │ Rule │ │ (TC/XDP) │ │ Compiler │ │ │ │ │ │ BPF Tables (Maps) │ │ BPF Code │ │ per_cpu_array │ │ Generation │ │ hash / lpm_trie │ └──────────────┘ └────────────────────────┘
|
1.2 关键类结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Iptables (主容器) ├─ 3 个 Chain 对象 │ ├─ INPUT │ ├─ FORWARD │ └─ OUTPUT │ ├─ 每个 Chain 包含 N 个 ChainRule 对象 │ ├─ Rule 0: src=10.0.0.1, dst=10.0.0.2, action=DROP │ ├─ Rule 1: src=10.0.0.3, dst=*, action=ACCEPT │ └─ Rule N: ... │ └─ SessionTable (连接追踪表) ├─ (src, dst, proto, sport, dport) → 连接状态 └─ 状态:NEW / ESTABLISHED / RELATED / INVALID
|
2. 规则结构
2.1 ChainRule 的匹配维度
每条规则可以指定以下匹配条件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| struct ChainRule { std::string src; std::string dst; std::string l4proto; uint16_t sport; uint16_t dport; std::string tcpflags; std::string inIface; std::string outIface; ConntrackstatusEnum conntrack; ActionEnum action; };
|
2.2 规则匹配过程
示例规则链:
1 2 3 4 5 6
| Rule ID | Src IP | Dst IP | Proto | DPort | Action --------|-------------|-------------|-------|-------|-------- 0 | 10.0.0.0/24 | 192.168.0.1 | TCP | 443 | DROP 1 | * | 10.0.0.1 | ICMP | * | ACCEPT 2 | 172.16.0.0/16 | * | UDP | 53 | ACCEPT 3 | * | * | * | * | DEFAULT
|
匹配流程示例(数据包 10.0.0.5 → 192.168.0.1:443 TCP):
1 2 3 4 5 6 7 8 9 10
| ┌─ BitScan 初始化:bits = 0x111...1 (所有规则) │ ├─ Rule 0 匹配:src ✓, dst ✓, proto ✓, dport ✓ → 规则 0 "中奖" │ bits 更新为:0 号位保留,其他置 0 │ ├─ BitScan 扫描找到最低的 1 位 → 规则 0 │ ├─ ActionLookup → 查询规则 0 的动作 = DROP │ └─ 返回 DROP(数据包被丢弃)
|
3. 控制平面工作原理
3.1 规则编译流程
用户通过 REST API 添加规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| POST /iptables/chain/INPUT/rule { "id": 0, "src": "10.0.0.0/24", "dst": "192.168.0.1", "l4proto": "tcp", "dport": 443, "action": "DROP" }
↓
Chain::addRule() ↓ ChainRule 对象创建 ├─ 解析 CIDR (10.0.0.0/24) ├─ 存储匹配条件 └─ 触发 Chain::updateChain() ↓ Chain::updateChain() ├─ 获取所有规则 ├─ 生成 BPF 规则代码 ├─ 编译成 BitScan / IpLookup / ... 的 BPF 代码 └─ 调用 Parser::reload() / ChainSelector::reload() 等 ↓ Program::reload() ├─ 调用 iptables_.reload(code, index) └─ 加载新的 eBPF 程序到内核
|
3.2 规则代码生成示例
规则 0:src=10.0.0.0/24, dst=192.168.0.1, proto=TCP, dport=443, action=DROP
控制平面生成对应的 BPF 匹配代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| struct lpm_k key = { .netmask_len = 24, .ip = htonl(0x0A000000) }; struct elements *result = ip_srcTrie_INPUT.lookup(&key); if (result != NULL) { __be32 dst_check = htonl(0xC0A80001); if (pkt->dstIp == dst_check) { if (pkt->l4proto == IPPROTO_TCP && pkt->dport == htons(443)) { (result->bits)[0] |= (1ULL << 0); } } }
|
3.3 Interactive vs Batch Mode
Interactive Mode(交互模式,默认):
1
| 添加规则 → 立即编译 → 立即加载到内核 → 规则生效
|
Batch Mode(批处理模式):
1 2 3 4
| 添加规则 1 → 内存更新 添加规则 2 → 内存更新 ... 调用 applyRules() → 编译所有规则 → 加载到内核
|
4. 数据平面工作原理
4.1 数据包入站处理(Ingress)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| 网络包进入 NIC ↓ TC/XDP Hook 触发(attach 点) ↓ [1] Parser ├─ 解析以太网/IP/L4 头 ├─ 填充 packetHeaders 结构 └─ 调用 _CHAINSELECTOR 或 _HORUS(如果启用) ↓ [2] ChainSelector (如果没启用 Horus) ├─ 查看包的目标 IP ├─ 检查是否为本机地址? │ ├─ YES → goto INPUT chain │ └─ NO → goto FORWARD chain └─ 初始化 sharedEle (规则位向量) ↓ [3] ConntrackLabel ├─ 查询连接追踪表 ├─ 确定连接状态 (NEW/ESTABLISHED/...) └─ 调用规则链处理 ↓ [4] 规则链处理 (_NEXT_HOP_INPUT_1 或 _NEXT_HOP_FORWARD_1) ├─ BitScan → 找最低匹配规则 ├─ IpLookup → 检查 src/dst IP ├─ InterfaceLookup → 检查入站接口 ├─ ConntrackMatch → 检查连接状态 ├─ L4ProtocolLookup → 检查 L4 协议 ├─ L4PortLookup → 检查源/目标端口 ├─ TcpFlagsLookup → 检查 TCP flags └─ ActionLookup → 查询动作 (DROP/ACCEPT) ↓ [5] ChainForwarder ├─ 根据 forwardingDecision │ ├─ INPUT_LABELING → return RX_OK 或 RX_DROP │ └─ FORWARD_LABELING → return RX_OK 或 RX_DROP └─ 如果是 ACCEPT,调用 ConntrackTableUpdate ↓ [6] ConntrackTableUpdate ├─ 如果是 ACCEPT,更新连接追踪表 ├─ 记录连接信息 (src/dst/sport/dport/proto) ├─ 设置 TTL 和状态 └─ 返回 RX_OK ↓ 数据包发往应用或转发
|
4.2 数据包出站处理(Egress)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 应用发送包 / 转发包出去 ↓ TC/XDP Hook 触发(egress 点) ↓ [1] Parser (egress) ├─ 解析包头 ├─ 填充 packetHeaders └─ 调用 _CHAINSELECTOR ↓ [2] ChainSelector (egress) ├─ 查看包的源 IP ├─ 检查是否为本机地址? │ ├─ YES → goto OUTPUT chain │ └─ NO → goto PASS (直接转发) └─ 初始化 sharedEle ↓ [3] 规则链处理 (如果是 OUTPUT 链) └─ 同 INPUT/FORWARD 链 ↓ 数据包送往网络
|
4.3 关键数据结构(Kernel-Side)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| struct elements { uint64_t bits[_MAXRULES]; };
struct packetHeaders { uint32_t srcIp; uint32_t dstIp; uint8_t l4proto; uint16_t srcPort; uint16_t dstPort; uint8_t flags; uint32_t seqN; uint32_t ackN; uint8_t connStatus; };
struct ct_k { uint32_t srcIp; uint32_t dstIp; uint8_t l4proto; uint16_t srcPort; uint16_t dstPort; };
struct ct_v { uint64_t ttl; uint8_t state; uint8_t ipRev; uint8_t portRev; uint32_t sequence; };
|
4.4 BPF Maps 映射表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| BPF_TABLE("extern", int, struct elements, sharedEle, 1) ↑ └─ 当前包的匹配位向量(与 control plane 同步)
BPF_TABLE("extern", int, struct packetHeaders, packet, 1) ↑ └─ 已解析的包头(由 Parser 填充)
BPF_TABLE("extern", int, int, forwardingDecision, 1) ↑ └─ 转发决策(INPUT_LABELING / FORWARD_LABELING / ...)
BPF_TABLE("lpm_trie", struct lpm_k, struct elements, ip_srcTrie_INPUT, 1024, BPF_F_NO_PREALLOC) ↑ └─ INPUT 链源 IP 前缀树(支持 CIDR 匹配)
BPF_TABLE("lpm_trie", struct lpm_k, struct elements, ip_dstTrie_INPUT, 1024, BPF_F_NO_PREALLOC) ↑ └─ INPUT 链目标 IP 前缀树
BPF_TABLE("hash", struct ct_k, struct ct_v, connections, 65536) ↑ └─ 连接追踪表(最多 65536 个连接)
BPF_TABLE("percpu_array", int, u64, pkts_INPUT_default, 1) ↑ └─ INPUT 链默认动作计数(包数量)
BPF_TABLE("percpu_array", int, u64, bytes_INPUT_default, 1) ↑ └─ INPUT 链默认动作计数(字节数)
BPF_TABLE("percpu_array", int, u64, pkts_action_0, 8000) ↑ └─ 规则 0 的包计数(支持最多 8000 条规则)
BPF_TABLE("percpu_array", int, u64, bytes_action_0, 8000) ↑ └─ 规则 0 的字节计数
|
5. 关键机制
5.1 BitScan 规则扫描
目的: 从位向量中高效找到最低的 1 位
代码:
1 2 3 4 5 6 7
| uint64_t bits = (ele->bits)[0]; if (bits != 0) { int index = (int)(((bits ^ (bits - 1)) * 0x03f79d71b4cb0a89) >> 58); matchingResult = index64.lookup(&index); }
|
例子:
1 2 3 4
| bits = 0b00010101 = 0x15 bits - 1 = 0b00010100 = 0x14 bits ^ (bits - 1) = 0b00000001 = 0x01 最低位位置 = 0(第 0 条规则)
|
5.2 LPM Trie 前缀匹配
用途: 支持 CIDR 表示的 IP 范围匹配
例子:
1 2 3 4 5 6 7 8 9 10 11
| 规则中的 src = "10.0.0.0/24"
在 BPF 中构建 LPM Trie: key.netmask_len = 24 key.ip = 10.0.0.0 value = 规则匹配位向量
查询时: 查询包的 srcIp = 10.0.0.100 → Trie 会自动匹配 10.0.0.0/24 → 返回对应的规则位向量
|
5.3 连接追踪状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| ┌─────────┐ │ START │ └────┬────┘ │ ├──[TCP SYN]──→ ┌──────┐ │ │ NEW │ │ └──┬───┘ │ │ │ ┌┴─────────────────┐ │ │[TCP SYN+ACK] │ │ ↓ ↓ │ ┌────────────┐ ┌──────────┐ │ │ESTABLISHED │ │ TIMEOUT │ │ └──┬─────────┘ └──────────┘ │ │ │ ┌┴──────────────┐ │ │ [TCP FIN/RST] │ │ ↓ ↓ │ ┌─────────┐ ┌────────────┐ │ │ CLOSE │ │ TIMEOUT │ │ └─────────┘ └────────────┘ │ ├──[UDP SYN]──→ ┌──────┐ │ │ NEW │ (UDP 无连接,快速过期) │ └──┬───┘ │ │[TIMEOUT] │ ↓ │ ┌─────────────┐ └──────────────│ INVALID │ └─────────────┘
|
状态对应的规则动作:
1 2 3 4 5
| Rules with conntrack: - conntrack=NEW → 仅匹配新连接 - conntrack=ESTABLISHED → 仅匹配已建立的连接 - conntrack=RELATED → 匹配相关连接 (如 ICMP error) - conntrack=INVALID → 匹配无效状态(通常用来 DROP)
|
5.4 Horus 优化
问题: 逐条规则扫描效率低
解决: 用哈希表快速跳过无关规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| struct horusKey { uint32_t srcIp; uint32_t dstIp; uint8_t l4proto; uint16_t srcPort; uint16_t dstPort; };
struct horusValue { uint32_t ruleID; };
BPF_TABLE("hash", struct horusKey, struct horusValue, horusTable, 2048);
struct horusValue *result = horusTable.lookup(&key); if (result != NULL) { }
|
适用场景: 规则数量 ≥ 2048 时启用
6. 统计信息收集
6.1 计数器类型
1 2 3 4 5 6 7
| 每条规则的计数器: ├─ 数据包数 (pkts_action_<rule_id>) └─ 字节数 (bytes_action_<rule_id>)
每条链的默认动作计数器: ├─ 数据包数 (pkts_<chain>_default) └─ 字节数 (bytes_<chain>_default)
|
6.2 计数器更新时机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| incrementCounters(&key, md->packet_len);
static void incrementCounters(int *action, u32 bytes) { u64 *value; value = pkts_DIRECTION.lookup(action); if (value) { *value += 1; } value = bytes_DIRECTION.lookup(action); if (value) { *value += bytes; } }
|
7. 端口与接口绑定
7.1 端口概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Iptables 需要 attach 到具体的网络接口:
用户 API: POST /iptables/ports/eth0 { "type": "physical" }
内部实现: Port 对象被创建 ↓ port->setPolycubeAttachPoint( polycube::service::CubeIface::TC_INGRESS, polycube::service::CubeIface::TC_EGRESS ) ↓ eBPF 程序被 attach 到 eth0 的 TC ingress/egress hook
|
7.2 多端口处理
1 2 3 4
| 如果有多个端口(eth0, eth1, eth2): ├─ 每个端口独立 attach TC hook ├─ 所有端口共享同一份 BPF 规则代码 └─ 包元数据包含端口号 (md->in_port)
|
8. 完整交互流程示例
场景:用户添加一条 DROP 规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| [用户侧] POST /iptables/chains/INPUT/rules { "id": 100, "src": "192.168.1.0/24", "dport": 22, "l4proto": "tcp", "action": "DROP" }
↓
[REST API 处理] IptablesApi::create_iptables_chain_rule_handler()
↓
[Control Plane] Chain::addRule(100, conf) ├─ 创建 ChainRule 对象 ├─ 存储规则参数 └─ 调用 Chain::updateChain() ├─ 遍历所有规则(0-100) ├─ 生成 BPF 代码: │ ├─ BitScan: 初始化位向量,扫描找到规则 100 │ ├─ IpLookup: 匹配 src = 192.168.1.0/24 │ ├─ L4ProtocolLookup: 匹配 proto = TCP │ ├─ L4PortLookup: 匹配 dport = 22 │ └─ ActionLookup: 返回 DROP ├─ 编译 eBPF 代码(BCC) └─ 调用 Parser::reload(), ChainSelector::reload() 等 ├─ 逐个加载新程序到内核 └─ BPF 程序被替换
↓
[Kernel] 新的 eBPF 程序被加载到 TC hook
↓
[下次包进入] TC ingress hook 触发: ├─ Parser 解析包 ├─ ChainSelector 识别为 INPUT 链 ├─ BitScan 扫描规则,找到规则 100 ├─ IpLookup 检查 src (192.168.1.100 ∈ 192.168.1.0/24) → 匹配 ├─ L4ProtocolLookup 检查 proto=TCP → 匹配 ├─ L4PortLookup 检查 dport=22 → 匹配 ├─ ActionLookup 返回 DROP └─ 包被丢弃(RX_DROP)
↓
[统计] 规则 100 的计数器 ++ pkts_action_100 += 1 bytes_action_100 += packet_length
|
9. 性能优化
9.1 为什么使用 BPF?
1 2 3 4 5 6 7 8 9 10 11 12 13
| 传统 Netfilter (内核): ├─ 在内核态执行,无上下文切换 ├─ 但规则处理在内核协议栈中,开销较大 └─ 性能:~100k pps
eBPF (Polycube): ├─ 在 TC/XDP hook 处理(比 Netfilter 更早) ├─ 可 JIT 编译到 CPU 指令 ├─ 支持高效的 LPM Trie 和 Hash 表 └─ 性能:~1M+ pps
用户态处理: └─ 太慢,每个包都需要陷入用户态
|
9.2 规则优化顺序
系统自动优化规则的执行顺序以提高性能:
1 2 3 4 5 6 7
| 输入规则(按添加顺序): Rule 0: src=10.0.0.0/8, action=DROP Rule 1: dst=192.168.0.0/16, action=ACCEPT Rule 2: dport=443, action=ACCEPT
优化后(频繁匹配的规则前置): 可能会调整顺序以减少平均匹配步数
|
9.3 Horus 表的大小
1 2 3 4
| Horus 优化适用于规则数量 ≥ 2048 时 ├─ 对于较少规则(<100),BitScan 更快 ├─ 对于大量规则 (>1000),哈希表查询更快 └─ 系统自动选择最优方式
|
10. 故障排查
10.1 常见问题
问题:规则不生效
1 2 3 4 5
| 排查步骤: 1. 检查是否调用了 applyRules()(非 interactive 模式) 2. 检查 rule ID 是否正确 3. 查看规则的 action 字段 4. 检查包是否真的到达了该链(INPUT/FORWARD/OUTPUT)
|
问题:性能下降
1 2 3 4 5
| 排查步骤: 1. 检查规则数量是否过多 2. 启用 Horus 优化 3. 查看连接追踪表是否溢出 4. 检查包是否过于复杂(IPv6/隧道等)
|
问题:连接追踪失效
1 2 3 4
| 排查步骤: 1. 检查是否启用了 conntrack 功能 2. 查看连接追踪表的状态 3. 确保规则中的 conntrack 字段正确设置
|
10.2 调试工具
1 2 3 4 5 6 7 8
| 查看内核日志: dmesg | grep -i iptables
查看 BPF 统计信息: bpftool map dump name pkts_action_0
查看规则编译后的代码: llvm-objdump -d <bpf_obj>
|
总结
pcn-iptables 的核心设计思想:
- 分层架构:用户态管理规则,内核态执行转发
- 动态编译:规则改变时动态生成 eBPF 代码
- 高效匹配:利用位扫描、LPM Trie、哈希表等数据结构
- 连接追踪:维护连接状态,支持有状态防火墙
- 可观测性:详细的计数器和统计信息
- 灵活扩展:支持链选择器、规则链式处理等机制
这种设计使得 pcn-iptables 能够在用户态实现高性能的防火墙功能,同时保持良好的可维护性和可观测性。
开发
安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| sudo apt install wget unzip build-essential golang-go
wget https://github.com/polycube-network/polycube/releases/download/v0.9.0/polycube-v0.9.0.zip
unzip polycube-v0.9.0.zip
cd polycube-v0.9.0/
sudo apt-get -y install git build-essential cmake bison flex \ libelf-dev libllvm5.0 llvm-5.0-dev libclang-5.0-dev libpcap-dev \ libnl-route-3-dev libnl-genl-3-dev uuid-dev pkg-config \ autoconf libtool m4 automake libssl-dev kmod jq bash-completion \ gnupg2chmod +x llvm.sh
|
参考链接