1 前置知识学习

1.1 MTU

MTU是最大传输单元( Maximum Transmission Unit)的缩写,指一个接口无需分片所能发送的数据包的最大字节数。 

MTU范围在46 ~ 1500字节,默认一般都是1500。

1)MTU为1500时计算总长度

7字节前导码+1字节帧开始定界符+6字节的目的MAC+6字节的源MAC+2字节的帧类型+1500字节IP头及数据+4字节的 FCS = 1526字节。

2)为什么我们抓包得到的最大帧是1514字节?

当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和错,就丢弃此帧。如果校验和正确,就去掉FCS再交给“设备驱动程序”做进一步处理。这时我们的抓包软件才能抓到数据,因此,抓包软件抓到的是去掉前导码、帧开始定界符、FCS之外的数据,其最大值是 6+6+2+1500=1514。

3)如果MTU为46,不分片的最大以太帧长度

以太网规定,以太网帧数据域部分最小为46字节,也就是以太网帧最小是 6+6+2+46+4=64。抓包时要除去4个字节的FCS,因此,抓包看到是60字节。

当数据字段的长度小于46字节时,MAC层(由驱动程序)会在数据字段的后面填充数据,以满足数据帧长不小于64字节。

1.2 IP分片原理

IP分片发生在IP层,不仅源端主机会进行分片,中间的路由器也有可能分片,因为不同的网络的MTU是不一样的,如果传输路径上的某个网络的MTU比源端网络的MTU要小,路由器就可能对IP数据报再次进行分片。而分片数据的重组只会发生在目的端的IP层。

下图红色框里是我们熟悉的IP首部格式,与分片相关的是图中浅绿色+深绿色的方框(共32位)

1)浅绿框的“16字节标识”

同一个数据报的各个分片的标识是一样的,目的端会根据这个标识来判断IP分片是否属于同一个IP数据报。

2)深绿框的“标志”

占3个标志位。标志0:保留,必须为零;DF:不分段标记;MF:更多分片标记,,如果是最后一个分片,该标志位为0,否则为1。

3)深绿框的“片偏移”

它表示分片在原始数据中的偏移,这里的原始数据是IP层收到的TCP或UDP数据,不包含IP首部。需要注意的是,在分片的数据中,传输层的首部只会出现在第一个分片中,因为传输层的数据格式对IP层是透明的,传输层的首部只有在传输层才会有它的作用,IP层不知道也不需要保证在每个分片中都有传输层首部。所以,在网络上传输的数据包是有可能没有传输层首部的。


1.3 避免IP分片

在网络编程中,我们要避免出现IP分片。因为IP层是没有超时重传机制的,如果IP层对一个数据包进行了分片,只要有一个分片丢失了,只能依赖于传输层进行重传,结果是所有的分片都要重传一遍,会大大降低传输层传送数据的成功率,所以我们要避免IP分片。

1)UDP

我们需要在应用层去限制每个包的大小,一般不要超过1472字节(不考虑IP首部选项字段的情况),即以太网MTU(1500) - IP首部(20)- UDP首部(8)。

2)TCP(不用考虑IP分片)

应用层不需要考虑这个问题,因为传输层已经帮我们做了。在建立连接的三次握手的过程中,连接双方会相互通告MSS(Maximum Segment Size,最大报文段长度),MSS肯定是<=网络层的最大路径MTU,然后tcp数据封装成ip数据包通过网络层发送,当服务器端传输层接收到tcp数据之后进行tcp重组。TCP的ip数据包在传输过程中是不会发生分片的。

1.4 内核里的分片重组

linux实现分析:https://www.cnblogs.com/wanpengcoder/p/7604715.html

BSD:TCP/IP详解卷二,第十章

2 IP分片及重组库

IP分段和重组库实现IPv4和IPv6数据包的分段和重组。

2.1 数据包分片

数据包分段逻辑将输入的数据包划分为多个分段。 rte_ipv4_fragment_packet()和rte_ipv6_fragment_packet()函数均假定输入mbuf数据指向数据包IP报头的开头(即L2报头已被剥离)。为避免复制实际数据包的数据,使用了零拷贝技术(rte_pktmbuf_attach)。

