跳转至

OpenNAS 固件实现指南

本文档详细介绍 OpenNAS 项目中 FPGA 固件的实现方法,包括 TCP 卸载引擎(TOE)、存储实现、网络加速和能效优化等核心功能。

概述

OpenNAS 固件基于 Xilinx Zynq-7000 系列 FPGA(XC7Z035)实现,采用 Scala 基于 SpinalHDL 混合 Verilog 来编写 HDL 代码。这种混合设计方式结合了 SpinalHDL 的类型安全和高级抽象能力,以及 Verilog 的灵活性和兼容性,使得代码更加健壮和易于维护。固件设计遵循模块化、可扩展的原则,所有代码完全开源。

为什么选择 SpinalHDL?

  • 类型安全:Scala 的强类型系统可以在编译时捕获许多错误
  • 高级抽象:SpinalHDL 提供了更高级的硬件描述抽象,减少代码量
  • 可复用性:更好的模块化和代码复用
  • 混合设计:可以无缝集成现有的 Verilog IP 核

开发环境

工具链

  • 主要工具:Xilinx Vivado(当前版本)
  • 未来计划:支持开源工具链(Yosys + nextpnr)
  • 仿真工具:XSim(Vivado 内置)、Verilator(开源仿真器)
  • 版本控制:Git
  • 构建工具:SBT(Scala Build Tool)

环境配置

Bash
1
2
3
4
5
# 安装 Scala 和 SBT
# 安装 Vivado
# 配置环境变量
export VIVADO_HOME=/path/to/vivado
export PATH=$PATH:$VIVADO_HOME/bin

TCP 卸载引擎(TOE)实现

架构设计

TOE 模块将 TCP/IP 协议栈从 CPU 卸载到 FPGA 硬件,实现高性能网络处理。该模块采用流水线设计,支持 10Gbps 线速处理。

模块划分

  1. MAC 层接口
  2. 10Gbps 以太网 MAC 接口
  3. 支持 SFP+ 光模块
  4. 自动协商和链路管理
  5. 支持 4 路独立网络接口

  6. IP 层处理

  7. IPv4/IPv6 数据包解析
  8. IP 路由和转发
  9. 分片和重组
  10. 支持多播和广播

  11. TCP 层处理

  12. 连接建立和拆除(三次握手、四次挥手)
  13. 序列号和确认号管理
  14. 流量控制和拥塞控制
  15. 重传机制
  16. 支持大量并发连接(最多 64K)

  17. 应用层接口

  18. 与 ARM CPU 的 AXI4 接口:用于控制平面通信和配置
  19. 与 NVMe 模块的 AXI-Stream 接口:用于数据平面零拷贝传输
  20. 零拷贝数据传输:数据直接在网络和存储间传输,不经过 CPU
  21. 事件通知机制:通过中断或轮询方式通知 CPU

实现细节

1. 接口说明

TOE 模块提供以下主要接口:

与 ARM CPU 的 AXI4 接口: - AXI4-Lite 控制接口:用于配置 TOE 参数、查询连接状态等 - AXI4 数据接口:用于少量控制数据的传输 - 中断接口:用于事件通知(如新连接建立、连接关闭等)

与 NVMe 模块的 AXI-Stream 接口: - 接收数据流(RX):从网络接收的数据直接通过 AXI-Stream 传输到 NVMe 模块 - 发送数据流(TX):从 NVMe 模块读取的数据直接通过 AXI-Stream 传输到网络 - 流控制信号treadytvalidtlast 等标准 AXI-Stream 信号 - 数据宽度:512-bit,匹配 NVMe 的数据宽度

网络接口: - 4× 10Gbps SFP+ 接口:支持光模块和直连铜缆 - MAC 层接口:与以太网 PHY 的接口

内部接口: - 连接表接口:用于查找和管理 TCP 连接 - 缓冲区接口:用于数据包的临时存储

2. TCP 状态机

性能优化

  1. 流水线设计:将数据包处理分为多个流水线阶段,提高吞吐量
  2. 并行处理:支持多路数据包同时处理,充分利用 FPGA 的并行性
  3. 零拷贝:数据直接在 FPGA 和内存间传输,不经过 CPU,降低延迟
  4. 硬件加速:TCP 校验和、IP 校验和等在硬件中计算

存储实现

NVMe 控制器

PCIe 软核实现

PCIe 软核使用 Xilinx GT(Gigabit Transceiver)实现 PCIe 3.0 x4 接口。该实现包括:

  • PCIe 配置空间:实现标准的 PCIe 配置寄存器
  • TLP(Transaction Layer Packet)处理:处理 PCIe 事务层数据包
  • 链路训练:自动协商链路速度和宽度
  • 错误处理:CRC 校验、重传机制等

PCIe 软核与 NVMe 控制器通过 AXI4 接口连接,实现高效的数据传输。

NVMe 队列管理

多队列并发是 NVMe 的核心特性之一。OpenNAS 实现了完整的 NVMe 多队列支持:

队列架构: - 管理队列(Admin Queue):1 个提交队列(SQ)和 1 个完成队列(CQ) - I/O 队列(I/O Queue):最多支持 65535 个 I/O 队列对(每个队列对包含 1 个 SQ 和 1 个 CQ) - 队列深度:每个队列支持最多 65536 个条目

并发处理: - 并行队列处理:多个 I/O 队列可以同时处理命令 - 队列优先级:支持队列优先级调度 - 中断聚合:多个完成队列的中断可以聚合,减少 CPU 中断开销

实现特点: - 使用 SpinalHDL 实现类型安全的队列管理 - 硬件实现的队列指针管理,避免软件开销 - 支持 MSI/MSI-X 中断机制 - 与 TOE 模块通过 AXI-Stream 接口直接连接,实现零拷贝

DMA 引擎

SGDMA(Scatter-Gather DMA)引擎实现高效的数据传输:

功能特性: - 分散/聚集传输:支持非连续内存区域的传输 - 自动页边界处理:自动处理跨页边界的传输 - 多通道支持:支持多个独立的 DMA 通道 - 优先级调度:支持通道优先级调度

与 NVMe 的集成: - DMA 引擎直接与 NVMe 控制器连接 - 支持 NVMe 的 PRP(Physical Region Page)和 SGL(Scatter-Gather List)描述符 - 自动处理 NVMe 命令的数据传输

性能优化: - 使用 AXI4 突发传输,提高带宽利用率 - 支持预取机制,减少延迟 - 硬件实现的描述符链表遍历,减少 CPU 负载

网络加速实现

负载均衡和故障转移

OpenNAS 提供 4 路 10Gbps 网络接口,支持多种聚合模式:

负载均衡模式: - 轮询(Round-Robin):按顺序将流量分配到各个接口 - 最少连接(Least Connections):将新连接分配给连接数最少的接口 - 哈希(Hash):根据源/目的 IP 和端口进行哈希,保证同一连接使用同一接口 - 加权轮询(Weighted Round-Robin):根据接口权重分配流量

故障转移模式: - 主备模式(Active-Standby):一个主接口工作,其他接口作为备份 - 链路聚合(Link Aggregation):多个接口聚合为一个逻辑接口,提高带宽和可靠性

应用场景: - 双网口网卡直连:两个设备通过双网口直连,实现高带宽和冗余 - 多路径传输:利用多个网络路径提高总带宽 - 网络冗余:当某个接口故障时,自动切换到其他接口

实现细节: - 硬件实现的负载均衡算法,低延迟 - 实时监控接口状态,快速故障检测 - 支持 LACP(Link Aggregation Control Protocol) - 与 TOE 模块集成,实现透明的负载均衡

能效优化实现

风扇曲线

OpenNAS 使用 XADC(Xilinx Analog-to-Digital Converter) 读取温度,并根据设置的风扇曲线控制风扇转速。

XADC 接口: - 温度传感器:读取 FPGA 内部温度传感器 - 外部温度传感器:支持连接外部温度传感器(如 CPU、NVMe SSD 等) - 12-bit ADC:高精度温度测量 - 采样频率:可配置的采样频率

风扇曲线配置: - 多段线性曲线:支持配置多段线性风扇曲线 - 温度阈值:可配置多个温度阈值点 - 转速范围:支持 PWM 控制,转速范围 0-100% - 平滑控制:使用 PID 控制器实现平滑的风扇转速调节

典型风扇曲线

Text Only
1
2
3
4
5
温度 < 40°C:  风扇转速 20%
40°C - 50°C: 风扇转速 20% - 40%(线性)
50°C - 60°C: 风扇转速 40% - 60%(线性)
60°C - 70°C: 风扇转速 60% - 80%(线性)
温度 > 70°C:  风扇转速 100%

实现方式: - 使用 SpinalHDL 实现温度监控模块 - 硬件实现的 PID 控制器,响应快速 - 支持通过 AXI4-Lite 接口配置风扇曲线参数 - 实时温度监控和风扇控制,无需 CPU 干预

安全特性: - 过温保护:当温度超过安全阈值时,自动提高风扇转速或降低工作频率 - 故障检测:检测风扇故障(如停转)并报警 - 温度历史记录:记录温度历史数据,用于分析和优化

仿真和验证

验证方法

  1. 单元测试:每个模块独立测试,使用 SpinalHDL 的测试框架
  2. 集成测试:模块间接口测试,验证数据流正确性
  3. 系统测试:完整功能测试,包括端到端的数据传输
  4. 性能测试:吞吐量、延迟测试,验证是否达到设计目标

仿真工具

XSim(Vivado Simulator): - Vivado 内置仿真器 - 支持 Verilog、VHDL、SystemVerilog - 与 Vivado 工具链无缝集成

Verilator: - 开源 Verilog 仿真器 - 高性能,适合大规模仿真 - 支持 SystemVerilog 子集

调试技巧

  1. ILA(Integrated Logic Analyzer):使用 Vivado ILA 进行在线调试,实时查看信号波形
  2. 仿真波形:使用 XSim 或 Verilator 查看详细波形,分析时序问题
  3. 日志输出:在 SpinalHDL 代码中使用 println 输出调试信息
  4. 断言(Assertions):使用 SystemVerilog 断言检查设计约束

开发指南

SpinalHDL 代码示例

混合设计

在 SpinalHDL 中集成 Verilog IP 核:

Scala
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class MixedDesign extends Component {
  // SpinalHDL 模块
  val spinalModule = new SpinalModule()

  // Verilog 模块(BlackBox)
  val verilogIP = new BlackBox {
    val io = new Bundle {
      val clk = in Bool()
      val rst = in Bool()
      val data = in UInt(32 bits)
      val result = out UInt(32 bits)
    }
    // 映射到 Verilog 模块
    mapClockDomain(clockDomain, io.clk)
  }

  // 连接
  verilogIP.io.data := spinalModule.io.data
  spinalModule.io.result := verilogIP.io.result
}

参考资料

贡献指南

欢迎贡献代码!请遵循以下步骤:

  1. Fork 项目
  2. 创建功能分支
  3. 编写代码和测试(使用 SpinalHDL 或 Verilog)
  4. 确保代码通过所有测试
  5. 提交 Pull Request

更多信息请参考项目的贡献指南。