首页
登录 | 注册

网络子系统23_skb常用函数

http://blog.csdn.net/nerdx/article/details/12209043
[cpp] view plaincopy
  1. //分配新的skb->data,将旧的skb->data、skb_shinfo(skb)->frags、skb_shinfo(skb)->frag_list中的内容拷贝到新skb->data的连续内存空间中,释放frags或frag_list  
  2. //其中frags用于支持分散聚集IO,frags_list用于支持数据分片  
  3. 1.1 int __skb_linearize(struct sk_buff *skb, int gfp_mask)  
  4. {  
  5.     unsigned int size;  
  6.     u8 *data;  
  7.     long offset;  
  8.     struct skb_shared_info *ninfo;  
  9.     int headerlen = skb->data - skb->head;  
  10.     int expand = (skb->tail + skb->data_len) - skb->end;  
  11.     //如果此skb被共享  
  12.     if (skb_shared(skb))  
  13.         BUG();//产生BUG oops  
  14.   
  15.     //还需要的内存大小  
  16.     if (expand <= 0)  
  17.         expand = 0;  
  18.     //新申请的skb的大小  
  19.     size = skb->end - skb->head + expand;  
  20.     //将size对齐到SMP_CACHE_BYTES  
  21.     size = SKB_DATA_ALIGN(size);  
  22.     //分配物理上联系的内存  
  23.     data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);  
  24.     if (!data)  
  25.         return -ENOMEM;  
  26.     //拷贝  
  27.     if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))  
  28.         BUG();  
  29.   
  30.     //初始化skb的skb_shared_info结构  
  31.     ninfo = (struct skb_shared_info*)(data + size);  
  32.     atomic_set(&ninfo->dataref, 1);  
  33.     ninfo->tso_size = skb_shinfo(skb)->tso_size;  
  34.     ninfo->tso_segs = skb_shinfo(skb)->tso_segs;  
  35.     //fraglist为NULL  
  36.     ninfo->nr_frags = 0;  
  37.     ninfo->frag_list = NULL;  
  38.   
  39.     offset = data - skb->head;  
  40.   
  41.     //释放之前skb的data  
  42.     skb_release_data(skb);  
  43.   
  44.     //将skb指向新的data  
  45.     skb->head = data;  
  46.     skb->end  = data + size;  
  47.     //重新初始化新skb的各个报头指针  
  48.     skb->h.raw   += offset;  
  49.     skb->nh.raw  += offset;  
  50.     skb->mac.raw += offset;  
  51.     skb->tail    += offset;  
  52.     skb->data    += offset;  
  53.   
  54.     skb->cloned    = 0;  
  55.   
  56.     skb->tail     += skb->data_len;  
  57.     skb->data_len  = 0;  
  58.     return 0;  
  59. }  
  60.   
  61. 1.2 SKB_DATA_ALIGN(X)   (((X) + (SMP_CACHE_BYTES - 1)) & \  
  62.                  ~(SMP_CACHE_BYTES - 1))  
  63.   
  64. //将skb中起始offset的内容拷贝到to中,拷贝长度为len  
  65. 1.3 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)  
  66. {  
  67.     int i, copy;  
  68.     //skb->len-skb->data_len,得到skb->head到skb->end之间的数据量  
  69.     int start = skb_headlen(skb);  
  70.     //偏移量+len > skb->len,说明可供拷贝的数据量不够  
  71.     if (offset > (int)skb->len - len)  
  72.         goto fault;  
  73.     //计算需要拷贝的数据量  
  74.     if ((copy = start - offset) > 0) {  
  75.         if (copy > len)  
  76.             copy = len;  
  77.         //拷贝  
  78.         memcpy(to, skb->data + offset, copy);  
  79.         if ((len -= copy) == 0)//拷贝量=需要拷贝的长度  
  80.             return 0;  
  81.         offset += copy;//更新偏移量  
  82.         to     += copy;  
  83.     }  
  84.     //接下来的数据从skb_shinfo的frags数组中进行拷贝  
  85.     for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {  
  86.         int end;  
  87.   
  88.         //遍历frags  
  89.         end = start + skb_shinfo(skb)->frags[i].size;  
  90.         if ((copy = end - offset) > 0) {  
  91.             u8 *vaddr;  
  92.   
  93.             if (copy > len)  
  94.                 copy = len;  
  95.             //映射skb的frag到内核地址空间  
  96.             vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);  
  97.             //拷贝  
  98.             memcpy(to,  
  99.                    vaddr + skb_shinfo(skb)->frags[i].page_offset+  
  100.                    offset - start, copy);  
  101.             //解除映射  
  102.             kunmap_skb_frag(vaddr);  
  103.   
  104.             if ((len -= copy) == 0)  
  105.                 return 0;  
  106.             offset += copy;  
  107.             to     += copy;  
  108.         }  
  109.         start = end;  
  110.     }  
  111.     //从skb的frag_list中拷贝  
  112.     if (skb_shinfo(skb)->frag_list) {  
  113.         struct sk_buff *list = skb_shinfo(skb)->frag_list;  
  114.   
  115.         for (; list; list = list->next) {  
  116.             int end;  
  117.   
  118.             BUG_TRAP(start <= offset + len);  
  119.   
  120.             end = start + list->len;  
  121.             if ((copy = end - offset) > 0) {  
  122.                 if (copy > len)  
  123.                     copy = len;  
  124.                 //递归调用  
  125.                 if (skb_copy_bits(list, offset - start,  
  126.                           to, copy))  
  127.                     goto fault;  
  128.                 if ((len -= copy) == 0)  
  129.                     return 0;  
  130.                 offset += copy;  
  131.                 to     += copy;  
  132.             }  
  133.             start = end;  
  134.         }  
  135.     }  
  136.     if (!len)  
  137.         return 0;  
  138.   
  139. fault:  
  140.     return -EFAULT;  
  141. }  




