- p4c是一款 p4编译器。
- BMv2是支持P4编程的软件交换机。
- PI是P4 runtime的实现,用于Control Plane对数据平面的控制。
- mininet的功能是构建一个虚拟的网络拓扑。 它通过linux内核的一些特性(net命名空间),在一个主机上划分出多个虚拟网络空间,各个网络空间之间相互隔离,有自己的端口, ip等等。mininet让一个或者多个vhost(虚拟主机), 软件交换机(如ovs, bmv2)等 以进程的状态分别绑定在这些网络空间之中,共同构成一个进程级别的虚拟网络拓扑。需要注意的是这些进程级别的主机和交换机他们只是网络上的隔离,而文件系统则是共享主机的文件系统。
- p4 tutorials 提供了用于学习的实例代码,它提供了很多个带有方向性的实际场景,例如负载均衡,简单的隧道机制,源路由等。并且它事先写好了控制面代码,让p4的初学者可以集中注意力在数据面编程的学习之上。
- scapy是一个python库,提供构建数据包,抓包,解析包等功能。它功能强大,但是效率很低。由于P4编程中经常会引入各种各样的数据包,有些甚至是开发者自定义的数据包格式。所以我们可以利用scapy进行便捷的组包,发包。如果需要高速率的发包和解析包就不能使用scapy了。
P4
├── behavioral-model ## BMv2 软件交换机
├── grpc ## 作为BMv2的依赖
├── mininet ## mininet 网络仿真
├── p4c ## p4c 编译器
├── PI ## PI P4 runtime库
├── protobuf ## 作为依赖
└── tutorials #### 教程目录,以及以后主要的学习,实验
tutorials/
├── exercises # 存放各种练习
├── utils # 工具脚本目录
└── vm # 用于vagrant构建虚拟机的目录,可以无视
其中utils里面存放了一些用于调用各个组件(mininet, bmv2, PI, p4c)的脚本,有了这些脚本,我们可以专注于p4代码的开发,控制面的编写,以及拓扑的构建,而不需要费神去了解bmv2的启动命令,p4c的调用选项等等。具体如何使用,也是非常的简单,我们进入一个具体的例子查看:
# 我们切换进入 exercises/basic 这个例子
basic
├── basic.p4 # 要编写的p4代码
├── build # 生成文件的目录
├── logs # 日志文件, 在调试的时候真的非常重要!
├── Makefile ### 通过Makefile 来调用utils下的脚本!
├── pcaps # 生成的pcap包,可以使用wireshark等工具来分析
├── README.md # 详细的指导
├── receive.py ## 利用scapy写的抓取和分析数据包的工具
├── s1-runtime.json #
├── s2-runtime.json # 在运行同时加载入交换机的控制面代码,这里有争议,稍后再谈
├── s3-runtime.json #
├── send.py ## 利用scapy写的构建和发送数据包的工具
├── solution # 这里有这个例子的示例代码(答案)
└── topology.json # 描述拓扑的json文件
可以看到,通过Makefile,我们可以调用utils下的脚本,让我们的p4代码跑起来:
make run # 启动命令
### ...启动过程中的输出
mininet> # mininet 命令行
### ... 你的一些实验操作
mininet> exit # 退出mininet 命令行
make clean # 清理上次运行留下的缓存文件和遗留的进程,重要,否则下次运行会可能使用旧的代码。
调用make run,我们可以运行当前目录下(以basic目录为例)的代码,它将执行以下几个步骤:
- 编译basic.p4 代码,生成basic.json
- 解析topology.json, 并且构建相应的mininet仿真拓扑,按照该拓扑启动一台或者多台BMv2交换机,以及一些host
- 启动BMv2的同时会将p4代码编译产生的json文件导入
- 启动BMv2后会解析 sN-runtime.json 文件,将其载入 交换机sN流表之中
- 进入mininet命令行,同时开始记录log以及搜集pcap文件
V1Switch(
MyParser(), // 解析数据包,提取包头
MyVerifyChecksum(), // 校验和验证
MyIngress(), // 输入处理
MyEgress(), // 输出处理
MyComputeChecksum(), // 计算新的校验和
MyDeparser() // 逆解析器
) main;
我们要需要完成以下几个基本的步骤,其余部分可以暂时省略。
- 定义相关数据结构:根据需求,我们需要定义 ipv4数据包头以及其下层的以太网包头结构。
- 解析数据包:我们在此提取ipv4包头。
- MyIngress:得到了数据包头,我们定义一个用于转发的流表,然后定义匹配域和动作。
- MyDeparser:逆解析器
- 写好控制面代码