进入可编程数据面的学习。如果说前面我们学的是"控制面可编程"(SDN 控制器),那接下来要学的是"数据面也可编程"——这就是 P4。

今天我们搞清楚三个问题:

  1. OpenFlow 有什么局限性?
  2. P4 是什么,它解决了什么问题?
  3. 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 会告诉交换机:

  1. 从第 0 字节开始读 6 字节 → 得到目的 MAC
  2. 从第 6 字节开始读 6 字节 → 得到源 MAC
  3. 从第 12 字节开始读 2 字节 → 得到类型字段
  4. 如果类型是 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 程序

参考资料

  1. “Advancing SDN from OpenFlow to P4: A Survey” — 顶刊综述
  2. P4 中文教程 — 张恒华
  3. P4 语法简要教程
  4. P4-16 Specification v1.2.5 — 官方规范

本文是「SDN 入门学习笔记」系列的第4篇。

系列导航:上一篇 → OpenFlow 协议详解 | 下一篇 → Mininet 网络实验