P4->NetFPGA 实战——自写P4程序并加载至NetFPGA-SUME
P4->NetFPGA 实战——自写P4程序并加载至NetFPGA-SUME
0.前言
自翻译了github上的内容:
之后,关于自己写的P4程序如何加载运行至sume呢?于是乎就有了以下文章。
此文章主要介绍如何将符合规范的自定义P4程序加载至NetFPGA-SUME上,由于知识水平有限,文章内部暂时缺少了关于测试测序的编写。
1.P4-NetFPGA-live 项目结构目录
以下图片摘自P4-NetFPGA_camp_2017_v1.pptx
- P4-NetFPGA-live根目录结构

- sume-sdnet-switch目录结构

- P4_PROJECT_DIR目录结构

以上即为P4->NetFPGA的几个重要的文件夹,其中sume-sdnet-switch目录下templates文件夹为我们提供了丰富的模板文件,其中就有最重要的P4项目模板,所以可以利用该文件夹创建我们的P4项目,我们只需更改内部的P4程序,以及gen_testdata.py 即可开始验证我们的实验,为我们节省了不少时间,点赞!
2. P4->NetFPGA Workflow

上图为 P4-NetFPGA_camp_2017_v1.pptx 给出的简易版workflow图,详细的可围观 github给出的workflow详细版 。由于笔者并没有完成上述第二步描述中的gen_testdata.py文件,所以在实验过程中通过复制其他参考项目中gen_testdata.py文件“欺骗” makefile 文件,从而过掉此步。
3.实验步骤
1)将templates内的p4项目模板复制到projects下,并将新文件夹取名为p4_test ;
#进入到P4-NetFPGA-live文件夹下
$ cd {path}/P4-NetFPGA-live
#进入到projects文件夹下
$ cd contrib-projects/sume-sdnet-switch/projects
#将templates的p4项目模板复制到projects文件夹下
$ cp -r ../templates/sss_p4_proj p4_test
2)修改settings.sh文件,将 P4_PROJECT_NAME=switch_calc 修改为 P4_PROJECT_NAME=p4_test ;
#进入到P4-NetFPGA-live文件夹下
$ cd {path}/P4-NetFPGA-live
#进入到tools文件下
$ cd tools
#修改settings.sh文件
$ gedit settings.sh
#修改完毕后,更新环境变量
$ source settings.sh
3)编写P4代码;
#进入p4_test文件夹下
$ cd $P4_PROJECT_DIR
#进入src文件下
$ cd src
#编写P4代码
$ gedit sss_p4_proj.p4
#将P4代码的文件名重命名为${P4_PROJECT_NAME}.p4
$ mv sss_p4_proj.p4 ${P4_PROJECT_NAME}.p4
以下代码为简单的端口转发应用的P4代码(即匹配报文的入端口,然后再选择其他某个端口转发出去)
#include <core.p4>
#include <sume_switch.p4>
typedef bit<48> EthAddr_t;
typedef bit<32> IPv4Addr_t;
#define IPV4_TYPE 0x0800
#define TCP_TYPE 6
// standard Ethernet header
header Ethernet_h {
EthAddr_t dstAddr;
EthAddr_t srcAddr;
bit<16> etherType;
}
// IPv4 header without options
header IPv4_h {
bit<4> version;
bit<4> ihl;
bit<8> tos;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
IPv4Addr_t srcAddr;
IPv4Addr_t dstAddr;
}
// TCP header without options
header TCP_h {
bit<16> srcPort;
bit<16> dstPort;
bit<32> seqNo;
bit<32> ackNo;
bit<4> dataOffset;
bit<4> res;
bit<8> flags;
bit<16> window;
bit<16> checksum;
bit<16> urgentPtr;
}
// List of all recognized headers
struct Parsed_packet {
Ethernet_h ethernet;
IPv4_h ip;
TCP_h tcp;
}
// user defined metadata: can be used to share information between
// TopParser, TopPipe, and TopDeparser
struct user_metadata_t {
bit<8> unused;
}
// digest data to send to cpu if desired. MUST be 80 bits!
struct digest_data_t {
bit<80> unused;
}
// Parser Implementation
@Xilinx_MaxPacketRegion(8192)
parser TopParser(packet_in b,
out Parsed_packet p,
out user_metadata_t user_metadata,
out digest_data_t digest_data,
inout sume_metadata_t sume_metadata) {
state start {
b.extract(p.ethernet);
user_metadata.unused = 0;
digest_data.unused = 0;
transition select(p.ethernet.etherType) {
IPV4_TYPE: parse_ipv4;
default: reject;
}
}
state parse_ipv4 {
b.extract(p.ip);
transition select(p.ip.protocol) {
TCP_TYPE: parse_tcp;
default: reject;
}
}
state parse_tcp {
b.extract(p.tcp);
transition accept;
}
}
// match-action pipeline
control TopPipe(inout Parsed_packet p,
inout user_metadata_t user_metadata,
inout digest_data_t digest_data,
inout sume_metadata_t sume_metadata) {
action set_output_port(port_t port) {
sume_metadata.dst_port = port;
}
action nop() {}
table forward {
key = { sume_metadata.src_port: exact; }
actions = {
set_output_port;
nop;
}
size = 64;
default_action = nop;
}
apply {
forward.apply();
}
}
// Deparser Implementation
@Xilinx_MaxPacketRegion(8192)
control TopDeparser(packet_out b,
in Parsed_packet p,
in user_metadata_t user_metadata,
inout digest_data_t digest_data,
inout sume_metadata_t sume_metadata) {
apply {
b.emit(p.ethernet);
b.emit(p.ip);
b.emit(p.tcp);
}
}
// Instantiate the switch
SimpleSumeSwitch(TopParser(), TopPipe(), TopDeparser()) main;
4)将其他参考项目的gen_testdata.py 复制至新建的p4_test项目下;
#进入p4_test文件夹下
$ cd $P4_PROJECT_DIR
#进入testdata文件夹下
$ cd testdata
#将其他参考项目的gen_testdata.py 复制至新建的p4_test项目下
$ cp -r ../../tcp_monitor/testdata/gen_testdata.py gen_testdata.py
大事告成,接下来利用 P4-NetFPGA-live 的 makefile 文件 开启傻瓜式操作
5)运行P4-SDNet编译器生成最终的HDL和初始仿真框架;
#进入p4_test文件夹并执行make
$ cd $P4_PROJECT_DIR && make
6)运行SDNet模拟;
$ cd $P4_PROJECT_DIR/nf_sume_sdnet_ip/SimpleSumeSwitch
$ ./vivado_sim.bash
7)生成可在NetFPGA SUME模拟中使用的脚本来配置表条目;
$ cd $P4_PROJECT_DIR
$ make config_writes
8)在包装模块中包装SDNet输出并作为SUME库核心进行安装;
$ cd $P4_PROJECT_DIR
$ make uninstall_sdnet && make install_sdnet
PS:因没有写gen_testdata.py,所以以上略去 github给出的workflow详细版 中 Workflow Steps 的 第8步(Set up the SUME simulation)及第9步(Run the SUME simulation)
9)编译比特流;
$ cd $NF_DESIGN_DIR && make
10)编程FPGA, 将比特流文件和config_writes.sh脚本复制到$ NF_DESIGN_DIR / bitfiles目录中;
$ cd $NF_DESIGN_DIR/bitfiles
$ cp ../hw/project/simple_sume_switch.runs/impl_1/top.bit ./ && mv top.bit ${P4_PROJECT_NAME}.bit
$ cp $P4_PROJECT_DIR/testdata/config_writes.sh ./
$ sudo bash
# bash program_switch.sh
注意:确保配置写入全部成功。 如果这是自上次断电以来首次对FPGA进行编程,则可能需要重新启动。
11)真实硬件测试
见下章节
4.真实硬件测试
1)测试环境简介
实验测试环境如下图所示:

将PC1接入到SUME的1口(NF0),将PC2接入到SUME的2口(NF1),SUME的10G光口需接电口进行光电转换才能够接入网线。
2)测试环境构建
SUME:
- 即实验步骤的配置,含有端口转发应用的交换机。
- 下发转发规则
步骤如下:
i:进入CLI文件夹,并开启CLI下发规则
#进入p4_test项目文件下
$ cd $P4_PROJECT_DIR
#进入CLI文件夹下
$ cd sw/CLI
#开启P4_SWITCH_CLI
$ sudo bash
# ./P4_SWITCH_CLI.py
ii:下发规则,在调出的CLI界面输入以下规则(可通过help查看CLI的更多命令)
#NF0进,NF1出
table_cam_add_entry forward set_output_port 0b00000001 => 0b00000100
#NF1进,NF0出
table_cam_add_entry forward set_output_port 0b00000100 => 0b00000001
PC1:
- 设置静态IP为:192.168.1.11/24
PC2:
- 设置静态IP为:192.168.1.22/24
3)实验测试
PC1测试:
在PC1(IP:192.168.1.11/24)主机中执行
ping 192.168.1.22
可成功ping通
PC2测试:
在PC2(IP:192.168.1.22/24)主机中执行
ping 192.168.1.11
可成功ping通
至此,实验验证结束
参考链接
[1] https://github.com/NetFPGA/P4-NetFPGA-public/wiki
[2] https://github.com/NetFPGA/P4-NetFPGA-public/wiki/Workflow-Overview
[3] https://github.com/NetFPGA/P4-NetFPGA-public/wiki/Getting-Started
[4] https://github.com/NetFPGA/P4-NetFPGA-live
[5] https://github.com/NetFPGA/P4-NetFPGA-public
[6] http://www.cnblogs.com/wpqwpq/p/7886596.html
浙公网安备 33010602011771号