我是靠谱客的博主 忧虑店员,最近开发中收集的这篇文章主要介绍IPv4之数据包发送接口ip_append_data(一)函数功能skb数据组织策略小结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

如IPv4之发送接口概述所介绍,ip_append_data()主要是由udp使用。因为ip_append_data()的实现非常的复杂,涉及skb对数据的组织方式,以及各种出于性能考虑的分配策略,所以在分析其代码实现之前,有必要先讨论下内核实际采取的数据组织方式。

函数功能

首先需要明确ip_append_data()要实现的功能:

  1. ip_append_data()的任务就是将多个片段合并成一个大的IP报文,该函数仅仅做合并工作,并不实际发送报文,如果要发送,调用者后面应该主动调用ip_push_pending_frames();
  2. 这里要注意区分IP报文和IP片段的不同,发送端可以组织一个很大的IP报文,但是在实际发送时,为了适配设备的MTU,需要将这一个IP报文拆封成多个IP片段,这些拆分的IP片段的ipid相同,片内偏移不同;
  3. 该函数将参数指定的数据(from,length)按照MTU大小组织成一个个的方便后面IP协议处理的skb,并且将这些skb放入传输控制块的发送缓冲区中,这些skb在代码中被称之为pending数据;

skb数据组织策略

  1. 一个IP报文可能超过了MTU大小,这时一个IP报文就需要拆分成多个IP片段分开传输以适配设备的MTU;
  2. 为了方便IP协议后续处理,ip_append_data()调用之后,IP片段和skb是一一对应的,不管skb内部是如何存储数据的,这点都是确定的。

下面我们来看一些可能的情况。

情形1

在这里插入图片描述

如上图所示,这是一种不需要分段的情形,即传输的数据长度小于PTMU,只需要分配一个skb就可以容纳下要发送的数据了。这里有些关键点需要说明:

  1. 实际分配skb时,会将L2所需头部、IP头部、L4的头部和数据部分都考虑进来,这样后续协议在处理该数据包是就无需再次分配缓冲区了;
  2. 示例中还有IPsec header和IPsec tailer两部分,这属于扩展首部和扩展末尾,当启用IPsec时,需要在IP报文的首尾追加IPsec特有的信息,所以如果是这种情况,在分配skb时也会将这种开销考虑进来;
  3. 实际分配时,如果一个IP数据包总长度小于PMTU,分配的skb长度是按照需要的大小来分配的,不会造成浪费,这点同样适用于需要分段时的最后一个片段(可能小于PMTU)的情况。

额外需要说明的是:ip_append_data()在分配了skb后,会拷贝L4 payload部分,还会初始化skb中的某些字段,如上图缓冲区左侧的图示;其余的如L4 header由调用ip_push_pending_frames()的函数负责填充、IP header由ip_push_pending_frames()填充。

情形2

在这里插入图片描述

这个例子比上一个稍微复杂一点,这个例子我们不考虑IPsec的情形。左下角为L4协议想要传输的报文,长度为length并且大于PMTU,一次调用ip_append_data()需要将这整个报文拆分成skb放入到套接字的发送缓冲区中,这里假设分配两个skb可以容纳length长度的数据,这时第一个skb大小为PTMU,它拷贝了x字节的数据;第二个skb拷贝了剩余的y字节(x+y=length),并且第二个skb的长度小于PMTU。

由于调用者可能会连续调用ip_append_data()多次,然后再调用ip_push_pending_frames()启动发送,所以如果按照上图的方式分配最后一个skb,再来数据时就需要重新分配skb,然后将最后一个skb的数据拷贝到新的缓冲区中,然后删除最后一个缓冲区,执行这样的动作是耗时的,会带来性能的损耗。为了处理这种问题,引入了MSG_MORE标记,如果在前一次调用ip_append_data()时指定了MSG_MORE标记,那么表示后面马上还会添加新的数据,这时就可以在处理最后一部分数据时预先分配一个容纳PMTU大小的skb,如下图所示:
在这里插入图片描述
虽然当前无法填满最后一个skb,但是因为很快有数据到达,所以这么分配没有问题。

情形3

case1和case2所举的例子都是设备不支持S/G IO时能够采取的解决方案,如果设备支持S/G IO,那么即使L4是多次传入小片段调用ip_append_data(),ip_append_data()也可以按照下图所示方式组织数据:

在这里插入图片描述

上图a表示支持S/G IO的情形下第一次调用ip_append_data()后的缓冲区结构,注意skb的分配是按需分配的,其大小并不是PMTU。图b是第二次调用ip_append_data()后,新增的数据保存在了前一个skb的frags数组中,这两块区域并不连续,但是由于设备支持S/G IO,所以这么分配是没有问题的。

要特别注意的是,上图中的x+S1的大小依然要小于PMTU,如果超过,那么还是需要分配一个新的skb,这是因为一个skb对应一个IP片段的原则不能打破。

小结

理解了上面这几个图,基本上就可以理解ip_append_data()的处理逻辑了,下一篇来介绍ip_append_data()的实现细节。

最后

以上就是忧虑店员为你收集整理的IPv4之数据包发送接口ip_append_data(一)函数功能skb数据组织策略小结的全部内容,希望文章能够帮你解决IPv4之数据包发送接口ip_append_data(一)函数功能skb数据组织策略小结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部