缓冲区的克隆和拷贝当一个缓冲区需要被特别处理时,可能需要修改sk_buff描述符的内容,但内核不需要完全拷贝sk_buff结构和相关联的数据缓冲区。为了提高效率,内核可以只克隆原始值,也就是拷贝sk_buff结构,然后增加数据缓冲区的引用计数,防止被释放。
当一个数据包需要被传输给多个接受者,如协议处理例程或多个网络分流器时,就需要使用数据包克隆技术。
sk_buff的克隆没有链接到任何表,而且也没有引用套接字的拥有者。skb->cloned字段在克隆的和原来的结构猪都设置为1.克隆的skb->users设置为1,但对数据缓冲区的引用计数会递增,因为又有一个sk_buff结构指向这个数据区。
skb_clone函数可用于检查一个skb缓冲区的克隆状态。
skb_share_check函数检查skb->users引用计数是否为1,当不为1时,则说明这个skb是共享的,克隆一个新的skb返回,同时将原来的skb引用计数减一。否则直接返回原来的skb。
当一个缓冲区被克隆是,数据区块的内容不能修改,因此访问该数据的代码不需要上锁机制。当若函数不仅需要修改sk_buff结构体的字段,还需要修改数据时,就必须连数据缓冲区一起克隆。这种情况有两种选择:若只需要修改skb->head和skb->end区域的数据内容,则可以使用pskb_copy只克隆这个区域。若需要修改分片数据块中的内容,则需要使用skb_copy将分片区域的数据一起克隆。在skb_shared_info结构中也可以包含一个sk_buff结构列表frag_list。
以下分别为pskb_copy和skb_copy函数的操作结果:
常见sk_buff元素队列的管理函数
skb_queue_head_init:对skb_buff_head队列头指针进行初始化
skb_queue_head、skb_queue_tail:把一个sk_buff添加到队列头或尾
skb_dequeue、skb_dequeue_tail:将一个sk_buff从队列头或尾移除
skb_queue_purge:把队列变为空队列
skb_queue_walk:遍历队列中的每个元素
这类函数必须以原子方式执行,所以会获取sk_buff_head队列头结构的自旋锁
- void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
- {
- unsigned long flags;
- spin_lock_irqsave(&list->lock, flags);
- __skb_queue_head(list, newsk);
- spin_unlock_irqrestore(&list->lock, flags);
- }
阅读(2914) | 评论(0) | 转发(1) |