#skb_buff的数据空间

#相关操作函数
对skb_buff结构体的相关操作,并不是直接修改相关数据,内核提供了一系列的函数用来操作此结构体

##skb_put
向后扩大数据区空间。headroom空间不变,tailroom空间降低,skb->data指针不变,skb->tail指针下移;

unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{/* 获取当前skb->tail */unsigned char *tmp = skb_tail_pointer(skb);/* 要求skb数据区必须为线性 */SKB_LINEAR_ASSERT(skb);/* skb尾部增加len字节 */skb->tail += len;/* skb数据总长度增加len字节 */skb->len  += len;/* 如果增加之后的tail > end ,则panic */if (unlikely(skb->tail > skb->end))skb_over_panic(skb, len, __builtin_return_address(0));//返回添加数据的第一个字节位置return tmp;}

##skb_push
向前扩大数据区空间。headroom空间降低,tailroom空间不变。skb->tail指针不变,skb->data指针上
移;

unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{/* 数据区data指针前移len字节 */skb->data -= len;/* 数据总长度增加len字节 */skb->len  += len;/* 添加数据长度溢出过header ,panic*/if (unlikely(skb->data<skb->head))skb_under_panic(skb, len, __builtin_return_address(0));/* 返回新的data指针 */return skb->data;}

##skb_pull
缩小数据区空间,headroom空间增大。tailroom空间不变,skb->data指针下移,skb->tail指针不变;

unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
{return skb_pull_inline(skb, len);
}

##skb_reserve
数据区不变,headroom空间增大,tailroom空间降低,skb->data和skb->tail同一时候下移;

static inline void skb_reserve(struct sk_buff *skb, int len){/* 数据区data指针增加len字节*/skb->data += len;/* 数据区tail指针增加len字节 */skb->tail += len;}

#skb_buff结构体相关
##kfree_skb
释放结构体空间

void kfree_skb(struct sk_buff *skb)
{  if (unlikely(!skb))  return;  if (likely(atomic_read(&skb->users) == 1))  smp_rmb();  else if (likely(!atomic_dec_and_test(&skb->users)))  return;  trace_kfree_skb(skb, __builtin_return_address(0));  __kfree_skb(skb);
}

##alloc_skb
该函数的作用是在上层协议要发送数据包的时候或网络设备准备接收数据包的时候会调用alloc_skb()函数分配sk_buff结构体

static inline struct sk_buff *alloc_skb(unsigned int size,  gfp_t priority)
{  return __alloc_skb(size, priority, 0, NUMA_NO_NODE);
}

该函数调用__alloc_skb函数,原型为:

struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  int fclone, int node)
{  struct kmem_cache *cache;  struct skb_shared_info *shinfo;  struct sk_buff *skb;  u8 *data;  cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;  /* Get the HEAD */  skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);//分配存储空间   if (!skb)  goto out;//分配失败,返回NULL   prefetchw(skb);  /* We do our best to align skb_shared_info on a separate cache * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives * aligned memory blocks, unless SLUB/SLAB debug is enabled. * Both skb->head and skb_shared_info are cache line aligned. */  size = SKB_DATA_ALIGN(size);//调整skb大小   size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));  data = kmalloc_node_track_caller(size, gfp_mask, node);//分配数据区   if (!data)  goto nodata;  /* kmalloc(size) might give us more room than requested. * Put skb_shared_info exactly at the end of allocated zone, * to allow max possible filling before reallocation. */  size = SKB_WITH_OVERHEAD(ksize(data));  prefetchw(data + size);  /* * Only clear those fields we need to clear, not those that we will * actually initialise below. Hence, don't put any more fields after * the tail pointer in struct sk_buff! */  //sk_buff结构体中最后6个属性不能改变位置,只能在最后   memset(skb, 0, offsetof(struct sk_buff, tail));//将sk_buff结构体中tail属性之前的属性清零   /* Account for allocated memory : skb + skb->head */  skb->truesize = SKB_TRUESIZE(size);//计算缓冲区的尺寸   atomic_set(&skb->users, 1);  //初始化数据区的指针   skb->head = data;  skb->data = data;  skb_reset_tail_pointer(skb);  skb->end = skb->tail + size;
#ifdef NET_SKBUFF_DATA_USES_OFFSET   skb->mac_header = ~0U;
#endif   /* make sure we initialize shinfo sequentially */  //初始化skb_shared_info   shinfo = skb_shinfo(skb);  memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));  atomic_set(&shinfo->dataref, 1);  kmemcheck_annotate_variable(shinfo->destructor_arg);  if (fclone) {  struct sk_buff *child = skb + 1;  atomic_t *fclone_ref = (atomic_t *) (child + 1);  kmemcheck_annotate_bitfield(child, flags1);  kmemcheck_annotate_bitfield(child, flags2);  skb->fclone = SKB_FCLONE_ORIG;  atomic_set(fclone_ref, 1);  child->fclone = SKB_FCLONE_UNAVAILABLE;  }
out:  return skb;
nodata:  kmem_cache_free(cache, skb);  skb = NULL;  goto out;
}

