本文转载自: FPGA的现今未微信公众号
IP报文的头部中有一个checksum字段,一般都知道这个字段的含义,校验IP报文的头部是否正确,但是究竟是如何计算出来的呢?以前没有怎么研究过,刚好最近工作涉及到这方面的东西,记录下。
其实IP报文头部的checksum计算非常简单,我们看看RFC1071中如何定义的。
(1) Adjacent octets to be checksummed are paired to form 16-bit integers, and the 1's complement sum of these 16-bit integers is formed.
(2) To generate a checksum, the checksum field itself is cleared,the 16-bit 1's complement sum is computed over the octets concerned, and the 1's complement of this sum is placed in the checksum field.
(3) To check a checksum, the 1's complement sum is computed over the same set of octets, including the checksum field. If the result is all 1 bits (-0 in 1's complement arithmetic), the check succeeds.
简单总结下,就是将头部以16bit为单位做反码求和。具体的操作步骤用一个例子来表示。如下图所示,是一个网络报文的IP首部。
(1)以16bit为单位分成10组,分别为:0x4500、0x0040、0x0、0x4000、0x4060、0x0(这是checksum的位置)、0xc0a8、0x0109、0x0a0d、0xe78f,然后把他们相加得到0x27893;
(2)对得到的结果重复上述步骤,得到 0x2+0x7893 = 0x7895
(3)对0x7895取反,即~0x7895 = 0x876a,即该ip报文的checksum为0x876a。
0x4500+0x40+0x0+0x4000+0x4006+0x0+0xc0a8+0x0109+0x0a0d+0xe78f = 0x27893 0x2 + 0x7893 = 0x7895 ~0x7895 = 0x876a
问题一:如何校验checksum?
当接收到报文后,提取IP报文头部共20byte,然后做反码求和,还是以上述报文为例:
0x4500+0x40+0x0+0x4000+0x4006+0x876a+0xc0a8+0x0109+0x0a0d+0xe78f = 0x2fffd 0x2 + 0xfffd = 0xffff ~0xffff = 0x0
通过反码求和后,得到的结果为0,即结果正确。
问题二、可以先取反再相加吗?
可以通过一个简单的例子来说明这个问题。这里假定4个数的反码求和。如下图所示:
无论是先取反再求和还是求和后再取反,结果都是一样的。
问题三,计算性能如何?
在FPGA的设计中,上述方法的性能如何呢?如果以16bit为单位两两相加,需要4拍才能得到计算结果。在短包场景下,性能可能就不算很友好了。这里有2种优化方法:
第一种,每次3个16bit的数相加,以xilinx 7系列芯片为例,3个16bit的数相加,在200M时钟下时序没有压力,这样只需要3拍就可以计算完;
第二种,可以以32bit为单位进行计算,还是以上述抓包的报文头为例,如下图所示,以32bit单位进行计算,得到的结果也是876a。
如果以32bit为单位,两两相加,也是3拍可以计算出结果,而且32bit的数相加同样对于7系列芯片来讲没有压力。
关于checksum的校验,还有其他更好的方法吗?欢迎交流。关于IP头部checksum的相关信息,可以查看:https://www.rfc-editor.org/rfc/rfc1071.txt