FPGA以太网学习笔记
OSI七层网络结构
1. 物理层(Physical Layer)
-
职责:传输 0和1的物理信号
-
关键操作:→ 定义电压、光脉冲、无线电波等物理表示→ 控制网线/光纤/无线信号的传输与接收
-
典型设备:网线(双绞线)、光纤、集线器(Hub)、中继器
-
类比:快递货车——只负责把包裹(比特流)从A点运到B点,不关心包裹内容。
2. 数据链路层(Data Link Layer)
-
职责:在同一局域网内可靠传输数据帧
-
关键操作:→ 将数据打包成帧(Frame)→ 物理寻址(MAC地址)→ 差错检测(CRC校验)→ 流量控制(如:交换机防拥堵)
-
典型设备:交换机(Switch)、网卡(NIC)
-
类比:快递站点分拣员——检查包裹是否损坏(CRC),按收货地址(MAC)分发给同一城市的正确网点。
3. 网络层(Network Layer)
-
职责:实现跨网络的数据路由(从源IP到目标IP)
-
关键操作:→ 逻辑寻址(IP地址)→ 路由选择(路由器决定最佳路径)→ 分片与重组(大数据拆包传输)
-
典型协议:IP、ICMP、ARP
-
典型设备:路由器(Router)
-
类比:快递总调度中心——分析目的地邮编(IP地址),规划跨城市运输路线(路由)。
4. 传输层(Transport Layer)
-
职责:提供端到端的可靠/不可靠数据传输
-
关键操作:→ 分段与重组(将数据拆分为报文段)→ 连接管理(TCP三次握手/四次挥手)→ 差错恢复(TCP重传机制)→ 流量控制(滑动窗口)
-
典型协议:TCP(可靠)、UDP(不可靠)
-
类比:快递公司客服与追踪系统——
-
TCP:确保包裹必达,丢件补发(可靠传输)
-
UDP:寄明信片,不保证到达(快速但不可靠)
-
5. 会话层(Session Layer)
-
职责:管理应用之间的对话(建立、维护、终止会话)
-
关键操作:→ 身份验证(登录校验)→ 会话恢复(断网续传)→ 同步检查点(如文件下载暂停/继续)
-
典型协议:SSH、RPC
-
类比:电话接线员——帮你接通对方(建立会话),中途断线帮你重拨(会话恢复)。
6. 表示层(Presentation Layer)
-
职责:翻译数据的格式与安全
-
关键操作:→ 数据编码/解码(如:UTF-8转ASCII)→ 加密/解密(TLS/SSL)→ 压缩/解压缩(如:GZIP)
-
典型协议:SSL/TLS、JPEG、MPEG
-
类比:翻译官+保密局——
-
把中文译成英文(编码转换)
-
把文件锁进密码箱(加密)
-
7. 应用层(Application Layer)
-
职责:为用户软件提供网络服务接口
-
关键操作:→ 定义应用协议规范(HTTP/FTP/SMTP)→ 提供用户交互界面(浏览器/邮箱客户端)
-
典型协议:HTTP、FTP、SMTP、DNS
-
类比:手机上的APP——
-
微信(应用层协议)让你发消息
-
浏览器(HTTP)让你看网页
-
MAC帧
IP数据包
部分字节的详细解释:
1. 区分服务(Differentiated Services, DS)
-
位置:IPv4头部第2字节(原为服务类型ToS字段,后重新定义)。
-
作用:用于QoS(服务质量)管理,标记数据包的优先级或服务类型。
-
组成:
-
DSCP(6位):区分服务代码点(0-63),定义优先级或转发行为。
-
常用值:
-
000000
(0):默认(Best Effort) -
101110
(46):EF(Expedited Forwarding,语音流量) -
010000
(16):AF41(Assured Forwarding,视频流量)
-
-
-
ECN(2位):显式拥塞通知(可选)。
-
-
示例:视频会议数据包可能标记为DSCP 46(EF)以获得低延迟。
2. 标识(Identification)
-
位置:IPv4头部第4字节(16位)。
-
作用:唯一标识同一源主机发出的数据包,用于分片重组。
- 同一数据包的所有分片共享相同标识值。
-
常用值:由发送方动态生成(如递增计数器),无固定值。
-
示例:数据包分片时,所有分片的标识字段均为
0xABCD
。
3. 标志(Flags)
-
位置:IPv4头部第6字节的前3位。
-
作用:控制分片行为,包含3个标志位:
-
Bit 0(保留位):必须为0。
-
Bit 1(DF, Don’t Fragment):
-
0
:允许分片(默认)。 -
1
:禁止分片(如ICMP探测路径MTU)。
-
-
Bit 2(MF, More Fragments):
-
0
:最后一个分片。 -
1
:后续还有分片。
-
-
-
常用值:
-
未分片数据包:
0x0
(DF=0, MF=0)。 -
分片的中间包:
0x1
(MF=1)。
-
-
示例:
DF=1
时,若数据包超过MTU则被丢弃并返回ICMP错误。
4. 片偏移(Fragment Offset)
-
位置:IPv4头部第6字节的后13位(单位:8字节块)。
-
作用:指示分片在原数据包中的位置,用于接收方按序重组。
-
计算:偏移值 × 8 = 实际字节偏移量。
-
常用值:
-
第一个分片:
0
。 -
后续分片:根据分片大小递增(如分片长1480字节,则偏移
185
)。
-
-
示例:若偏移为
185
,则该分片从原数据包的1480字节处开始。
5. 生存时间(Time to Live, TTL)
-
位置:IPv4头部第8字节(8位)。
-
作用:限制数据包经过的最大跳数,防止无限循环。
- 每经过一个路由器,TTL减1;若归零则丢弃并返回ICMP超时。
-
常用值:
-
Windows:
128
。 -
Linux:
64
。 -
网络探测(如traceroute):从1开始递增。
-
-
示例:
ping
命令默认TTL为64,显示目标距离为64 - 接收TTL
。
-
UDP数据包
三种协议
TCP数据包
- 源端口 (Source Port) - 16 bits:
-
作用: 标识发送该TCP段的应用程序进程。
-
范围: 0 - 65535 (0 通常不用,1-1023 是知名端口,如HTTP 80, FTP 21, 1024-49151 是注册端口, 49152-65535 是动态/私有端口)。
-
类比FPGA: 想象FPGA上有多个需要网络通信的模块(如UART转TCP、传感器采集、控制输出),每个模块绑定一个不同的端口号,就像不同的硬件外设有不同的寄存器地址空间一样。
- 目的端口 (Destination Port) - 16 bits:
-
作用: 标识接收该TCP段的远端目标应用程序进程。
-
范围: 同源端口。
-
意义: 服务器上的特定服务监听在固定的知名端口(如Web服务器监听80)。客户端发起连接时指定目的端口告诉服务器它要访问哪个服务。
- 序列号 (Sequence Number) - 32 bits:
-
作用: TCP可靠性的核心之一! 标识该TCP段中第一个字节在整个数据流中的位置(字节偏移量)。在建立连接时,双方会随机生成一个初始序列号(ISN)。
-
如何工作:
-
发送方发送数据时,给每个字节分配一个序列号。
-
发送一个TCP段时,
Sequence Number
字段填该段中第一个数据字节的序列号。 -
接收方根据序列号确保数据按序到达,并检测丢失或重复。
-
-
FPGA视角: 类似于一个不断递增的计数器,标记你通过DMA发送出去的每一个字节在内存缓冲区中的起始地址偏移。接收端需要按顺序重组。
-
确认号 (Acknowledgment Number) - 32 bits:**作用: TCP可靠性的另一个核心! 仅在ACK标志位(ACK=1)被设置时有效。它表示接收方期望收到的下一个字节的序列号**。这也意味着确认号减1就是接收方已成功接收并确认的最大连续字节的序列号。如何工作: “我(接收方)已经成功收到了序列号 N-1 及之前的所有字节,现在期待你(发送方)发送序列号从 N 开始的字节”。FPGA视角: 接收端FPGA告诉发送端FPGA:“我的接收缓冲区已经处理到了地址X,请从地址X开始发下一段数据”。类似于DMA传输完成中断后更新读指针。
-
报头长度 - 4 bits:
-
作用: 指示TCP头部的长度是多少个 32位字(4字节)。因为TCP头部有固定部分(20字节)和可变长的选项部分。
-
计算:
Header Length = Data Offset * 4
字节。 -
最小值: 5 (表示 5 * 4 = 20 字节,无选项)。
-
最大值: 15 (表示 15 * 4 = 60 字节,选项最多40字节)。
-
FPGA视角: 类似一个寄存器的位域,用来指示变长结构体的起始位置偏移量。解析包头时,先读这个字段才知道选项在哪里结束,数据从哪里开始。
- 保留 (Reserved) - 6 bits :
-
作用: 保留供未来使用,必须设为0。
-
位置: 紧跟在Data Offset后面的6bits。
- 标志位 (Flags / Control Bits) - 6 bits (包含保留位后的1bit):
-
作用: 控制TCP连接的状态、数据流和特殊处理。每个标志位占1bit (0 或 1)。
-
具体标志位 (按上图位置顺序,重要!):
-
URG
(Urgent): (1 bit) 表示此段包含紧急数据。Urgent Pointer
字段有效。(实践中很少使用,通常被带外数据替代)。 -
ACK
(Acknowledgment): (1 bit) 至关重要! 表示Acknowledgment Number
字段有效。除了初始SYN包,几乎所有的TCP包都会设置此位。 -
PSH
(Push): (1 bit) 提示接收端应立即将接收到的数据推送给应用层,而不是等待缓冲区填满。发送方设置,希望对方立即处理数据。 -
RST
(Reset): (1 bit) 强制终止连接。 表示连接出现严重错误(如端口未监听、异常中断),需要立即重置连接。 -
SYN
(Synchronize): (1 bit) 用于建立连接(三次握手)。 在连接建立阶段设置,用来同步序列号。携带SYN标志的包会消耗一个序列号(数据长度视为1)。 -
FIN
(Finish): (1 bit) 用于关闭连接(四次挥手)。 发送方设置,表示它已完成数据发送,希望关闭本方向的连接。携带FIN标志的包也会消耗一个序列号。
-
-
FPGA视角: 就像FPGA状态机中的控制信号线。
SYN
和FIN
控制连接建立/拆除状态机;ACK
是确认信号;RST
是错误复位信号;PSH
类似于DMA传输的“立即提交”请求。
- 窗口大小 (Window Size) - 16 bits:
-
作用: TCP流量控制的核心! 接收方通过此字段告知发送方自己当前还有多少可用接收缓冲区空间(单位是字节)。
-
意义: 发送方发送的数据量不能超过接收方通告的窗口大小,防止接收方缓冲区溢出。
-
动态变化: 随着接收方处理数据,可用空间增大,窗口通告值也随之增大;当接收方处理不过来时,窗口值减小甚至变为0(发送方停止发送)。
-
FPGA视角: 接收端FPGA的接收FIFO或缓冲区剩余空间计数器。发送端FPGA需要根据这个值来调度数据发送,避免FIFO溢出。类似于流控信号。
- 校验和 (Checksum) - 16 bits:
-
作用: 保证TCP段(头部+数据)在传输过程中的完整性。 覆盖TCP伪头部(12字节)、TCP头部和TCP数据。
-
计算范围:
-
伪头部 (Pseudo-Header): (12字节) 包含源IP地址(4)、目的IP地址(4)、协议(1, 值=6)、TCP段总长度(头部+数据)(2)。注意: 伪头部仅用于计算校验和,并不实际传输!它的目的是让TCP校验能检测到IP层地址或协议错误。
-
TCP头部: 整个TCP头(包括选项)。
-
TCP数据: 有效载荷数据。
-
-
计算方法: 标准的16位二进制反码求和(与IP、UDP、ICMP校验和算法相同)。发送方计算,接收方验证。如果校验失败,接收方会直接丢弃该包(不发送ACK,等待发送方超时重传)。
-
FPGA视角: 硬件CRC校验或校验和计算模块的典型应用场景。FPGA实现TCP/IP时,校验和计算/验证是硬件加速的重点之一。
- 紧急指针 (Urgent Pointer) - 16 bits:
-
作用: 仅在
URG
标志位=1时有效。它是一个偏移量,指向TCP数据部分中紧急数据的最后一个字节的下一个字节的序列号(相对于Sequence Number
)。 -
意义:
Urgent Pointer = Sequence Number + Urgent Offset
。接收方应将Sequence Number
到(Sequence Number + Urgent Pointer - 1)
之间的数据视为紧急数据。 -
现状: 现代TCP应用极少使用URG机制,更多使用带外数据(OOB)或独立的控制通道。在FPGA实现中,通常可以忽略此字段。
- 选项 (Options) - 变长 (0-40字节):
-
作用: 提供额外的、非强制性的功能。如果存在,长度必须是4字节的倍数(不足用
NOP
填充)。使用TLV (Type-Length-Value) 格式。 -
常见选项:
-
最大段大小 (Maximum Segment Size, MSS - Type 2): (4字节) 在SYN包中通告本端愿意接收的TCP段的最大数据长度(不包括TCP头)。用于避免IP分片。典型值如1460 (以太网MTU 1500 - IP头20 - TCP头20)。
-
窗口缩放因子 (Window Scale - Type 3): (3字节) 在SYN包中协商。用于扩展
Window Size
字段(16位最大只能表示65535字节)。缩放因子是一个左移位数 (0-14)。实际窗口大小 =Window Size
* 2^(Window Scale)。 -
选择确认 (Selective Acknowledgment - SACK, Type 4 & 5): 允许接收方确认非连续接收到的数据块,提高重传效率(尤其是在有多个包丢失时)。需要两端都支持(SACK Permitted选项协商)。
-
时间戳 (Timestamp - Type 8): (10字节) 包含发送时间戳(Timestamp Value)和回显时间戳(Timestamp Echo Reply)。用于精确计算往返时间(RTT)和防止序列号回绕(PAWS)。
-
无操作 (No-Operation - NOP - Type 1): (1字节) 用于填充,使后续选项对齐4字节边界。
-
结束选项列表 (End of Option List - EOL - Type 0): (1字节) 标记选项结束。
-
-
FPGA视角: 可配置的功能寄存器组。实现时需要解析这些选项来启用相应的高级功能(如计算RTT需要时间戳,大窗口需要缩放因子)。
- 填充 (Padding):
-
作用: 确保TCP头部长度是4字节的整数倍(由
Data Offset
保证)。通常用0填充。 -
位置: 紧跟在选项之后,数据之前。
运用在TCP或UDP上的协议
TCP的三次握手四次挥手
TCP是可靠的通信协议,所以再发送数据前需要通讯双方需要在彼此之间建立一条连接,所谓“连接”,就是客户端和服务端保存的对方的信息,如ip地址和端口号等;
当一个连接被建立或者终止时,交换的报文段只包含TCP头部,不包含数据;
三次握手
三次握手的本质时确认通信双方收发数据的能力;
举个例子:我让信使运输一份信件给对方,对方收到了,那么他就知道我的发件能力和他的收件能力是可以的,于是他给我回信,我若收到了,我便知道我的发件能力和他的收件能力是可以的,并且知道他的发件能力和我的收件能力是可以的,然后此时他还不知道我的收件能力和他的发件能力到底可不可以,于是我最后反馈一次,**他若收到了,他便知道了他的发件能力和我的收件能力是可以的
首先,序列号中的ack和标志位中的ACK是不同的;
-
序列号中的ack在TCP头部的9-12字节(确认号),长度32bit, 作用是传递接收方“读指针”位置;
-
标志位中的ACK在第14字节的bit4,长度1位,作用是表示确认号字段是否有效
第一次握手:
客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如100),那么客户端向服务端发送的报文段包含SYN标志位(SYN=1),序列seq=100;
第二次握手:
服务端接收到客户端发来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端发送的起始序列号100存起来,并且生成一个客户端的随机起始序列号(比如300),然后给客户端回复一段报文,回复报文包含SYN和ACK标志(SYN=1,ACK=1),序列号seq=300,确认号ack=101(客户端发过来的序列号+1);
第三次握手:
客户端收到的服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到序列号为100的那段报文,同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存了下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1),ack=301(服务端系列号+1),seq=101(第一次握手时发送报文是占据一个序列号的,所以这次的seq是从101开始的,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了。
就这样客户端和服务端通过TCP建立了连接;
四次挥手
四次挥手的目的是关闭一个连接;
假如:客户端初始化的序列号ISN=100,服务端初始化的序列号ISN=300,TCP连接成功后,客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据:
第一次挥手:
当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1),序列号seq=1101(100+1+1000,其中的1时建立连接时占的一个序列)。需要注意的是客户端发出FIN报文段后只是不能发送数据了,但是还可以正常接收数据;另外,FIN报文段即使不携带数据也要占据一个序列号;
第二次挥手:
服务端收到客户端发送的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1),确认号ack=1102(客户端FIN报文序列号1101+1),序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,也不是立刻给客户端发FIN报文,这个状态要持续一段时间,因为服务端可能还有数据没有发完;
第三次挥手:
服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1),确认号和第二次挥手一样ack=1102,序列号seq=2350(2300+50);
第四次挥手:
客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1),确认号ack=2351,序列号seq=1102。注意客户端发出确认报文后不是立刻释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立刻释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些;
MII(Media Independent Interface)和RMII(Reduced Media Independent Interface)
MII: 时钟频率是25Mhz,每个时钟传输4bit,先发高位;发送TX_CLK和接收RX_CLK的时钟都由PHY芯片提供,FPGA需要处理异步时钟域(TX_CLK和RX_CLK这两个时钟域);
RMII:时钟频率是50Mhz,每个时钟周期传输2bit,先发高位;时钟由外部提供REF_CLK(50Mhz),所有信号同步与REF_CLK;注意,REF_CLK必须 由外部晶振或PLL生成;
MII引脚
// 发送端 (FPGA → PHY)output [3:0] TXD; // 4位发送数据
output TX_EN; // 发送使能
output TX_ER; // 发送错误 (极少用)
input TX_CLK; // 25MHz发送时钟 (PHY提供)
// 接收端 (PHY → FPGA)
input [3:0] RXD; // 4位接收数据
input RX_DV; // 接收数据有效
input RX_ER; // 接收错误
input RX_CLK; // 25MHz接收时钟 (PHY提供)
// 公共信号
input CRS; // 载波侦听
input COL; // 冲突检测
RMII引脚
// 数据 + 时钟 (共7根必需信号)
inout [1:0] TXD; // 2位发送数据 (FPGA → PHY)
inout [1:0] RXD; // 2位接收数据 (PHY → FPGA)
input REF_CLK; // 50MHz参考时钟 (外部晶振或FPGA提供)
// 控制信号
output TX_EN; // 发送使能
input CRS_DV; // 复用信号: CRS(载波侦听) + RX_DV(接收有效) // CRS_DV=1: 接收有效; CRS_DV=0: 空闲或错误