首页 > 代码库 > Lwip IP包分片重组

Lwip IP包分片重组

1. 开发环境

操作系统:SylixOS

编程环境:RealEvo-IDE3.1

硬件平台:AT9x25开发板

2. 技术实现

SylixOS系统使用的网络协议栈是Lwip协议栈。LwipLight Weight (轻型)IP协议,有无操作系统的支持都可以运行。Lwip实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KBRAM40K左右的ROM就可以运行,这使Lwip协议栈适合在低端的嵌入式系统中使用。

Lwip协议栈主要关注的是怎么样减少内存的使用和代码的大小,这样就可以让Lwip适用于资源有限的小型平台例如嵌入式系统。为了简化处理过程和内存要求,LwipAPI进行了裁减,可以不需要复制一些数据。

网络协议栈是以层的结构来实现的。链路层具有最大传输单元MTU这个特性,它限制了数据帧的最大长度,不同的网络类型都有一个上限值。以太网的MTU1500。如果IP层有数据包要传,而且数据包的长度超过了MTU,那么IP层就要对数据包进行分片(fragmentation)操作,使每一片的长度都小于或等于MTU。我们假设要传输一个UDP数据包,以太网的MTU1500字节,一般IP首部为20字节,UDP首部为8字节,数据的净荷(payload)部分预留是1500-20-8=1472字节。如果数据部分大于1472字节,就会出现分片现象。

本篇文章主要介绍Lwip里对收到的IP分片报文重组的实现。


 2.1      IP报文重组宏观分析

技术分享

21 IP包重组框图


IP包的重组的简单流程如图2-1所示

首先,Lwip协议里会有一个单向链表,每个结点是一个ip_reassdata的结构体,reassdatagrams指向这个链表。

ip_reassdata结点用来进行分片包的重组,每个结点对应着一个完整的IP包。这个结构体里有一个指向pbuf的成员。当一个IP报文通过ip4_input向上层传输时,会检测是否属于分片包,如果是,则需要进行分片重组。

重组时,会从reassdatagrams链表里查找是否已经有ip_reassdata这个结构体了,如果有,就会改变每个分片包的报头,这里是通过一个ip_reass_helper结构体改变的。改变完之后,会把这个分片包根据偏移插入到ip_reassdata这个结构体后面对应的位置。如果在reassdatagrams链表里查找不到对应的ip_reassdata这个结构体,那么说明这个分片包是收到帧的第一个报文,因此会创建一个新的ip_reassdata结构体,然后再进行后续操作。插入完成后,协议栈会检测报文是否全部接收并重组完成。如果完成,就会从reassdatagrams链表中把ip_reassdata结构体删除并把重组好的报文返回给ip4_input


2.2      代码分析

IP包的分片重组是通过ip4_reass 这个函数来完成的。判断需要重组时都会调用这个函数,这个函数的主要内容如下:

  1. 对收到的IP报文的首部长度检测,Lwip目前是不支持IP报文头带填充位的。

  2. 通过IP报文头,获得偏移和数据报文的长度。         

  3. lwip的一个特性:它对reassdatagrams链表上的pbuf的总数是有限制的,因此协议栈会判断加上收到的这些pbuf的个数后,会不会超过这个限制。        

  4. 如果超过了,会删除链表中存在时间最长的那个。         

  5. 从链表中寻找对当前的pbuf对应的ip_reassdata结构体。如果没有,则会新创建一个结构体。          

  6. 现在应该已经找到一个合适的 ip_reassdata结构体了,此时会做一个判断:如果当前的这个IP报文的偏移为0并且此时的 ip_reassdata结构体的偏移也不等于0,那么需要把当前的这个IP分片报文的头部拷贝到 ip_reassdata结构体中。        

  7. 检测当前收到的IP分片报文是不是最后一个,如果是最后一个,那么,就更新一下当前IP分片报文对应的 ip_reassdata结构体。        

  8. 上述两个检测完成之后,会调用ip_reass_chain_frag_into_datagram_and_validate,找到一个合适的地方,把IP分片包插进去。      

  9. 检测当前的报文是否组装完成,如果完成,返回一个非0的值。否则,返回0       

  10. 上述检测结果如果是没有完成,则ip4_reass 直接返回。如果完成了,则会对 ip_reassdata结构体的iphdr字段做修改,包括报文总长度、校验和,并且把iphdr字段全部拷贝到第一个分片包的头部,这样,整个IP包的信息就出现在第一个分片包的信息里。        

  11. 接下来,把其他的IP分片包的的信息头删除,这样一个完整的IP包就重组完成了。       

最后,调用 ip_reass_dequeue_datagramip_reassdata结构体从整个链表中删除。 代码执行到这里,整个重组基本完成。 


3. 参考资料


本文出自 “11451177” 博客,请务必保留此出处http://11461177.blog.51cto.com/11451177/1939621

Lwip IP包分片重组