一、以太网基础:从七层模型到ARP协议
做FPGA以太网开发,说白了就是跟数据包打交道。我记得刚入行那会儿,总觉得协议栈这东西太抽象,直到亲手在FPGA上搭出一个能收发UDP包的系统,才真正理解——嗯,底层的东西其实没那么玄乎。
今天咱们先打好地基。这一章我会带你过一遍以太网最核心的几个概念:OSI模型、TCP/IP模型、MAC地址、IP地址、以太网帧格式,还有ARP协议。这些是后续实现UDP协议栈的必备知识。
核心要点:FPGA实现以太网,本质上就是按照协议规定的格式,在硬件层面完成数据的封装与解析。你不需要背下所有细节,但必须理解数据是怎么“打包”和“拆包”的。
1.1 OSI七层模型与TCP/IP四层模型
先说说这两个模型。OSI七层模型是国际标准,从上到下分别是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。但实际互联网用的是TCP/IP四层模型:应用层、传输层、网络层、网络接口层。
你可能会问:为什么不用OSI?我个人习惯直接看TCP/IP模型,因为更贴近实际开发。OSI的表示层和会话层,在TCP/IP里被合并到应用层了。说白了,TCP/IP就是OSI的“精简实战版”。
在FPGA开发中,我们最关心的是下面三层:
- 物理层:处理电信号、时钟同步、编码解码。对应FPGA里的PHY芯片和GMII/RGMII接口。
- 数据链路层:处理MAC地址、帧校验、流量控制。对应FPGA里的MAC核。
- 网络层:处理IP地址、路由选择。对应FPGA里的IP模块。
我在项目中遇到过一个问题:只实现了MAC层,没做IP层,结果数据能发出去但对方路由器不认。为什么?因为路由器只看IP地址,不看MAC地址。这就是分层的好处——各层各司其职。
1.2 MAC地址与IP地址
这两个地址经常被搞混。我简单解释一下:
- MAC地址:48位,出厂烧录在网卡里,全球唯一。它负责“局域网内”的设备寻址。
- IP地址:32位(IPv4),由网络管理员分配。它负责“互联网上”的设备寻址。
打个比方:IP地址就像你的家庭住址(北京市海淀区xx路xx号),MAC地址就像你的身份证号。快递员先看住址找到你家小区,再根据身份证号确认是你本人签收。
避坑指南:我曾经在FPGA里写死了一个MAC地址,结果板子换到另一个网络环境就通信失败。后来发现是交换机做了MAC地址过滤。建议在设计中预留MAC地址配置接口,方便调试。
1.3 以太网帧格式
这是FPGA实现中最需要死磕的部分。一个标准的以太网帧长这样:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 前导码 | 7 | 同步时钟用,FPGA接收时直接丢弃 |
| 帧起始定界符 | 1 | 标志帧开始,0xD5 |
| 目的MAC地址 | 6 | 接收方MAC |
| 源MAC地址 | 6 | 发送方MAC |
| 类型/长度 | 2 | 0x0800表示IP包,0x0806表示ARP包 |
| 数据载荷 | 46~1500 | 实际传输的数据,不足46字节要填充 |
| 帧校验序列 | 4 | CRC32校验,确保数据完整性 |
在FPGA里,我们通常只处理从“目的MAC”到“FCS”之间的部分。前导码和定界符由PHY芯片自动处理。嗯,这里要注意:数据载荷最小46字节,如果UDP数据不够,必须填充0到46字节,否则对方网卡会丢弃这个帧。
重要:类型字段的值决定了上层协议。0x0800是IP,0x0806是ARP。FPGA解析时,必须根据这个字段决定把数据交给IP模块还是ARP模块。我曾经见过有人写死成IP类型,结果ARP请求来了直接丢弃——整个网络都ping不通。
1.4 ARP协议工作原理
ARP协议解决的是“已知IP地址,求MAC地址”的问题。为什么需要它?因为数据链路层只认MAC地址,网络层只认IP地址。两者之间需要一座桥。
工作流程很简单:
- 主机A想给主机B发数据,但只知道B的IP地址,不知道B的MAC地址。
- 主机A广播一个ARP请求:“谁是192.168.1.2?请告诉我你的MAC地址。”
- 所有主机都收到这个广播,但只有IP为192.168.1.2的主机B回应:“我是192.168.1.2,我的MAC是AA:BB:CC:DD:EE:FF。”
- 主机A收到回应后,把IP和MAC的对应关系缓存起来,下次直接使用。
在FPGA里实现ARP模块,核心就是处理两种帧:
- ARP请求:收到后,检查目标IP是否是自己。如果是,回复ARP应答。
- ARP应答:收到后,提取IP和MAC,更新缓存表。
实战经验:我建议在FPGA里维护一个简单的ARP缓存表,至少能存4~8个条目。缓存超时时间设为120秒左右。为什么?因为如果对方换了网卡,MAC地址变了,你还用旧的缓存去发数据,对方收不到。我曾经因为这个bug调了整整两天。
下面这张图展示了ARP请求与应答的完整流程:
你看,整个过程其实就两步。在FPGA里实现时,我建议把ARP模块设计成状态机:IDLE -> WAIT_REQ -> SEND_REPLY -> UPDATE_CACHE。这样逻辑清晰,也容易调试。
小技巧:调试ARP时,可以用Wireshark抓包。先看FPGA有没有发出ARP请求,再看对方有没有回复。如果只看到请求没看到回复,大概率是FPGA的MAC地址或IP地址配置错了。我每次调网络问题,第一件事就是抓ARP包。
好了,这一章的内容就这些。记住:以太网帧格式是FPGA实现的基础,ARP协议是网络通信的起点。把这些搞明白,后面实现UDP协议栈就会轻松很多。
公众号:蓝海资料掘金营,微信deep3321