分配SKB


1.alloc_skb()


alloc_skb()用来分配SKB。数据缓存区和SKB描述符是两个不同的实体,这就意味着,在分配一个SKB时,需要分配两块内存,一块是数据缓存区,一块是SKB描述符。__alloc_skb()调用kmem_cache_alloc_node()从高速缓存中获取一个sk_buff结构的空间,然后调用kmalloc_node_track_caller()分配数据缓存区。参数说明如下:


size,待分配SKB的线性存储区的长度。


gfp_mask,分配内存的方式,见表25-3。


fclone,预测是否会克隆,用于确定从哪个高速缓存中分配。

node,当支持NUMA(非均匀质存储结构)时,用于确定何种区域中分配SKB。

144 struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  
145                 int fclone, int node)  
146 {  
147     struct kmem_cache *cache;  
148     struct skb_shared_info *shinfo;  
149     struct sk_buff *skb;  
150     u8 *data;  
151  
152     cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;  
153  
154     /* Get the HEAD */  
155     skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);  
156     if (!skb)  
157         goto out;  
158  
159     /* Get the DATA. Size must match skb_add_mtu(). */  
160     size = SKB_DATA_ALIGN(size);  
161     data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),  
162             gfp_mask, node);  
163     if (!data)  
164         goto nodata;  
165  
166     memset(skb, 0, offsetof(struct sk_buff, truesize));  
167     skb->truesize = size + sizeof(struct sk_buff);  
168     atomic_set(&skb->users, 1);  
169     skb->head = data;  
170     skb->datadata = data;  
171     skb->tail = data;  
172     skb->end  = data + size;  
173     /* make sure we initialize shinfo sequentially */  
174     shinfo = skb_shinfo(skb);  
175     atomic_set(&shinfo->dataref, 1);  
176     shinfo->nr_frags  = 0;  
177     shinfo->gso_size = 0;  
178     shinfo->gso_segs = 0;  
179     shinfo->gso_type = 0;  
180     shinfo->ip6_frag_id = 0;  
181     shinfo->frag_list = NULL;  
182  
183     if (fclone) {  
184         struct sk_buff *child = skb + 1;  
185         atomic_t *fclone_ref = (atomic_t *) (child + 1);  
186  
187         skb->fclone = SKB_FCLONE_ORIG;  
188         atomic_set(fclone_ref, 1);  
189  
190         child->fclone = SKB_FCLONE_UNAVAILABLE;  
191     }  
192 out:  
193     return skb;  
194 nodata:  
195     kmem_cache_free(cache, skb);  
196     skb = NULL;  
197     goto out;  
198 }

152 根据参数fclone确定从哪个高速缓存中分配SKB。

155 调用kmem_cache_alloc_node()从选定的高速缓存中分配一个SKB。在此从分配标志中去除GFP_DMA,是为了不从DMA内存区域中分配SKB描述符,因为DMA内存区域比较小且有特定用途,没有必要用来分配SKB描述符。而后面分配数据缓存区时,就不会去掉GFP_DMA标志,因为很有可能数据缓存区就需要在DMA内存区域中分配,这样硬件可以直接进行DMA操作,参见161~162行。

160 在分配数据缓存区之前,强制对给定的数据缓存区大小size作对齐操作。

161-165 调用kmalloc_node_track_caller()分配数据缓存区,其长度为size和sizeof(struct skb_shared_info)之和,因为在缓存区尾部紧跟着一个skb_shared_info结构。

168-181 初始化新分配SKB描述符和skb_shared_info结构。

183-191 如果是skbuff_fclone_cache高速缓存中分配SKB描述符,则还需置父SKB描述符的fclone为SKB_FCLONE_ORIG,表示可以被克隆;同时将子SKB描述符的fclone成员置为SKB_FCLONE_UNAVAILABLE,表示该SKB还没有被创建出来;最后将引用计数置为1。

最后SKB结构如图3-13所示,在图右边所示的内存块中部,可以看到对齐操作所带来的填充区域。需要说明的是,__alloc_skb()一般不被直接调用,而是被封装函数调用,如__netdev_alloc_skb()、alloc_skb()、alloc_skb_fclone()等函数。


2.dev_alloc_skb()

dev_alloc_skb()也是一个缓存区分配函数,通常被设备驱动用在中断上下文中。这是一个alloc_skb()的封装函数,因为是在中断处理函数中被调用的,因此要求原子操作(GFP_ATOMIC)。

 
 
  1. 1124 static inline struct sk_buff *dev_alloc_skb(unsigned int length)  
  2. 1125 {  
  3. 1126     return __dev_alloc_skb(length, GFP_ATOMIC);  
  4. 1127 }  
  5. ... ...  
  6. 1103 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,  
  7. 1104                           gfp_t gfp_mask)  
  8. 1105 {  
  9. 1106     struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);  
  10. 1107     if (likely(skb))  
  11. 1108         skb_reserve(skb, NET_SKB_PAD);  
  12. 1109     return skb;  
  13. 1110 } 

1108 调用skb_reserve()在skb->head与skb->data之间预留NET_SKB_PAD个字节。NET_SKB_PAD的定义在skbuff.h中,其值为 16。这部分空间将被填入硬件帧头,如14B的以太网帧头。

1126 以GFP_ATOMIC为内存分配优先级,表示分配过程为原子操作,不能被中断。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值