作者简介:汪培侨,福州大学数计学院2014级计算机科学与技术(实验班)本科生,目前针对软件定义网络SDN的P4语言进行研究。
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 ;
1 2 3 4 5 6 |
#进入到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
;
1 2 3 4 5 6 7 8 |
#进入到P4-NetFPGA-live文件夹下 $ cd {path}/P4-NetFPGA-live #进入到tools文件下 $ cd tools #修改settings.sh文件 $ gedit settings.sh #修改完毕后,更新环境变量 $ source settings.sh |
3)编写P4代码;
1 2 3 4 5 6 7 8 |
#进入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代码(即匹配报文的入端口,然后再选择其他某个端口转发出去)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
#include #include <sume_switch.p4> typedef bit EthAddr_t; typedef bit IPv4Addr_t; #define IPV4_TYPE 0x0800 #define TCP_TYPE 6 // standard Ethernet header header Ethernet_h { EthAddr_t dstAddr; EthAddr_t srcAddr; bit etherType; } // IPv4 header without options header IPv4_h { bit version; bit ihl; bit tos; bit totalLen; bit identification; bit flags; bit fragOffset; bit ttl; bit protocol; bit hdrChecksum; IPv4Addr_t srcAddr; IPv4Addr_t dstAddr; } // TCP header without options header TCP_h { bit srcPort; bit dstPort; bit seqNo; bit ackNo; bit dataOffset; bit res; bit flags; bit window; bit checksum; bit 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 unused; } // digest data to send to cpu if desired. MUST be 80 bits! struct digest_data_t { bit 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项目下;
1 2 3 4 5 6 |
#进入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和初始仿真框架;
1 2 |
#进入p4_test文件夹并执行make $ cd $P4_PROJECT_DIR $$ make |
6)运行SDNet模拟;
1 2 |
$ cd $P4_PROJECT_DIR/nf_sume_sdnet_ip/SimpleSumeSwitch $ ./vivado_sim.bash |
7)生成可在NetFPGA SUME模拟中使用的脚本来配置表条目;
1 2 |
$ cd $P4_PROJECT_DIR $ make config_writes |
8)在包装模块中包装SDNet输出并作为SUME库核心进行安装;
1 2 |
$ 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)编译比特流;
1 |
$ cd $NF_DESIGN_DIR $$ make |
10)编程FPGA, 将比特流文件和config_writes.sh
脚本复制到$ NF_DESIGN_DIR / bitfiles
目录中;
1 2 3 4 5 6 |
$ 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下发规则
1 2 3 4 5 6 7 |
#进入p4_test项目文件下 $ cd $P4_PROJECT_DIR #进入CLI文件夹下 $ cd sw/CLI #开启P4_SWITCH_CLI $ sudo bash # ./P4_SWITCH_CLI.py |
ii:下发规则,在调出的CLI界面输入以下规则(可通过help查看CLI的更多命令)
1 2 3 4 |
#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)主机中执行
1 |
ping 192.168.1.22 |
可成功ping通。
PC2测试:
在PC2(IP:192.168.1.22/24)主机中执行
1 |
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