[cpp] view plaincopy
  1. //保证skb->data 到 skb->tail之间有len长度的数据  
  2. 2.1 static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)  
  3. {  
  4.     //skb->data 到 skb->tail之间的数据足够len长度  
  5.     if (likely(len <= skb_headlen(skb)))  
  6.         return 1;  
  7.     //len长度超过skb总长度  
  8.     if (unlikely(len > skb->len))  
  9.         return 0;  
  10.     //移动后边的数据到skb->data中  
  11.     return __pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL;  
  12. }  
  13.   
  14. //调用流程pskb_may_pull->__pskb_pull_tail  
  15. //delta为需要从frags或者frag_list向前移动的数据量  
  16. 2.2 unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)  
  17. {   //eat为去除当前skb可用内存,还需要多少内存  
  18.     int i, k, eat = (skb->tail + delta) - skb->end;  
  19.     //判断当前skb是否被克隆  
  20.     if (eat > 0 || skb_cloned(skb)) {  
  21.         //对sk_buff重新分配头  
  22.         if (pskb_expand_head(skb, 0, eat > 0 ? eat + 128 : 0,  
  23.                      GFP_ATOMIC))  
  24.             return NULL;  
  25.     }  
  26.     //从skb的offset(skb->tail),拷贝delta个字节到skb->tail之后  
  27.     if (skb_copy_bits(skb, skb_headlen(skb), skb->tail, delta))  
  28.         BUG();  
  29.     //没有分段  
  30.     if (!skb_shinfo(skb)->frag_list)  
  31.         goto pull_pages;  
  32.     //由于数据已经拷贝到了skb->data中,因此需要释放frags,frag_list中被拷贝过的数据  
  33.     //计算从frags数组中拷贝的数据量  
  34.     eat = delta;  
  35.     for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {  
  36.         //寻找到满足eat这么多数据量的最后一个page  
  37.         if (skb_shinfo(skb)->frags[i].size >= eat)  
  38.             //在frags数组中的数据量可以满足delta时,则只释放frags即可  
  39.             goto pull_pages;  
  40.         eat -= skb_shinfo(skb)->frags[i].size;  
  41.     }  
  42.     //eat仍不为0,说明从frag_list中进行了拷贝,释放frag_list  
  43.     if (eat) {  
  44.         struct sk_buff *list = skb_shinfo(skb)->frag_list;  
  45.         struct sk_buff *clone = NULL;  
  46.         struct sk_buff *insp = NULL;  
  47.   
  48.         do {  
  49.             //list为null,说明数据量不够  
  50.             if (!list)  
  51.                 BUG();  
  52.             //当前skb的长度小于需要的长度  
  53.             if (list->len <= eat) {  
  54.                 //找到下一个skb  
  55.                 eat -= list->len;  
  56.                 //list指向下一个需要的skb  
  57.                 list = list->next;  
  58.                 //insp指向当前的skb  
  59.                 insp = list;  
  60.             } else {  
  61.                 //此时insp指向前一个skb  
  62.                 //说明当前skb可以满足需要的数据量  
  63.                 if (skb_shared(list)) {//但是当前skb被共享  
  64.                     clone = skb_clone(list, GFP_ATOMIC);//对最后那个拷贝不完全的skb,进行克隆  
  65.                     if (!clone)  
  66.                         return NULL;  
  67.                     //list指向当前被克隆的的skb  
  68.                     //insp指向下一个skb  
  69.                     insp = list->next;  
  70.                     list = clone;  
  71.                 } else {  
  72.                     //list与insp指向当前的skb  
  73.                     insp = list;  
  74.                 }  
  75.                 //修改最后一个skb,移动指针,删除掉被拷贝的数据  
  76.                 if (!pskb_pull(list, eat)) {  
  77.                     if (clone)  
  78.                         kfree_skb(clone);//递减clone的引用计数  
  79.                     return NULL;  
  80.                 }  
  81.                 break;  
  82.             }  
  83.         } while (eat);  
  84.         //list指向frag_list头  
  85.         //直到list遍历到数据量足够的最后一个skb  
  86.         while ((list = skb_shinfo(skb)->frag_list) != insp) {  
  87.             skb_shinfo(skb)->frag_list = list->next;  
  88.             //释放当前的skb  
  89.             kfree_skb(list);//递减当前skb的引用技术,如果引用计数=0,则释放list  
  90.         }  
  91.         //说明最后一个skb只被拷贝了一部分,将此skb挂到frag_list头  
  92.         if (clone) {  
  93.             clone->next = list;  
  94.             skb_shinfo(skb)->frag_list = clone;  
  95.         }  
  96.     }  
  97.   
  98. pull_pages:  
  99.     eat = delta;  
  100.     k = 0;  
  101.     //释放frags中的page  
  102.     for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {  
  103.         if (skb_shinfo(skb)->frags[i].size <= eat) {  
  104.             put_page(skb_shinfo(skb)->frags[i].page);  
  105.             eat -= skb_shinfo(skb)->frags[i].size;  
  106.         } else {  
  107.             skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];  
  108.             if (eat) {  
  109.                 skb_shinfo(skb)->frags[k].page_offset += eat;  
  110.                 skb_shinfo(skb)->frags[k].size -= eat;  
  111.                 eat = 0;  
  112.             }  
  113.             k++;  
  114.         }  
  115.     }  
  116.     skb_shinfo(skb)->nr_frags = k;  
  117.   
  118.     skb->tail     += delta;  
  119.     skb->data_len -= delta;  
  120.   
  121.     return skb->tail;  
  122. }  

[cpp] view plaincopy
  1. //skb->users指定skb被引用的个数  
  2. 3.1 static inline int skb_shared(const struct sk_buff *skb)  
  3. {  
  4.     return atomic_read(&skb->users) != 1;  
  5. }  

相关文章

  •         两个重要概念:         1.临界区         2.原子         信号量:睡眠锁         自旋锁:忙等待         阻塞:就是指在执行设备操作时若不能获得资源则挂起操作,直到满足可操作的条件 ...
  • Google Inception Net,ILSVRC 2014比赛第一名.控制计算量.参数量,分类性能非常好.V1,top-5错误率6.67%,22层,15亿次浮点运算,500万参数(AlexNet 6000万).V1降低参数量目的,参数 ...
  • 内建函数,顾名思义,就是编译器内部实现的函数.这些函数跟关键字一样,可以直接使用,无须像标准库函数那样,要 #include 对应的头文件才能使用. 用来处理变长参数列表: 用来处理程序运行异常: 程序的编译优化.性能优化: 查看函数运行中 ...
  •          lua语言作为苹果iOS系统支持的一种编程语言,同时常见于游戏脚本(比如冰封王座等),也常用与嵌入式系统(OpenWRT堪称经典),但是Lua语言自身却缺少一些实用的,或者说是常用的函数,这里根据经验编写和总结了一些实用函 ...
  • Node.js 回调函数 Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数. ...
  • FFmpeg使用手册 - FFmpeg 的常用命令-T
    ffmpeg在做音视频编解码时非常方便,所以很多场景下转码使用的是ffmpeg,铜鼓通过ffmpeg –help命令操作可以看到ffmpeg常见的命令大概分为六部分: 1. ffmpeg信息查询部分 2. 公共做操参数部分 3. 文件主要操 ...

2020 unjeep.com webmaster#unjeep.com
12 q. 0.014 s.
京ICP备10005923号