第十章 IP的分片与重装

一、本章把前两章ip_output函数中的分片部分,和ipintr函数中的重装部分进行了讲解。IP分组的分片和重装的是在IP首部中有一些标识为,如ip_off和MF这些。而且分片有一个原则,就是除了最后一个分片,其他分片的数据部分的大小都应为8字节的倍数。
二、ip_output函数中的分片:

  • 1.确定分片大小:如果分组中的标识位禁止分片,那么函数对于大于接口MTU的分组进行丢弃,并返回。针对数据报生成地方的不同,进行不同的处理。如果数据报是在本地生成的,那么将错误信息传递给相应的进程;如果数据报是被转发的(即主机被配置成路由器了),那么将错误信息生成一个ICMP目的地不可达的差错报文,并指出不分片就无法转发该分组,发送给源地址中的进程。
  • 2.构造分片表:分片表在第221和第222页有源代码及讲解。在一个分片中,均包含一个IP首部、某些原始分组中的选项和最多len长度的数据。分配的时候基础的数据结构是mbuf,用mbuf链。即每一个分片由若干个mbuf结构构成,第一个mbuf结构承载IP首部(基本首部及选项,选项用ip_optcopy函数进行复制,注意还要在前面预留16字节的链路层首部),然后存储分片的数据部分,如果有必要还要新分配若干个mbuf结构来承载分片的数据部分。一个分片搞好后,就用mbuf中的m_nextpkt指针将各个mbuf链(各个分片)链接起来。
  • 3.把分片都搞好后,开始发送分片。如果一个分片发送失败,会造成后面的分片也失败。

三、ipintr函数中的重装:

  • 1.要重装分片,首先要判断一下到达的分组是不是一个完整的数据报,如果是一个完整的数据报,那么就不执行重装的代码。
  • 2.然后,如果如果需要进行重装也需要使用m_pullup函数将分组的首部提升到第一个mbuf中。
  • 3.构建一个重装表,像填词一样往里面填分片(不同时刻到达的分片可能会有地方重叠,那么就根据情况来切除掉或者抛弃掉重叠的部分)。为了判断到达的分片属于哪一个数据报,需要通过一些标识来判断。标识为一个四元组{ip_id,ip_src,ip_dst,ip_p},重装表的结构在后面进行叙述,还没有找到TCP避免重装调用m_pullup的机制。
  • 4.关于ip_erass函数,在每一个接收到一个分片后,通过ip_erass函数暂存收到的分片,然后判断是否已经组装完成一个数据报了。如果完成了,就向上层提交;否则就通过goto语句转向接收下一个分片的语句。对重装表的各种操作都在ip_earss函数中。
  • 5.重装结束。

四、ip_erass函数:ip_erass函数是在ipintr函数中被调用的,用来对重装表进行各种操作的。

  • 1.首先要引入两种数据结构:ipq结构和ipasfrag结构,这两个结构都是被放置在mbuf结构中的m_data[]中,而且ipq结构、ipasfrag结构和ip结构可以互相覆盖和转换
  • 2.第229页图10-17展示了一个重装表的实例,就一个图就里理解了。
  • 3.对于ip_erass函数的执行流程: 首先,创建重装表;然后通过前面介绍的标识四元组查找分片对应的位置;之后在将分片放置到相应位置的时候要对有覆盖的部分进行截断或者丢弃;然后判断是否组装完成,如果没有完成,函数返回,等待接收更多的分片(有代码会设置一个定时器,如果在规定的时间内没有组装完成,就认为超时,丢弃已接受到的这个数据报的所有分片),如果完成了,就用m_cat函数把分片重新构造成数据报(暂时还不知道这么做的原因,有待看源码);然后对数据区域强制类型转换(如把首部区域转换成ip结构等);然后就没有然后了,就完结了

五、还有两个函数起到一些辅助作用:
ip_slowtimo函数:一个定时器函数,500ms被调用一次,为重装链表上的分片计时。
ip_drain函数:当内核需要更多内存的时候被调用。

你可能感兴趣的:(TCP/IP详解读书笔记)