免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 17087 | 回复: 8
打印 上一主题 下一主题

再请教skb_buff相关问题,len、data_len和线性skb相关 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-03-02 15:37 |只看该作者 |倒序浏览
本帖最后由 samzc2010 于 2010-03-02 15:38 编辑

请结合下面2个skb_buff函数的实现,再谈谈len、data_len的区别和联系。
  1. static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
  2. {
  3.         skb->len-=len;        // 数据长度减小
  4.         if (skb->len < skb->data_len) // ???len小于当前线性skb的内存分配长度了!
  5.                 out_of_line_bug();
  6.         return         skb->data+=len; // data指针后移,意味部分数据removed,返回新的data指针
  7. }

  8. /**
  9. *        skb_pull - remove data from the start of a buffer
  10. *        @skb: buffer to use
  11. *        @len: amount of data to remove
  12. *
  13. *        This function removes data from the start of a buffer, returning
  14. *        the memory to the headroom. A pointer to the next data in the buffer
  15. *        is returned. Once the data has been pulled future pushes will overwrite
  16. *        the old data.
  17. */

  18. static inline unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
  19. {       
  20.         if (len > skb->len) // 长度检查
  21.                 return NULL;
  22.         return __skb_pull(skb,len);
  23. }
复制代码
if (skb->len < skb->data_len) // ???是我解释不清楚的地方,还请指点。

这是个老问题了,我查看了很多朋友相关问题的解答,但是并不是十分的透彻。先说说我的理解:
len -- 完整数据报文的总长度。以以太网帧ip数据包为例,比如一个3000bytes的数据包,那么len就是3000,就是data指针指向的线性连续内存buffer的长度
data_len -- 没有其他情况,那么data_len = len;另外一种情况就是data_len和len的区别了,也是我的问题所在

我看到一些解答是这么说的
‘len’ 表示此 SKB 管理的 Data Buffer 中数据的总长度;
通常,Data Buffer 只是一个简单的线性 buffer,这时候 len 就是线性 buffer 中的数据长度;
但在有 ‘paged data’ 情况下, Data Buffer 不仅包括第一个线性 buffer ,还包括多个 page buffer;这种情况下, ‘data_len’ 指的是 page buffer 中数据的长度,’len’ 指的是线性 buffer 加上 page buffer 的长度;len – data_len 就是线性 buffer 的长度。

有人称此为分片 frag情况,不过我的理解这里的分片并不是ip碎片的fragmentation。而是skb_buff的分片???我不清楚skb这种情况下的数据包存放和处理。

请大侠指点。这种分片发生的情形,以及对数据的管理,大家提到的frag_list到底是指的什么?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
2 [报告]
发表于 2010-03-02 15:46 |只看该作者
skb->len会随着skb->data而变化的。我在你上个帖子中给的连接中提到了。他是skb中数据部分的总长度。如果skb中frag_list有相关内容的话,那么说明data_len表示了所有分片包的数据长度。

skb->len = skb中线性数据区长度 + frag_list中所有数据长度。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
3 [报告]
发表于 2010-03-02 15:47 |只看该作者
如果对sk_buff结构体理解不充分的话,建议先看一下《网络内幕》中第2章,详细介绍了这个结构体以及相关的接口。

论坛徽章:
0
4 [报告]
发表于 2010-03-02 16:06 |只看该作者
好的,多谢!

我不明白那个frag_list以及我引用提到的paged模式的skb使用情况。我再查查资料看看。

论坛徽章:
0
5 [报告]
发表于 2010-03-02 16:33 |只看该作者

141 struct sk_buff *frag_list

135 unsigned short nr_frags

142 skb_frag_t frags[MAX_SKB_FRAGS]

nr_frags, fragsfrag_listIP分片的存储有关。通常数据都存储在线性区域中,但当为了支持聚合分散I/O,数据需要存储在支持聚合分散I/O的区域中。fragsfrag_list支持聚合分散I/O数据,而零拷贝技术也是需要聚合分散I/O支持的。

那什么是聚合分散I/O呢?网络中创建一个发送报文的过程包括组合多个片。报文数据必须从用户空间拷贝到内核空间,同时加上由网络协议栈各层的首部。这个组合可能要求相当数量的数据拷贝。但如果发送报文的网络接口能够支持聚合分散I/O,报文就无需组装成一个单块,可避免大量拷贝。聚合分散I/O从用户空间启动零拷贝网络发送。内核传递发送报文给hard_start_xmit()之前需要判断网络设置是否支持NETIF_F_SG,不然只能对分散的报文进行线性化处理,再聚合成一个单独的报文。如果网络设备已经设置了该标志, 接下来就要检查nr_frags的值,因为该字段确定了片段数,这些分散的片段用关联的方式存储在frags数组中。

接下来再来看一下skb_frag_struct结构。

120#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2)

121

122typedef struct skb_frag_struct skb_frag_t;

123

124struct skb_frag_struct {

125    struct page *page;

126    __u16 page_offset;

127   __u16 size;

128};

120 #defineMAX_SKB_FRAGS (65536/PAGE_SIZE + 2)

MAX_SKB_FRAGSfrags数组的大小因此最多可支持到64K个分片。

125 struct page *page

指向文件系统缓存页的指针。

126 __u16 page_offset

数据起始地址在文件系统缓存页中的偏移。

127 __u16 size

数据在文件系统缓存页面中使用的长度。

frag_list有以下几种使用方法:

1)使用于在接收分片组后,链接多个分片,组成一个完成IP数据报;

2)UDP数据报的输出中,将待分片的SKB链接到第一个SKB中,然后在输出过程中能够快速的分片;

3)用于存放FRAGLIST类型的聚合分散I/O的数据包,如果输出网络设备支持FRAGLIST类型的聚合分散I/O(目前只有回环设备支持),则可以直接输出。

fragsnr_frags用于支持SG类型的聚合分散I/O分片。frags是用于存放聚合分散I/O分片的数组。nr_frags为当前使用聚合分散I/O分片的数量,即为frags数组中使用的数量,不超过MAX_SKB_FRAGS

skb_is_nonlinear()用来测试SKB的缓冲区聚合分散I/O缓存区,实际上就是判断sk_buffdata_len成员。而skb_linearize()可以把含有聚合分散I/O缓存区中的数据线性化到线性缓冲区中。线性过程中涉及到数据复制,所以如果多次进行数据的复制,将严重影响系统性能,因此在没有必要的时候,建议不要进行数据的线性化。

论坛徽章:
0
6 [报告]
发表于 2010-03-02 17:37 |只看该作者
141 struct sk_buff *frag_list135 unsigned short nr_frags142 skb_frag_t frags[MAX_SKB_FRAGS]nr_frags, ...
lmarsin 发表于 2010-03-02 16:33


多谢!原文?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
7 [报告]
发表于 2010-03-02 17:38 |只看该作者
应该摘自lmarsin兄的大作

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
8 [报告]
发表于 2010-03-02 21:36 |只看该作者
本帖最后由 jiufei19 于 2010-03-02 21:37 编辑

回复 4# samzc2010


    楼主需要仔细阅读下understanding Linux network internal一书,上面有非常清晰的解释,当然这个需要一定过程,建议不要直接就这样阅读代码,那样会耽误很多时间的,必须先理论再实践,下面我贴一个图供楼主参考,或许有帮助

skb.jpg (19.42 KB, 下载次数: 88)

skb.jpg

论坛徽章:
0
9 [报告]
发表于 2010-03-02 22:00 |只看该作者
回复  samzc2010


    楼主需要仔细阅读下understanding Linux network internal一书,上面有非常清晰 ...
jiufei19 发表于 2010-03-02 21:36



谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP