电子说
blue-ethernet项目使用Bluespec SystemVerilog(BSV)硬件描述语言实现了一系列在FPGA上加速网络数据包处理的硬件模块。具体来说,其提供了用于生成和解析Ethernet/IP/UDP网络报文的硬件模块。此外,还提供了一个具有非阻塞高速缓存的APR报文处理单元,用于自动解析设备的物理MAC地址。
除了构建标准的UDP/IP/Ethernet协议栈,blue-ethernet还增加了对RoCE(RDMA over Converged Ethernet)协议的支持,具体包括:
1)在UDP/IP报文处理流程中集成 ICRC校验码的生成和验证功能;
2)提供对Priority Flow Control(PFC)协议的支持,实现无损网络传输。
最后,本项目还实现了与 Xilinx 100G以太网子系统(CMAC)进行交互的单元。
本项目关键目录的介绍如下:
├── lib # 外部库
│ ├── blue-crc # 高性能CRC硬件实现
│ └── blue-wrapper # BSV接口封装模块
├── scripts # 脚本
├── src # 设计源文件
│ └── includes
├── syn # 综合脚本
└── test # 测试源文件
├── bluesim # 基于bluesim的测试源文件
├── cocotb # 基于python的测试源文件
└── vivado # 和CMAC IP进行联合仿真的测试文件
以下是部分源文件的介绍:
./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
│ └── Utils.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
本节将详细介绍blue-ethernet实现的一些重要组件,包括其功能、接口定义和硬件架构等内容。
数据流处理模块
硬件网络报文处理本质上是对数据流的各种操作。报文生成模块实际上是将报头数据流插入发送内容数据流的头部,以生成完整的报文数据流。相反,解析模块则是从报文数据流中提取出报头数据流和发送信息数据流。为报文添加校验和,则是先将报文数据流传入CRC计算单元,然后将输出的CRC校验值附加到报文流的尾部。这里提到的数据流,其对应的硬件实体是由valid-ready握手信号控制的一组数据信号。在基于valid-ready握手的交互协议下,valid信号表示主端(Source)发起了数据传输请求,ready信号则表示从端(Sink)准备好接收来自主端的数据。只有当valid和ready同时为高电平时,即主从双方同时准备好后,才成功完成一次传输。如果需要传输的数据量大于一次传输的容量,则需要对数据进行分段,并通过多次握手传递。在对数据流的处理中最棘手以及最容易出错的部分是多个数据流交互时如何处理不同流的valid-ready控制信号。在BSV中,控制信号的处理由编译器实现,在语法层面上是不可见的,这更有助于设计人员专注于不同数据流之间的交互逻辑,而不用处理底层复杂的控制信号。
blue-ethernet提供的用于数据流处理的模块包括:
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,
PipeOut#(DataStream) dataStreamIn,
PipeOut#(dType) appendDataIn
)(PipeOut#(DataStream));
module mkAppendDataStreamTail#(
IsSwapEndian swapDataStream,
IsSwapEndian swapAppendData,
PipeOut#(DataStream) dataStreamIn,
PipeOut#(dType) appendDataIn,
PipeOut#(Bit#(streamLenWidth)) streamLengthIn
)(PipeOut#(DataStream));
interface ExtractDataStream#(type dType);
interface PipeOut#(dType) extractDataOut;
interface PipeOut#(DataStream) dataStreamOut;
endinterface
module mkExtractDataStreamHead#(
PipeOut#(DataStream) dataStreamIn
)(ExtractDataStream#(dType));
UdpIpLayer
UdpIpLayer包中的定义的模块用于生成和解析基于UDP/IP协议的报文:
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;
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,
PipeOut#(DataStream) dataStreamIn,
PipeOut#(UdpIpMetaData) udpIpMetaDataIn,
function UdpIpHeader genHeader(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId)
)(PipeOut#(DataStream));
interface UdpIpMetaDataAndDataStream;
interface PipeOut#(UdpIpMetaData) udpIpMetaDataOut;
interface PipeOut#(DataStream) dataStreamOut;
endinterface
module mkUdpIpMetaDataAndDataStream#(
UdpConfig udpConfig,
PipeOut#(DataStream) udpIpStreamIn,
function UdpIpMetaData extractMetaData(UdpIpHeader hdr)
)(UdpIpMetaDataAndDataStream);
UdpIpLayerForRdma
UdpIpLayerForRdma包在UdpIpLayer的基础上提供了对RoCE(RDMA over Converged Ethernet)协议的支持。为支持RoCE协议,需要在报文生成和解析模块中分别添加生成和检查RoCE数据包ICRC校验和的功能。RoCE数据包的格式定义如下,和标准的UDP/IP协议相比,RoCE协议需要额外计算整个IP报文的CRC校验和并附加到尾部。
功能模块详解:
MacLayer
MacLayer中提供的模块用于生成和解析链路层的Ethernet报文: 生成以太网数据包需要的报头信息被定义在MacMetaData结构体中,包括目标物理地址macAddr和报文类型ethType:
typedef struct {
EthMacAddr macAddr; # Destination MAC address
EthType ethType; # Type of Ethernet frame
} MacMetaData deriving(Bits, Eq, FShow);
需要注意的是,在目前的实现中,MacLayer处理的Ethernet报文只包括下图中红色矩形框内的字段。其他字段由Xilinx提供的CMAC模块处理。
module mkMacStream#(
PipeOut#(DataStream) udpIpStreamIn,
PipeOut#(MacMetaData) macMetaDataIn,
UdpConfig udpConfig
)(PipeOut#(DataStream));
interface MacMetaDataAndUdpIpStream;
interface PipeOut#(MacMetaData) macMetaDataOut;
interface PipeOut#(DataStream) udpIpStreamOut;
endinterface
module mkMacMetaDataAndUdpIpStream#(
PipeOut#(DataStream) macStreamIn,
UdpConfig udpConfig
)(MacMetaDataAndUdpIpStream);
ARP Processor
地址解析协议(ARP)用于解析给定IP地址对应的MAC物理地址。在blue-ethernet中,mkArpProcessor模块负责ARP协议的处理,其集成了ARP报文生成器、解析器以及缓存MAC地址信息的mkArpCache等模块。
mkArpCache
mkArpCache模块用于缓存解析得到的MAC物理地址。在ARP的应用场景下,缓存地址为32-bit的IP地址,缓存数据为48-bit的MAC物理地址。mkArpCache存储阵列的组织形式为4路组相联,每路包含64行,每行包括1-bit有效位、26-bit标记位以及48-bit数据。在该默认配置下存储容量的总大小约为1.2KB,同时设计也支持改变行数和路数进一步提升缓存空间。在此内存阵列的基础上,缓存还支持outstanding模式以及伪LRU(Least Frequently Used)行替换算法。
mkArpCache模块的接口定义和结构图如下所示。ArpCache可以分成两个子接口:cacheServer接口与Ethernet报文生成模块进行交互,接收并响应其发起的MAC地址检索请求;arpClient接口与ARP报文生成和解析模块交互,处理缓存未命中的情况。mkArpCache模块的工作流程如下:
当收到Ethernet报文生成模块检索MAC地址的请求后,首先根据给定IP地址搜索缓存阵列,检查所需的MAC地址是否已经存储在缓存阵列中。如果缓存命中,则将获取的MAC地址发送到hitBuf。若未命中,则将IP地址发送到arpReqBuf以向外发起ARP请求。当ARP响应返回时,将解析得到的MAC地址同时写入cacheWrBuf和missHitBuf,更新缓存阵列内的数据,同时响应Ethernet报文生成器检索MAC地址的请求。
interface ArpCache;
interface Server#(CacheAddr, CacheData) cacheServer;
interface Client#(CacheAddr, ArpResp) arpClient;
endinterface
mkArpProcessor
mkArpProcessor集成了MAC地址信息缓存单元mkArpCache以及对ARP报文的解析和生成模块。在处理ARP请求和响应时,mkArpProcessor既可作为请求端,在Cache Miss时发出ARP请求报文并接收从目标设备返回的ARP响应报文。同时也可作为被请求端,接收其他设备发出的ARP请求报文并将自己的MAC地址信息通过ARP响应返回给请求端。
interface ArpProcessor;
interface PipeOut#(DataStream) arpStreamOut;
interface PipeOut#(MacMetaData) macMetaDataOut;
interface Put#(UdpConfig) udpConfig;
endinterface
module mkArpProcessor#(
PipeOut#(DataStream) arpStreamIn,
PipeOut#(UdpIpMetaData) udpIpMetaDataIn
)(ArpProcessor);
UdpIpEthRx
UdpIpEthRx包提供的模块用于接收并解析UDP/IP/Ethernet报文流:
interface UdpIpEthRx;
interface Put#(UdpConfig) udpConfig;
interface Put#(AxiStream512) axiStreamIn;
interface PipeOut#(MacMetaData) macMetaDataOut;
interface PipeOut#(UdpIpMetaData) udpIpMetaDataOut;
interface PipeOut#(DataStream) dataStreamOut;
endinterface
module mkGenericUdpIpEthRx#(Bool isSupportRdma)(UdpIpEthRx)
UdpIpEthTx
UdpIpEthTx包提供的模块用于生成并输出UDP/IP/Ethernet报文流。
interface UdpIpEthTx;
interface Put#(UdpConfig) udpConfig;
interface Put#(UdpIpMetaData) udpIpMetaDataIn;
interface Put#(MacMetaData) macMetaDataIn;
interface Put#(DataStream) dataStreamIn;
interface AxiStream512PipeOut axiStreamOut;
endinterface
module mkGenericUdpIpEthTx#(Bool isSupportRdma)(UdpIpEthTx);
UdpIpArpEthRxTx
UdpIpArpEthRxTx包中的模块集成了生成和解析UDP/IP/Ethernet报文,以及处理ARP请求和响应等功能,提供对UDP/IP/Ethernet协议栈完整的支持:
interface UdpIpArpEthRxTx;
interface Put#(UdpConfig) udpConfig;
// Tx
interface Put#(UdpIpMetaData) udpIpMetaDataInTx;
interface Put#(DataStream) dataStreamInTx;
interface AxiStream512PipeOut axiStreamOutTx;
// Rx
interface Put#(AxiStream512) axiStreamInRx;
interface PipeOut#(UdpIpMetaData) udpIpMetaDataOutRx;
interface PipeOut#(DataStream) dataStreamOutRx;
endinterface
module mkGenericUdpIpArpEthRxTx#(Bool isSupportRdma)(UdpIpArpEthRxTx);
PriorityFlowControl
PriorityFlowControl包中的模块用于实现PFC协议,以确保无损网络数据传输。
interface PriorityFlowControlTx;
interface Get#(UdpIpMetaData) udpIpMetaDataOut;
interface Get#(DataStream) dataStreamOut;
endinterface
module mkPriorityFlowControlTx#(
PipeOut#(FlowControlReqVec) flowControlReqVecIn,
Vector#(VIRTUAL_CHANNEL_NUM, DataStreamPipeOut) dataStreamInVec,
Vector#(VIRTUAL_CHANNEL_NUM, UdpIpMetaDataPipeOut) udpIpMetaDataInVec
)(PriorityFlowControlTx);
interface PriorityFlowControlRx#(
numeric type bufPacketNum,
numeric type maxPacketFrameNum,
numeric type pfcThreshold
);
interface PipeOut#(FlowControlReqVec) flowControlReqVecOut;
interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamOutVec;
interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataOutVec;
endinterface
module mkPriorityFlowControlRx#(
DataStreamPipeOut dataStreamIn,
UdpIpMetaDataPipeOut udpIpMetaDataIn
)(PriorityFlowControlRx#(bufPacketNum, maxPacketFrameNum, pfcThreshold));
基于Xilinx xcvu9p FPGA,使用Vivado对blue-ethernet中的主要模块mkGenericUdpIpArpEthRxTx进行综合和实现。结果表明,电路的工作频率可达 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脚本配置开发环境。以下列出了开发环境依赖的软件包:
git clone --recursive https://github.com/wengwz/blue-ethernet.git $(BLUE_ETH)
仿真测试
blue-ethernet提供了三种不同级别的测试平台:
# 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
综合与物理实现在Vivado下运行综合和物理实现的脚本位于目录$(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 ...
全部0条评论
快来发表一下你的评论吧 !