P4->NetFPGA 工作流程概述
前言
結構
本頁面介紹了P4-> NetFPGA工作流程的以下幾個方面:
- SimpleSumeSwitch Architecture
- Xilinx P4-SDNet
- Workflow Steps
- Writing P4 Programs
- Testing P4 Programs
- Debugging P4 Programs
- P4->NetFPGA Extern Library
- API / CLI
- Limitations
SimpleSumeSwitch Architecture
SimpleSumeSwitch是目前為NetFPGA SUME定義的P4架構。 體系結構描述可以在/opt/Xilinx/SDNet/<version_number>/data/p4include/sume_switch.p4
中找到,或者您已經安裝了Xilinx SDNet的地方。 該體系結構由單個解析器,單個匹配操作管道和單個解析器組成。 如下所示:
- sume_metadata: 對應於SUME reference_switch設計中的tuser總線,定義如下:
struct sume_metadata_t {
bit<16> dma_q_size; // measured in 32-byte words
bit<16> nf3_q_size; // measured in 32-byte words
bit<16> nf2_q_size; // measured in 32-byte words
bit<16> nf1_q_size; // measured in 32-byte words
bit<16> nf0_q_size; // measured in 32-byte words
bit<8> send_dig_to_cpu; // send digest_data to CPU
bit<8> drop;
port_t dst_port; // one-hot encoded: {DMA, NF3, DMA, NF2, DMA, NF1, DMA, NF0}
port_t src_port; // one-hot encoded: {DMA, NF3, DMA, NF2, DMA, NF1, DMA, NF0}
bit<16> pkt_len; // (bytes) unsigned int
}
其中:
pkt_len
- 數據包的大小(不包括FCS的以太網前綴),單位為字節。src_port
- 數據包到達的端口。 例如,如果數據包到達端口nf1,則該字段將被設置為0b00000100。dst_port
- 應由用戶的P4程序設置,以指示哪個或哪些端口(如果有的話)數據包應該被發送出去。 例如,要從端口nf0和nf2發送數據包,該字段應設置為0b00010001。drop
- 如果該字段的最低有效位被設置為1,則該分組將被丟棄。send_dig_to_cpu
- 如果該字段的最低有效位設置為1,則摘要數據將通過DMA發送到CPU。_q_size
- 每個輸出隊列的大小,以32字節的單詞來衡量(向上舍入)。 這是P4程序開始處理數據包時輸出隊列的大小。
- digest_data: 這個總線的格式是由P4程序員定義的。 唯一的限制是它必須被定義為80位寬。 例如,要實現一個L2學習開關,可以將digest_data總線配置如下:
struct digest_data_t {
bit<8> src_port;
bit<48> eth_src_addr;
bit<24> unused;
}
- user_metadata: 這個總線的格式也由P4程序員定義。 它可以用來將解析器的任何附加信息傳遞給M / A流水線,並從M / A流水線傳遞給解析器。
- in/out control: 這些信號用於添加/刪除表和讀/寫控制寄存器的條目。
Xilinx P4-SDNet工具鏈創建一個HDL模塊,然后將其封裝在一個小封裝中,並插入到NetFPGA SUME參考交換機架構中,如下圖所示。
Xilinx P4-SDNet
賽靈思P4-SDNet編譯器是P4-> NetFPGA工作流程的核心。 它將面向SimpleSumeSwitch體系結構的P4程序編譯成一個具有標准AXI-Stream數據包接口和AXI-Lite控制接口的HDL模塊。 SDNet輸出設計為100G速率,因此能夠輕松處理SUME參考開關設計中的總計40G速率。 有關賽靈思SDNet工具的更多信息,請參見此處。
Workflow Steps
1)修改$ SUME_FOLDER / tools / settings.sh
以確保將P4_PROJECT_NAME
環境變量設置為您想要處理的項目的名稱。 運行$ source settings.sh
2)編寫P4程序和commands.txt - commands.txt文件允許你添加條目到你在P4程序中定義的表中。
3)寫 gen_testdata.py
4)運行P4-SDNet編譯器生成最終的HDL和初始仿真框架:
$ cd $P4_PROJECT_DIR && make
5)運行SDNet模擬:
$ cd $P4_PROJECT_DIR/nf_sume_sdnet_ip/SimpleSumeSwitch
$ ./vivado_sim.bash
注意:如果您想啟動Vivado GUI並查看HDL波形(這是一個非常有用的調試工具),您也可以運行vivado_sim_waveform.bash。
如果這個模擬通過很好! 如果沒有,你將需要修改你的P4程序或你的gen_testdata.py腳本。
6)生成可在NetFPGA SUME模擬中使用的腳本來配置表條目。
$ cd $P4_PROJECT_DIR
$ make config_writes
7)在包裝模塊中包裝SDNet輸出並作為SUME庫核心進行安裝:
$ cd $P4_PROJECT_DIR
$ make uninstall_sdnet && make install_sdnet
8)設置SUME模擬。 $ NF_DESIGN_DIR / test / sim_switch_default目錄包含負責運行SUME模擬的run.py腳本,請檢查一下。 您將看到它讀取由步驟3中的gen_testdata.py腳本生成的測試數據包,並將數據包應用於SUME接口。 我們所需要做的就是將步驟6中生成的config_writes.py腳本復制到這個目錄中。
$ cd $NF_DESIGN_DIR/test/sim_switch_default && make
9)運行SUME模擬:
$ cd $SUME_FOLDER
$ ./tools/scripts/nf_test.py sim --major switch --minor default
注意:您也可以使用--gui選項運行上述命令來啟動Vivado GUI並查看HDL波形。 再次,一個非常有用的調試工具。
10)編譯比特流:
$ cd $NF_DESIGN_DIR && make
11)檢查以確保設計符合時間要求。 看到這個this FAQ,看看如何做到這一點。
12)編程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進行編程,則可能需要重新啟動。
13)在真實硬件上測試設計! 轉到$ P4_PROJECT_DIR / sw / CLI
目錄並運行P4_SWITCH_CLI.py
腳本。 這啟動了一個交互式命令行界面,您可以使用該界面與您的交換機進行交互(例如,讀取/寫入寄存器,添加/刪除表條目等)。 輸入help以查看可用命令的列表。
Writing P4 Programs
該庫目前支持Xilinx P4 _ 16前端編譯器請參閱此處以獲取有關P4_16語言當前標准的鏈接。 有關開源P4語言聯盟的更多信息,請訪問P4.org。
賽靈思P4-SDNet指定了一些可用於P4程序的附加注釋:
@Xilinx_MaxPacketRegion()
- for parser/deparser; 聲明解析器/解析器需要支持的最大數據包大小(以位為單位)。@Xilinx_MaxLatency()
- 對於extern; 外部函數需要完成的最大時鍾周期數。@Xilinx_ControlWidth()
- 為extern; 地址空間的大小分配給一個extern函數。@Xilinx_ExternallyConnected()
- 表格; 將表的請求和響應元組拉到設計的頂層
有關使用和編寫extern函數的更多信息,請參見“P4-> NetFPGA Extern庫”一節。
Table Types:在P4程序中可以使用3種表格類型:
exact
- 完全匹配指定的標題或元數據字段,然后執行所需的操作。 可以指定多個鍵匹配。ternary
- 完全匹配指定鍵的一些所需子集。lpm
- 匹配與指定key共享最長前綴匹配的表中的條目。 只能指定一個鍵。
Commands.txt: 這是$ P4_PROJECT_DIR / src /
目錄中的文件,其中包含用於填充表條目的命令。 以下是用於填充每種類型的表中的表項的命令的格式:
Table Type | Command |
---|---|
exact |
table_cam_add_entry <table_name> <action_name> <keys (space separated)> => <action_data (space separated)> |
ternary |
table_tcam_add_entry <table_name> <entry_address> <action_name> <key1/mask1 ... keyN/maskN> => <action_data (space separated)> |
lpm |
table_lpm_add_entry <table_name> <action_name> <key>/<prefix_length> => <action_data (space separated)> |
上面列出的命令是commands.txt文件中唯一支持的命令。
注意:使用lpm表時,SDNet編譯器將生成一個bash腳本(即create_ip_forward.bash
),在啟動SDNet仿真之前必須運行它。
Testing P4 Programs
通過在$ P4_PROJECT_DIR / testdata
目錄中寫入一個gen_testdata.py
腳本來測試你的P4程序。 gen_testdata.py腳本大量使用python scapy模塊。 Scapy是一個非常方便和易於使用的數據包操作庫。 它允許你定義任意數據包,甚至定義你自己的頭類型(例如switch_calc_headers.py
)。 gen_testdata.py
腳本必須生成:
src.pcap
- 數據包通過P4交換機dst.pcap
- 數據包在P4交換機的輸出處預期Tuples_in.txt
- 與src.pcap中的每個數據包關聯的metadataTuples_expect.txt
- 與dst.pcap中的每個數據包關聯的metadata
上面列出的文件用於初始SDNet模擬。 文件$ P4_PROJECT_DIR / testdata / sss_sdnet_tuples.py
可以用於為針對SimpleSumeSwitch體系結構的項目創建Tuples_in.txt
和Tuples_expect.txt
文件。 對於每個數據包,更新sume_tuple_in
,dig_tuple_in
,sume_tuple_expect
和dig_tuple_expect
,隨后調用write_tuples()
向Tuples _ *.txt
文件添加一行。
建議gen_testdata.py腳本也會生成:
nf0_applied.pcap
...nf3_applied.pcap
nf0_expected.pcap
...nf3_expected.pcap
這些是可以在SUME模擬中使用的文件。 該腳本還應該為每個應用數據包設置時間字段,以便可以按正確的順序應用SUME模擬。
$ {NF_DESIGN_DIR} /test/sim_switch_default/run.py
腳本運行一個SUME模擬。 它可以使用由gen_tesdata.py
腳本生成的數據包追蹤,或者可以創建新數據包並使用它們。 有關編寫run.py
腳本的更多詳細信息,請參閱此處。
Debugging P4 Programs
如果你做了足夠的P4開發,你可能需要在某個時候進行調試。 本節旨在為您提供一些調試技巧。
SDNet產生你的P4程序的兩個實現:一個HDL實現和一個C ++模型。 為了將C ++模型的輸出與HDL實現的輸出進行比較,請執行以下操作:
$ cd $P4_PROJECT_DIR && make_cpp_test
$ cd nf_sume_sdnet_ip/SimpleSumeSwitch/
$ ./vivado_sim.bash
這對於測試SDNet編譯器的功能非常有用,因為C ++模型的輸出應該始終與HDL實現的輸出相匹配。 所以如果運行上面的模擬失敗這可能表明SDNet編譯器的問題,但它也可能表明另一個問題。 例如,也許你正在試圖添加更多的條目比你的表可以容納? 要解決這個問題,你需要在你的P4程序中增加你的表的大小。 或者,也許你正在使用的任何外部函數的C ++模型是不正確的實現?
SDNet C ++模型有用的另一個原因是因為它產生了經過處理的數據包的PCAP文件Packet_expect.pcap。 要生成C ++模型輸出PCAP文件,請執行以下操作:
$ cd $P4_PROJECT_DIR && make
$ cd nf_sume_sdnet_ip/SimpleSumeSwitch/SimpleSumeSwitch.TB/
$ ./compile
$ ./SimpleSumeSwitch
生成的PCAP文件被稱為Packet_expect.pcap
,可以與gen_testdata.py
腳本生成的dst.pcap文件進行比較。 運行C ++模型產生非常詳細的輸出,描述如何處理數據包。 例如,您可以看到整個設計中元數據字段的修改方式,以及您定義的表中是否存在命中或未命中。
一旦確定Packet_expect.pcap
文件與dst.pcap
文件相匹配,您可以運行SDNet模擬,將HDL實現輸出與dst.pcap
中的數據包以及Tuple_expect.txt
中的預期元數據進行比較:
$ cd $P4_PROJECT_DIR && make
$ cd nf_sume_sdnet_ip/SimpleSumeSwitch/
$ ./vivado_sim.bash
如果運行此模擬會導致元數據錯誤(即期望元組與實際元組之間不匹配),則可以輕松地檢查哪些字段不匹配:
$ ./vivado_sim.bash
...
expected < tuple_out_sume_metadata > = < 00000000000000000000000100040041 >
actual < tuple_out_sume_metadata > = < 00000000000000000000000100040040 >
...
$ $P4_PROJECT_DIR/testdata/sss_sdnet_tuples.py --parse 00000000000000000000000100040041 sume
Parsed Tuple:
-----------------------
dma_q_size = 0
nf3_q_size = 0
nf2_q_size = 0
nf1_q_size = 0
nf0_q_size = 0
send_dig_to_cpu = 0
drop = 1
dst_port = 00000000
src_port = 00000100
pkt_len = 65
如果SDNet模擬通過但SUME模擬失敗,該怎么辦?
如果你遇到這個問題,我會建議檢查幾件事情:
1)確保你已經運行:
$ cd $P4_PROJECT_DIR && make config_writes
$ cd $NF_DESIGN_DIR/test/sim_major_minor && make
$ cd $P4_PROJECT_DIR && make install_sdnet
2)請注意,數據包的接收順序很重要。 如果您的nf _ * _ expected.pcap文件中的數據包包含的數據包順序與實際收到的數據包不同,則會導致模擬失敗。
3)運行SUME模擬更長時間 - 如果您看到所有預期的數據包尚未到達,則可能是問題所在。
4)確保所有配置寫入在應用測試數據包之前已經完成。
5)要檢查SUME模擬的實際和預期數據包,請檢查$ NF_DESIGN_DIR / test / nf _ * _ expected.axi
和$ NF_DESIGN_DIR / test / nf _ * _ logged.axi
。
6)通過在$ NF_DESIGN_DIR / hw / tcl / simple_sume_switch_sim.tcland
的底部添加--gui選項來運行SUME仿真,將信號添加到仿真波形。
P4->NetFPGA Extern Library
外部功能旨在讓P4程序員在其P4程序中使用自定義邏輯。 對於NetFPGA平台,這些外部函數必須用HDL(或者可能是一些生成HDL的高級語言)來實現。 為了從P4開發者中抽象出HDL細節,P4-> NetFPGA工作流提供了一個可用於P4程序的外部函數庫。 有狀態的原子實驗是受Domino原子的啟發。 下表介紹了當前支持的外部函數:
Stateful Atomic Extern Functions
Name | Description |
---|---|
RW | 讀寫狀態 |
RAW | Read, add to, or overwrite state |
PRAW | Either perform RAW or don't perform RAW based on predicate |
ifElseRAW | Two RAWs, one each for when a predicate is true or false |
Sub | IfElseRAW with stateful subtraction capability |
IMPORTANT:每個有狀態原子(即寄存器)只能在P4代碼中被訪問一次。 多次調用extern函數會生成原子的多個實例,您可能會得到意想不到的結果。
注:Vivado將寄存器的大小限制為1百萬個條目。 所以這些有狀態原子的索引寬度必須小於20位。
Stateless Extern Functions
Name | Description |
---|---|
IP Checksum | Given an IP header, compute the IP checksum |
LRC | longitudinal redundancy check, simple hash function |
timestamp | generate timestamp (measure in clock cycles, granularity of 5ns) |
Adding new extern functions:
為工作流添加新的外部函數是非常容易的。 實現extern函數,只需將條目添加到$ {SUME_SDNET} /bin/extern_data.py
文件中即可。 每個條目是一個有兩個鍵的Python字典:
- “template_file” - 指定相對於
$ {SUME_SDNET} / templates
目錄的extern函數模板的路徑。 - “replacements” - 一個python字典,指定要在模板文件中替換的模式,以及替換模式的模式。 支持的命令是:
Command | Description |
---|---|
"module_name" | The name of the module. This is determined by the P4-SDNet compiler and so must be replaced in the template file. |
"extern_name" | The full name of the extern function. This is also determined by the P4-SDNet compiler and so must be replaced in the template file. |
"prefix_name" | The name given to the extern function by the P4 programmer. For example, for an extern function called pktCnt_reg_raw the "prefix_name" would be called pktCnt . |
"addr_width" | The size (in bits) of the address space allocated to the extern function. Specified by the P4 programmer using the @Xilinx_ControlWidth annotation. |
"input_width(field)" | The width (in bits) of a particular input field. |
"output_width(field)" | The width (in bits) of a particular output field. |
如果一個P4程序實例化一個控制寬度大於0的外部函數,P4-> NetFPGA工具將自動生成一個可以在外部模塊中使用的<prefix_name> _cpu_regs
模塊。 它的目的是使用AXI-Lite接口輕松暴露控制寄存器。
強烈建議實現新的外部函數的用戶將其貢獻給P4-> NetFPGA項目,以便其他人也可以使用它們。
API / CLI
python和C API都是由工作流生成的,而且可以用來操作P4程序中實例化的寄存器和表。 C API由P4-SDNet直接生成,文件被復制到$ {P4_PROJECT_DIR} / sw / API
目錄中。 python API只是這些C API函數的一個包裝,使開發人員可以很容易地編寫python程序來控制它們的開關設計。 python API文件名為p4_tables_api.py
和p4_regs_api.py
,位於$ {P4_PROJECT_DIR} / sw / CLI
目錄中。
這些工具生成一個交互式命令行環境,可用於查詢有關生成的P4設計的編譯時間信息,以及在物理交換機加載到FPGA時與交換機進行交互。 運行:$ ./P4_SWITCH_CLI.py進入環境,輸入help查看命令列表及其文檔。
Limitations
-
lpm和三元表只有輕微的測試。 為這些表類型開發項目和測試用例需要社區支持。
-
從控制面訪問的寄存器必須限制在32位寬。 因為這是SUME控制數據總線的寬度。
-
所有的P4設計必須至少有一個表或外部功能與控制界面。 這是因為HDL包裝模塊目前假定SimpleSumeSwitch模塊將具有AXI-Lite控制接口。
-
有關更多問題,請參閱github issue頁面。