赞
踩
前面已经完成了协议的解析分类,但是不能对分类好的数据帧再进行相关的校验计算,白白浪费时间,为降低延时,所以需要在分类的同时完成校验计算。
校验,就是通过增加冗余位来验证数据完整性的一个操作,对于谁是真正的“国际巨星”,我们不能章口就莱,还得上来试试。
在以太网帧中有两类校验,一个是checksum(校验和),一个是利用CRC算法的FCS(帧校验序列),所以本文针对这两种校验进行说明。
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呢?
比如同样告知上述的一组数据,然后告知checksum为16'h3d31,那验证的办法可以是:
目前设计的支持ARP/ICMP/UDP三个协议,那么直接从其报文格式中可以发现,ARP中没有Checksum字段,而在ICMP中含有IP首部的Checksum字段和ICMP首部的Checksum字段,同样UDP中也含有IP首部Checksum和UDP首部Checksum,所有存在三个Checksum的计算,接下来就依次说明其计算过程。
IP首部的组成如下:
其首部的Checksum需计算首部20字节(如果有option则更长一点,本文暂时不考虑),即将上图中各字段按照16bit划分(Checksum先填16'h0),再按照之前说的进行计算。
笔者在图中填充上wireshark任意抓获了一帧数据的IP首部部分,可以计算验证,即:
换成verilog则如下:
always
对于ICMP的checksum不再举例说明计算过程了,只说明参与计算的数据构成。
ICMP的Checksum计算如上图所示,包括首部和选项数据部分,同样计算时将Checksum字段置零进行计算,即16'h0000 + 16'h0000 + 16'h0001 + 16'h0013 + 16'h6162 + ....... + 16'h6869,同样再进行循环累加和按位取反操作。
(实现RTL可参考笔者之后上传的)
而UDP首部中的Checksum字段计算与前面有略微区别,它与TCP首部的Checksum计算一样,需要将伪首部(pseudo header)加到计算当中,其中UDP的伪首部组成如下图所示:
其伪首部包括:源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,frame check sequence,帧校验序列,位于以太网帧的尾部,如下图所示,用于校验以太网数据帧是否出错。
前面说过,FCS是采用CRC32算法得到的4字节长度的校验序列,其中CRC算法入门可以参考文章:
循环冗余校验(CRC)算法入门引导_Ivan 的专栏-CSDN博客_crc校验blog.csdn.net当然,也可以直接参考Xilinx的官方手册xapp209[1],同时该文档也提供了FCS的实现结构,如下图所示,其中crc_reg[31:0]即每次计算得到结果,而crc[7:0]即计算结束后输出4字节FCS。
其中使用的CRC32的硬件实现算法可详见论文[2],具体的硬件实现代码如下图所示。
上述实现结构翻译成verilog就是:
always
可以直接生成CRC的verilog或者VHDL源码:
CRC Generation Toolwww.easics.com得到上图的所示的源码后,可以发现其为一个function,可以对模块添加输入输出,并调用该function即可进行CRC计算。
网页的工具还可以任意勾选多项式并生成源码,方便使用。
不过,有时候网页工具打不开,不知道为啥。。。
以上即协议栈设计中的校验部分,为确保接收的数据帧的正确,笔者在接收协议分类中即进行了校验计算,当前帧校验无误后再向后级模块传输处理,此外,对于需发送的数据帧在进行封包的过程中完成校验计算,使可进行发送。
若有不足之处还望批评指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。