LINUX 中 SKB 的分配最终是由函数 :struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, int fclone, int node) 来完成.
SKB 可以分为 SKB 描述符与 SKB 数据区两个部分,其中描述符必须从 CACHE 中来分配 : 或者从skbuff_fclone_cache 中分配,或者从 skbuff_head_cache 中来分配.
如果从分配描述符失败,则直接反回 NULL,表示 SKB 分配失败.
SKB 描述符分配成功后,即可分配数据区.
在具体分配数据区之前首先要对数据区的长度进行 ALIGN 操作, 通过宏 SKB_DATA_ALIGN 来重新确定 size 大小. 然后调用 kmalloc 函数分配数据区 :
data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
需要注意的是数据区的大小是 SIZE 的大小加上 skb_shared_info 结构的大小.
数据区分配成功后,便对 SKB 描述符进行与此数据区相关的赋值操作 :
memset(skb, 0, offsetof(struct sk_buff, truesize));
skb->truesize = size + sizeof(struct sk_buff);
atomic_set(&skb->users, 1);
skb->head = data;
skb->data = data;
skb->tail = data;
skb->end = data + size;
需要主意的是, SKB 的 truesize 的大小并不包含 skb_shared_info 结构的大小. 另外,skb 的 end 成员指针也就事 skb_shared_info 结构的起始指针,系统用
一个宏 : skb_shinfo 来完成寻找 skb_shared_info 结构指针的操作.
最后,系统初始化 skb_shared_info 结构的成员变量 :
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->tso_size = 0;
skb_shinfo(skb)->tso_segs = 0;
skb_shinfo(skb)->frag_list = NULL;
skb_shinfo(skb)->ufo_size = 0;
skb_shinfo(skb)->ip6_frag_id = 0;
最后,返回 SKB 的指针.

内核中还有一些其他操作skb_buff结构体的函数,这里简单介绍了几个主要的,其他的如有使用到再回来补充

