1,struct sk_buff数据结构

struct sk_buff{
//这两个结构必须放在最前面
struct sk_buff *next;
struct sk_buff *prev;
struct sk_buff_head *list; struct sock *sk; //指向所属的sock结构
ktime_t tstamp; //表示包接收的时间 /*
这个变量的类型是net_device,net_device它代表一个网络设备。dev的作用与这
个包是准备发出的包还是刚接收的包有关。当收到一个包时,设备驱动会把sk_buff
的dev指针指向收到这个包的网络设备;当一个包被发送时,这个变量代表将要发
送这个包的设备。在发送网络包时设置这个值的代码要比接收网络包时设置这个值
的代码复杂。有些网络功能可以把多个网 络设备组成一个虚拟的网络设备(也就是
说,这些设备没有和物理设备直接关联),并由一个虚拟网络设备驱动管理。当虚拟
设备被使用时,dev指针指向虚拟设 备的net_device结构。而虚拟设备驱动会在一
组设备中选择一个设备并把dev指针修改为这个设备的net_device结构。因此,在某
些情况 下,指向传输设备的指针会在包处理过程中被改变。
*/
struct net_device *dev;
struct dst_entry *dst;
struct sec_path *sp; union{//运输层的的头信息
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
struct igmphdr *igmph;
.......
unsigned char *raw;
}h; union{//网络层头信息
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
unsigned char *raw;
}nh; union{//链路层头信息
struct ethhdr *ethernet;
unsigned char *raw
} unsigned char cloned;//是否是克隆的 char cb[48]; .......
//这几个变量相当重要
unsigned char *head;
unsigned char *data;
unsigned char *tail;
unsigned char *end; ....... }

2,内核是如何维护sk_buff结构的,我们以一图明了:

由上图我们可以清晰的看到内核为何sk_buff结构

head:指针指向内存中已分配的用于存储网路数据的缓冲区起始地址,sk_buff和相关数据块在分配后,该指针的值就固定了。
data:指针指向对应当前协议层有效数据的起始地址。每个协议的有效数据含义不同。
tail:指向对应当前协议层有效数据负载的结尾地址,与data对应。
end:指向内存分配的数据缓冲区的结尾地址,与head指针对应。和head一样,sk_buff和相关数据块被分配后,end指针也就固定了

3,skb_buff的操作

Skb操作
1, skb_queue_empty检查队列是否为空
原型:int skb_queue_empty(struct sk_buff_head *list)
参数:list为队列的头
描述:如果队列为空返回真,否则返回假

2, skb_get引用缓冲区
原型:struct skb_buff* skb_get(struct sk_buff *skb)
参数:skb为要引用的缓冲区;
描述:对套接字缓冲区引用一次,返回指向缓冲区的指针

3, skb_free释放一个缓冲区
原型:void kree_skb(struct sk_buff *skb)
参数:skb为要释放的缓冲区
描述:删除一个缓冲区的引用,如果其引用计数变为0,则释放它

4, skb_cloned判断缓冲区是否是克隆的
原型:int skb_cloned(struct sk_buff *skb)
参数:skb为要检查的缓冲区
描述:如果以skb_clone标志来产生缓冲区,则返回真,否则返回假

5, skb_shared缓冲区是否是共享的
原型:int skb_shared(struct sk_buff *skb)
参数:skb为要检查的缓冲区
描述:如果有多于一个人引用这个缓冲区就返回真

6, skb_share_check检查缓冲区是否是共享的,如果是就克隆它
原型:struct sk_buff *skb_share_check(struct *skb,int pri)
参数:skb为要检查的缓冲区,pri为内存分配的优先级
描述:如果缓冲区的共享的,就克隆这个缓冲区,并把原来缓冲区的引用计数减一,返回新克隆的缓冲区,如果不是共享的,则返回原来的缓冲区,当从中断或者全局锁调用该函数时pri必须为GFP_ATOMIC,内存分配失败返回NULL

7, skb_unshare产生一个共享缓冲区的拷贝
原型:struct sk_buff *skb_unshare(struct sk_buff *skb,int pri);
参数:skb为要检查的缓冲区,pri为内存非配的优先级
描述:如果套接字缓冲区是克隆的,那么这个函数就创建一个新的数据数据拷贝,并把原来缓冲区的引用计数减一,返回因为计数为一的新拷贝,如果不是克隆的,就返回原来的缓冲区,当从中断或者全局锁调用该函数时,pri必须是GFP_ATOMIC,内存分配错误返回NULL

8, skb_queue_len获得队列的长度
原型:__u32 sk_queue_len(struct sk_buff_head *list)
参数:list为测量的链表

9, skb_queue_head,skb_que_tail将newsk添加到链表的首部/尾部
原型:void skb_queue_head/tail(struct sk_buff_head *list,
struct sk_buff *newsk)
参数:list为要使用的链表,newsk为要添加的缓冲区

下面是几个常用的,在此贴出源代码以便更好的理解


static inline void skb_reserve( struct sk_buff *skb , int len )
{
skb->data += len ;
skb->tail += len ;
} /**
* skb_put - add data to a buffer
* @skb : buffer to use
* @len : amount of data to add
*
* This function extends the used data area of the buffer. If this would
* exceed the total buffer size the kernel will panic. A pointer to the
* first byte of the extra data is returned.
*/ unsigned char *skb_put( struct sk_buff *skb , unsigned int len )
{
unsigned char *tmp = skb_tail_pointer(skb) ;
/* 如果存在非线性区,即data_len > 0 ,则报bug */
SKB_LINEAR_ASSERT(skb) ;
skb->tail += len ;
skb->len += len ;
if (unlikely(skb->tail > skb->end ))
skb_over_panic(skb , len , __builtin_return_address(0)) ;
return tmp ;
} /**
* skb_push - add data to the start of a buffer
* @skb : buffer to use
* @len : amount of data to add
*
* This function extends the used data area of the buffer at the buffer
* start. If this would exceed the total buffer headroom the kernel will
* panic. A pointer to the first byte of the extra data is returned.
*/ unsigned char *skb_push( struct sk_buff *skb , unsigned int len )
{
skb->data -= len ;
skb->len += len ;
if ( unlikely(skb->data < skb->head ) )
skb_under_panic(skb , len , __builtin_return_address(0)) ;
return skb->data ;
} /**
* skb_pull - remove data from the start of a buffer
* @skb : buffer to use
* @len : amount of data to remove
*
* This function removes data from the start of a buffer, returning the memory to
* the headroom. A pointer to the next data in the buffer is returned. Once the
* data has been pulled future pushes will overwrite the old data.
*/ unsigned char *skb_pull( struct sk_buff *skb , unsigned int len )
{
return skb_pull_inline(skb , len ) ;
} static inline unsigned char *skb_pull_inline(struct sk_buff *skb , unsigned int len)
{
return unlikely(len > skb->len ) ? NULL : __skb_pull(skb , len) ;
} static inline unsigned char *__skb_pull(struct sk_buff *skb , unsigned int len)
{
skb->len -= len ;
BUG_ON(skb->len < skb->data_len ) ;
return skb->data += len ;
}

linux内核skb操作的更多相关文章

  1. Linux内核 GPIO操作部分API

    内核中关于GPIO的操作API主要集中在<linux/of_gpio.h>和<linux/gpio.h>中,前者主要是GPIO直接与设备树相关的操作,在Linux 设备树操作A ...

  2. Linux 内核热插拔操作

    热插拔事件的实际控制是通过一套存储于 kset_hotplug_ops 结构的方法完成. struct kset_hotplug_ops { int (*filter)(struct kset *ks ...

  3. linux协议栈skb操作函数

  4. linux内核--中断处理程序

    一个设备的中断处理程序是它设备驱动程序的一部分--设备驱动程序是用于对设备进行管理的内核代码.中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断 ...

  5. 芯灵思Sinlinx A64开发板Linux内核定时器编程

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 Linux 内核定时器是内 ...

  6. 全志A33开发板Linux内核定时器编程

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...

  7. 芯灵思SinlinxA33开发板Linux内核定时器编程

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...

  8. Linux内核0.11体系结构 ——《Linux内核完全注释》笔记打卡

    0 总体介绍 一个完整的操作系统主要由4部分组成:硬件.操作系统内核.操作系统服务和用户应用程序,如图0.1所示.操作系统内核程序主要用于对硬件资源的抽象和访问调度. 图0.1 操作系统组成部分 内核 ...

  9. Linux内核调试的方式以及工具集锦【转】

    转自:https://blog.csdn.net/gatieme/article/details/68948080 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...

随机推荐

  1. 多线程编程 (1) -NSThread

    每个iOS应用程序都有个专门用来更新显示UI界面.处理用户触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将那 ...

  2. poj 3273 Monthly Expense (二分)

    //最大值最小 //天数的a[i]值是固定的 不能改变顺序 # include <algorithm> # include <string.h> # include <s ...

  3. Android开发----------- 手电筒改进版本号

    在之前的基础上 在 res 目录以下: 加入一个 drawable/local_me.xml localme_cml <selector xmlns:android="http://s ...

  4. Android Material Design带UI变化

    谷歌Matias Duarte称,"Material Design是漂亮和大胆的.由于干净的排版和布局简单且easy理解.内容才是焦点. 谷歌I/O 014开发人员大会上宣布全新的设计语言& ...

  5. C# ASP.NET CSV文件导入数据库

    原文:C# ASP.NET CSV文件导入数据库 using System; using System.Collections.Generic; using System.Text; using Sy ...

  6. Installshield在安装结束时刷新系统

    原文:Installshield在安装结束时刷新系统 在OnEnd里添加代码,两种解决方案 群友kevin的解决方案 #include "ifx.h"  //Call to Win ...

  7. 快速构建Windows 8风格应用19-基础控件II

    原文:快速构建Windows 8风格应用19-基础控件II 本篇博文接着上篇博文<快速构建Windows 8风格应用18-基础控件I>介绍开发Windows 8风格应用中常用控件. Sli ...

  8. VS2015集成新潮工具4

    VS2015集成新潮工具(四)   本课程来源与微软connect视频教程,Modern Web Tooling in Visual Studio 2015 本课程主要讲下当下流行的前端工具 bowe ...

  9. 在PHP中如何连接到数据库

    首先我们先运行WampServer中的phpMyAdmin随即弹出phpMyAdmin页面   在弹出的页面中左边是数据库列表  右边是相应的设置 选择一个数据库  在里面创建一张数据表  注意创建数 ...

  10. Varnish缓存服务

    Varnish缓存服务详解及应用实现   1.varnish的基本介绍   Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已 ...