該儲存庫在 Bluespec SystemVerilog(BSV) 中實作了一系列與乙太網路相關的元件,以便在 FPGA 上進行高效能資料包處理。具體來說,該儲存庫提供了用於生成和解析 UDP/IP/乙太網路封包的模組。也提供具有儲存位址資訊的非阻塞快取的 ARP 處理單元,以自動處理 MAC 位址解析。除了建構標準的UDP/IP/乙太網路堆疊外,blue-ethernet還增加了對RoCE(RDMA over Converged Ethernet)的支援:1)在UDP/IP封包處理中整合ICRC(Invariant Cyclic Redundancy)的生成和驗證; 2)提供PFC(Priority Flow Control)處理模組,實現無損網路傳輸。最後也提供了介面轉換模組,供封包產生器和解析器與 Xilinx 100G 乙太網路子系統 (CMAC) 互動。
該倉庫的一些關鍵目錄如下所示:
├── lib # external libraries/repos
│ ├── blue-crc # high-performance CRC hardware implementation
│ └── blue-wrapper # BSV wrappers for generating ready-to-use Verilog interface
├── scripts # scripts used to build project
├── src # design source files
│ └── includes # files containing some commonly-used BSV types and modules
├── syn # scripts for vivado synthesis and implementation
└── test # source files for verification
├── bluesim # testbenches based on bluesim
├── cocotb # python testbenches based on cocotb
└── vivado # co-simulation with cmac using vivado
以下是一些關鍵來源檔案的清單:
./src
├── ArpCache.bsv # Cache implementation storing MAC addresses got from ARP
├── ArpProcessor.bsv # processing unit handling ARP requests and responses
├── includes
│ ├── CompletionBuf.bsv
│ ├── ContentAddressMem.bsv
│ ├── EthernetTypes.bsv # numeric and struct types about protocol definition
│ ├── PortConversion.bsv # interface conversion modules used to generate ready-to-use Verilog
│ ├── Ports.bsv # numeric and struct types about in/output ports of modules
│ ├── RFile.bsv
│ ├── StreamHandler.bsv # modules implemented for manipulating data stream
│ └── EthUtils.bsv # utility functions and modules
├── MacLayer.bsv # generator and parser for Ethernet packet
├── PfcUdpIpArpEthRxTx.bsv # generator and parser for UDP/IP/Ethernet packet with PFC
├── PriorityFlowControl.bsv # modules handling PFC
├── UdpIpArpEthRxTx.bsv # generator and parser for UDP/IP/Ethernet packet
├── UdpIpEthRx.bsv # parser for UDP/IP/Ethernet packet
├── UdpIpEthTx.bsv # generator for UDP/IP/Ethernet packet
├── UdpIpLayer.bsv # parser and generator for UDP/IP packet
├── UdpIpLayerForRdma.bsv # parser and generator for UDP/IP packet with support for RoCE
└── XilinxCmacRxTxWrapper.bsv # bridge modules between parser/generator and Xilinx CMAC
本節詳細描述了藍色乙太網路中實現的一些重要元件,包括它們的功能、介面和硬體架構。
乙太網路相關的硬體元件所做的基本上就是一系列流操作。資料包產生器負責將標頭流插入有效負載流的頭部以產生完整的資料包流。相反,解析器所做的就是從資料包流中提取頭部流和有效負載流。至於為封包新增校驗和,封包流被傳遞到 CRC 計算器,然後輸出的 CRC 值附加到封包流的尾部。
我們在這裡提到的流對應的硬體實體實際上是由有效-就緒控制訊號對守護的一組資料訊號。有效訊號表示來源元件想要傳輸資料。而ready表示sink已經準備好接收來自source的資料。只有當 valid 和 ready 都為高電位時,來源和接收器之間的傳輸才會成功。如果要傳輸的資料大小大於一次傳輸的大小,則需要將資料分片並在一系列傳輸中傳輸。
流處理中最棘手、最容易出錯的部分是如何處理不同流的有效就緒控制訊號。在BSV中,控制訊號的操作是由編譯器實現的,在語法層面上是不可見的,這有助於設計者專注於流程處理的邏輯。
用於在不同元件之間傳輸資料包流的資料訊號被封裝在DataStream結構體中,其中包括256位元資料訊號、32位元組啟用訊號、兩個布林訊號表示本次傳輸是資料包流的最後一個還是第一個。
typedef 256 DATA_BUS_WIDTH ;
typedef TDiv # ( DATA_BUS_WIDTH , 8 ) DATA_BUS_BYTE_WIDTH ;
typedef Bit # ( DATA_BUS_WIDTH ) Data ;
typedef Bit # ( DATA_BUS_BYTE_WIDTH ) ByteEn ;
typedef struct {
Data data ;
ByteEn byteEn ;
Bool isFirst ;
Bool isLast ;
} DataStream deriving ( Bits , Bounded , Eq , FShow ) ;
module mkAppendDataStreamHead # (
IsSwapEndian swapDataStream ,
IsSwapEndian swapAppendData ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( dType ) appendDataIn
)( FifoOut # ( DataStream )) ;
module mkAppendDataStreamTail # (
IsSwapEndian swapDataStream ,
IsSwapEndian swapAppendData ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( dType ) appendDataIn ,
FifoOut # ( Bit # ( streamLenWidth )) streamLengthIn
)( FifoOut # ( DataStream )) ;
interface ExtractDataStream # ( type dType ) ;
interface FifoOut # ( dType ) extractDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkExtractDataStreamHead # (
FifoOut # ( DataStream ) dataStreamIn
)( ExtractDataStream # ( dType )) ;
UdpIpLayer套件中的模組用於產生和解析 UDP/IP 封包。
封包產生器接收包含 UDP/IP 標頭資訊和有效負載流的UdpIpMetaData ,並輸出完整的 UDP/IP 封包流。封包解析器以相反的方式運作,從 UDP/IP 封包流中提取UdpIpMetaData和有效負載流。
typedef struct {
UdpLength dataLen ; # The Length of payload data
IpAddr ipAddr ; # Desitnation IP address
IpDscp ipDscp ; # DSCP field used for PFC
IpEcn ipEcn ; # ECN field
UdpPort dstPort ; # Destination port number
UdpPort srcPort ; # Source port number
} UdpIpMetaData ;
封裝在UdpIpMetaData結構中的訊號不涵蓋 UDP/IP 標頭中定義的所有欄位。標頭的某些欄位對於特定網路設備是固定的,這些欄位封裝在UdpConfig結構體中,需要在發送或接收任何資料包之前進行配置。還有一些其他字段是恆定的並且硬編碼在硬體組件中。
typedef struct {
EthMacAddr macAddr ; # Source MAC address
IpAddr ipAddr ; # Source IP address
IpNetMask netMask ; # IP netmask
IpGateWay gateWay ; # IP gateway
} UdpConfig ;
module mkUdpIpStream # (
UdpConfig udpConfig ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( UdpIpMetaData ) udpIpMetaDataIn ,
function UdpIpHeader genHeader ( UdpIpMetaData meta , UdpConfig udpConfig , IpID ipId )
)( FifoOut # ( DataStream )) ;
interface UdpIpMetaDataAndDataStream ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkUdpIpMetaDataAndDataStream # (
UdpConfig udpConfig ,
FifoOut # ( DataStream ) udpIpStreamIn ,
function UdpIpMetaData extractMetaData ( UdpIpHeader hdr )
)( UdpIpMetaDataAndDataStream ) ;
UdpIpLayerForRdma套件中的模組基於UdpIpLayer實現,支援 RoCE(RDMA over Converged Ethernet)。為支援 RoCE 而新增的附加功能是產生和驗證 RoCE 封包所需的 ICRC(不變 CRC)。 RoCE資料包的格式定義如下:
MacLayer套件中的模組用於產生和解析乙太網路封包。生成器將乙太網路標頭插入到UDP/IP封包流的頭部以產生乙太網路封包流。解析器從乙太網路封包流中提取乙太網路標頭和UDP/IP封包流。
用於產生乙太網路封包的標頭資訊在MacMetaData結構中定義。
typedef struct {
EthMacAddr macAddr ; # Destination MAC address
EthType ethType ; # Type of Ethernet frame
} MacMetaData deriving ( Bits , Eq , FShow ) ;
需要注意的是, MacLayer處理的乙太網路封包僅涵蓋下圖中紅色矩形框內的欄位。其他字段由 Xilinx CMAC IP 處理。
module mkMacStream # (
FifoOut # ( DataStream ) udpIpStreamIn ,
FifoOut # ( MacMetaData ) macMetaDataIn ,
UdpConfig udpConfig
)( FifoOut # ( DataStream )) ;
interface MacMetaDataAndUdpIpStream ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface FifoOut # ( DataStream ) udpIpStreamOut ;
endinterface
module mkMacMetaDataAndUdpIpStream # (
FifoOut # ( DataStream ) macStreamIn ,
UdpConfig udpConfig
)( MacMetaDataAndUdpIpStream ) ;
位址解析協定 (ARP) 用於發現與給定 IP 位址關聯的 MAC 位址。在blue-ethernet中,實作了ARP處理模組mkArpProcessor ,該模組整合了ARP封包產生器、解析器和儲存MAC位址的mkArpCache模組。
對於ARP處理中使用的緩存,32位元IP位址對應快取位址,48位元MAC位址對應快取資料。 ARP 快取的預設記憶體陣列排列如下所示,為 4 路組相聯結構,每路包含 64 行,每行包括 1 位元有效、26 位元標記和 48 位元資料。此預設陣列配置的總大小約為 1.2KB。支援透過設定行數和路數來改變記憶體陣列的大小。基於此記憶體陣列,快取被設計為非阻塞的,支援未完成的請求(飛行中的多個請求)並使用偽LRU演算法進行快取行替換。
mkArpCache模組的介面定義和簡化結構圖如下所示。 ArpCache有兩個子介面: cacheServer處理與 MAC 位址解析服務的元件的交互作用; arpClient處理與mkArpProcessor的交互以發起 ARP 請求並從 ARP 回應中取得 MAC 位址。 mkArpCache模組的基本工作流程如下:
當cache收到讀取請求時,它首先搜尋記憶體陣列以取得與給定IP位址對應的所有標籤和資料。然後它檢查標籤以查看我們需要的資料是否儲存在快取中。如果快取命中,則將獲取的資料傳送到hitBuf 。或將IP位址傳送到arpReqBuf發起ARP請求。當ARP回應返回時,其攜帶的資料和位址資訊都會寫入cacheWrBuf和missHitBuf ,以更新記憶體陣列並傳回快取讀取回應。
interface ArpCache ;
interface Server # ( CacheAddr , CacheData ) cacheServer ;
interface Client # ( CacheAddr , ArpResp ) arpClient ;
endinterface
快取實作中最困難的部分是支援一個突出的特性,即支援飛行中的多個讀取請求。未完成的問題是每個動態 ARP 請求的回應時間不同,這意味著遲到的請求可能會先收到回應。因此需要重新排序機制來保證快取未命中時請求位址和回應資料的對應關係。為了實現有序回應,完成緩衝區respCBuf和內容可尋址記憶體missReqTab整合在資料流中。完成緩衝區的工作方式類似於 FIFO,並額外支援預留功能。在實際入隊操作之前,我們可以先在完成緩衝區中保留一個訂單。無論入隊操作的實際順序為何,出隊操作都遵循保留的順序。對於每個讀取請求,一旦收到,就會在respCBuf中反轉出隊順序。而由於ARP請求中不能攜帶訂單訊息,所以實現了missReqTab來儲存訂單資訊。
此模組既可以充當 ARP 用戶端,也可以充當伺服器。作為伺服器,如果目標IP的MAC位址未知,處理器需要產生ARP請求,然後等待目標設備的ARP回應。 ARP處理器作為客戶端,接收其他設備的ARP請求,並傳回攜帶自己MAC位址的ARP回應。
interface ArpProcessor ;
interface FifoOut # ( DataStream ) arpStreamOut ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface Put # ( UdpConfig ) udpConfig ;
endinterface
module mkArpProcessor # (
FifoOut # ( DataStream ) arpStreamIn ,
FifoOut # ( UdpIpMetaData ) udpIpMetaDataIn
)( ArpProcessor ) ;
UdpIpEthRx套件中的模組用於接收和解析 UDP/IP/乙太網路封包。
interface UdpIpEthRx ;
interface Put # ( UdpConfig ) udpConfig ;
interface Put # ( AxiStream512 ) axiStreamIn ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkGenericUdpIpEthRx # ( Bool isSupportRdma )( UdpIpEthRx )
UdpIpEthTx套件中的模組用於產生和傳輸 UDP/IP/乙太網路封包。
interface UdpIpEthTx ;
interface Put # ( UdpConfig ) udpConfig ;
interface Put # ( UdpIpMetaData ) udpIpMetaDataIn ;
interface Put # ( MacMetaData ) macMetaDataIn ;
interface Put # ( DataStream ) dataStreamIn ;
interface AxiStream512FifoOut axiStreamOut ;
endinterface
module mkGenericUdpIpEthTx # ( Bool isSupportRdma )( UdpIpEthTx ) ;
UdpIpArpEthRxTx套件中提供的模組旨在接收和發送 UDP/IP/乙太網路封包,同時處理 ARP 請求和回應。
此模組可分為兩條相反的碼流路徑,包括發送路徑和接收路徑:
對於傳輸路徑,它接收攜帶負載流的dataStreamInTx和攜帶頭資訊流的udpIpMetaDataIn ,並產生攜帶UDP/IP/乙太網路封包流的axiStreamOutTx 。不需要提供包含乙太網路頭資訊的MacMetaData作為mkUdpIpEthTx模組,因為mkArpProcessor負責處理MAC位址解析和產生乙太網路頭資訊。
對於接收路徑,則以相反的方式工作,從攜帶UDP/IP/乙太網路封包流的axiStreamInRx中提取攜帶有效負載流的dataStreamOutRx和攜帶頭資訊流的udpIpMetaDataOutRx 。
乙太網路封包產生器和解析器由UDP/IP封包和ARP封包共享,因此在傳輸和接收路徑中需要額外的Mux和Demux來進行串流仲裁和分發。模組參數isSupportRdma指定是否支援RoCE資料包處理。如果停用對 RDMA 的支持,我們只需要分別在發送和接收路徑中使用mkUdpIpStream和mkUdpIpMetaAndDataStream 。
interface UdpIpArpEthRxTx ;
interface Put # ( UdpConfig ) udpConfig ;
// Tx
interface Put # ( UdpIpMetaData ) udpIpMetaDataInTx ;
interface Put # ( DataStream ) dataStreamInTx ;
interface AxiStream512FifoOut axiStreamOutTx ;
// Rx
interface Put # ( AxiStream512 ) axiStreamInRx ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOutRx ;
interface FifoOut # ( DataStream ) dataStreamOutRx ;
endinterface
module mkGenericUdpIpArpEthRxTx # ( Bool isSupportRdma )( UdpIpArpEthRxTx ) ;
此模組使用 blue-wrapper 中提供的模組包裝mkGenericUdpIpArpEthRxTx ,以便產生隨時可用的 Verilog 介面。
此模組整合了mkGenericUdpIpArpEthRxTx模組和mkXilinxCmacTxWrapper模組。它旨在與 Xilinx CMAC IP 交互,以在實體介質之間傳輸和接收 UDP/IP/乙太網路封包。
PriorityFlowControl包中的模組實現了優先權流量控制機制,確保網路無損傳輸。
interface PriorityFlowControlTx ;
interface Get # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface Get # ( DataStream ) dataStreamOut ;
endinterface
module mkPriorityFlowControlTx # (
FifoOut # ( FlowControlReqVec ) flowControlReqVecIn ,
Vector # ( VIRTUAL_CHANNEL_NUM , DataStreamFifoOut ) dataStreamInVec ,
Vector # ( VIRTUAL_CHANNEL_NUM , UdpIpMetaDataFifoOut ) udpIpMetaDataInVec
)( PriorityFlowControlTx ) ;
interface PriorityFlowControlRx # (
numeric type bufPacketNum ,
numeric type maxPacketFrameNum ,
numeric type pfcThreshold
) ;
interface FifoOut # ( FlowControlReqVec ) flowControlReqVecOut ;
interface Vector # ( VIRTUAL_CHANNEL_NUM , Get # ( DataStream )) dataStreamOutVec ;
interface Vector # ( VIRTUAL_CHANNEL_NUM , Get # ( UdpIpMetaData )) udpIpMetaDataOutVec ;
endinterface
module mkPriorityFlowControlRx # (
DataStreamFifoOut dataStreamIn ,
UdpIpMetaDataFifoOut udpIpMetaDataIn
)( PriorityFlowControlRx # ( bufPacketNum , maxPacketFrameNum , pfcThreshold )) ;
mkGenericPfcUdpIpArpEthRxTx整合了mkPriorityFlowControlRx/Tx和mkGenericUdpIpArpEthRxTx ,提供產生和解析 UDP/IP/乙太網路封包的功能,同時支援優先權流量控制。對於封包傳輸,它需要八個通道的有效負載流和UDP/IP頭訊息,並輸出一個UDP/IP/乙太網路封包流。對於封包接收,它接收一個 UDP/IP/乙太網路封包流,並將提取的 UDP/IP 標頭和有效負載流路由到八個輸出通道之一。
mkPfcUdpIpArpEthCmacRxTx整合了mkGenericPfcUdpIpArpEthRxTx模組和mkXilinxCmacTxWrapper模組。它旨在與 Xilinx CMAC IP 交互,以在實體介質之間傳輸和接收 UDP/IP/乙太網路封包。
主模組mkGenericUdpIpArpEthRxTx的綜合和實作是基於Xilinx xcvu9p元件使用Vivado進行的。結果表明,該電路可以達到500MHz的工作頻率,並提供128Gbps的峰值吞吐量。硬體資源使用情況如下:
CLB Logic
+----------------------------+-------+-------+------------+-----------+-------+
| Site Type | Used | Fixed | Prohibited | Available | Util % |
+----------------------------+-------+-------+------------+-----------+-------+
| CLB LUTs | 63886 | 0 | 0 | 1182240 | 5.40 |
| LUT as Logic | 41242 | 0 | 0 | 1182240 | 3.49 |
| LUT as Memory | 22644 | 0 | 0 | 591840 | 3.83 |
| LUT as Distributed RAM | 22644 | 0 | | | |
| LUT as Shift Register | 0 | 0 | | | |
| CLB Registers | 44099 | 0 | 0 | 2364480 | 1.87 |
| Register as Flip Flop | 44099 | 0 | 0 | 2364480 | 1.87 |
| Register as Latch | 0 | 0 | 0 | 2364480 | 0.00 |
| CARRY8 | 73 | 0 | 0 | 147780 | 0.05 |
| F7 Muxes | 194 | 0 | 0 | 591120 | 0.03 |
| F8 Muxes | 28 | 0 | 0 | 295560 | < 0.01 |
| F9 Muxes | 0 | 0 | 0 | 147780 | 0.00 |
+----------------------------+-------+-------+------------+-----------+-------+
BLOCKRAM
+-------------------+------+-------+------------+-----------+-------+
| Site Type | Used | Fixed | Prohibited | Available | Util % |
+-------------------+------+-------+------------+-----------+-------+
| Block RAM Tile | 4.5 | 0 | 0 | 2160 | 0.21 |
| RAMB36 / FIFO * | 4 | 0 | 0 | 2160 | 0.19 |
| RAMB36E2 only | 4 | | | | |
| RAMB18 | 1 | 0 | 0 | 4320 | 0.02 |
| RAMB18E2 only | 1 | | | | |
| URAM | 0 | 0 | 0 | 960 | 0.00 |
+-------------------+------+-------+------------+-----------+-------+
本節介紹如何開始這個專案。在執行任何其他步驟之前,您首先需要參考腳本 setup.sh 設定開發環境。這是依賴項列表:
設定環境後,將此儲存庫複製到特定目錄。這裡我們將該目錄稱為 BLUE_ETH:
git clone --recursive https://github.com/wengwz/blue-ethernet.git $( BLUE_ETH )
藍色乙太網路提供了三個不同層次的測試平台:
# Specify TARGET to the name of target component
cd $( BLUE_ETH ) /test/bluesim
make TARGET=ArpCache
# Run tests of UdpIpEthRx/Tx
# Enable/Disable support for RDMA by setting SUPPORT_RDAM to True/False
cd $( BLUE_ETH ) /test/cocotb
make cocotb TARGET=UdpIpEthTx SUPPORT_RDMA=TRUE
# Run simulation on virtual network
# Change NET_IFC in run_docker_net_test.sh to the name of your network card
cd $( BLUE_ETH ) /test/cocotb
docker build -f ./build_docker/Dockerfile -t ethernet-test ./build_docker
./run_docker_net_test.sh
# Available TARGET includes UdpIpArpEthCmacRxTx/PfcUdpIpArpEthCmacRxTx
# Enable/Disable support for RDMA by setting SUPPORT_RDAM to True/False
cd $( BLUE_ETH ) /test/vivado
make sim TARGET=UdpIpArpEthCmacRxTx SUPPORT_RDMA=False
用於運行綜合和設計實現的腳本在目錄 $(BLUE_ETH)/syn 中提供。
# TARGET specifies the top module to be synthsized or implemented
# SUPPORT_RDMA specifies whether modules supports RoCE packet processing
# ONLYSYNTH decides whether or not run implemetation after synthesis
cd $( BLUE_ETH ) /syn
make vivado TARGET=UdpIpArpEthRxTx SUPPORT_RDMA=False ONLYSYNTH=0
# TARGET specifies the name of top module to be generated
# Specify SUPPORT_RDMA if needed
cd $( BLUE_ETH ) /test/cocotb
make verilog TARGET=UdpIpEthTx SUPPORT_RDMA=TRUE
bsc -p +: $( BLUE_ETH ) /src: $( BLUE_ETH ) /src/includes ...
藍色乙太網路的實作涉及以下外部函式庫的使用: