进入可编程数据面的学习。如果说前面我们学的是"控制面可编程"(SDN 控制器),那接下来要学的是"数据面也可编程"——这就是 P4。
今天我们搞清楚三个问题:
- OpenFlow 有什么局限性?
- P4 是什么,它解决了什么问题?
- P4 的核心概念长什么样?
一、从 OpenFlow 到 P4
1.1 OpenFlow 的局限
OpenFlow 让网络设备的控制面变得可编程,但数据面仍然是固定的。具体来说:
| 局限 | 说明 |
|---|---|
| 固定匹配字段 | OpenFlow 只能匹配预定义的字段(MAC、IP、端口等),无法解析自定义协议 |
| 协议依赖 | 交换机硬件决定了支持哪些协议,新加协议需要换硬件 |
| 功能受限 | 只能做转发、修改、丢弃等基本操作,复杂的包处理做不到 |
| 硬件绑定 | 流表结构与特定硬件绑定,不同厂商的实现不统一 |
打个比方:OpenFlow 让你能决定"流量怎么走",但不能决定"交换机认识哪些协议"。
1.2 P4 的核心思想
P4(Programming Protocol-independent Packet Processors)的核心思想是:
让数据面也变得可编程——你可以定义交换机如何解析数据包、如何匹配、如何处理。
与 OpenFlow 的对比:
| OpenFlow | P4 | |
|---|---|---|
| 编程对象 | 控制面 | 数据面 |
| 协议支持 | 固定字段(IP/MAC/端口) | 任意协议(自定义解析) |
| 可编程范围 | 流表规则 | 整个包处理流水线 |
| 硬件依赖 | 与特定流表结构绑定 | 协议无关,硬件可复用 |
| 适用场景 | 传统 SDN 网络 | 新兴网络协议研究 |
1.3 一个直观的例子
假设你想在网络中支持一个新的自定义协议 “MyProto”:
用 OpenFlow:做不到。交换机不认识 MyProto,无法解析它的字段,也就无法做匹配和转发。
用 P4:可以。你写一个 P4 程序,告诉交换机"MyProto 长什么样、字段在哪个位置、怎么解析",交换机就能处理这种新协议了。
二、P4 核心概念
P4 程序定义了一个完整的包处理流水线,由三个主要部分组成:
2.1 流水线架构
P4 包处理流水线
┌──────────────────────────────────────────────┐
│ │
│ ┌─────────┐ ┌──────────────┐ ┌────────┐│
│ │ Parser │ → │ Match-Action │ → │Deparser││
│ │ 解析器 │ │ 匹配-动作 │ │ 解码器 ││
│ └─────────┘ └──────────────┘ └────────┘│
│ │ │ │ │
│ 解析包头 按规则处理包 重新编码 │
│ │
└──────────────────────────────────────────────┘
2.2 Parser(解析器)
Parser 的作用是定义"如何从原始数据包中提取出有意义的字段"。
比如,一个以太网帧的结构是:
┌──────────┬──────────┬──────────┬──────────┐
│ 目的 MAC │ 源 MAC │ 类型字段 │ 负载 │
│ 6 字节 │ 6 字节 │ 2 字节 │ 可变 │
└──────────┴──────────┴──────────┴──────────┘
P4 的 Parser 会告诉交换机:
- 从第 0 字节开始读 6 字节 → 得到目的 MAC
- 从第 6 字节开始读 6 字节 → 得到源 MAC
- 从第 12 字节开始读 2 字节 → 得到类型字段
- 如果类型是 0x0800(IPv4),继续解析 IP 头…
关键点:你可以定义任意的解析逻辑,不限于标准协议。
2.3 Match-Action(匹配-动作)
这是 P4 的核心处理阶段,类似于 OpenFlow 的流表,但更灵活。
匹配阶段:从解析后的包头中提取字段,查找匹配表。
动作阶段:根据匹配结果执行操作。
P4 定义了三种动作类型:
| 类型 | 说明 | 例子 |
|---|---|---|
| 无参数动作 | 固定行为 | 转发到指定端口 |
| 有参数动作 | 带参数的行为 | 修改某个字段为指定值 |
| 表动作 | 引用其他表的结果 | 根据查表结果决定转发端口 |
2.4 Deparser(解码器)
Deparser 的作用是把处理后的包头字段重新组装成完整的数据包,发送出去。
与 Parser 相反:Parser 是"拆包",Deparser 是"打包"。
三、P4 程序结构
一个最小的 P4 程序包含以下部分:
#include <core.p4> // P4 核心库
#include <v1model.p4> // BMv2 模型定义
// 1. 定义包头类型
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
// 2. 定义解析器
parser MyParser(packet_in pkt, ...) {
state start {
pkt.extract(ethernet); // 提取以太网头
transition accept; // 解析完成
}
}
// 3. 定义匹配-动作表
table my_table {
key = {
hdr.ethernet.dstAddr : exact; // 按目的 MAC 精确匹配
}
actions = {
forward; // 转发
drop; // 丢弃
}
size = 1024; // 表容量
}
// 4. 定义控制逻辑
apply {
my_table.apply(); // 应用匹配-动作表
}
// 5. 定义解码器
control MyDeparser(packet_out pkt, ...) {
apply {
pkt.emit(ethernet); // 输出以太网头
}
}
四、P4 与 OpenFlow Pipeline 对比
| 对比维度 | OpenFlow Pipeline | P4 Pipeline |
|---|---|---|
| 流水线结构 | 固定的多级流表 | 自定义任意处理阶段 |
| 包解析 | 只能解析 OpenFlow 支持的字段 | 可以解析任意协议头 |
| 匹配字段 | 预定义的 12+ 个字段 | 自由定义 |
| 动作集 | 预定义动作(output/drop/set-field) | 自定义动作 |
| 协议支持 | 固定(以太网/IPv4/IPv6/TCP/UDP) | 任意协议 |
| 扩展性 | 需要新 OpenFlow 版本 | 写 P4 程序即可 |
OpenFlow Pipeline
Packet In → [流表0] → [流表1] → [流表2] → Packet Out
↑ ↑ ↑
固定匹配 固定匹配 固定匹配
P4 Pipeline
Packet In → [Parser] → [Stage 1] → [Stage 2] → [Deparser] → Packet Out
↑ ↑ ↑
自定义解析 自定义处理 自定义处理
五、P4 的应用场景
| 场景 | 说明 |
|---|---|
| 新协议实验 | 在交换机上实现全新的网络协议 |
| INT(In-band Network Telemetry,带内网络遥测) | 在数据包中嵌入网络状态信息,实现高精度监控 |
| 网络内计算 | 利用交换机硬件完成聚合、缓存等计算 |
| 安全检测 | 在数据面直接做包过滤和异常检测 |
| 网络虚拟化 | 自定义封装格式,实现灵活的虚拟网络 |
六、今日学习总结
| 项目 | 内容 |
|---|---|
| 阅读 | Advancing SDN from OpenFlow to P4(顶刊综述) |
| 阅读 | P4 中文教程前 3 章 |
| 浏览 | P4-16-spec-v1.2.5.pdf 第 1~2 章 |
| 核心收获 | P4 的三大组件(Parser/Match-Action/Deparser)、与 OpenFlow 的本质区别 |
| 待深入 | 明天搭建 P4 开发环境(BMv2 + Mininet),动手写第一个 P4 程序 |
参考资料
- “Advancing SDN from OpenFlow to P4: A Survey” — 顶刊综述
- P4 中文教程 — 张恒华
- P4 语法简要教程
- P4-16 Specification v1.2.5 — 官方规范
本文是「SDN 入门学习笔记」系列的第4篇。
系列导航:上一篇 → OpenFlow 协议详解 | 下一篇 → Mininet 网络实验