版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
sk_buff目录1sk_buff介绍2sk_buff组成3structsk_buff结构体4sk_buff成员变量4.1Layout布局4.2General通用4.3Feature-specific功能相关5sk_buff管理和操作函数5.1缓冲区操作函数skb_reserveskb_putskb_pushskb_pull5.2发送tcp报文示例5.3缓冲区分配、克隆和释放函数alloc_skbskb_clonepskb_copyskb_copykfree_skb1sk_buff介绍sk_buff(socketbuffer)结构是linux网络代码中重要的数据结构,它管理和控制接收或发送数据包的信息。2sk_buff组成Packetdata:通过网卡收发的报文,包括链路层、网络层、传输层的协议头和携带的应用数据,包括headroom,data,tailroom三部分。skb_shared_info作为packetdata的补充,用于存储ip分片,其中sk_buff*frag_list是一系列子skbuff链表,而frag[]是由一组单独的page组成的数据缓冲区。Databuffer:用于存储packetdata的缓冲区,分为以上两部分。Sk_buff:缓冲区控制结构sk_buff。整个sk_buff结构图如图1。headheaddatatailendHeadroomDATATailroom…frag_listfrags[0]frags[1]…PacketdataDataBuffersk_bufffrags[MAX_SKB..]skb_shared_info分片1分片2页碎片图1sk_buff结构图3structsk_buff结构体/*structsk_buff-socketbuffer*/structsk_buff{/*Thesetwomembersmustbefirst.*/structsk_buff *next;structsk_buff *prev;structsock *sk;structskb_timeval tstamp;/*Timewearrived,记录接收或发送报文的时间戳*/structnet_device *dev;/*通过该设备接收或发送,记录网络接口的信息和完成操作structnet_device *input_dev;/*接收数据的网络设备structnet_device *curlayer_input_dev;structnet_device *l2tp_input_dev;union{structtcphdr *th;structudphdr *uh;structicmphdr *icmph;structigmphdr *igmph;structiphdr *ipiph;structipv6hdr *ipv6h;unsignedchar *raw;}h;//传输层报头union{structiphdr *iph;structipv6hdr *ipv6h;structarphdr *arph;unsignedchar *raw;}nh;//网络层报头union{unsignedchar *raw;}mac;//链路层报头...unsignedint len,//len缓冲区中数据部分的长度。data_len,//data_len只计算分片中数据的长度mac_len,//mac头的长度csum;//校验和__u32 priority;__u8 local_df:1,cloned:1,//表示该结构是另一个sk_buff克隆的ip_summed:2,nohdr:1,nfctinfo:3;__u8 pkt_type:3,fclone:2,ipvs_property:1;__be16 protocol;__u32flag;/*packetflags*/.../*Theseelementsmustbeattheend,seealloc_skb()fordetails.*/unsignedint truesize;//这是缓冲区的总长度,包括sk_buff结构和数据部分atomic_t users;unsignedchar *head,//指向缓冲区的头部*data,//指向实际数据的头部*tail,//指向实际数据的尾部*end;//指向缓冲区的尾部};4sk_buff成员变量Sk_buff成员变量主要包括以下3类1Layout布局2General通用3Feature-specific功能相关4.1Layout布局1structsk_buff*next,structsk_buff*prev有些sk_buff成员变量的作用是方便查找,或者是连接数据结构本身.内核可以把sk_buff组织成一个双向链表。当然,这个链表的结构要比常见的双向链表的结构复杂一点。就像任何一个双向链表一样,sk_buff中有两个指针next和prev,其中,next指向下一个节点,而prev指向上一个节点。但是,这个链表还有另一个需求:每个sk_buff结构都必须能够很快找到链表头节点。为了满足这个需求,在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点,它的定义如下sk_buff和sk_buff_head的前两个元素是一样的:next和prev指针。这使得它们可以放到同一个链表中,尽管sk_buff_head要比sk_buff小得多。另外,相同的函数可以同样应用于sk_buff和sk_buff_head。图22structsock*sk这是一个指向拥有这个sk_buff的sock结构的指针。这个指针在网络包由本机发出或者由本机进程接收时有效,因为插口相关的信息被L4(TCP或UDP)或者用户空间程序使用。如果sk_buff只在转发中使用(这意味着,源地址和目的地址都不是本机地址),这个指针是NULL。3unsignedintlen这是缓冲区中数据部分的长度。它包括主缓冲区中的数据长度(data指针指向它)和分片中的数据长度。它的值在缓冲区从一个层向另一个层传递时改变,因为往上层传递,旧的头部就没有用了,而往下层传递,需要添加本层的头部。len同样包含了协议头的长度。4unsignedintdata_len和len不同,data_len只计算分片中数据的长度。5unsignedintmac_len这是mac头的长度。6atomic_tusers这是一个引用计数,用于计算有多少实体引用了这个sk_buff缓冲区。它的主要用途是防止释放sk_buff后,还有其他实体引用这个sk_buff。因此,每个引用这个缓冲区的实体都必须在适当的时候增加或减小这个变量。这个计数器只保护sk_buff结构本身,而缓冲区的数据部分由类似的计数器(dataref)来保护。有时可以用atomic_inc和atomic_dec函数来直接增加或减小users,但是,通常还是使用函数skb_get和kfree_skb来操作这个变量。7unsignedinttruesize这是缓冲区的总长度,包括sk_buff结构和数据部分。如果申请一个len字节的缓冲区,alloc_skb函数会把它初始化成len+sizeof(sk_buff)。8unsignedchar*head,*end,*data,*tail它们表示缓冲区和数据部分的边界。在每一层申请缓冲区时,它会分配比协议头或协议数据大的空间。head和end指向缓冲区的头部和尾部,而data和tail指向实际数据的头部和尾部,参见图3。每一层会在head和data之间填充协议头,或者在tail和end之间添加新的协议数据。图3中右边数据部分会在尾部包含一个附加的头部。图39void(*destructor)(...)这个函数指针可以初始化成一个在缓冲区释放时完成某些动作的函数。如果缓冲区不属于一个socket,这个函数指针通常是不会被赋值的。如果缓冲区属于一个socket,这个函数指针会被赋值为sock_rfree或sock_wfree(分别由skb_set_owner_r或skb_set_owner_w函数初始化)。这两个sock_xxx函数用于更新socket队列中的内存容量。4.2General通用本节描述sk_buff的主要成员变量,这些成员变量与特定的内核功能无关。1structtimevaltstamp这个变量只对接收到的包有意义。它代表包接收时的时间戳,或者有时代表包准备发出时的时间戳。它在netif_rx里面由函数net_timestamp设置,而netif_rx是设备驱动收到一个包后调用的函数。2structnet_device*dev这个变量的类型是net_device,net_device它代表一个网络设备。dev的作用与这个包是准备发出的包,还是刚接收的包有关。当收到一个包时,设备驱动会把sk_buff的dev指针指向收到这个包的设备的数据结构,就像下面的vortex_rx里的一段代码所做的一样,这个函数属于3c59x系列以太网卡驱动,用于接收一个帧。(drivers/net/3c59x.c):当一个包被发送时,这个变量代表将要发送这个包的设备。在发送网络包时设置这个值的代码要比接收网络包时设置这个值的代码复杂。有些网络功能可以把多个网络设备组成一个虚拟的网络设备(也就是说,这些设备没有和物理设备直接关联),并由一个虚拟网络设备驱动管理。当虚拟设备被使用时,dev指针指向虚拟设备的net_device结构。而虚拟设备驱动会在一组设备中选择一个设备并把dev指针修改为这个设备的net_device结构。因此,在某些情况下,指向传输设备的指针会在包处理过程中被改变。3structnet_device*input_dev这是收到包的网络设备的指针。如果包是本地生成的,这个值为NULL。对以太网设备来说,这个值由eth_type_trans初始化,它主要被流量控制代码使用。4structnet_device*real_dev这个变量只对虚拟设备有意义,它代表与虚拟设备关联的真实设备。例如,Bonding和VLAN设备都使用它来指向收到包的真实设备。5union{...}hunion{...}nhunion{...}mac这些是指向TCP/IP各层协议头的指针:h指向L4,nh指向L3,mac指向L2。每个指针的类型都是一个联合,包含多个数据结构,每一个数据结构都表示内核在这一层可以解析的协议。例如,h是一个包含内核所能解析的L4协议的数据结构的联合。每一个联合都有一个raw变量用于初始化,后续的访问都是通过协议相关的变量进行的。当接收一个包时,处理n层协议头的函数从n-1层收到一个缓冲区,它的skb->data指向n层协议的头。处理n层协议的函数把本层的指针(例如,L3对应的是skb->nh指针)初始化为skb->data,因为这个指针的值会在处理下一层协议时改变(skb->data将被初始化成缓冲区里的其他地址)。在处理n层协议的函数结束时,在把包传递给n+1层的处理函数前,它会把skb->data指针指向n层协议头的末尾,这正好是n+1层协议的协议头(参见图4)。发送包的过程与此相反,但是由于要为每一层添加新的协议头,这个过程要比接收包的过程复杂。图46structdst_entrydst这个变量在路由子系统中使用。7charcb[40]这是一个控制缓存,或者说是一个私有信息的存储空间,由每一层自己维护并使用。它在分配sk_buff结构时分配(它目前的大小是40字节,已经足够为每一层存储必要的私有信息了)。在每一层中,访问这个变量的代码通常用宏实现,以增强代码的可读性。例如,TCP用这个变量存储tcp_skb_cb结构,这个结构在include/net/tcp.h中定义:下面这个宏被TCP代码用来访问cb变量。在这个宏里面,有一个简单的类型转换:#defineTCP_SKB_CB(__skb)((structtcp_skb_cb*)&((__skb)->cb[0]))下面的例子是TCP子系统在收到一个分段时填充相关数据结构的代码:inttcp_v4_rcv(structsk_buff*skb)8unsignedintcsumunsignedcharip_summed表示校验和以及相关状态标记。unsignedcharcloned一个布尔标记,当被设置时,表示这个结构是另一个sk_buff的克隆。9unsignedcharpkt_type这个变量表示帧的类型,分类是由L2的目的地址来决定的。可能的取值都在include/linux/if_packet.h中定义。对以太网设备来说,这个变量由eth_type_trans函数初始化。10__u32priority这个变量描述发送或转发包的QoS类别。如果包是本地生成的,socket层会设置priority变量。如果包是将要被转发的,rt_tos2priority函数会根据ip头中的Tos域来计算赋给这个变量的值。这个变量的值与DSCP(DiffServCodePoint)没有任何关系。unsignedshortprotocol这个变量是高层协议从二层设备的角度所看到的协议。典型的协议包括IP,IPV6和ARP。完整的列表在include/linux/if_ether.h中。由于每个协议都有自己的协议处理函数来处理接收到的包,因此,这个域被设备驱动用于通知上层调用哪个协议处理函数。每个网络驱动都调用netif_rx来通知上层网络协议的协议处理函数,因此protocol变量必须在这些协议处理函数调用之前初始化。unsignedshortsecurity这是包的安全级别。这个变量最初由IPSec子系统使用,但现在已经作废了。4.3Feature-specific功能相关linux内核是模块化的,你可以选择包含或者删除某些功能。因此,sk_buff结构里面的一些成员变量只有在内核选择支持某些功能时才有效,比如防火墙(netfilter)或者qos:1unsignedlongnfmark__u32nfcache__u32nfctinfostructnf_conntrack*nfctunsignedintnfdebugstructnf_bridge_info*nf_bridge这些变量被netfilter使用(防火墙代码),内核编译选项是“DeviceDrivers->Networkingsupport->Networkingoptions->Networkpacketfiltering”和两个子选项“Networkpacketfilteringdebugging”和“BridgedIP/ARPpacketsfiltering”2union{...}private这个联合结构被高性能并行接口(HIPPI)使用。相应的内核编译选项是“Device->Drivers->Networkingsupport->Networkdevicesupport->HIPPIdriversupport”3__u32tc_index__u32tc_verd__u32tc_classid这些变量被流量控制代码使用,内核编译选项是“DeviceDrivers->Networking->support->Networkingoptions->QoSand/orfairqueueing”和它的子选项“PacketclassifierAPI”4structsec_path*sp这个变量被IPSec协议用于跟踪传输的信息。5sk_buff管理和操作函数5.1缓冲区操作函数有很多函数,通常都比较短小而且简单,内核用这些函数操作sk_buff的成员变量或者sk_buff链表。首先来看分配和释放缓冲区的函数,然后是一些通过移动指针在缓冲区的头部或尾部预留空间的函数。如果你看过include/linux/skbuff.h和net/core/skbuff.c中的函数,你会发现,基本上每个函数都有两个版本,名字分别是do_something和__do_something。通常第一种函数是一个包装函数,它会在第二种函数的基础上增加合法性检查或者锁。一般来说,类似__do_something的函数不能被直接调用(除非满足特定的条件,比如说锁)。那些违反这条规则而直接引用这些函数的不良代码会最终被更正。各操作函数缓冲区与移动指针变化如图5所示。图5操作前与操作后指针变化图:(a)skb_put,(b)skb_push,(c)skb_pull,and(d)skb_reserve1unsignedchar*skb_put(structsk_buff*skb,unsignedintlen)在缓冲区的尾部空间扩充len字节数据区l,将tail指针下移,并增加skb的len值。data和tail之间的空间就是可以存放网络报文的空间。这个操作增加了可以存储网络报文的空间,但是增加不能使tail的值大于end的值,skb的len值大于truesize的值。2unsignedchar*skb_push(structsk_buff*skb,unsignedintlen)在缓冲区的头部空间扩充len字节的数据区。将data指针上移,并增加skb的len值。这个操作在存储空间的头部增加了一段可以存储网络报文的空间,但是增加不能使data的值小于head的值,skb的len值大于truesize的值。3unsignedchar*skb_pull(structsk_buff*skb,unsignedintlen)从缓冲区的数据区删除len字节,把腾出的内存归还给头部空间。将data指针下移,并减小skb的len值。这个操作使data指针指向下一层网络报文的头部。4voidskb_reserve(structsk_buff*skb,unsignedintlen)从空白缓冲区中分配len字节的数据区,通过减少尾部空间,增加一个空&sk_buff的首部空间,将data指针和tail指针同时下移。这个操作在存储空间的头部预留len长度的空隙。如果查看某个以太网设备驱动的收包函数(例如,drivers/net/3c59x.c中的vortex_rx),你就会发现它在分配缓冲区之后,在向缓冲区中填充数据之前,会调用下面的函数:由于以太网帧的头部长度是14个八位组,这个函数把缓冲区的头部指针向后移动了2个字节。这样,紧跟在以太网头部之后的IP头部在缓冲区中存储时就可以在16字节的边界上对齐。如图6所示。图6(a)skb_reserve开始前,(b)skb_reserve后(c)复制数据到缓冲区5.2发送tcp报文示例发送报文时,在不同协议层处理数据时,该数据要添加相应的协议头。因此,最高层添加数据和自身的协议头。alloc_skb用来申请一个sk_buff。skb_reserve用来创建头空间。skb_put用来创建用户数据空间,用户数据复制到sk->data指向的数据区。接下来使用skb_push是在用户数据的前面加上各层协议头。图7是发送tcp报文的整个过程示意图。1)当TCP发送数据时,它根据一些条件分配一个缓冲区(比如,TCP的最大分段长度(mss),是否支持散读散写I/O等2)TCP在缓冲区的头部预留足够的空间(用skb_reserve)用于填充各层的头部(如TCP,IP,链路层等)。MAX_TCP_HEADER参数是各层头部长度的总和,它考虑了最坏的情况:由于tcp层不知道将要用哪个接口发送包,它为每一层预留了最大的头部长度。它甚至考虑了出现多个IP头的可能性(如果内核编译支持IPoverIP,我们就会遇到多个IP头的情况)。3)把TCP的负载拷贝到缓冲区(用skb_put,复制数据)。需要注意的是:图7只是一个例子。TCP的负载可能会被组织成其他形式。例如它可以存储到分片中。4)TCP层添加自己的头部(用skb_push)。5)TCP层把缓冲区传递给IP层,IP层同样添加自己的头部(用skb_push)。6)IP层把缓冲区传递给邻居层,邻居层添加链路层头部(用skb_push)。Tcp报文发送过程如图6所示。接收报文时:当缓冲区在协议栈中向下层传递时,每一层都把skb->data指针向下移动,然后拷贝自己的头部,同时更新skb->len。图7tcp报文发送过程5.3缓冲区分配、克隆和释放函数分析1alloc_skballoc_skb是net/core/skbuff.c里面定义的,用于分配缓冲区的函数。我们已经知道,数据缓冲区和缓冲区的描述结构(sk_buff结构)是两种不同的实体,这就意味着,在分配一个缓冲区时,需要分配两块内存(一个是缓冲区,一个是缓冲区的描述结构sk_buff)。alloc_skb函数起始可以看作三部分,第一部分是从cache中分配内存,第二部分是初始化分配的skb的相关域。第三部分是处理fclone。1)分配内存首先调用函数kmem_cache_alloc从缓存中获取一个sk_buff结构,然后调用kmalloc_cachhe_alloc_node分配缓冲区(如果有缓存的话,它同样从缓存中获取内存)。2)初始化在调用kmalloc前,size参数通过SKB_DATA_ALIGN宏强制对齐。在函数返回前,它会初始化结构中的一些变量。3)处理fclone每次skb_clone一个skb的时候,都是要调用kmem_cache_alloc从cache中alloc一块新的内存。而现在当我们拥有了fastclone之后,通过调用alloc_skb_fclone函数来分配一块大于sizeof(structsk_buff)的内存,也就是在这次请求的skb的下方多申请了一些内存,然后返回的时候设置返回的skb的fclone标记为SKB_FCLONE_ORIG,而多申请的那块内存的sk_buff的fclone为SKB_FCLONE_UNAVAILABLE,这样当我们调用skb_clone克隆这个skb的时候看到fclone的标记就可以直接将skb的指针+1,而不需要从cache中取了。这样的话节省了一次内存存取,提高了clone的效率,不过调用flcone一般都是我们确定接下来这个skb会被clone很多次。4)skb指针状态alloc_skb之后的skb的指针的状态如图8所示。在图7右边所示的内存块的底部,可以能看到对齐操作所带来的填充区域(padding)。图8skb指针状态2克隆skb_clone如果一个缓冲区需要被不同的用户独立地操作,而这些用户可能会修改sk_buff中某些变量的值(比如h和nh值),内核没有必要为每个用户复制一份完整的sk_buff以及相应的缓冲区。相反,为提高性能,内核克隆一个缓冲区。克隆过程只复制sk_buff结构,同时修改缓冲区的引用计数以避免共享的数据被提前释放。克隆缓冲区使用skb_clone函数。一个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 小型仓储建设方案
- 农产品促销工作方案
- 数字乡村建设推动方案
- 浙江省杭州市杭州中学2025-2026学年下学期八年级阶段性综合练习数学试题(含答案)
- 深圳妇女儿童建设方案
- 2026年元宇宙商业模式分析方案
- 海水监测工作方案怎么写
- 地下电缆敷设施工方案
- 少年警队活动实施方案
- 经常性督导工作方案
- NCCN临床实践指南:睾丸癌(2025.v2)解读
- 中国糖尿病防治指南(2024版)课件
- 2025年电力系统智能调度平台建设项目可行性研究报告
- 曹妃甸职业技术学院教师招聘考试试题及答案
- 医院内消毒液的浓度及配置方法
- 河南省2025年普通高中学业水平合格性考试历史试卷及答案
- 项目安全员安全生产责任制
- 酒店行业卫生管理标准手册
- 2025年新疆辅警笔试试题含答案
- T/CFCA 0058-2024零嘌呤低醇配制酒
- 水电站检修安全培训课件
评论
0/150
提交评论