skb_buff操作相关推荐

  1. 关于大型网站技术演进的思考

    关于大型网站技术演进的思考(一)--存储的瓶颈(1) 前不久公司请来了位互联网界的技术大牛跟我们做了一次大型网站架构的培训,两天12个小时信息量非常大,知识的广度和难度也非常大,培训完后我很难完整理出 ...

  2. skb_buff协议头指针操作函数

    1 数据链路层 1.1 skb_mac_header skb_mac_header返回数据链路层协议头数据的地址 static inline unsigned char *skb_mac_header ...

  3. linux skb 结构和相关操作函数分析

    sk_buff是Linux网络中最核心的结构体,它用来管理和控制接收或发送数据包的信息.各层协议都依赖于sk_buff而存在.内核中sk_buff结构体在各层协议之间传输不是用拷贝sk_buff结构体 ...

  4. linux协议栈skb操作函数

    一. SKB_BUFF的基本概念 1. 一个完整的skb buff组成 (1) struct sk_buff--用于维护socket buffer状态和描述信息 (2) header data--独立 ...

  5. 使用JPA进行Update操作 @Query注解的用法,JPL

    使用jpa进行update操作有两种,第一种就是先查询,set,再进行save更新.这种做法过于繁杂,我只是要进行一个更新操作却变成了三步,所以我推荐使用第二种: @Modifying @Query( ...

  6. 使用JPA进行update操作时,报org.springframework.beans.factory.BeanCreationException: Error creating bean with

    使用JPA进行update操作时,报org.springframework.beans.factory.BeanCreationException: Error creating bean with ...

  7. 【golang程序包推荐分享】分享亿点点golang json操作及myJsonMarshal程序包开发的踩坑经历 :)

    目录[阅读时间:约5分钟] 一.概述 1.Json的作用 2.Go官方 encoding/json 包 3. golang json的主要操作 二.Json Marshal:将数据编码成json字符串 ...

  8. VScode的撤销操作的快捷键

    撤销刚才的操作:Ctrl+Z 恢复刚才的操作:Ctrl+Shift+Z

  9. python中排序英文单词怎么写_Python实现对文件进行单词划分并去重排序操作示例...

    本文实例讲述了Python实现对文件进行单词划分并去重排序操作.,具体如下: 文件名:test1.txt 文件内容: But soft what light through yonder window ...

  10. 提交表单自动刷新_Web自动化测试:元素的基础操作和浏览器基础操作

    上一节,我们了解了如何定位元素,其实也有涉及对于元素的操作,这一节我们就详细的介绍一下对于元素的操作和对于浏览器的一些操作 一.对于元素的基础操作: clear():清除输入框内的文本 send_ke ...

最新文章

  1. 201771010111李瑞红《面向对象的程序设计》第八周实验总结
  2. Quartz.NET在ASP.NET 中使用
  3. 图解Ubuntu 9.10 Alpha 6
  4. ASP.NET一般处理程序新建一个方法里使用context.Response.Write的解决方法
  5. chrome 适配调试_移动端适配
  6. ASP.NET中String.IndexOf 方法的使用
  7. boost的chrono模块线程时钟的测试程序
  8. 深入理解函数式编程之柯里化
  9. (硬 核)使用MySQL管理和查询数据 ( 入 门 须 知 ②)
  10. 游戏“外挂”?—— AI生成游戏最强攻略
  11. 关于Debug.exe
  12. 一个比较好的多人网络游戏菜单程序。
  13. 2020-12-08
  14. 泛微e9隐藏明细表_泛微Ecology权限整理大全相当全要点
  15. 永恒之蓝漏洞自查-MS17010漏洞自查与修复
  16. Python-xlsx转置,行转列,列转行
  17. Vue 自定义移动端的 滑动事件
  18. 20829-55-4,cyclo-(L-Trp-L-Trp),cyclo-L-tryptophan-L-tryptophan,cyclo(Trp-Trp)
  19. 极客学院 Android 系统体系教程
  20. c++常见面试问题总结

热门文章

  1. Opencv学习——LSD直线检测
  2. win10 下装win7
  3. contest14 CF160div2 oooxx oooxx ooooo
  4. Quarkus 初见
  5. (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  6. NLP-D23-cs224nkaggle房价预测复习chap5深度学习计算算法R2D7Unicorn
  7. linux csv乱码,CSV格式文件中文乱码问题解决
  8. 苹果基带坏了怎么办_「手机维修自学教程」苹果手机的基带逻辑码片读取技巧 保资料搬板...
  9. 什么时候做都不晚——十大大器晚成的人物
  10. Visual Studio Code 官方护眼主题绿豆沙颜色修改,让你的眼睛远离疲劳!