




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
在这几天的工作中总是或多或少的接触到了sk_buff结构体。后来我觉得这样时不时地学点sk_buff结构还不如干脆花段时间来研究下这个重要的结构体。所以我就学习了深入理解linux网络技术内幕有关sk_buff结构的介绍,这系列博文本来是我根据深入理解linux网络技术内幕学习整理而来的,可以算作是笔记吧。后来在看sk_buff克隆和拷贝时,又看了下linux内核源码剖析:TCP/IP实现。现在这博文是经过修改的,所以也加进了在llinux内核源码剖析:TCP/IP实现学习到的内容。大家也可以看看原文对sk_buff结构体的一些讲解,原文分别在第二章关键数据结构:套接字缓冲区:sk_buff结构和第三章:套接字缓存。如果没有电子书的,可以私信我留下邮箱地址。 我要先感谢下这两本书的作者以及译者,深入理解linux网络技术内幕是linux网络中的一本经典之作,对于学习linux网络来说是非常有用的,这是本全面宏观的介绍linux网络的书;linux内核源码剖析:TCP/IP实现我开始看的是电子书,这本书吸引我的地方是讲解的非常详细,而且是非常简洁,尤其是对各个知识点的讲解非常透彻。 下面开始正式的讲解sk_buff结构内容,至于sk_buff结构体的重要性以及历史背景之类的我就不过多废话了。sk_buff结构体: 第一、内核中sk_buff结构体在各层协议之间传输不是用拷贝sk_buff结构体,而是通过增加协议头和移动指针来操作的。如果是从L4传输到L2,则是通过往sk_buff结构体中增加该层协议头来操作;如果是从L4到L2,则是通过移动sk_buff结构体中的data指针来实现,不会删除各层协议头。这样做是为了提高CPU的工作效率。 第二、sk_buff结构体中有很多条件编译,比如: #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info*nf_bridge; #endif 因为sk_buff结构体是linux网络代码中最重要的数据结构,是整个网络传输载体。所以sk_buff结构体里面有很多关于其他功能的成员字段,比如:防火墙,子路由系统,多播等。这些字段并不是一定有的,只有在满足特点条件才有的。所以可以在需要的时候再去关心这些成员字段,现在我们只来讲解下一般的成员字段。 第三、下面就直接来看sk_buff结构体了。为了好理解结构中的一些成员字段,先把后面要讲的内容提前说下。sk_buff结构体关联多个其他结构体,第一是数据区:由sk_buff中head和end指向的数据块,用来存储sk_buff结构的数据也即是存储数据包的内容和各层协议头。第二是分片结构:用来表示IP分片的一个结构体,实则上是和sk_buff结构的数据区相连的,即是end指针的下一个字节开始就是分片结构。也正是此原因,所以分片结构和sk_buff数据区内存分配及销毁时都是一起的。第三个是分片结构指向的数据区,即是IP分片内容。下面开始看sk_buff结构体:struct sk_buff /* These two members must be first. */struct sk_buff*next; / 因为sk_buff结构体是双链表,所以有前驱后继。这是个指向后面的sk_buff结构体指针struct sk_buff*prev; / 这是指向前一个sk_buff结构体指针/老版本(2.6以前)应该还有个字段: sk_buff_head *list /即每个sk_buff结构都有个指针指向头节点struct sock *sk; / 指向拥有此缓冲的套接字sock结构体,即:宿主传输控制模块ktime_ttstamp; / 时间戳,表示这个skb的接收到的时间,一般是在包从驱动中往二层发送的接口函数中设置struct net_device*dev; / 表示一个网络设备,当skb为输出/输入时,dev表示要输出/输入到的设备unsigned long_skb_dst; / 主要用于路由子系统,保存路由有关的东西charcb48; / 保存每层的控制信息,每一层的私有信息unsigned intlen, / 表示数据区的长度(tail - data)与分片结构体数据区的长度之和。其实这个len中数据区长度是个有效长度, / 因为不删除协议头,所以只计算有效协议头和包内容。如:当在L3时,不会计算L2的协议头长度。data_len; / 只表示分片结构体数据区的长度,所以len = (tail - data) + data_len;_u16mac_len, / mac报头的长度hdr_len; / 用于clone时,表示clone的skb的头长度/ 接下来是校验相关域,这里就不详细讲了。_u32priority; / 优先级,主要用于QOSkmemcheck_bitfield_begin(flags1);_u8local_df:1, / 是否可以本地切片的标志cloned:1, / 为1表示该结构被克隆,或者自己是个克隆的结构体;同理被克隆时,自身skb和克隆skb的cloned都要置1ip_summed:2, nohdr:1, / nohdr标识payload是否被单独引用,不存在协议首部。 / 如果被引用,则决不能再修改协议首部,也不能通过skb-data来访问协议首部。nfctinfo:3;_u8pkt_type:3, / 标记帧的类型fclone:2, / 这个成员字段是克隆时使用,表示克隆状态ipvs_property:1,peeked:1,nf_trace:1;_be16protocol:16; / 这是包的协议类型,标识是IP包还是ARP包或者其他数据包。kmemcheck_bitfield_end(flags1);void(*destructor)(struct sk_buff *skb); / 这是析构函数,后期在skb内存销毁时会用到#if defined(CONFIG_NF_CONNTRACK) | defined(CONFIG_NF_CONNTRACK_MODULE)struct nf_conntrack*nfct;struct sk_buff*nfct_reasm;#endif#ifdef CONFIG_BRIDGE_NETFILTERstruct nf_bridge_info*nf_bridge;#endifintiif; / 接受设备的index#ifdef CONFIG_NET_SCHED_u16tc_index;/* traffic control index */#ifdef CONFIG_NET_CLS_ACT_u16tc_verd;/* traffic control verdict */#endif#endifkmemcheck_bitfield_begin(flags2);_u16queue_mapping:16;#ifdef CONFIG_IPV6_NDISC_NODETYPE_u8ndisc_nodetype:2;#endifkmemcheck_bitfield_end(flags2);/* 0/14 bit hole */#ifdef CONFIG_NET_DMAdma_cookie_tdma_cookie;#endif#ifdef CONFIG_NETWORK_SECMARK_u32secmark;#endif_u32mark;_u16vlan_tci;sk_buff_data_ttransport_header; / 指向四层帧头结构体指针sk_buff_data_tnetwork_header; / 指向三层IP头结构体指针sk_buff_data_tmac_header; / 指向二层mac头的头/* These elements must be at the end, see alloc_skb() for details. */sk_buff_data_ttail; / 指向数据区中实际数据结束的位置sk_buff_data_tend; / 指向数据区中结束的位置(非实际数据区域结束位置)unsigned char*head, / 指向数据区中开始的位置(非实际数据区域开始位置)*data; / 指向数据区中实际数据开始的位置unsigned inttruesize; / 表示总长度,包括sk_buff自身长度和数据区以及分片结构体的数据区长度atomic_tusers; / skb被克隆引用的次数,在内存申请和克隆时会用到; /end sk_buff 第四、结构体中常用字段解释: char cb48;这个字段是skb信息控制块,也就是存储每层的一些协议信息,当数据包在哪一层时,存储的就是哪一层协议信息。这个字段由数据包所在层使用和维护,如果要访问本层协议信息,可以通过用一些宏来操作这个成员字段。如:#define TCP_SKB_CB(_skb) (struct tcp_skb_cb *)&(_skb)-cb0) _u8 fclone:2;这是个克隆状态标志,到sk_buff结构内存申请时会使用到。这里提前讲下:若fclone =SKB_FCLONE_UNAVAILABLE,则表明SKB未被克隆;若fclone =SKB_FCLONE_ORIG,则表明是从skbuff_fclone_cache缓存池(这个缓存池上分配内存时,每次都分配一对skb内存)中分配的父skb,可以被克隆;若fclone =SKB_FCLONE_CLONE,则表明是在skbuff_fclone_cache分配的子SKB,从父SKB克隆得到的; atomic_t users;这是个引用计数,表明了有多少实体引用了这个skb。其作用就是在销毁skb结构体时,先查看下users是否为零,若不为零,则调用函数递减下引用计数users即可;当某一次销毁时,users为零才真正释放内存空间。有两个操作函数:atomic_inc()引用计数增加1;atomic_dec()引用计数减去1; 第五、几个数据长度len的解析: (1)sk_buff-data_len:只计算分片中数据的长度,即是分片结构体中page指向的数据区长度。这个在分片结构体中会再详细讲解下。 (2)sk_buff-len:表示当前缓冲区中数据块的大小的总长度。它包括主缓冲中(即是sk_buff结构中指针data指向)的数据区的实际长度(data-tail)和分片中的数据长度。这个长度在数据包在各层间传输时会改变,因为分片数据长度不变,从L2到L4时,则len要减去帧头大小和网络头大小;从L4到L2则相反,要加上帧头和网络头大小。所以:len = (data - tail) + data_len; (3)sk_buff-truesize:这是缓冲区的总长度,包括sk_buff结构和数据部分。如果申请一个len字节的缓冲区,alloc_skb函数会把它初始化成len+sizeof(sk_buff)。当skb-len变化时,这个变量也会变化。所以:truesize = len + sizeof(sk_buff) = (data - tail) + data_len + sizeof(sk_buff); 第六、数据包在各层间传输时,data指针的变化: 在第一的时候就讲了,sk_buff在各层间传输时,只改变指针和添加协议头,不拷贝也不删除协议头。下面来看下处理的详细进过,首先要说下,每一层协议都有个自身的协议头指针,如:二层有mac,三层有nh(nethead网络头),四层有h(head)。现在我用的内核版本把这几个协议头指针变为了:二层为mac_header,三层为network_header,四层为transport_header。下面就简单介绍下包的传输和data指针变化情况。 假设从收包开始: (1)开始进入第二层时,这时data指针指向帧头。mac = data,然后操作mac指针已经数据包。当二层操作完后把包往三层传送时,会调用一个函数(具体什么函数后面会详细讲)让data指针指向三层的IP头; (2)当包进入第三层时,这时data指针已经指向了IP头,让nh = data,然后操作nh指针已经数据包,当三层操作完后把包往四层传送时,同样调用一个函数把data指向四层的TCP头;同理,四层也是一样处理的,只移动指针,不删除协议头。发包时就相反了,只是变成了为每一层添加协议头了。下面是书上的图,供参考。 sk_buff_head结构体: sk_buff结构体是双链表结构,其头结点就是sk_buff_head结构。struct sk_buff_head /* These two members must be first. */struct sk_buff*next;struct sk_buff*prev;_u32 qlen;/代表表中skb元数的个数spinlock_t lock;/锁,防止并发访问; 其实如果要学习linux内核我建议还是从list.h文件开始学起,因为那是内核常用的结构(循环双链表,哈希链表),以及里面还有些操作宏。如果学懂了list.h文件,那么看内核中其他结构将会更简单些(因为里面的一些指针和内核定义的操作宏都非常类似)。先来解释下sk_buff_head结构体成员,qlen表示当前链表中skb的个数,lock成员是自旋锁这个为了构成一个原子操作,防止多条线程同时访问结构体,后面会详细解释下。这里重点解释下next和prev,这是个前驱后继指针,这里内核特意注释规定了前两个成员一定要是:next和prev指针。因为这使得sk_buff_head和sk_buff可以放到同一个链表中,尽管他们不是同一种结构体。另外,相同的函数可以同样应用于sk_buff_head和sk_buff。很多blog都这么说,但为什么sk_buff的指针(prev和next)能够指向sk_buff_head结构呢?我查了很多资料,没结果。但最后我发现原文有句话是关键:“.在表的开端额外增加一个sk_buff_head结构作为一种哑元元素。” sk_buff_head结构体和sk_buff结构体关系: 上面的图为深入理解linux网络技术内幕原文图,显示了sk_buff_head和sk_buff结构体链表。但上面sk_buff结构体是内核2.6.xx.xx比较前的版本的,我现在用的是:内核2.6.32.63版本的。sk_buff结构中没有list这个成员了。sk_buff结构体数据区: sk_buff结构体只是网络数据包中的一些配置,真正包含传输内容和传输协议的都是在sk_buff结构体中几个指针所指向的数据区中。这里先简称数据区,数据区的大小是:(skb-end - skb-head);对于每个数据包来说这个大小都是固定的,而且在传输过程中skb-end和skb-head所指向的地址都是不变的。这块数据区是用来存放应用层发下来的数据和各层的协议信息。但在计算数据长度或者操作协议信息时,一般都要和实际的数据存放指针为准。实际数据指针为data和tail,data指向实际数据开始的地方,tail指向实际数据结束的地方。 下面来看下sk_buff结构体中的指针和数据区关系: 讲到了sk_buff结构和其数据区,那么就把包的形成和数据区的变化一起讲下: (1)sk_buff结构数据区刚被申请好,此时head指针、data指针、tail指针都是指向同一个地方。记住前面讲过的:head指针和end指针指向的位置一直都不变,而对于数据的变化和协议信息的添加都是通过data指针和tail指针的改变来表现的。 (2)开始准备存储应用层下发过来的数据,通过调用函数skb_reserve()来使data指针和tail指针同时向下移动,空出一部分空间来为后期添加协议信息。 (3)开始存储数据了,通过调用函数skb_put()来使tail指针向下移动空出空间来添加数据,此时skb-data和skb-tail之间存放的都是数据信息,无协议信息。 (4)这时就开始调用函数skb_push()来使data指针向上移动,空出空间来添加各层协议信息。直到最后到达二层,添加完帧头然后就开始发包了。 下面来看过程图:(上面提到的这几个操作函数在第二篇博文会详细讲到) skb_shared_info分片结构体: 本来只是想讲sk_buff结构体不想牵扯太多(因为牵扯越多将要花更多时间去学这些东西),但发现到后面克隆和复制skb时,如果不讲分片结构将很难区分开实现克隆、复制的那几个函数。所以这里就稍微的讲解下这个结构体,但是不对结构体中的各个成员字段过多的解释(因为有些成员字段我也不了解,见谅)。 还是先来看看结构体代码吧:struct skb_shared_info atomic_tdataref;/ 用于数据区的引用计数,克隆一个skb结构体时,会增加一个引用计数unsigned shortnr_frags;/ 表示有多少个分片结构unsigned shortgso_size;#ifdef CONFIG_HAS_DMAdma_addr_tdma_head;#endif/* Warning: this field is not always filled in (UFO)! */unsigned shortgso_segs;unsigned short gso_type; / 分片的类型_be32 ip6_frag_id;union skb_shared_tx tx_flags;struct sk_buff*frag_list; / 这也是一种类型的分配数据struct skb_shared_hwtstamps hwtstamps;skb_frag_tfragsMAX_SKB_FRAGS; / 这是个比较重要的数组,到讲分片结构数据区时会细讲#ifdef CONFIG_HAS_DMAdma_addr_tdma_mapsMAX_SKB_FRAGS;#endif/* Intermediate layers must ensure that destructor_arg * remains valid until skb destructor */void *destructor_arg; 这个分片结构体和sk_buff结构的数据区是一体的,所以在各种操作时都把
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 个人煤矿出售合同范本
- 入学教育心得体会左右大学五篇
- 文化教育合作协议书
- 娱乐游戏活动策划方案
- 商品购销合同的基本要素
- 环境评价公众参与机制在2025年公众参与评价体系构建中的应用报告
- 病历采集试题及答案
- 2025年数学阅读能力题库及答案
- 视唱模拟考试试题及答案
- 2025年食品科学与工程考公务员面试题(附答案+解析)
- 公路铣刨机转向桥关键结构疲劳寿命的深度剖析与精准预测
- 民事起诉状要素式(民间借贷纠纷)
- 幼儿园健康预防蚊虫叮咬
- 肺孢子菌肺炎护理查房
- 三级安全教育培训试题(含答案)
- 绿城好房子建设的理念与实践
- 茶叶施肥技术课件
- 老人进食护理课件
- 开学第一课:反诈教育主题班会
- 2025年湖南省长沙市中考物理试卷(含答案)
- 污水处理厂二期成套设备供货及安装调试项目施工组织设计
评论
0/150
提交评论