В этом репозитории реализован набор связанных с Ethernet компонентов в Bluespec SystemVerilog (BSV) для высокопроизводительной обработки пакетов на FPGA. В частности, этот репозиторий предоставляет модули для генерации и анализа пакетов UDP/IP/Ethernet. Также предусмотрен блок обработки ARP с неблокируемым кешем, в котором хранится информация об адресе, для автоматического разрешения MAC-адреса. Помимо создания стандартного стека UDP/IP/Ethernet, blue-ethernet добавляет поддержку RoCE (RDMA через конвергентный Ethernet): 1) интегрирует генерацию и проверку ICRC (инвариантное циклическое резервирование) в обработку пакетов UDP/IP; 2) предоставить модули для обработки PFC (управления приоритетным потоком) для реализации передачи по сети без потерь. И, наконец, также предусмотрены модули преобразования интерфейса для генератора пакетов и анализатора для взаимодействия с подсистемой Xilinx 100G Ethernet (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
В этом разделе представлены подробные описания некоторых важных компонентов, реализованных в blue-Ethernet, включая их функциональность, интерфейс и аппаратную архитектуру.
Аппаратные компоненты, связанные с Ethernet, по сути, представляют собой серию манипуляций с потоками. Генератор пакетов отвечает за вставку потока заголовка в заголовок потока полезной нагрузки для создания полного потока пакетов. Напротив, анализатор извлекает поток заголовков и поток полезной нагрузки из потока пакетов. Что касается добавления контрольной суммы для пакета, поток пакетов передается в калькулятор CRC, а затем выходное значение CRC добавляется в конец потока пакетов.
Аппаратный объект, соответствующий упомянутому здесь потоку, на самом деле представляет собой группу сигналов данных, защищенных парой сигналов управления «готовность к действию». Действительный сигнал указывает, что исходный компонент хочет передать данные. И готово указывает, что приемник готов получать данные из источника. Передача между источником и приемником происходит успешно только в том случае, если оба значения действительны и готовы. Если размер передаваемых данных превышает размер одной передачи, данные необходимо фрагментировать и передать в серии передач.
Самая сложная и подверженная ошибкам часть обработки потока связана с обработкой сигналов управления, готовых к проверке различных потоков. В 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.
Генератор пакетов принимает UdpIpMetaData , содержащую информацию заголовка UDP/IP и поток полезной нагрузки, и выводит полный поток пакетов UDP/IP. Анализатор пакетов работает противоположным образом, извлекая UdpIpMetaData и поток полезной нагрузки из потока пакетов 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 ;
Сигналы, инкапсулированные в структуру 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, — это генерация и проверка ICRC (инвариантной CRC), необходимой для пакетов RoCE. Формат пакета RoCE определяется следующим образом:
Модули в пакете MacLayer реализованы для генерации и анализа пакетов Ethernet. Генератор вставляет заголовок Ethernet в заголовок потока пакетов UDP/IP для генерации потока пакетов Ethernet. Анализатор извлекает заголовок Ethernet и поток пакетов UDP/IP из потока пакетов Ethernet.
Информация заголовка, используемая для генерации пакета Ethernet, определяется в структуре MacMetaData .
typedef struct {
EthMacAddr macAddr ; # Destination MAC address
EthType ethType ; # Type of Ethernet frame
} MacMetaData deriving ( Bits , Eq , FShow ) ;
Следует отметить, что пакет Ethernet, обрабатываемый в 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) используется для обнаружения MAC-адреса, связанного с данным IP-адресом. В blue-ethernet для обработки ARP реализован модуль mkArpProcessor , который объединяет генератор ARP-пакетов, анализатор и модуль mkArpCache , хранящий MAC-адреса.
Для кеша, используемого при обработке ARP, 32-битный IP-адрес соответствует адресу кэша, а 48-битный MAC-адрес соответствует данным кэша. Ниже показано расположение массива памяти по умолчанию для кэша ARP: это четырехсторонняя наборно-ассоциативная структура, каждый путь содержит 64 строки, и каждая строка включает 1-битный действительный, 26-битный тег и 48-битные данные. Общий размер этой конфигурации массива по умолчанию составляет около 1,2 КБ. Поддерживается изменение размера массива памяти путем установки количества строк и способов. На основе этого массива памяти кэш спроектирован так, чтобы быть неблокирующим, поддерживать ожидающие запросы (множественные запросы в процессе выполнения) и использовать алгоритм псевдо-LRU для замены строк кэша.
Определение интерфейса и упрощенная структурная схема модуля mkArpCache показаны ниже. ArpCache имеет два субинтерфейса: кэш-сервер обрабатывает взаимодействие с компонентами службы разрешения MAC-адресов; а arpClient обрабатывает взаимодействие с mkArpProcessor для инициирования запроса ARP и получения MAC-адреса из ответа ARP. Основной рабочий процесс модуля mkArpCache выглядит следующим образом:
Когда кеш получает запрос на чтение, он сначала ищет в массиве памяти все теги и данные, соответствующие данному IP-адресу. Затем он проверяет теги, чтобы увидеть, хранятся ли в кеше нужные нам данные. Если кэш попадает, полученные данные отправляются в hitBuf . Или IP-адрес отправляется в arpReqBuf для инициации запроса ARP. И когда ответ ARP возвращается, данные и информация об адресе, которые он несет, записываются в кэшWrBuf и MissHitBuf для обновления массива памяти и возврата ответа на чтение кэша.
interface ArpCache ;
interface Server # ( CacheAddr , CacheData ) cacheServer ;
interface Client # ( CacheAddr , ArpResp ) arpClient ;
endinterface
Самая сложная часть реализации кэша — поддержка функции выдающегося типа, то есть поддержки нескольких запросов на чтение во время полета. Проблема, вызванная выдающимся, заключается в том, что время ответа для каждого запроса ARP в полете различно, а это означает, что поздний запрос может получить ответ первым. Таким образом, необходим механизм переупорядочения, чтобы гарантировать соответствие между адресом запроса и данными ответа при возникновении промаха в кэше. Для реализации упорядоченного ответа в поток данных интегрируются буфер завершения respCBuf и адресуемая по содержимому память MissReqTab . Буфер завершения работает как FIFO с дополнительной поддержкой функции резервирования. Перед фактической операцией постановки в очередь мы можем сначала зарезервировать заказ в буфере завершения. Операция удаления из очереди следует зарезервированному порядку независимо от фактического порядка операций постановки в очередь. Для каждого запроса на чтение порядок удаления из очереди меняется в respCBuf после его получения. А поскольку запрос ARP не может передавать информацию о заказе, для ее хранения реализовано MissReqTab .
Модуль может вести себя как клиент ARP, так и сервер. Как сервер, процессор должен сгенерировать запрос ARP, если MAC-адрес целевого IP неизвестен, а затем ожидает ответа ARP от целевого устройства. В качестве клиента процессор ARP получает запрос ARP от других устройств и отправляет ответ ARP со своим собственным MAC-адресом.
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/Ethernet.
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/Ethernet.
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/Ethernet и одновременной обработки запросов и ответов ARP.
Модуль можно разделить на два противоположных пути потоков, включая путь передачи и путь приема:
Для пути передачи он принимает dataStreamInTx , несущий поток полезной нагрузки, и udpIpMetaDataIn, несущий поток информации заголовка, и генерирует axiStreamOutTx, несущий поток пакетов UDP/IP/Ethernet. Нет необходимости предоставлять MacMetaData , содержащую информацию заголовка Ethernet, в качестве модуля mkUdpIpEthTx , поскольку mkArpProcessor отвечает за обработку разрешения MAC-адреса и генерацию информации заголовка Ethernet.
Для пути приема он работает противоположным образом, извлекая dataStreamOutRx, несущий поток полезной нагрузки, и udpIpMetaDataOutRx, несущий поток информации заголовка, из axiStreamInRx, несущего поток пакетов UDP/IP/Ethernet.
Генератор и анализатор пакетов Ethernet используются как в пакете UDP/IP, так и в пакете ARP, поэтому на пути передачи и приема для арбитража и распределения потока необходимы дополнительные мультиплексоры и демультиплексоры . Параметр модуля 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 ) ;
Модуль обертывает mkGenericUdpIpArpEthRxTx , используя модули, предоставленные в синей оболочке, чтобы генерировать готовый к использованию интерфейс Verilog.
Модуль объединяет модуль mkGenericUdpIpArpEthRxTx и модуль mkXilinxCmacTxWrapper . Он предназначен для взаимодействия с Xilinx CMAC IP для передачи и получения пакетов UDP/IP/Ethernet на физическую среду и обратно.
Модули в пакете 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/Ethernet, одновременно поддерживая управление приоритетом потока. Для передачи пакетов он принимает восемь каналов потока полезной нагрузки и информацию заголовка UDP/IP и выводит один поток пакетов UDP/IP/Ethernet. Для приема пакетов он принимает один поток пакетов UDP/IP/Ethernet и направляет извлеченный заголовок UDP/IP и поток полезной нагрузки в один из восьми выходных каналов.
mkPfcUdpIpArpEthCmacRxTx объединяет модуль mkGenericPfcUdpIpArpEthRxTx и модуль mkXilinxCmacTxWrapper . Он предназначен для взаимодействия с Xilinx CMAC IP для передачи и получения пакетов UDP/IP/Ethernet на физическую среду и обратно.
Синтез и реализация основного модуля mkGenericUdpIpArpEthRxTx выполнены на базе устройства Xilinx xcvu9p с использованием Vivado. Результаты показывают, что схема может достигать рабочей частоты 500 МГц и обеспечивать пиковую пропускную способность 128 Гбит/с. Использование аппаратных ресурсов указано следующим образом:
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 )
В 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
Скрипты, используемые для запуска синтеза и реализации проектов, находятся в каталоге $(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 ...
Реализация blue-ethernet предполагает использование следующих внешних библиотек: