linux tcp ip 协议栈分析 pdf,linux tcpip协议栈分析.doc

62e50291a81fc54b507f33cb80033297.gif linux tcpip协议栈分析.doc

(22页)

fed4556243bcb4fcccb60d42974e48bf.png

本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!

14.9 积分

sk_buff结构可能是linux网络代码中最逍要的数据结构,它表示接收或发送数据包的包头信息。它在中定义,并包含很多成员变量供网络代码中的各子系统使用。这个结构在linux内核的发展过程屮改动过很多次,或者是增加新的选项,或者是乖新组织已存在的成员 变最以使得成员变最的布局更加清晰。它的成员变量可以大致分为以下几类:• Layout 布局• General 通用• Feature-specific 功能相关• Management functions 管理函数这个结构被不同的网络层(MAC或者其他二层链路协议,三层的IP,四层的TCP或UDP等)使用,并 且其中的成员变最在结构从一层向另一层传递时改变。L4向L3传递前会添加一个L4的头部,同样,L3 向L2传递前,会添加一个L3的头部。添加头部比在不同层之间拷贝数据的效率更高。山于在缓冲区的头 部添加数据意味着要修改指向缓冲区的指针,这是个复杂的操作,所以内核提供了一个函数skb.reserve (在后面的章节中描述)來完成这个功能。协议栈中的毎一层在往下一层传递缓冲区前,第一件申就是调 用skb_reserve在缓冲区的头部给协议头预留一定的空间。skb_reserve同样被设备驱动使用來对齐接收到包的包头。如果缓冲区向上层协议传递,I口的协议层的头 部信息就没什么用了。例如,L2的头部只有在网络驱动处理L2的协议时有用,L3是不会关心它的信息的。 但是,内核并没有把L2的头部从缓冲区中删除,而是把有效荷载的指针指向L3的头部,这样做,可以节 省CPU时间。1.网络参数和内核数据结构就像你在浏览TCP/1P规范或者配置内核时所看到的一样,网络代码提供了很多有用的功能,但是这些功 能并不是必须的,比如说,防火墙,多播,还有其他一些功能。大部分的功能都需要在内核数据结构中添 加自己的成员变量。因此,sk.buff里面包含了很多像# ifdef这样的预编译指令。例如,在sk_buff结构 的最后,你可以找到:struct skbuff {ttifdef CONFIG NET SCHEDu32 tc index;#ifdef C07FIG_NET_CLS_ACT u32 tcverd;u32 tc_classid;ttendifttendif}它表明.tcjndex只有在编译时定义了 CONFIG_NET_SCHED符号才有效。这个符号可以通过选择特 定的编译选项來定义(例如:"Device Drivers Networking supportNetworking options QoS and/or fair queueing")。这些编译选项可以山管理员通过make config來选择,或者通过一些自动安装T.具 來选择。前面的例子有两个恢套的选项:CONFIG_NET_CLS_ACT (包分类器)只有在选择支持“QoS and/or fair queueing"时才能生效。顺便提一下,QoS选项不能被编译成内核模块。原因就是,内核编译之后,山某个选项所控制的数据结构 是不能动态变化的。一毀來说,如果某个选项会修改内核数据结构(比如说,在sk_buff里面增加一个项tcjndex),那么,包含这个选项的组件就不能被编译成内核模块。你可能经常需要查找是哪个make config编译选项或者变种定义了某个# ifdef标记,以便理解内核中包 含的某段代码。在2.6内核中,最快的,查找它们之间关联关系的方法,就是査找分布在内核源代码树屮 的kconfig文件中是否定义了相应的符号(每个目录都有一个这样的文件)。在2.4 内核屮,你需要査看 Document at ion/Configure, help 文件。2. Layout Fields有些sk_buff成员变量的作用是方便查找或者是连接数据结构木身。内核可以把sk_buff组织成一个双向 链表。当然,这个链表的结构要比常见的双向链表的结构复杂一点。就像任何一个双向链表一样,sk_buff中有两个指针next和prev,其中,next指向下一个节点,而 prev指向上一个节点。但是,这个链表还有另一个需求:毎个sk_buff结构都必须能够很快找到链表头 节点。为了满足这个需求,在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点,它 的定义如下:struct sk buff head {/* These two members must be first・ */ struct sk buff *nex t;struct sk buff * prev; u32 qlen;spinl()ck_t lock;}; ~qlen代表链表元素的个数Jock用于防止对链表的并发访问。sk_buff和sk_buff_head的前两个元索是一样的:next和prev指针。这使得它们可以放到同一个链表 中,尽管sk_buff_head要比sk_buff小得多。另外,相同的函数可以同样应用于sk_buff和 sk_buff_heado为了使这个数据结构更灵活,每个sk_buff结构都包含一个指向sk_buff_head的指针。这个指针的名字 是list。图1会帮助你理解它们之间的关系。Figure 1. List of sk_buff elem entsstruct sk^buff^headne* 1nextnextnext■prev. 1prev--prevprevlistlist—Ibtlistsksksksk— ••・ •“••• •••••• ••••••struct sk buffstruct sk-buffstruct sk buffstruct sk^buff其他有趣的成员变量如下:struct sock * sk这是一个指向拥有这个sk_buff的sock结构的指针。这个指针在网络包山木机发出或者山木机进程接收 时有效,因为插口相关的信息被L4(TCP或UDP)或者用户空间程序使用。如呆sk_buff只在转发中使用(这 意味着,源地址和目的地址都不是本机地址),这个指针是NULL。unsigned int len这是缓冲区中数据部分的长度。它包括主缓冲区屮的数据长度(data指针指向它)和分片屮的数据长度。它 的值在缓冲区从一个层向另一个层传递时改变,因为往上层传递,旧的头部就没有用了,而往下层传递, 盂要添加本层的头部。len同样包含了协议头的长度。unsigned int data_len和len不同,datajen只计算分片中数据的长度。unsigned int mac_len这是mac头的长度。atomic_t users这是一个引用计数,用于计算有多少实体引用了这个sk_buff缓冲区。它的主要用途是。省略部分。s, fragjist和 frags用于存储IP分片。skb_is_nonlinear函数用于测试—个缓冲区是否是分片的,而skb_linearize 可以把分片纽合成一个单一的缓冲区。纽合分片涉及到数据拷贝,它将严重影响系统性能。有昨网卡碱件可以完成一些传统上山CPU完成的任务。故常见的例子就是计算L3和L4校验和。有些网 卡甚至可以维护L4协议的状态机。在下面的例子中,我们主要讨论TCP段卸载TCP segmentation offload,这些网卡实现了 TCP层的一部分功能。tso_size和tso_seqs就在这种情况下使用。需要注意的是:sk_buff +没有指向skb_shared_info结构的指针。如果要访问这个结构,就需要使用 skb_info宏,这个公简单地返冋end指针:#define skb shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))下面的语句展示了如何使用这个宏來增加结构屮的某个成员变量的值:skb_shi nfo(skb)->dataref++;2.1.5.5・ Cloning and copying buffers如果一个缓冲区需要被不同的用户独立地操作,而这些用户可能会修改sk_buff中某些变最的值(比如h 和nh值),内核没有必要为每个用户复制一份完整的sk_buff以及相应的缓冲区。相反,为提高性能,内 核克隆一个缓冲区。克隆过程只复制sk_buff结构,同时修改缓冲区的引用计数以避免共享的数据被提 前释放。克隆缓冲区使用skb_clone函数。一个使用包克隆的场景是:一个接收包的过程需要把这个包传递给多个接收者,例如包处理函数或者一个 或多个网络模块。被克隆的sk_buff不会放在任何链表屮,同时也不会有到socket的引用。原始的和克隆的sk_buff 4*的 skb-> cloned值都被置为1。克隆包的skb-> users值被置为1,这样,在释放时,可以先释放sk.buff 结构。同时,缓冲区的引用计数(dataref)增加1(因为有多个sk_buff结构指向它)。图9展示了克隆缓冲 区的例子。Figure 9. skb_clone functionheaddatatailendstruct sLbuffsk_shinfo(done)headroomVDATAtailroomdataref=2 n(_frag = 1 frags■page pdge^,offset=0 $ire=S1• • •struct skb^shared」nfo I• head• data• tail・end users =1struct sk^buffsk_$hinfo(skb)+ Cloneskb_cloned函数可以用來测试skb的克隆状态。图9展示了一个分片缓冲区的例子,这个缓冲区的一些数据保存在分片结构数组frags屮。skb_share_check用于检査引用计数skb-> users,如果users变量表明skb是被共亨的,则克隆一 个新的sk_buffo如果一个缓冲区被克隆了,这个缓冲区的内容就不能被修改。这就意味着,访问数据的函数没有必要加锁。 因此,当一个函数不仅要修改sk_buff,而且要修改缓冲区内容时,就需要同时复制缓冲区。在这种情况 下,程序员有两个选择。如果他知道所修改的数据在skb->start和skb・>end之间,他可以使用pskb_copy來复制这部分数据。如果他同时需要修改分片中的数据,他就必须使用 skb_copy。图 10 展示了 pskb_copy 和 skb_copy 的结果。skb_shared_info 结构也口1 以包含一个 sk_buff的链表(链表名称是frag」ist)。这个链表在pskb_copy和skb_copy中的处理方式与frags数 组的处理方式相同(图10忽略了 frag_list)。Figure 1 0. (a) pskb_copy function and (b) skb_copy function(a)$kb_shtnfo(skb)—>headroomDATAtailroomnrjrag$=1diarCT=1nrjrag$=1 diarCT=1 frags page page_oftset=0 size 二 SIhead data tail endd— $kb_shinfo(new)strud(b)fra®pagepage_oftset=0 size 二 SIDataI copied)v— skb_$hinfo(new)在决定克隆或复制一个缓冲区时,子系统的程序员不能预测其他内核组件(其他了系统)是否需要使用缓冲 区里的原始数据。内核是模块化的,它的状态变化是不可预测的,因此,每个子系统都不知道其他子系统 是如何操作缓冲区的。因此,内核程序员需要记录它们对缓冲区的修改,并且在修改缓冲区前,复制一个 新的缓冲区,以避免其他子系统在使用缓冲区的原始数据时出现错误。2.1.5.6. List management functions这些函数管理 sk_buff 的链表(也被称作队列)。在v include/linux/skbuff.h> 和v net/core/skbuff.c> 中有函数完整列表。以下是一些经常使用的函数:skb_queue_head_init初始化sk buff head结构,创建一个空队列。skb_queue_head, skb_queue_tail把一个缓冲区加入队列的头部或尾部。skb_dequeue, skb_dequeue_tail从队列的头部或尾部取F—个缓冲区。第一个函数的名字应该是skb_dequeue_head,以保持和其他函 数的名字风格一致。skb_queue_purge清空一个队列。skb_queue_walkRuns a loop on each element of a queue in turn.这些函数都是原子操作,它们必须先获取sk_buff_head屮的自旋锁,然后才能访问队列中的元素。否则, 它们有可能被其他异步的添加或删除操作打断,比如在定时器屮调用的函数,这将导致链表出现错误而使 得系统崩溃。因此,每个函数的实现都采用下面这种形式:static inline function name ( parameter_ 1 ist ){ - ~unsigned long flags;spin lock irqsave (...); function name ( parcimeter_ 1 ist ) spin unlock irqrestore (. < •);} ~ ~这些函数先获取锁,然后调用一个以两个下划线开头的同名函数(这个函数做具体的操作,而且不需要锁), 然后释放锁。 关 键 词: 分析 协议 linux tcpip

524d6daf746efaa52c3c71bbfe7ba172.gif  天天文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值