skbuff详解及功能分析.doc
《skbuff详解及功能分析.doc》由会员分享,可在线阅读,更多相关《skbuff详解及功能分析.doc(8页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流skbuff详解及功能分析.精品文档.sk_buffstruct sk_buff可能是linux网络代码中最重要的数据结构,它表示接收或发送数据包的包头信息,并包含很多成员变量供网络代码中的各子系统使用。这个结构被网络的不同层(MAC或者其他二层链路协议,三层的IP,四层的TCP或UDP等)使用,并且其中的成员变量在结构从一层向另一层传递时改变。 L4向L3传递前会添加一个L4的头部,同样,L3向L2传递前,会添加一个L3的头部。添加头部比在不同层之间拷贝数据的效率更高。由于在缓冲区的头部 添加数据意味着要修改指向缓冲区的指针,这是个复杂的操
2、作,所以内核提供了一个函数skb_reserve来完成这个功能。协议栈中的每一层在往下一层传 递缓冲区前,第一件事就是调用skb_reserve在缓冲区的头部给协议头预留一定的空间。 skb_reserve同样被设备驱动使用来对齐接收到包的包头。如果缓冲区向上层协议传递,旧的协议层的头部信息就没什么用了。例如,L2的头部只有在 网络驱动处理L2的协议时有用,L3是不会关心它的信息的。但是,内核并没有把L2的头部从缓冲区中删除,而是把有效荷载的指针指向L3的头部,这样做, 可以节省CPU时间。 有些sk_buff成员变量的作用是方便查找或者是连接数据结构本身。内核可以把sk_buff组织成一个双
3、向链表。当然,这个链表的结构要比常见的双向 链表的结构复杂一点。就像任何一个双向链表一样,sk_buff中有两个指针next和prev,其中,next指向下一个节点,而prev指向上一个节 点。在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点(作为sk_buff双向链表的头),它的定义如下:struct sk_buff_head struct sk_buff-*next; struct sk_buff-*prev; _u32 qlen; spinlock_t lock; qlen代表链表元素的个数 lock用于防止对链表的并发访问 sk_buff和sk_buff_he
4、ad的前两个元素是一样的:next和prev指针。这使得它们可以放到同一个链表中,尽管 sk_buff_head要比sk_buff小得多。另外,相同的函数可以同样应用于sk_buff和sk_buff_head。sk_buff-sk 这是一个指向拥有这个sk_buff的sock结构的指针。这个指针在网络包由本机发出或者由本机进程接收时有效,因为插口相关的信息被L4(TCP或 UDP)或者用户空间程序使用。如果sk_buff只在转发中使用(这意味着,源地址和目的地址都不是本机地址),这个指针是NULLsk_buff-len表示当前协议数据包的长度。它包括主缓冲区中的数据长度(data指针指向它)和
5、分片中的数据长度。sk_buff-data_len 和len不同,data_len只计算分片中数据的长度sk_buff-mac_len 这是mac头的长度sk_buff-users 这是一个引用计数,用于计算有多少实体引用了这个sk_buff缓冲区。它的主要用途是防止释放sk_buff后,还有其他实体引用这个sk_buff。 因此,每个引用这个缓冲区的实体都必须在适当的时候增加或减小这个变量。这个计数器只保护sk_buff结构本身,而缓冲区的数据部分由类似的计数器 (dataref)来保护.有时可以用atomic_inc和atomic_dec函数来直接增加或减小users,但是,通常还是使用函
6、数 skb_get和kfree_skb来操作这个变量。sk_buff-truesize 这是缓冲区的总长度,包括sk_buff结构和数据部分。如果申请一个len字节的缓冲区,alloc_skb函数会把它初始化成len+sizeof(sk_buff)。当skb-len变化时,这个变量也会变化。sk_buff-headsk_buff-datask_buff-tailsk_buff-end 它们表示缓冲区和数据部分的边界。在每一层申请缓冲区时,它会分配比协议头或协议数据大的空间。head和end指向缓冲区的头部和尾部,而data和 tail指向实际数据的头部和尾部。每一层会在head和data之间填
7、充协议头,或者在tail和end之间添加新的协议数据。数据部分会在尾部包含一 个附加的头部。void (*destructor)(struct sk_buff *skb) 这个函数指针可以初始化成一个在缓冲区释放时完成某些动作的函数。如果缓冲区不属于一个socket,这个函数指针通常是不会被赋值的。如果缓冲区属于一 个socket,这个函数指针会被赋值为sock_rfree或sock_wfree(分别由skb_set_owner_r或 skb_set_owner_w函数初始化)。这两个sock_xxx函数用于更新socket的队列中的内存容量。sk_buff-tstamp 这个变量只对接收到的
8、包有意义。它代表包接收时的时间戳,或者有时代表包准备发出时的时间戳。它在netif_rx里面由函数net_timestamp设置,而netif_rx是设备驱动收到一个包后调用的函数。 sk_buff-dev 这个变量的类型是net_device,net_device它代表一个网络设备。dev的作用与这个包是准备发出的包还是刚接收的包有关。当收到一个包 时,设备驱动会把sk_buff的dev指针指向收到这个包的网络设备;当一个包被发送时,这个变量代表将要发送这个包的设备。在发送网络包时设置这个值 的代码要比接收网络包时设置这个值的代码复杂。有些网络功能可以把多个网 络设备组成一个虚拟的网络设备(
9、也就是说,这些设备没有和物理设备直接关联),并由一个虚拟网络设备驱动管理。当虚拟设备被使用时,dev指针指向虚拟设 备的net_device结构。而虚拟设备驱动会在一组设备中选择一个设备并把dev指针修改为这个设备的net_device结构。因此,在某些情况 下,指向传输设备的指针会在包处理过程中被改变。sk_buff-input_dev 这是收到包的网络设备的指针。如果包是本地生成的,这个值为NULL。对以太网设备来说,这个值由eth_type_trans初始化,它主要被流量控制代码使用。sk_buff-hsk_buff-nhsk_buff-mac 这些是指向TCP/IP各层协议头的指针:h
10、指向L4(传输层),nh指向L3(网络层),mac指向L2(数据链路层)。每个指针的类型都是一个联合, 包含多个数据结构,每一个数据结构都表示内核在这一层可以解析的协议。例如,h是一个包含内核所能解析的L4协议的数据结构的联合。每一个联合都有一个 raw变量用于初始化,后续的访问都是通过协议相关的变量进行的。 当接收一个包时,处理n层协议头的函数从其下层(n-1层)收到一个缓冲区,它的skb-data指向n层协议的头。处理n层协议的函数把本层的 指针(例如,L3对应的是skb-nh指针)初始化为skb-data,因为这个指针(data指针)的值会在处理下一层协议时改变 (skb-data将被初
11、始化成缓冲区里的其他地址)。在处理n层协议的函数结束时,在把包传递给n+1层的处理函数前,它会把skb- data指针指向n层协议头的末尾,这正好是n+1层协议的协议头。 当网卡驱动程序收到一个UDP数据报后,它创建一个结构体struct sk_buff,确保sk_buff-data成员指向的空间足够存放收到的数据(对于数据报分片的情况,因为比较复杂,我们暂时忽略,我们假设 一次收到的是一个完整的UDP数据报)。把收到的数据全部拷贝到sk_buff-data指向的空间,然后,把skb-mac.raw指 向data,此时,数据报的开始位置是一个以太网头,所以skb-mac.raw指向链路层的以太
12、网头。然后通过调用skb_pull剥掉以太网 头,所谓剥掉以太网头,只是把data加上sizeof(struct ethhdr),同时len减去这个值,这样,在逻辑上,skb已经不包含以太网头了,但通过skb-mac.raw还能找到它。这就是我们通常 所说的,IP数据报被收到后,在链路层被剥去以太网头。sk_buff-dst 这个变量在路由子系统中使用sk_buff-sp 这个变量被IPSec协议用于跟踪传输的信息sk_buff-cb48 这是一个“control buffer”,或者说是一个私有信息的存储空间,由每一层自己维护并使用。它在分配sk_buff结构时分配(它目前的大小是48字节,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- skbuff 详解 功能分析
限制150内