P4-相关工具链

P4 程序运行的整体结构

如图:

其主要可以分 4 个步骤

Step1 编译

.p4 程序编译为 .json.p4info 文件:

1
2
3
4
5
p4c-bm2-ss --p4v 16 \
-o test.json \
--p4runtime-file test.p4info \
--p4runtime-format text \
test.p4
  • p4c-bm2-ss 指, 使用 BMv2 后端来编译
  • --p4v 16, p4 version, 指定 P4 的版本, 16 表示 P4-16
  • -o test.json, 指定编译输出文件名
  • --p4runtime-file test.p4info 指定生成的 P4Runtime 信息文件的名称, 该文件包含有关数据平面对象 (如表, 动作等) 的元数据
  • --p4runtime-format text, 指定生成的 P4Runtime 文件的格式. text 表示生成的文件将采用文本格式, 而不是二进制格式

一个 p4 程序编译为 p4info 的示例如下:

Step2 创建 veth 接口

veth 指 virtual ethernet, 虚拟以太网接口, 是在 Linux 内核中成对创建的 (这一对是相连的, 形成一个虚拟以太网链路), 用于连接不同的命名空间或容器. 数据包从一个 veth 设备进入, 从另一个 veth 输出.

可以直接用 ip 命令创建:

1
2
3
4
5
6
7
8
9
ip link add name veth0 type veth peer name veth1
for iface in "veth0 veth1"; do
ip link set dev ${ifaace} up
sysctl net.ipv6.conf.${iface}.disable_ipv6=1
TOE_OPTIONS="'rx tx sg ufo gso gro lro rxvlan txvlan rxhash"
for TOE_OPTION in $TOE_OPTIONS; do
/sbin/ethtool --offload $intf "$TOE_OPTION"
done
done

这里每行命令的作用分别是:

  • ip link add name veth0 type veth peer name veth1, 创建了一对虚拟以太网设备, 分别命名为 veth0veth1
  • ip link set dev ${ifaace} up, 启用 veth 设备
  • sysctl net.ipv6.conf.${iface}.disable_ipv6=1, 禁用 IPv6 功能, 用于提高性能, 简化测试场景
  • TOE_OPTIONS="'rx tx sg ufo gso gro lro rxvlan txvlan rxhash", 设置一组以太网卡的 TCP 卸载选项
  • /sbin/ethtool --offload $intf "$TOE_OPTION", 用 ethtool 禁用指定选项

启动 BMv2

BMv2, Behavioral Model version2, 是 P4.org 提供的一个软件交换机实现, 旨在支持 P4 语言编写的程序. 它是一个开源项目, 主要用于开发, 测试和验证 P4 程序, 启用命令如下:

1
2
3
4
sudo simple_switch_grpc --log-console --dump-packet-data 64 \
-i 0@veth0 -i 1@veth2 ... [--pcap] --no-p4 \
-- --grpc-server-addr 0.0.0.0:50051 --cpu-port 255 \
test.json
  • gRPC (Remote Process Control) 服务, 用于实现控制平面和数据平面之间的通信, P4 程序可以通过 gRPC 接口暴露自己的功能和状态信息, 从而允许外部控制器对其进行编程和管理
  • simple_switch_grpc 是一中基于 BMv2 的交换机模拟器, 可移植性 P4 程序并提供 gRPC 服务接口
  • --log-console 将日志输出到控制台, 方便调试
  • --dump-packet-data 64 设置数据包转储的最大长度为 64 字节
  • -i 0@veth0 -i 1@veth2 ... 将虚拟网络接口连接到模拟器的输入端口
  • --no-p4 表明不需要编译 P4 程序
  • --grpc-server-addr 0.0.0.0:50051 指定 gRPC 服务器的监听地址和端口
  • --cpu-port 255, 指定了一个特殊的 CPU 端口, 用于处理不能由数据平面处理的数据包
  • test.json 是前面 P4 程序的编译输出

Step 4: 启用 P4Runtime 静态控制器

静态 P4Runtime 控制器是指一种在运行时预先配置和初始化的控制器, 其主要功能是管理和配置 P4 数据平面设备 (如交换机或路由器). 与动态控制器不同, 静态控制器通常不会根据实时网络流量或事件进行调整, 而是在启动时加载固定的配置.

1
python $(RUN_SCRIPT) -t $(TOPO) $(run_args)

Runtime Control

对于 P4 而言, 用 P4Runtime 是最好的.

Protocol Buffers

Protocol Buffers (简称 protobuf) 是一种用于序列化结构化数据的开源库和协议. 它由 Google 开发并开源, 提供了一种语言中立, 平台中立的方式来高效地处理可扩展的结构化数据. P4Runtime 用其作为通信协议, 来序列化要传输的数据.

Protobuf 的消息定义示例如下:

buffer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
syntax = "proto3";

message Person {
string name = 1;
int32 id = 2;
string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phone = 4;
}
  • syntax = "proto3" 指定了使用的 Protobuf 语法版本为 proto3
  • message Person 定义一个名为 Person 的 Protobuf 消息
  • string name = 1 定义 “Person” 消息中的一个字段, 名为 “name”, 类型为 “string”, 标识号为 1
  • int32 id = 2, 定义一个字段, 名为 “id”, 类型为 “int32”, 标识号为 2
  • enum PhoneType { ... } 定义一个枚举类型, 包含 MOBILE, HOME, WORK 三个值
  • repeated PhoneNumber phone = 4;, 定义一个 名为 phone 的字段其可以添加多个 “PhoneNumber” 类型元素 (相当于一个数组, 具体怎么加暂时不谈)

使用 protobuf 的好处在于:

  • 主流语言都支持其格式解析
  • 跨平台
  • 强类型

P4Runtime 所定义的 protobuf 可以在 https://github.com/p4lang/p4runtime/blob/master/proto/p4/v1/p4runtime.proto 查看.

gRPC

gRPC 主要由两部分组成:

  • gRPC Server, 处理来自客户端的请求并返回响应
  • gRPC Stub, 将客户端 (比如 Ruby 程序) 的调用翻译成 Protocol Buffers 请求, 并将响应转换回客户端可以理解的格式

工作示意图如下:

服务编写示例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// The greeter service definition
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReplyjA {})
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}

(可以在 https://grpc.io/docs/guides/ 查看文档 )

P4Runtime 的工作流程


P4-相关工具链
http://example.com/2024/11/19/P4-相关工具链/
作者
Jie
发布于
2024年11月19日
许可协议