对于每个片段,将创建两个新的mbuf:

  • 直接mbuf,它包含新片段的L3头。

  • 间接mbuf,它附加到带有原始数据包的mbuf。它的数据字段指向原始数据包数据的开头加上片段偏移量。

然后,将L3头部从原始mbuf复制到“直接”mbuf,并进行更新以反映新的分片状态。请注意,对于IPv4,不重新计算标头校验和,并将其设置为零。

最后,每个片段的“直接”和“间接” mbuf通过mbuf的next字段链接在一起,以组成新片段的数据包。

调用方可以明确指定应使用哪些内存池来分配“直接”和“间接” mbuf。

有关直接和间接mbuf的更多信息,请参考mbuf库的直接和间接缓冲区说明。

2.2 数据包重组

2.2.1 IP分片表

分片表中维护已经接收到的数据包片段的信息。

每个IP数据包均由有三个字段唯一标识:<源IP地址>,<目标IP地址>,<ID>。

请注意,片段表上的所有更新/查找操作都不是线程安全的。因此,如果不同的执行上下文(线程/进程)要同时访问同一张表时,必须提供一些外部同步机制。

每个表条目都可以保存有关数据包的信息,这些信息最多由RTE_LIBRTE_IP_FRAG_MAX(默认为4个)片段组成。

该代码示例演示了如何创建新的分片表:

frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S * max_flow_ttl;
bucket_num = max_flow_num + max_flow_num / 4;
frag_tbl = rte_ip_frag_table_create(max_flow_num, bucket_entries, max_flow_num, frag_cycles, socket_id);

内部分片表是一个简单的哈希表。基本思想是使用两个哈希函数和主备两个hash桶,每个桶下有若干<bucket_entries>。这为每个键在哈希表中提供了2 * <bucket_entries>个可能的位置。当冲突发生并且所有2 * <bucket_entries>都被占用时,ip_frag_tbl_add()不会将现有键重新插入替代位置,而只会返回失败。(我的理解,这里是对hash库里cuckoo算法的简化说明)。

此外,表中驻留时间长于<max_cycles>的条目被视为无效,可以被新条目替换或删除。

请注意,重组需要分配大量的mbuf。在任何给定时间,最多可以将(2 * bucket_entries * RTE_LIBRTE_IP_FRAG_MAX * <每个数据包的最大mbufs个数>)存储在分片表中,以等待剩余的分片。

2.2.2 数据包重组

分片数据包的处理和重组是由rte_ipv4_frag_reassemble_packet()/ rte_ipv6_frag_reassemble_packet()函数完成的。它们要么返回一个指向“包含重组后数据包的有效mbuf“的指针,要么返回NULL(由于某种原因而无法完成据包重组数)。

这些功能包括:

  • 在片段表中搜索数据包的<IPv4源地址,IPv4目标地址,数据包ID>。

  • 如果找到该条目,则检查该条目是否已超时。如果是,则释放所有先前收到的片段,并从条目中删除有关它们的信息。
  • 如果未找到带有此类密钥的条目,请尝试通过以下两种方法之一创建一个新的键:

1)占用一个空条目。

2)删除超时条目,释放与它相关联的mbufs,并在其中存储具有指定键的新条目。

  • 使用新的片段信息更新条目,并检查包是否可以重新组合(包的条目包含所有片段)。

1)如果是,则重新组合数据包,将表的条目标记为空,然后将重新组合的mbuf返回给调用方。

2)如果否,则将NULL返回给调用方。

如果在数据包处理的任何阶段遇到错误(例如:无法将新条目插入分片表或无效/超时的片段),则该函数将释放所有与数据包分片相关的信息,标记表条目为无效,并将NULL返回给调用者。

2.2.3 调试日志记录和统计信息收集

RTE_LIBRTE_IP_FRAG_TBL_STAT配置宏控制分片表的统计信息收集。默认情况下不启用此宏。

RTE_LIBRTE_IP_FRAG_DEBUG控制IP分片处理和重组的调试日志记录。默认情况下禁用此宏。请注意,虽然日志记录包含许多详细信息,但它减慢了数据包处理的速度,并可能导致许多数据包的丢失。

参考:

DPDK官方编程指南:http://doc.dpdk.org/guides-20.02/prog_guide/ip_fragment_reassembly_lib.html

DPDK IP分片及重组库(学习笔记)的更多相关文章

  1. numpy, matplotlib库学习笔记

    Numpy库学习笔记: 1.array()   创建数组或者转化数组 例如,把列表转化为数组 >>>Np.array([1,2,3,4,5]) Array([1,2,3,4,5]) ...

  2. IP2——IP地址和子网划分学习笔记之《子网掩码详解》

    2018-05-04 16:21:21   在学习掌握了前面的<进制计数><IP地址详解>这两部分知识后,要学习子网划分,首先就要必须知道子网掩码,只有掌握了子网掩码这部分内容 ...

  3. IP地址和子网划分学习笔记之《IP地址详解》

    2018-05-03 18:47:37   在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. ...

  4. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  5. muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制

    目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...

  6. muduo网络库学习笔记(三)TimerQueue定时器队列

    目录 muduo网络库学习笔记(三)TimerQueue定时器队列 Linux中的时间函数 timerfd简单使用介绍 timerfd示例 muduo中对timerfd的封装 TimerQueue的结 ...

  7. IP地址和子网划分学习笔记之《预备知识:进制计数》

    一.序:IP地址和子网划分学习笔记开篇 只要记住你的名字,不管你在世界的哪个地方,我一定会去见你.——新海诚 电影<你的名字> 在我们的日常生活中,每个人的名字对应一个唯一的身(敏)份(感 ...

  8. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  9. 【python】numpy库和matplotlib库学习笔记

    Numpy库 numpy:科学计算包,支持N维数组运算.处理大型矩阵.成熟的广播函数库.矢量运算.线性代数.傅里叶变换.随机数生成,并可与C++/Fortran语言无缝结合.树莓派Python v3默 ...

随机推荐

  1. 2019-2020-1 20199329《Linux内核原理与分析》第三周作业

    <Linux内核原理与分析>第三周作业 一.上周问题总结: 第二周头脑风暴完成较慢 虚拟机libc配置错误 书本知识使用不够熟练 二.本周学习内容: 1.实验楼环境虚拟一个x86的CPU硬 ...

  2. [Inno Setup] Do not show application version in “Program and Features” control panel

    Set AppVersion empty. But, then you have to set the AppVerName. Depending on your needs either set i ...

  3. Django Channel实时推送与聊天

    先来看一下最终的效果吧 开始聊天,输入消息并点击发送消息就可以开始聊天了 点击 “获取后端数据”开启实时推送 先来简单了解一下 Django Channel Channels是一个采用Django并将 ...

  4. js之 DOM与BOM

    JavaScript HTML DOM (文档对象模型)(Document Object Model) 什么是DOM? DOM是W3C标准. DOM定义了访问文档的标准: “W3C文档对象模型(DOM ...

  5. sed命令的正则表达式实践

    1. 取系统ip [root@oldboy logs]# ifconfig eth3 eth3 Link encap:Ethernet HWaddr 08:00:27:4C:6F:AD inet ad ...

  6. 自定义fastjson对枚举类型的序列化及反序列化过程

    通常,fastjson在序列化及反序列化枚举时,一般以下几种策略: 1).根据枚举的name值序列化及反序列化(默认) 2).根据枚举的ordinal序列化及反序列化 3).根据枚举的toString ...

  7. windows 7或以上系统的实用小工具,你知道么?

    今晚给大家介绍个实用的好工具,可以做简单的问题记录,再也不用截图加注释这么辛苦了····· 经测试,这东东在win7,2008 及2008R2里适用,也就是说,在win7以上的系统中才有.好了,下面直 ...

  8. 图论--树的重心(DFS) 模板

    const int maxn=500005; int tot=0,n; int ans,size; int sx[maxn],head[maxn]; int vis[maxn]; struct edg ...

  9. Appium-desktop 元素定位

    1.打开 appium-desktop ,点击 start session 2.打开后,点击屏幕右上角的搜索按钮 3.然后会打开配置页面,在本地服务配置信息同上面写的代码链接配置.填入正确的信息后,点 ...

  10. JavaScript从入门到精通(转)

    JavaScript从入门到精通 转自: https://github.com/Eished/JavaScript_notes 视频连接:https://www.bilibili.com/video/ ...