it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第1张图片

前面已经完成了协议的解析分类,但是不能对分类好的数据帧再进行相关的校验计算,白白浪费时间,为降低延时,所以需要在分类的同时完成校验计算。

校验,就是通过增加冗余位来验证数据完整性的一个操作,对于谁是真正的“国际巨星”,我们不能章口就莱,还得上来试试。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第2张图片
“你说你演的比我好,那咱们上来试试”

在以太网帧中有两类校验,一个是checksum(校验和),一个是利用CRC算法的FCS(帧校验序列),所以本文针对这两种校验进行说明。


Checksum计算

Checksum,校验和,从名字可以知道就是通过累加数据的方式完成的校验计算,以下所举例的checksum计算是以太网帧数据报文中使用的方法。

  • 那该怎么计算呢?

举个栗子,我有一组数据:{8'hf0, 8'hf1, 8'hf2, 8'hf3, 8'hf4, 8'hf5, 8'hf6, 8'hf7, 8'hf8, 8'hf9, 8'hfa}等11字节的数据,我该怎么计算其checksum呢?

  1. 将数据组成16bit的一组数据,即{16'hf0f1, 16'hf2f3, 16'hf4f5, 16'hf6f7, 16'hf8f9, 16'hfa00},其中若为奇数个字节,则最后一个字节置于16bit的高八位上;
  2. 将这新组成的数据进行累加计算,即16'hf0f1+16'hf2f3+16'hf4f5+16'hf6f7+16'hf8f9+16'hfa00 = 32'h5c2c9;
  3. 若2中计算的结果高位溢出了,则将高位再累加到低位上(循环累加),即 16'h0005 + 16'hc2c9 = 16'hc2ce,如果还有溢出则再次将高位累加到低位上;
  4. 对3中的计算结果按位取反,即~16'hc2ce = 16'h3d31,得到的16'h3d31即checksum的值;
  • 怎么验证checksum是对的呢?

比如同样告知上述的一组数据,然后告知checksum为16'h3d31,那验证的办法可以是:

  1. 重新计算这组数据的checksum,然后与已知的比较,看是否一致;
  2. 在进行16bit数据累加的计算中,把16'h3d31也累加上,即32'h5c2c9 + 16'h3d31 = 32'h5fffa,然后将溢出的高16位加到低16位上,即16'h0005 + 16'hfffa = 16'hffff,如果为16位全1,则说明校验正确,否则则校验失败;
  • 那协议栈需要计算哪些Checksum呢?

目前设计的支持ARP/ICMP/UDP三个协议,那么直接从其报文格式中可以发现,ARP中没有Checksum字段,而在ICMP中含有IP首部的Checksum字段和ICMP首部的Checksum字段,同样UDP中也含有IP首部Checksum和UDP首部Checksum,所有存在三个Checksum的计算,接下来就依次说明其计算过程。

  • IP首部checksum

IP首部的组成如下:

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第3张图片
IP首部Checksum计算部分

其首部的Checksum需计算首部20字节(如果有option则更长一点,本文暂时不考虑),即将上图中各字段按照16bit划分(Checksum先填16'h0),再按照之前说的进行计算。

笔者在图中填充上wireshark任意抓获了一帧数据的IP首部部分,可以计算验证,即:

  1. 16'4500 + 16'h0028 + 16'ha140 + 16'h4000 + 16'h6706 + 16'h0000 + 16'h0d6b + 16'h04fe + 16'hc0a8 + 16'hd07c = 32'h330fb
  2. 16'0003 + 16'h30fb = 16'h30fe
  3. ~16'h30fe = 16'hcf01 (计算正确!)

换成verilog则如下:

always 
  • ICMP首部checksum

对于ICMP的checksum不再举例说明计算过程了,只说明参与计算的数据构成。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第4张图片
ICMP的Checksum计算部分

ICMP的Checksum计算如上图所示,包括首部和选项数据部分,同样计算时将Checksum字段置零进行计算,即16'h0000 + 16'h0000 + 16'h0001 + 16'h0013 + 16'h6162 + ....... + 16'h6869,同样再进行循环累加和按位取反操作。

(实现RTL可参考笔者之后上传的)

  • UDP首部checksum

而UDP首部中的Checksum字段计算与前面有略微区别,它与TCP首部的Checksum计算一样,需要将伪首部(pseudo header)加到计算当中,其中UDP的伪首部组成如下图所示:

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第5张图片
UDP首部Checksum计算部分

其伪首部包括:源IP(32),目的IP(32),预留(8),协议(8),UDP长度(8);

同时再将UDP首部的端口号和UDP长度字段加入计算,需要注意的是伪首部中的UDP长度和UDP首部中的长度一致,所以上图的累加应该是:16'hc0a8 + 16'h0001 + 16'hc0a8 + 16'h000a + ....... + 16'h9900,(字节数为奇数,注意最后一个16bit的低八位需填0)。

(实现RTL可参考笔者之后上传的)

FCS计算

FCS,frame check sequence,帧校验序列,位于以太网帧的尾部,如下图所示,用于校验以太网数据帧是否出错。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第6张图片
以太网帧结构

前面说过,FCS是采用CRC32算法得到的4字节长度的校验序列,其中CRC算法入门可以参考文章:

循环冗余校验(CRC)算法入门引导_Ivan 的专栏-CSDN博客_crc校验​blog.csdn.net
it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第7张图片

当然,也可以直接参考Xilinx的官方手册xapp209[1],同时该文档也提供了FCS的实现结构,如下图所示,其中crc_reg[31:0]即每次计算得到结果,而crc[7:0]即计算结束后输出4字节FCS。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第8张图片
基于CRC32的FCS实现结构图

其中使用的CRC32的硬件实现算法可详见论文[2],具体的硬件实现代码如下图所示。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第9张图片
CRC32的硬件实现

上述实现结构翻译成verilog就是:

always 
  • 顺手再推荐一个网站

可以直接生成CRC的verilog或者VHDL源码:

CRC Generation Tool​www.easics.com
it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第10张图片

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第11张图片
crctool 操作说明

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第12张图片
下载得到的CRC计算的verilog源码

得到上图的所示的源码后,可以发现其为一个function,可以对模块添加输入输出,并调用该function即可进行CRC计算。

网页的工具还可以任意勾选多项式并生成源码,方便使用。

不过,有时候网页工具打不开,不知道为啥。。。

it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第13张图片

以上即协议栈设计中的校验部分,为确保接收的数据帧的正确,笔者在接收协议分类中即进行了校验计算,当前帧校验无误后再向后级模块传输处理,此外,对于需发送的数据帧在进行封包的过程中完成校验计算,使可进行发送。

若有不足之处还望批评指正!


十二点过九分:UDP/IP硬件协议栈设计(四):ARP​zhuanlan.zhihu.com
it6000串口号校验失败_UDP/IP硬件协议栈设计(三):校验_第14张图片

参考

  1. ^Xilinx手册xapp209 https://www.xilinx.com/support/documentation/application_notes/xapp209.pdf
  2. ^Rajesh Nair, Gerry Ryan and Farivar Farzaneh, A Symbol Based Algorithm for Hardware Implementation of Cyclic Redundancy Check (CRC), Bay Networks. https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=623934

你可能感兴趣的:(it6000串口号校验失败)