本文译自 p4app README,对内容结构进行少量调整,并附上运行 log。
简介
p4app 仓库创建于 2017-02-23,是一种构建、运行、调试和测试 P4 程序的工具。哲学是“简单的东西应尽可能简单”,旨在使小而简单的 P4 程序易于编写、易于与他人分享。
p4factory 或 switch 等 P4 样例依赖安装步骤复杂、编译时间超长。p4app 可很好地解决此问题,降低 P4 入门门槛。与预期的相符,p4app 将 bmv2 等基础组件整合成一个 docker image。
安装
- 下载 p4app
1 | git clone https://github.com/p4lang/p4app |
- Bug fix.
p4app bug: pull request 17,docker 镜像名已由 p4lang/p4app:stable
改为 p4lang/p4app:latest
。修改 p4app
L16 为:
1 | -P4APP_IMAGE=${P4APP_IMAGE:-p4lang/p4app:latest} |
如果没有安装 docker ,需先安装。一键搞定:
wget -qO- https://get.docker.com/ | sh
。为方便,建议把
p4app
脚本拷贝到 PATH 路径,例如:
1 | sudo cp p4app /usr/local/bin |
程序安装到此结束!
使用
p4app 运行以 .p4app
为后缀的目录,称 p4app 包。p4app 仓库中包含多个样例,例如 simple_router.p4app
,运行方法:
1 | p4app run examples/simple_router.p4app |
此样例最终进入 mininet 命令行,在此之前,p4app 进行如下处理:
- 【首次运行 p4app 命令时】自动下载 docker 镜像
p4lang/p4app:latest
,该镜像包含 P4 编译器、抓包工具 tshark、发包工具 scapy、net-tools 和 nmap 套件等工具 - 编译
simper_router.p4
- 设置并启动一个容器做为软件交换机
- 设置并启动 mininet 模拟实验网络
p4app 命令参数
- run,运行 p4app,可带 target 参数。
- pack,压缩 p4app 包为单独文件,便于分享。使用 gzip 压缩
- unpack,解压上述压缩包
- update,更新 p4app 本地缓存的 P4 编译器和相关工具到最新版本。p4app 在本地缓存P4编译器和工具,因此不必每次都重新下载。
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app$ ./p4app -h |
target 与 backend
p4app 包最终将怎么运行,由配置文件 manifest file p4app.json
的参数targets
指定。目前支持有多种运行方式,例如仅编译成 bmv2 目标、进行 stf 测试、mininet 单交换机测试、mininet 多交换机测试等。本文将这些运行方式称为 backend,一个 p4app 包可以有多个 target,每个 target 必须指定其 backend。
通过在 p4app run
时指定 target 运行非默认 target,例如运行 simple_counter.p4app 的 debug target:
1 | p4app run examples/simple_couter.p4app debug |
如果有多个 target,且使用者没有通过名字指定默认 target,则 p4app 随机运行其中一个。可使用 default-target
选项,设置默认 backend。例如:
1 | { |
这里定义一个名为 “debug” 的 mininet backend,以及两个 STF backend,分别名为 “test1” 和 “test2”。"user":"mininet"
用于指明每个 target 使用哪个 backend,如果不使用 user 字段,则 target 名同时被认定为 backend 名。这也是为什么,在之前的样例中,不需要指明"use": "mininet"
,因为 target 名就已经是 mininet,如果直接被用成 backend 名,p4app 也可以识别。
目前支持以下几种 backend,具体见后文详述。
- mininet
- multiswitch
- custom
- stf
- compile-bmv2
创建一个 p4app 包
p4app 包的目录结构一般为:
1 | my_program.p4app |
p4app.json
是这个包的 manifest 文件,说明如何构建和运行 p4 程序,功能有点像 Makefile 文件。样例:
1 | { |
样例 manifest 告诉 p4app 应该运行 my_program.p4
,该 p4 程序使用 p4-14
编写(同样也可以用 p4-16
,P4-16 版本)。该样例定义一个 target,该 target 的 backend 为 mininet
,同时提供一些 mininet 配置选项:测试网络有两个 host,一个模拟交换机,该交换机启机默认加载 my_program.config
中的配置。如果你在 p4app.json
中引用像 my_program.config
时,则需要将 my_program.config
文件包在 p4app 包中,p4app 将确保相应工具可找到它。
Backend
mininet
该后端编译 p4 程序,并加载到 BMv2 simple_switch,然后创建 mininet 实验环境。
支持以下配置值(皆为可选):
1 | "mininet": { |
mininet 将创建星形拓扑网络,并创建 num-hosts
个数的 host,通过不同端口连接到模拟交换机。
模拟交换机的启机默认配置可通过 switch-config
配置。配置的文件是一系列 BMV2 simple_switch_CLI 命令。
在启机过程中,有信息提示网络配置信息以及如何使用 logging 和 debugging 工具。
BMV2 debugger 很方便,这里 阅读如何使用。
该 backend 还支持compile-bmv2
配置编译选项,详见下文相应章节。
multiswitch
和 mininet
一样,这个 target 包含 P4 程序,并运行在 mininet 环境。但是这个 backend 支持配置多个交换机、自定义拓扑并在 host 上执行自定义命令。这些交换机默认自动配置 l2/l3 规则,用于所有 host 之间的互通,即假设 P4 程序有 ipv4_lpm
、send_frame
和 forward
表,详见 simple_router.p4。
配置样例:
1 | "multiswitch": { |
该配置创建以下拓扑:
1 | h1 <---> s1 <---> s2 <---> h2 |
其中 s2-h2
链路人工配置 50ms 的延迟。host 配置选项:
cmd
- 在 host 上运行的命令wait
- 等待命令执行结束。如果配置成 false,表示在后台运行此命令。startup_sleep
- 启动命令后应等待的时间(以秒为单位)。latency
- 主机与交换机之间的延迟。配置值是数字(解释为秒)或具有时间单位的字符串(例如50ms
或1s
)。该配置将覆盖“links”对象中设置的延迟。
通过将主机名(例如 “h1”)替换为相应的 IP 地址来格式化该命令。 目标中指定的参数将作为环境变量(即$
后跟变量名称)可用于命令,详见 multiswitch 样例。
限制
目前每个 host 最多只能连一个 switch。
指定每个交换机表项
路由表(ipv4_lpm
,send_frame
和 forward
)在本 target 中自动下发。使用者可根据自己的需要下发表项到每个交换机中,形式为包含一个命令文件或命令数组。这些自定义的表项优先级比路由表的自动生成的高。例如:
1 | "multiswitch": { |
如果上述 s2
表项与自动生成的表项一样(例如自动生成的表项 set_nhop 10.0.1.10 / 32
),这些自定义表项将具有更高的优先权,在下发表项时将警告表项重复。
自定义拓扑类
通过 topo_module
选项指定自己的 mininet 拓扑类。例如:
1 | "multiswitch": { |
这将 import mytopo
模块 mytopo.py
,该文件应与 manifest 文件(p4app.json
)放在同一目录下,同时应实现 CustomAppTopo
类。可 extend 默认的 topo 类 apptopo.AppTopo。例如:
1 | # mytopo.py |
详见样例 customtopo.p4app。
自定义控制器
类似 topo_module
选项,通过 controller_module
选项自定义控制器。该模块应实现 CustomAppController
类。默认的控制器类为 appcontroller.AppController,可直接对该类进行扩展。详见样例 customtopo.p4app。
Logging
当本 target 运行时,host 上的临时目录 /tmp/p4app_log
将加载到 guest 的 /tmp/p4app_log
。运行 p4app 后, host 上保存有所有的 log。 host 命令的标准输出 stdout 将保存在该目录,如果需要保存某个命令的 log,将可以将其输出到该目录。
设置 "bmv2_log":true
,保存 P4 交换机的调试 log。
设置 "pcap_dump":true
,抓取所有交换机的报文,交保存为 PCAP 格式。
以上文件将被保存到 /tmp/p4app_log
。详见样例 broadcast.p4app
Cleanup commands
运行 target 后(在 mininet stop 之前),如果需要在 docker 容器内执行命令,可使用 after
选项,其后必须包含 cmd
,可以是一个或多个命令,例如:
1 | "multiswitch": { |
custom
该 backend 允许使用者指定 python program
,该 program
使用 Mininet python API 指定网络拓扑和配置。例如:
1 | { |
该 target 在启动 Mninet 时运行 topy.py
脚本。将使用以下参数调用 program
:
参数 | 说明 |
---|---|
–behavioral-exe | switch 可执行文件 |
–json | P4 程序编译结果 |
–cli | switch_CLI 命令 |
样例:
1 | PYTHONPATH=$PYTHONPATH:/scripts/mininet/ python2 topo.py \ |
同时可以指定其他参数传递给自定义拓扑程序,方法是将它们包含在 program
定义中,如下所示:
1 | { |
program
可通过 HOSTNAME
变量获取 docker 容器 ID。
1 | import os |
stf
stf 后端编译给定的 p4 程序,并运行 stf 测试用例。
stf,simple testing framework,一种模拟网络测试框架。
“simple testing framework”, which can help you test small P4 programs and ensure they behave the way you expect.
simple_counter.p4app
样例使用 stf 测试框架,运行该样例:
1 | p4app run examples/simple_counter.p4app |
运行后,p4app 启动 docker 容器,并在容器中:
- 自动编译
simple_counter.p4
- 运行 simple_switch 交换机
- stf 下发默认表项
- stf 发送定义在
simple_counter.stf
中的报文,并验证 simple_switch 是否转发出预期的报文
和 mininet 不一样的是, stf 最终直接退出。
simple_counter.p4app stf 配置
p4app.json
配置
1 | { |
- stf 文件 simple_counter.stf 配置
1 | add test1 data.f1:0x01010101 c1_2(val1:0x01, val2:0x02) |
必须使用 stf 格式编写 stf target 指定的配置文件,目前还没有该格式的说明文档。(如果您想反向工程并提供一些文档,请提交PR!)请参阅 p4app 相关样例,参考其中的基本用法。
此后端还支持 compile-bmv2
target 的配置值。
compile-bmv2
一个简单的后端,将 p4 程序编译成 BMV2 目标。
支持以下可选配置值:
1 | "compile-bmv2": { |
高级功能
指定 docker image
如果想使用自定义的 P4 工具链或 p4app,可通过 P4APP_IMAGE
环境变量配置 Docker image,替代标准 p4lang image。例如:
1 | P4APP_IMAGE=me/my_p4app_image:latest p4app run examples/simple_router.p4app |
指定 manifest 文件
默认情况下,p4app 使用 app 目录下一个名为 p4app.json
的 manifest 文件。如果你的 manifest 文件名称不是 p4app.json
,则可通过 --manifest
选项指定 manifest 文件。例如:
1 | p4app run myapp.p4app --manifest testing.p4app |
指定 log 目录
默认情况下,p4app 挂载 host 目录 /tmp/p4app_logs
到 docker 容器 guest 目录 /tmp/p4app_logs
。bmv2 以及其他程序的输出将保存在此目录。可通过 $P4APP_LOGDIR
环境变量指定其他目录为 log 目录,例如:
1 | P4APP_LOGDIR=./out p4app run myapp.p4app |
运行 log 汇总
运行 simple_router.p4app
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app$ sudo cp p4app /usr/local/bin/ |
运行 simple_counter.p4app
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app$ p4app run examples/simple_counter.p4app/ |
pack & unpack 样例 log
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app/examples$ ls multiswitch.p4app/ |
compile-bmv2 backend 样例
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app$ p4app run examples/compile_only.p4app/ |
logging 功能样例
运行样例 bcast_router.p4app,虽然运行后有提示错误,但是不影响 logging 样例展示。
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app/examples$ p4app run broadcast.p4app/ |
docker 镜像大小
当前版本 docker 镜像只有 908MB,已集成 tshark / scapy 等工具,不算大。
1 | sunyongfeng@openswitch-OptiPlex-380:~/workshop/p4app$ docker images |