传统交换机的转发行为被 ASIC 固定死:硬件能解析什么协议、按什么字段查表,出厂即定。今天的新协议(QUIC、SRv6、VXLAN)层出不穷,固化的数据面要么等硬件升级,要么靠 CPU 慢速兜底。P4(Programming Protocol-Independent Packet Processors)把「转发行为」从硬件中解放出来:用一门语言描述包如何处理,再编译到可重构的硬件。这标志着网络数据面从「黑盒固件」走向「可编程软件」。
一、从固定数据面到可编程数据面
1.1 固定数据面的困境
传统交换机工作方式:
芯片厂商固化「协议解析 + 查表 + 转发」流程
新协议支持 = 等新芯片 / 加中间盒子
三大痛点:
1. 迭代慢:新协议落地以年计
2. 盒子泛滥:负载均衡、防火墙、IDS 各自为政
3. 控制有限:运维只能调参数,改不了行为
| 维度 | 固定数据面 | 可编程数据面 |
|---|---|---|
| 协议支持 | 出厂固定 | 运行时定义 |
| 行为定制 | 配置现有功能 | 定义全新功能 |
| 迭代速度 | 硬件周期 | 软件编译周期 |
| 硬件效率 | 高 | 高(PISA 仍走硬件) |
| 典型代表 | 传统交换机 | P4 交换机 / DPU |
一句话:可编程数据面的本质是「把网络芯片从专用硬件变成可重新编程的处理器」。
1.2 控制面与数据面的分工
网络可编程的分层:
控制面(慢路径):路由计算、策略下发(CPU 上跑)
数据面(快路径):逐包处理、查表转发(硬件加速)
P4 聚焦数据面:
- 描述「包进来 → 如何解析 → 如何查表 → 如何转发/修改」
- 控制面通过 API(如 P4Runtime)动态增删表项
二、P4 语言基础
2.1 P4 的核心抽象
P4 是一门领域专用语言(DSL),围绕「解析 + 匹配-动作」组织:
P4 程序的三段式:
1. 解析器(Parser):用状态机描述如何解析包头
2. 匹配-动作表(Match-Action Tables):按字段查表,执行动作
3. 逆解析器(Deparser):把修改后的包重新组装发出
// P4 程序骨架示意
parser MyParser(packet_in b, out headers hdr, ...) {
state start {
b.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
0x0800: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
b.extract(hdr.ipv4);
transition accept;
}
}
control MyIngress(inout headers hdr, ...) {
action drop() { mark_to_drop(); }
action forward(macAddr_t dst) {
hdr.ethernet.dstAddr = dst;
standard_metadata.egress_spec = 1;
}
table ip_lookup {
key = { hdr.ipv4.dstAddr: lpm; }
actions = { forward; drop; }
default_action = drop();
size = 1024;
}
apply { ip_lookup.apply(); }
}
2.2 匹配-动作模型
P4 的核心处理原语是 Match-Action:对包头字段做匹配,命中后执行对应动作:
| 匹配类型 | 语义 | 适用场景 |
|---|---|---|
| Exact | 精确相等 | 五元组、MAC |
| LPM | 最长前缀 | IP 路由 |
| Ternary | 带掩码匹配 | ACL、任意字段 |
| Range | 区间匹配 | 端口范围 |
动作(Action)示例:
转发:改写目的 MAC + 设定出口端口
丢弃:mark_to_drop
封装:添加 VXLAN/GENEVE 头
计数:meter/计数器自增(供遥测使用)
2.3 P4 的版本与生态
P4 语言演进:
P4-14(旧):面向特定目标,语法与芯片耦合
P4-16(现行):目标无关、更干净的 DSL 语义
P4Runtime:控制面协议,把「表项操作」标准化
生态分层:
语言层:P4-16
架构层:v1model / TNA(Tofino Native Architecture)
目标层:BMv2(模拟)/ Tofino(硬件)/ DPU
三、PISA 架构
3.1 PISA 的原理
PISA(Protocol-Independent Switch Architecture)是 P4 落地的核心硬件模型,由 Intel Tofino 等芯片实现:
PISA 数据流:
RX ──► 可编程解析器(Programmable Parser)
──► 匹配-动作单元(Match-Action Pipeline,多级级联)
──► 逆解析器(Programmable Deparser)──► TX
每个阶段可以执行:
查表(TCAM + SRAM)
算术与位运算(ALU)
状态更新(计数器、meter、寄存器)
为什么 PISA 快:
解析与查表都在硬件流水线中完成(线速)
行为由「运行时加载的程序」决定,而非重新设计芯片
3.2 Match-Action 流水线
多级流水线示意:
Stage1: 解析 Ethernet/IPv4
Stage2: IP 路由查表(LPM)+ TTL 减 1
Stage3: ACL / QoS 分类
Stage4: VXLAN 封装
Stage5: 出口调度
各级之间共享数据(metadata 寄存器)
控制面可单独为每级下发表项
3.3 可编程解析器与逆解析器
解析器是可编程的关键:
固定芯片:只认「内置」的协议头(Ethernet/IP/TCP)
PISA 解析器:状态机可编程,认识任意自定义头
示例:为私有隧道协议写解析
识别自定义头 0x88B5 → 提取内部字段 → 继续解析
逆解析器反向组装:按需添加/剥离自定义头
四、协议无关转发
4.1 无协议绑定
「协议无关」(Protocol-Independent)的含义:
处理逻辑不绑定特定协议,而是「按字段操作」
字段可以是标准头,也可以是自定义头
好处:
新协议 = 写一段解析器 + 表定义,无需换硬件
IPv6、SRv6、INT、自定义 Overlay 一视同仁
4.2 自定义头与隧道
// 定义一个自定义头并参与转发(示意)
header my_hdr_t {
bit<16> magic;
bit<8> version;
bit<8> flags;
}
table my_lookup {
key = { hdr.my_hdr.magic: exact; }
actions = { forward_my; drop; }
default_action = drop();
}
4.3 与 OpenFlow 对比
| 维度 | OpenFlow | P4 |
|---|---|---|
| 关注面 | 控制面(流表下发) | 数据面(转发行为定义) |
| 协议解析 | 固定协议头 | 可编程解析 |
| 灵活性 | 匹配现有字段 | 定义任意字段 |
| 表动作 | 预定义集合 | 用户自定义动作 |
| 适用 | 白盒交换机配置 | 全新数据面设计 |
一句话:OpenFlow 让控制器能「配置」数据面,P4 让程序员能「编写」数据面——后者是质的跨越。
五、P4 交换机与智能网卡
5.1 硬件实现:Tofino 与竞品
Intel Tofino:
首款 PISA 商用芯片,2×200Gbps 级
运行时加载 P4 程序(重新编译下载)
支持多程序切换(热加载)
5.2 智能网卡与 DPU
DPU 把「可编程数据面」放到服务器边缘:
主机 CPU 卸载:网络、存储、安全都下沉到网卡
用 P4 描述网卡处理逻辑(或 P4-like 模型)
典型卸载场景:
- vSwitch 数据面(OVS offload)
- 负载均衡四层转发(LB offload)
- 防火墙/加密终结
- RDMA 与拥塞控制加速
DPU 卸载的价值:
释放主机 CPU(一个核都宝贵)
线速处理:不再经过内核协议栈
隔离与安全:租户流量在网卡内隔离
5.3 软件 P4 目标
软件实现(学习与开发):
BMv2:行为模型,纯软件模拟 P4 目标
P4Pi / eBPF 后端:基于 Linux 内核的 P4 编译后端
用软件目标验证逻辑 → 再部署到硬件:
开发流程闭环:P4 源码 → 模拟验证 → 硬件编译
六、可编程网络的应用场景
6.1 可编程负载均衡
在数据面实现「应用感知的四层 LB」:
解析自定义隧道头 + 哈希到后端池
会话保持用寄存器(不依赖控制面)
示例行为:
- 加权哈希调度(数据面动态调整)
- 连接迁移:后端故障时重哈希到备用池
- 在网卡上直接终结 VIP → 后端 IP 映射
为什么用 P4 做 LB:
传统 LB 是独立盒子 → 加了跳数、限制了拓扑
数据面 LB:交换机/网卡内置,无额外设备
6.2 带内遥测(In-band Network Telemetry)
INT 让包携带路径信息,无需额外探针:
每个交换机在包内追加自己的端口、队列深度、延迟
接收端还原整条路径的逐跳状态
P4 实现 INT:
解析器认识 INT 头
每跳动作:追加 metadata(端口号、队列占用)
逆解析器:维护 INT 头长度
INT 的价值:
精准定位「哪一跳排队、哪一跳丢包」
比 NetFlow 更细:逐包、逐跳、逐时刻
6.3 数据面安全与 DDoS 防护
数据面安全应用:
- SYN 洪水:数据面计数 + 速率限制(不惊动 CPU)
- 可疑字段:自定义规则实时丢弃
- 加密卸载:TLS/IPsec 终结在网卡
- 微隔离:按自定义头实现租户间策略
优势:
处理在硬件线速,不占 CPU
规则热更新:控制面下发即可
七、P4 开发与工具链
7.1 编译与验证流程
P4 开发闭环:
1. 编写 P4-16 程序
2. p4c 编译器 → 目标相关 IR / 可执行
3. BMv2 模拟器验证行为
4. PTF 数据面测试 / P4Runtime 表项下发
5. 部署到硬件(Tofino/DPU)
工具:p4c、BMv2、PTF(Python 测试框架)、P4Runtime
# 编译 P4 程序到 BMv2 目标并启动模拟交换机
p4c --target bmv2 --arch v1model \
--std p4-16 -o /tmp/build my_switch.p4
# 生成:my_switch.json + my_switch.p4info.txt
simple_switch -i 0@veth0 -i 1@veth1 \
--thrift-port 9090 /tmp/build/my_switch.json
7.2 控制面配合:P4Runtime
P4Runtime 与 P4 的分工:
P4:编译期定义「程序」(表结构、动作、解析器)
P4Runtime:运行期下发「表项」(谁匹配、执行哪个动作)
示例控制面操作:
- Write:增删表项
- Read:查询表项/计数器
- PacketIn/Out:与控制面交换非命中包
- Stream:订阅事件(端口状态、计数器)
# 用 p4runtime-shell 下发一条转发表项
from p4runtime_shell import P4RuntimeShell
s = P4RuntimeShell('/tmp/build/my_switch.p4info.txt',
device_id=0, addr='127.0.0.1:50051')
s.add_table_entry(
table_name='ip_lookup',
match_fields={'hdr.ipv4.dstAddr': ('10.0.0.0/8', 'lpm')},
action_name='forward',
action_params={'dst': '02:00:00:00:00:01'})
7.3 落地挑战
现实挑战:
1. 硬件成本:可编程芯片比固定芯片贵
2. 技能门槛:需要「协议 + 硬件 + 语言」复合能力
3. 生态成熟度:工具链与调试手段仍不如传统网络
4. 兼容性:不同目标(Tofino/DPU/FPGA)差异大
5. 可维护性:数据面程序也要测试、版本管理、灰度
应对:
从软件目标(BMv2)验证逻辑入手
先做单一场景(LB/遥测)试点,再扩大
用 CI 固化 P4 测试:每个改动跑 PTF 回归
八、总结
| 主题 | 核心知识点 | 落地建议 |
|---|---|---|
| 数据面编程 | P4 解析 + 匹配-动作 + 逆解析 | 从 BMv2 模拟起步 |
| PISA | 硬件流水线 + 可编程解析器 | 理解多级流水限制 |
| 协议无关 | 自定义头与字段操作 | 新协议无需换硬件 |
| 硬件形态 | Tofino / DPU / FPGA | 按场景选目标 |
| 应用 | LB / INT / 安全卸载 | 单场景试点再扩展 |
| 工具链 | p4c + P4Runtime + PTF | 用 CI 固化回归测试 |
P4 把「网络芯片」从专用硬件变成了「可编程处理器」:解析器、匹配-动作流水线、逆解析器三者构成 PISA,让交换机既能保持线速,又能按需改写转发行为。对后端与网络工程师而言,可编程网络意味着把过去「加盒子」的解决方案(LB、防火墙、遥测)直接折叠进数据面——更低的延迟、更少的设备、更强的定制能力。它不会取代所有传统网络,但正在成为云数据中心、智能网卡与新协议演进的核心底座,值得每个关注网络演进的人掌握。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。