77范文网 - 专业文章范例文档资料分享平台

sk_buff详解(4)

来源:网络收集 时间:2019-04-10 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

* The downside to this alignment of the IP header is that the DMA is now * unaligned. On some architectures the cost of an unaligned DMA is high * and this cost outweighs the gains made by aligning the IP header. *

* Since this trade off varies between architectures, we allow NET_IP_ALIGN * to be overridden. */

#ifndef NET_IP_ALIGN #define NET_IP_ALIGN #endif /*

* The networking layer reserves some headroom in skb data (via

* dev_alloc_skb). This is used to avoid having to reallocate skb data when * the header has to grow. In the default case, if the header has to grow * 16 bytes or less we avoid the reallocation. *

* Unfortunately this headroom changes the DMA alignment of the resulting * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive * on some architectures. An architecture can override this value, * perhaps setting it to a cacheline in size (since that will maintain * cacheline alignment of the DMA). It must be a power of 2. *

* Various parts of the networking layer expect at least 16 bytes of * headroom, you should not reduce this. */

#ifndef NET_SKB_PAD #define NET_SKB_PAD 16 #endif ?

netdev_alloc_skb和__netdev_alloc_skb:也是用于网卡驱动分配skb,与前面提到的dev_alloc_skb的区别在于:调用alloc_skb时多了一个numa node的判断,如下: static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, unsigned int length) { }

struct sk_buff *__netdev_alloc_skb(struct net_device *dev, {

unsigned int length, gfp_t gfp_mask)

return __netdev_alloc_skb(dev, length, GFP_ATOMIC);

2

int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; struct sk_buff *skb;

} ?

skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); if (likely(skb)) { skb_reserve(skb, NET_SKB_PAD); }

skb->dev = dev;

return skb;

sock_alloc_send_skb和sock_alloc_send_pskb:sock_alloc_send_skb是

sock_alloc_send_pskb的包装,一般在ip_output,af_unix, af_packet, raw.c,udp等处调用,我们主要关心skb的分配和初始化情况,socket相关的代码不作讨论: 1. 输入参数:

a) size:线性buffer的长度;(header_len)

b) data_len:paged data的长度;kernel里目前都是直接使用

sock_alloc_send_skb来调用sock_alloc_send_pskb,所以data_len = 0

2. skb分配过程:

a) 先调用alloc_skb,传入的size参数为header_len; b) 如果没有data_len,直接返回;否则 i. ii. iii.

根据data_len,获得page数目,赋给skb_shinfo(skb)->nr_frags; skb->truesize += data_len; 通过调用alloc_page分配paged data,除了最后一个frags之外,其他的frags->offset = 0; frags->size = PAGE_SIZE;最后一个的frags->size = data_len % PAGE_SIZE。

?

sk_stream_alloc_skb是sk_stream_alloc_pskb的包装,从名字上看,就是用于stream发送的时候分配skb,一般是在tcp层调用,下面三处调用sk_stream_alloc_pskb ? tso_fragment ?

tcp_sendmsg

? do_tcp_sendpages

下面两个调用sk_stream_alloc_skb ? tcp_fragment ? tcp_mtu_probe 下面分析代码: 1. 输入参数:

a) size:待发送的字节流长度;

b) mem:不知道干啥用的,看起来只是修改了skb->truesize,所有调用的地方

传递的值也都是0;

2. skb分配过程:

a) size + 根据sk->sk_proto算出来的最大头部长度(对于TCP,#define

MAX_TCP_HEADER (128 + MAX_HEADER))作为分配的skb里线性Buffer的长度;

b) 调用alloc_skb_fclone分配skb(因为很快就会被clone?) c) 调用skb_reserve,把头部空出来以备后用。

? sock_wmalloc:如果在发送一个很长的数据包,L4在处理的时候会为IP层的分片提前

做一些工作,比如将数据放置在一系列的skb中,一般调用sock_alloc_send_skb来创建这一系列skb中的第一个(可以参考ip_append_data),调用sock_wmalloc来分配剩下的分片skb。函数体本身很简单,如下:

struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, gfp_t priority) { }

if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {

struct sk_buff * skb = alloc_skb(size, priority); if (skb) { }

skb_set_owner_w(skb, sk); return skb;

}

return NULL;

skb释放

kfree_skb和__kfree_skb

kfree_skb()是__kfree_skb()的一个包装,首先检查skb的引用计数skb->users,为1才继续调用__kfree_skb(),否则只是skb->users - 1(原子操作)。

在kernel的协议栈代码中,很多地方都是先显式的调用atomic_inc(&skb->users);然后处理一堆内容后,调用kfree_skb,而不是调用atomic_dec(&skb->users)。这样做的好处是,可以在合适的地方尽快释放skb,并且可以让处理skb结构的代码逻辑更独立。(调用处理skb的函数之前可能增加过skb->users,也可能没有)

__kfree_skb()是真正释放skb的函数:先将skb结构里指向其他网络子系统的指针release或put,并且调用析构函数skb->destructor(),最后通过kfree_skbmem()来释放内存: ? 首先调用skb_release_data来处理线性buffer区域和paged_data(包括frag_list);

判断skb的Data Buffer区域可以被释放的条件是以下二者之一: ?

!skb->cloned:skb没有被clone(注意被clone的和clone生成的skb->cloned

都被置1,两个skb里的skb_shinfo(skb)->dataref都atomic_inc,见skb_clone的讨论),skb没被clone,说明数据区肯定只有唯一一个skb指向;

!atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1, &skb_shinfo(skb)->dataref) 对skb_shinfo(skb)->dataref进行判断:

? 如果nohdr被设置,代表dataref被分成两部分,前面SKB_DATAREF_SHIFT(16)

bit代表skb->data里的payload部分的引用计数;后面16bits代表整个

skb->data的引用计数。所以需要把dataref-(1 << SKB_DATAREF_SHIFT) + 1),来判断是否可以释放skb->data;

? nohdr没被设置,不需要把skb->data的payload单独考虑引用计数,只需要?

dataref-1来决定是否释放skb->data 释放Data Buffer分为三个部分:

?

? put_page释放“paged data”;

? skb_drop_fraglist,进而调用kfree_skb,来释放frag_list里的所有skb; ? kfree(skb->head),释放“线性Buffer”。

然后根据skb->fclone标志将skb结构本身归还slab cache。见fclone讨论部分

?

skb共享复制相关操作

skb_clone, skb_cloned, skb_header_cloned, skb_shared, skb_share_check, skb_unshare, skb_clone_fraglist, skb_copy, pskb_copy, skb_header_release

内核的网络子系统核心数据结构是sk_buff,同一个skb可能会被很多个子系统共享,同时使用或修改,出于性能的考虑,内核中提供了一系列对skb的共享和拷贝函数,网络子系统根据各自的需求来调用:

skb_share: 只读的共享需求

? ?

需要共享的地方调用:直接调用atomic_inc(skb->users),或者skb_get(); 判断是否被共享:skb_shared()

static inline int skb_shared(const struct sk_buff *skb) { return atomic_read(&skb->users) != 1; }

? ?

取消共享的地方调用:kfree_skb()(见kfree_skb一节的讨论) 对分片队列的共享:skb_clone_fraglist(),(pskb_expand_head()里用了),其实就是把skb队列里每一个skb的引用计数+1;然后在取消共享时,对队列里每一个skb调用kfree_skb()见减小引用计数。

static inline void skb_drop_fraglist(struct sk_buff *skb) { }

skb_drop_list(&skb_shinfo(skb)->frag_list);

static void skb_drop_list(struct sk_buff **listp) { }

struct sk_buff *list = *listp; *listp = NULL;

do { struct sk_buff *this = list;

list = list->next; kfree_skb(this);

} while (list);

static void skb_clone_fraglist(struct sk_buff *skb) { struct sk_buff *list; }

for (list = skb_shinfo(skb)->frag_list; list; list = list->next) skb_get(list);

skb_clone: 只修改sk_buff结构本身

?

需要共享的地方调用:skb_clone() i. 首先根据skb->fclone决定采用快速clone机制还是普通机制;

新分配的skb暂时不用和skb链表,socket关联,都设为NULL;

其他成员的值都copy,需要增加引用计数的也都使用XXX_get()处理;

新skb的users为1(与alloc_skb()一样),n->nohdr = 0, destructor = NULL; 新老skb的skb->cloned = 1;

新老skb指向的数据区是一样的(包括线性buffer和paged data,分片等),则需要把dataref+1:atomic_inc(&(skb_shinfo(skb)->dataref))(整个数据区的引用计数)

ii. iii. iv. v. vi.

?

判断是否被共享: ?

skb_cloned():返回1的条件为skb->cloned = 1并且dataref的低16bit部分(整个数据区的引用计数)不为1;

static inline int skb_cloned(const struct sk_buff *skb) {

return skb->cloned &&

(atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1;

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库sk_buff详解(4)在线全文阅读。

sk_buff详解(4).doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/zonghe/583952.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: