p4app
说明:翻译自https://github.com/p4lang/p4app,自学使用
p4app是可以构建、运行、调试和测试P4程序的工具。p4app背后的理念是“easy things should be easy”—p4app旨在使小型、简单的P4程序易于编写并易于与他人共享。
安装
-
如果尚未安装docker,请安装它。
-
如果需要,可以将
p4app
脚本放在路径中的某个位置。例如:cp p4app /usr/local/bin
用法
p4app运行p4app软件包。p4app软件包是带有.p4app
扩展名的目录—例如,如果您在P4中编写了路由器,则可以将其放在中router.p4app
。在目录内,您将放置P4程序,所有支持文件以及一个p4app.json
告诉p4app如何运行它的文件。
该存储库附带一个名为simple_router.p4app
的示例p4app。用如下命令运行:
p4app run examples/simple_router.p4app
如果运行此命令,则会最终打开Mininet命令提示符。p4app将自动下载包含P4编译器和工具的Docker映像,编译simpler_router.p4
,并设置一个带有模拟网络的容器,您可以使用该网络进行实验。除了Mininet本身,您还可以直接使用tshark
、scapy
以及net-tools和nmap套件。
但是,Mininet不是p4app支持的唯一后端。这是p4app的另一个示例:
p4app run examples/simple_counter.p4app
如果运行此命令,则p4app将自动编译simple_counter.p4
,向其提供定义的输入数据包序列simple_counter.stf
,并确保输出数据包符合期望。本示例使用“简单测试框架”,该框架可以帮助您测试确保小型P4程序符合您的期望。
一个p4app软件包包含一个程序,但是它可以包含多个“目标”—例如,一个p4app可能包括Mininet的几种不同网络配置,整套STF测试或两者的混合。p4app默认会运行默认目标,但是您可以通过以下方式通过名称指定目标:
p4app run examples/simple_router.p4app mininet
到这里入门就差不多了!不过,还有一个更有用的命令。您不必每次都重新下载p4app在本地缓存P4编译器和工具,但您可能会不时需要更新到最新版本。这时候可以运行:
p4app update
创建一个p4app包
p4app软件包的目录结构如下所示:
my_program.p4app
|
|- p4app.json
|
|- my_program.p4
|
|- ...other files...
该p4app.json
文件是一个软件包清单,它告诉p4app如何构建和运行P4程序。看起来和Makefile差不多。这是一个例子:
{
"program": "my_program.p4",
"language": "p4-14",
"targets": {
"mininet": {
"num-hosts": 2,
"switch-config": "my_program.config"
}
}
}
该清单告诉p4app它应该运行my_program.p4
,它是用p4-14
—编写的—这是P4语言的当前版本,尽管您也可以使用p4-16
P4-16草案修订版。它定义了一个目标—mininet
并提供了一些Mininet配置选项:网络上将有两台主机,并且将使用my_program.config
文件配置模拟交换机。当您以p4app.json
这种方式引用外部文件时,只需将该文件放入包中,p4app将确保可以找到它。
如果有多个目标,并且用户未按名称指定一个目标,则p4app将运行任意选择的目标之一。您可以使用该default-target
选项设置要运行的默认目标。这是一个具有多个目标的示例:
{
"program": "my_program.p4",
"language": "p4-14",
"default-target": "debug",
"targets": {
"debug": { "use": "mininet", "num-hosts": 2 },
"test1": { "use": "stf", "test": "test1.stf" },
"test2": { "use": "stf", "test": "test2.stf" },
}
}
这定义了一个Mininet目标“debug”和两个STF目标“test1”和“test2”。该use
字段指定目标使用哪个后端。如果不提供,则目标名称也用作后端名称。因此,在前面的示例中,我们不必指定"use":"mininet"
—目标的名称是mininet,这足以让p4app知道您的意思。
言尽于此。最后一个提示:如果您想与其他人共享p4app软件包,则可以运行p4app pack my-program.p4app
,p4app会将软件包压缩为一个文件。p4app可以透明地运行压缩程序包,因此您发送给它的人甚至不必解压缩它。但是,如果他们想查看其中包含的文件,则可以运行p4app unpack my-program.p4app
,p4app会返回软件包目录。
后端
Mininet
这个后端编译一个P4程序,将其加载到一个simple_switch,的BMV2并创建一个Mininet环境,您可以试一下。
支持以下配置值:
"mininet": {
"num-hosts": 2,
"switch-config": "file.config"
}
所有字段都是可选的。
Mininet网络将使用星型拓扑,num-hosts
字段的每个主机都通过单独的接口连接到交换机。
您可以在启动时使用switch-config
来将配置加载到交换机中。文件格式仅仅是一个BMV2的命令序列simple_switch_CLI。
在启动过程中,将显示info,告诉您有关网络配置以及如何访问日志记录和调试功能的信息。BMV2调试器特别方便。您可以在此处阅读如何使用它。
此目标还支持目标的配置值compile-bvm2
。
多交换机
像mininet
一样,此目标编译P4程序并在Mininet环境中运行它。此外,该目标允许您使用自定义拓扑运行多个交换机并在主机上执行任意命令。开关与L2和L3规则路由流量的所有主机自动配置的(假定P4程序有ipv4_lpm
,send_frame
和forward
表)。例如:
"multiswitch": {
"links": [
["h1", "s1"],
["s1", "s2"],
["s2", "h2", 50]
],
"hosts": {
"h1": {
"cmd": "python echo_server.py $port",
"startup_sleep": 0.2,
"wait": false
},
"h2": {
"cmd": "python echo_client.py h1 $port $echo_msg",
"wait": true
}
},
"parameters": {
"port": 8000,
"echo_msg": "foobar"
}
}
此配置将创建如下拓扑:
h1 <---> s1 <---> s2 <---> h2
当s2-h2
链路需要具有50ms的人为延迟。可以使用以下选项配置主机:
-
cmd
—要在主机上执行的命令。 -
wait
—等待命令完成后再继续。通过将其设置为false,可以在后台主机(如守护程序/服务器)上启动进程。 -
startup_sleep
—启动命令后应等待的时间(以秒为单位)。 -
latency
—此主机与交换机之间的延迟。可以是数字(解释为秒),也可以是带有时间单位的字符串(例如50ms
或1s
)。这将覆盖links
对象中设置的延迟。
通过用h1
相应的IP地址替换主机名(例如)来格式化命令。目标中指定的参数将作为环境变量(即$
后跟变量名)供命令使用。例如,查看多交换机示例应用程序的清单。
局限性
当前,每个主机最多可以连接到一个交换机。
为每个交换机指定条目(命令)
路由表(ipv4_lpm
,send_frame
和forward
)将自动填充该目标。此外,您可以指定在每个交换机上运行的自定义命令。您可以自定义文件命令或数组命令。这些自定义命令将在为路由表自动生成命令之前发送。例如:
"multiswitch": {
"links": [ ... ],
"hosts": { ... },
"switches": {
"s1": {
"commands": "s1_commands.txt"
},
"s2": {
"commands": [
"table_add ipv4_lpm set_nhop 10.0.1.10/32 => 10.0.1.10 1",
"table_add ipv4_lpm set_nhop 10.0.2.10/32 => 10.0.2.10 2"
]
}
}
}
如果用以上命令给s2
下流表与自动生成命令的流表重复(例如,有一个自动输入set_nhop 10.0.1.10/32
),则这些自定义命令应该具有不同优先级,并且在填充表时,您将看到有关重复条目的警告。
自定义拓扑类
您可以使用自己的类来代替让该目标创建mininet Topo类。使用topo_module
选项指定模块的名称。例如:
"multiswitch": {
...
"topo_module": "mytopo"
...
}
这将导入mytopo
模块,该模块mytopo.py
应与清单文件(p4app.json
)位于同一目录中。该模块应实现CustomAppTopo
类。它可以扩展默认的topo类apptopo.AppTopo。例如:
# mytopo.py
from apptopo import AppTopo
class CustomAppTopo(AppTopo):
def __init__(self, *args, **kwargs):
AppTopo.__init__(self, *args, **kwargs)
print self.links()
请参阅customtopo.p4app工作示例。
定制控制器
与该topo_module
选项类似,您可以使用该controller_module
选项指定控制器。这个模块应该实现CustomAppController
类。默认控制器类为appcontroller.AppController。您可以扩展此类,如customtopo.p4app示例所示。
自定义主机进程运行器
AppProcRunner类负责在每个mininet主机中执行程序。通过指定controller_module
选项,您可以覆盖在主机上启动和终止程序的默认行为。这个模块应该实现CustomAppProcRunner
类。默认控制器类为appprocrunner.AppProcRunner。您可以扩展此类,如customtopo.p4app示例所示。
logging
运行此目标时,主机上的临时目录/tmp/p4app_log
挂载在客户机上的/tmp/p4app_log
。运行p4app之后,此目录中的所有数据都将保留到主机。主机命令的标准输出存储在此位置。如果需要保存命令的输出(例如日志),也可以将其放在此目录中。
要从P4开关保存调试日志,请在"bmv2_log": true
目标中设置。要从所有交换机捕获PCAP,请设置"pcap_dump": true
。这些文件将保存到/tmp/p4app_log
。有关用法示例,请参见广播示例应用程序的清单。
清理命令
如果需要在运行目标后(并且Mininet停止之前)在docker容器中执行命令,可以使用after
。after
应该包含cmd
,可以是命令,也可以是命令列表。例如:
"multiswitch": {
"links": [ ... ],
"hosts": { ... },
"after": {
"cmd": [
"echo register_read my_register 1 | simple_switch_CLI --json p4src/my_router.p4.json",
"echo register_read my_register 2 | simple_switch_CLI --json p4src/my_router.p4.json"
]
}
}
custom
这是编译P4程序以在Mininet环境中运行的第三种方法。该目标允许您指定一个使用Mininet的Python API即program
来指定网络拓扑和配置的Python。例如:
{
"program": "source_routing.p4",
"language": "p4-14",
"targets": {
"custom": {
"program": "topo.py"
}
}
}
该目标将调用python脚本topo.py
来启动Mininet。而program
会调用下面的参数:
Argument | Argument |
---|---|
-behavioral-exe | Value将是switch可执行文件 |
--json | Value将是P4编译器的输出 |
--cli | Value将是switch命令行界面程序 |
调用示例:
PYTHONPATH=$PYTHONPATH:/scripts/mininet/ python2 topo.py \
--behavioral-exe simple_switch \
--json SOME_FILE \
--cli simple_switch_CLI
您可以通过将其他参数包含在program
定义里来指定其他参数以传递到自定义拓扑程序:
{
"program": "source_routing.p4",
"language": "p4-14",
"targets": {
"custom": {
"program": "topo.py --num-hosts 2 --switch-config simple_router.config"
}
}
}
上述program
可在HOSTNAME
环境变量中找到的docker容器ID,以便它可以复制/粘贴输出有用的命令:
import os
container = os.environ['HOSTNAME']
print 'Run the switch CLI as follows:'
print ' docker exec -t -i %s %s' % (container, args.cli)
stf
该目标编译提供的P4程序并针对为STF测试框架编写的程序运行测试。
以下配置值是必需的:
"stf": {
"test": "file.stf"
}
您必须test
以STF格式编写指定的文件,但很遗憾,当前没有文档说明。(如果您想对它进行逆向工程并提供一些文档,请提交PR!)您可以看一下此仓库中包含的示例p4apps,以了解基础知识。
此目标还支持目标的配置值compile-bvm2
。
编译bmv2
这是一个简单的后端,仅用于BMV2体系结构编译提供的P4程序。
支持以下可选配置值:
"compile-bmv2": {
"compiler-flags": ["-v", "-E"],
"run-before-compile": ["date"],
"run-after-compile": ["date"]
}
高级功能
如果您要入侵P4工具链或p4app本身,则可能要使用修改后的Docker映像,而不是标准的p4lang映像。这很容易做到;只需将P4APP_IMAGE
环境变量设置为您要使用的Docker映像即可。例如:
P4APP_IMAGE=me/my_p4app_image:latest p4app run examples/simple_router.p4app
指定文件清单的名称
默认情况下,p4app将使用p4app.json
在应用程序目录中调用的清单文件。如果未调用清单文件,则p4app.json
可以使用--manifest
选项指定清单的名称。例如:
p4app run myapp.p4app --manifest testing.p4app
指定日志的目录位置
默认情况下,p4app会将/tmp/p4app_logs
主机上的/tmp/p4app_logs
目录挂载到docker容器客户虚拟机上。bmv2的输出以及程序的所有输出将保存到此目录。(/tmp/p4app_logs
)您可以使用$P4APP_LOGDIR
环境变量指定另一个目录。例如,运行:
P4APP_LOGDIR=./out p4app run myapp.p4app
所有日志文件都将存储到./out
。
启动交互执行的命令
要在当前运行的p4app上交互式运行命令,可以使用
p4app exec command arg1 arg2 ...
这将在当前正在运行的p4app实例中运行命令。如果有多个实例在运行,该命令将在最近启动的p4app上执行。
要在Mininet主机上运行命令,可以使用p4app中包含的Mininet的m
实用程序脚本。例如,ping
在Mininet主机上运行h1
:
p4app exec m h1 ping 10.0.2.101
您还可以在Mininet主机上运行tcpdump
以使用Wireshark实时查看数据包:
p4app exec m h1 tcpdump -Uw - | wireshark -ki -
网友评论