zoukankan      html  css  js  c++  java
  • 《TCP/IP具体解释卷2:实现》笔记--IP的分片和重装

    IP首部内有三个字段实现分片和重装:标识字段(ip_id)、标志字段(ip_off的3个高位比特)和偏移字段(ip_off的13个低位

    比特)。标志字段由3个1bit标志组成。比特0是保留的必须为0,;比特1是“不分片”(DF)标志;比特2是“很多其它分片”(MF)标志。

    Net/3中,标志和偏移字段结合起来,由ip_off訪问,例如以下图所看到的:


    ip_off的其它13bit指出在原始数据报内分片的位置,以8字节为单位计算。因此,除最后一个分片外,其它的分片都希望是一个

    8字节倍数的数据,从而使后面的分片从8字节边界開始。下图显示了在原始数据报内的字节偏移关系,以及在分片的IP首部内

    分片的偏移。


    除最后一个分片外,设置了其余分片的MF比特。

    ip_id唯一地标识某个特定数据报的分片。源系统用同样的源地址(ip_src)、目的地址(ip_dst)和协议(ip_p)值,作为

    数据报在互联网上生命期的值,把每一个数据报的ip_id设置成一个唯一的值。

    1.分片

    在ip_output函数(IP:网际协议章节)中,假设分组正好适合选定出接口的MTU,就在一个链路级帧中发送它。否则,必须对

    分组分片,并在多个帧中将其发送,分组能够是一个完整的数据报或者它自己也是前边系统创建的分片。分片的代码主要

    分三部分:

    1.确定分片大小

    假设DF被设置,则ip_output丢弃该分组,并返回,假设该数据报是在本地生成的,则运输层协议把该错误传回该进程,假设

    分组是被转发的,则生成ICMP目的不可达差错报文。

    Net/3没有实现“路径MTU发现”算法。

    每一个新的分片中包括:一个IP首部,某些原始分组中的选项以及最多len长度的数据。当中len的计算是用接口的MTU减去分组

    首部的长度后,去掉低位的3比特后成为8字节倍数。

    2.构造分片表

    从第二个分片開始构造分片表,在表生成后,原来的分组被转换成第一个分片(降低一次mbuf的生成),对于每个分片,

    ip_output函数採取下面动作:

    分配一个新的分组缓存


    从原来的分组中把IP首部和IP选项拷贝到新的分组,并非全部的选项都会被复制,假设IPOPT_COPIED指示copied比特被

    置位,则会把选项拷贝到芯片中。


    设置MF比特和偏移字段(ip_off)


    为分片设置长度


    从原始分组中把数据拷贝到该分组中


    调整新创建的分片的mbuf分组首部,使其具有正确的全长,把新分片的接口指针清零,把ip_off转换成网络字节序,计算新

    分片的检验和。将该分片通过mbuf的m_nextpkt与前面的分片链接起来。

    3.构造第一个分片并发送分片

    将末尾多余的数据截断后,原来的分组就被转换成第一个分片,同一时候设置MF比特、把ip_len和ip_off转换成网络字节序,计算

    新的检验和。在这个分片中,保留全部的IP选项。在目的地址重装时,仅仅保留数据报的第一个分片的IP选项。某些选项,如

    源路由选项,必须被拷贝到每一个分片中,即使在重装时都被丢弃了。

    最后将每一个分片进行发送。在发送期间遇到全部错误都会使后面的分片被丢弃。


    2.重装

    ipintr重装分片,并把数据报整个地交给运输层处理。ipintr须要尝试把分片重装成一个完整的数据报。

    Net/3在一个全局双向链表ipq上记录不完整的数据报。能够在链表的不论什么地方插入和删除,并不限制一定要在末尾。ipintr

    函数对表进行线性搜索,为当前分片找到合适的数据报。记住分片是由4元组{ip_id、ip_src、ip_des和ip_p}唯一标识的。ipq

    的每一个入口是一个分片表,假设ipintr赵大牌一个匹配,则fp指向匹配的表。ipq的数据结构例如以下:


    很多工作是由ip_reass做的。假设ip_reass通过把当前分片与曾经收到的分片组合在一起,能重装成一个完整的数据报,它就返回

    指向该重装好的数据报的指针。假设没有重装好,则ip_reass保存该分片,ipintr去处理下一个分片。

    假设重装处理产生一个完整的数据包,ipintr就把这个完整的数据报上传给合适的运输层。


    3.ip_reass函数

    ipintr把一个要处理的分片和一个指针传给ip_reass,当中指针指向的是ipq中匹配的重装首部。ip_reass可能重装成功并返回

    一个完整的数据报,可能把该分片链接到数据报的重装链表上,等待其它分片到达后重装。每一个重装链表的表头是一个ipq结构。

    用来标识一个数据报分片的四个段,ip_id、ip_src、ip_dst和ip_p,被保存在每一个重装链表表头的ipq结构中。Net/3用next和prev

    构造数据报链表,用ipq_next和ipq_prev构造分片的链表。

    到达分组的IP首部被放到重装链表之前,首先被转换成一个ipasfrag结构。


    ip_reass在一个由ipf_next和ip_prev连接起来的双向循环链表上,收集某个数据报的分片。下图显示了分片首部链表ipq和

    分片ipasgrag之间的关系。


    上图没有显示重装结构的全部复杂性。重装全然依靠把指针指向底层mbuf上的三个不同的结构。下图显示了mbuf、ipq结构、

    ipasfrag结构和ip结构之间的关系。


    图中含有大量的信息:

    1.全部结构都放在一个mbuf的数据区内。

    2.ipq链表由next和prev连接起来的ipq结构组成。每一个ipq结构保存了唯一标识一个IP数据报的四个字段。

    3.当作为分片链表的头訪问时,每一个ipq结构被看成是一个ipasfrag结构。这些分片由ipf_next和ipf_prev链接起来,分别

    覆盖了ipq结构的ipq_next和ipq_prev成员。

    4.每一个ipasfrag结构都覆盖了到达分片的ip结构,与分片一起到达的数据在缓存中跟在该结构之后。

    下图从逻辑的观点说明重装结构,该图显示了三个数据报的重装,以及ipq链表和ipasfrag结构之间的关系,阴影部分为缺少

    的分片。



    以下分几个部分说明重装

    1.创建重装表

    假设没有符合条件的ipq,则用新的数据报的第一个分片创建一个重装表。它分配一个mbuf来存放新表的头(一个ipq结构),

    并把该结构插入到重装表的链表中。

    2.重装超时

    在Net/3中,使用生命期字段ipq_ttl来管理重超时,重装超过的初始值设置为60,每次内容调用ip_slowtimo时,ipq_ttl就减去1,

    而内核每500ms调用ip_slowtimo一次。假设系统在接受到数据报的任一分片30秒后,还没有组装好一个完整的IP数据报,那么

    系统就丢弃该IP重装链表。

    3.数据报标识符

    在目的主机上,分片包括的字节范围可能会互相覆盖,发生这样的情况的原因是,当一个运输层协议重传某个数据报时,採用

    与原来数据报不同的路由,并且分片的模式也可能不同,这就导致在目的主机上的项目覆盖。传输协议必须强制IP使用原来

    ID字段,确保目的主机识别该数据报是重传的。

    Net/3并不为运输层协议提供机制保证在重传的数据报中重用IP ID字段。在准备新数据时,ip_output通过添加全局整数ip_id

    来赋一个新值。虽然如此,Net/3系统也能让运输层用同样ID字段重传IP数据报的系统上接收重叠分片。

    下图说明分片可能会以不同的方式与已经到达的分片重叠。分片是依照它们到达目的主机的顺序编号的,重装的分片在图底部

    显示,分片的阴影部分是被丢弃的多余字节。


    4.重建数据报首部

    ip_reass把ip指向链表的第一个分片,将ipasfrag结构恢复成ip结构。并将整个分组从重装链表中移走,丢弃表头的ipq结构,

    调整缓存中的m_len和m_data,将前面被隐藏起来的第一个分片的首部和选项包括进来。

    5.计算分组长度

    计算缓存链中数据的字节数,并把值保存在m_pkthdr.len中。

  • 相关阅读:
    龙井和碧螺春的功效与作用
    064 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 无参带返回值方法
    063 01 Android 零基础入门 01 Java基础语法 08 Java方法 01 无参无返回值方法
    062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用
    061 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 08 一维数组总结
    060 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 07 冒泡排序
    059 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 06 增强型for循环
    058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值
    057 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 04 案例:求整型数组的数组元素的元素值累加和
    056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4008368.html
Copyright © 2011-2022 走看看