博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lwip IP包分片重组
阅读量:6816 次
发布时间:2019-06-26

本文共 2075 字,大约阅读时间需要 6 分钟。

  hot3.png

1. 开发环境

 操作系统:SylixOS  编程环境:RealEvo-IDE3.1  硬件平台:AT9x25开发板


2. 技术实现

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

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

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

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

2.1 IP报文重组宏观分析

这里写图片描述

图 2-1 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包就重组完成了。
  12. 最后,调用 ip_reass_dequeue_datagram 将ip_reassdata结构体从整个链表中删除。 代码执行到这里,整个重组基本完成。

#3. 参考资料 无

转载于:https://my.oschina.net/SeanHa/blog/983161

你可能感兴趣的文章
PLook——记录你的知识
查看>>
css布局基础总结
查看>>
如何成为一位「不那么差」的程序员
查看>>
深入理解计算机系统读书笔记
查看>>
前端开发工作一年小记
查看>>
Java知识点总结(Java容器-TreeSet)
查看>>
ionic3 UI Components学习4:Button 按钮
查看>>
highcharts实现饼状图
查看>>
npm常用命令集合
查看>>
6. Java 中的基本数据类型 【连载 6】
查看>>
three.js简介 —— 3D框架
查看>>
MySQL - 索引详解
查看>>
比特币:交易的数据结构
查看>>
基于vue-electron的小项目
查看>>
【收藏】15个常用的javaScript正则表达式
查看>>
大数据可视化 - 收藏集 - 掘金
查看>>
尤大低仿博客带回家
查看>>
库,组件,框架 - 收藏集 - 掘金
查看>>
vue server render实践
查看>>
PHP各大支付平台在线支付集成源码
查看>>