sk_buff是Linux网络协议栈最重要的数据结构之一,该数据结构贯穿于整个数据包处理的流程。由于协议采用分层结构,上层向下层传递数据时需要增加包头,下层向上层数据时又需要去掉包头。sk_buff中保存了L2,L3,L4层的头指针,这样在层传递时只需要对数据缓冲区改变头部信息,并调整sk_buff中的指针,而不需要拷贝数据,这样大大减少了内存拷贝的需要。

/** *    struct sk_buff - socket buffer* @next: Next buffer in list*    @prev: Previous buffer in list*    @tstamp: Time we arrived*  @sk: Socket we are owned by*   @dev: Device we arrived on/are leaving by* @cb: Control buffer. Free for use by every layer. Put private vars here*   @_skb_refdst: destination entry (with norefcount bit)* @sp: the security path, used for xfrm* @len: Length of actual data*   @data_len: Data length*    @mac_len: Length of link layer header* @hdr_len: writable header length of cloned skb*    @csum: Checksum (must include start/offset pair)*  @csum_start: Offset from skb->head where checksumming should start* @csum_offset: Offset from csum_start where checksum should be stored*  @priority: Packet queueing priority*   @local_df: allow local fragmentation*  @cloned: Head may be cloned (check refcnt to be sure)* @ip_summed: Driver fed us an IP checksum*  @nohdr: Payload reference only, must not modify header*    @nfctinfo: Relationship of this skb to the connection* @pkt_type: Packet class*   @fclone: skbuff clone status*  @ipvs_property: skbuff is owned by ipvs*   @peeked: this packet has been seen already, so stats have been*        done for it, don't do them again*  @nf_trace: netfilter packet trace flag*    @protocol: Packet protocol from driver*    @destructor: Destruct function*    @nfct: Associated connection, if any*  @nfct_reasm: netfilter conntrack re-assembly pointer*  @nf_bridge: Saved data about a bridged frame - see br_netfilter.c* @skb_iif: ifindex of device we arrived on* @tc_index: Traffic control index*  @tc_verd: traffic control verdict* @rxhash: the packet hash computed on receive*  @queue_mapping: Queue mapping for multiqueue devices*  @ndisc_nodetype: router type (from link layer)*    @ooo_okay: allow the mapping of a socket to a queue to be changed* @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport*        ports.* @wifi_acked_valid: wifi_acked was set* @wifi_acked: whether frame was acked on wifi or not*   @no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS*   @dma_cookie: a cookie to one of several possible DMA operations*       done by skb DMA functions*  @secmark: security marking*    @mark: Generic packet mark*    @dropcount: total number of sk_receive_queue overflows*    @vlan_tci: vlan tag control information*   @inner_transport_header: Inner transport layer header (encapsulation)* @inner_network_header: Network layer header (encapsulation)*   @transport_header: Transport layer header* @network_header: Network layer header* @mac_header: Link layer header*    @tail: Tail pointer*   @end: End pointer* @head: Head of buffer* @data: Data head pointer*  @truesize: Buffer size*    @users: User count - see {datagram,tcp}.c*/struct sk_buff {/* These two members must be first. */struct sk_buff        *next;struct sk_buff        *prev;ktime_t           tstamp;struct sock      *sk;struct net_device   *dev;/** This is the control buffer. It is free to use for every* layer. Please put your private variables there. If you* want to keep them across layers you have to do a skb_clone()* first. This is owned by whoever has the skb queued ATM.*/char           cb[48] __aligned(8);unsigned long       _skb_refdst;
#ifdef CONFIG_XFRMstruct    sec_path    *sp;
#endifunsigned int      len,data_len;__u16          mac_len,hdr_len;union {__wsum       csum;struct {__u16  csum_start;__u16    csum_offset;};};__u32           priority;kmemcheck_bitfield_begin(flags1);__u8          local_df:1,cloned:1,ip_summed:2,nohdr:1,nfctinfo:3;__u8         pkt_type:3,fclone:2,ipvs_property:1,peeked:1,nf_trace:1;kmemcheck_bitfield_end(flags1);__be16           protocol;void           (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)struct nf_conntrack  *nfct;
#endif
#ifdef NET_SKBUFF_NF_DEFRAG_NEEDEDstruct sk_buff        *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTERstruct nf_bridge_info *nf_bridge;
#endifint           skb_iif;__u32           rxhash;__u16            vlan_tci;#ifdef CONFIG_NET_SCHED__u16           tc_index;   /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT__u16          tc_verd;    /* traffic control verdict */
#endif
#endif__u16         queue_mapping;kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE__u8           ndisc_nodetype:2;
#endif__u8          pfmemalloc:1;__u8           ooo_okay:1;__u8         l4_rxhash:1;__u8            wifi_acked_valid:1;__u8         wifi_acked:1;__u8           no_fcs:1;__u8           head_frag:1;/* Encapsulation protocol and NIC drivers should use* this flag to indicate to each other if the skb contains* encapsulated packet or not and maybe use the inner packet* headers if needed*/__u8           encapsulation:1;/* 7/9 bit hole (depending on ndisc_nodetype presence) */kmemcheck_bitfield_end(flags2);#ifdef CONFIG_NET_DMAdma_cookie_t       dma_cookie;
#endif
#ifdef CONFIG_NETWORK_SECMARK__u32          secmark;
#endifunion {__u32      mark;__u32      dropcount;__u32     reserved_tailroom;};sk_buff_data_t      inner_transport_header;sk_buff_data_t       inner_network_header;sk_buff_data_t     transport_header;sk_buff_data_t     network_header;sk_buff_data_t       mac_header;/* These elements must be at the end, see alloc_skb() for details.  */sk_buff_data_t     tail;sk_buff_data_t     end;unsigned char       *head,*data;unsigned int        truesize;atomic_t       users;
};

struct sk_buff {//介绍 
    struct sk_buff *next *prev;//双向链表指针
    ktime_t tstamp ;//时间撮
    struct sock *sk;   //对应于传输层,标示属于哪个socket ?
    struct net_device *dev;    //数据来自或者发送自哪个设备
    char cb[48];//控制信息buffer,在每个层都可以用,并且目前为止足够大
    int len;      实际总长度
    int data_len; 数据的长度 //也许是paged的data 
    __u16 mac_len; 数据链路层头的长度
    __u16 hdr_len; writable header length of cloned skb 
    
     sk_buff_data_t   transport_header;   传输层头指针
    sk_buff_data_t   network_header;    网络层头指针
    sk_buff_data_t   mac_header;        数据链路层头

unsigned char *head; //buffer 头
    unsigned char *data; 数据头
    sk_buff_data_t tail; 数据结尾
    sk_buff_data_t end;  buffer 结尾
    unsigned int truesize; //bufffer 大小

cloned 是不是cloned
    mark 数据包mark
    destructor 销毁函数指针 
    pkt_type : 根据二层头确定的包信息
    __be16 protocol : 三层协议 IP ARP 等,用于和全局数组qtype_base中的数据对比,该数组可以通过dev_add_pack()注册.
}

由于该结构将用于各个层,内核提供了一系列的sk_buff的操作函数
skb_put()  减小tailroom,buffer下后扩展
skb_push() 减小headroom,buffer向上扩张 
skb_trim() cut buffer到一个长度
skb_pull   从数据头cut一定长度的数据 
skb_reserve 增大headroom,减少tailroom,只能用于buffer为空时
skb_headroom headroom的大小
skb_tailroom tailroom的太小

alloc_skb() 分配一个sk_buff结构及buffer区域
kfree_slb() reference 减一,并且free skb和buffer如果不再有引用

dev_alloc_skb() 方便接收数据的sk_buff的分配函数
dev_free_skb()

skb_shinfo() 获得和sk_buff 一块分配的struct skb_shared_info

skb_clone() //复制sk_buff ,但是buffer不变 
pskb_copy()  //拷贝sk_buff和私有的头部,常用于需要修改sk_buff的头部时
skb_copy() //完全拷贝

skb_queue_head_init()
skb_queue_head()
skb_queue_tail()
skb_dequeue_head()
skb_dequeue_tail()
skb_queue_purge() //list 清空

skb_queue_walk() //遍历list用

在Linux2.6中,struct sk_buf承担了socket的输入输出的传输缓存的任务。
首先,还是先看struct socket的定义

/**
 * struct socket - general BSD socket
 * @state: socket state (%SS_CONNECTED, etc)
 * @type: socket type (%SOCK_STREAM, etc)
 * @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
 * @ops: protocol specific socket operations
 * @file: File back pointer for gc
 * @sk: internal networking protocol agnostic socket representation
 * @wq: wait queue for several uses
 */
struct socket {
    socket_state        state;

kmemcheck_bitfield_begin(type);
    short            type;
    kmemcheck_bitfield_end(type);

unsigned long        flags;

struct socket_wq    *wq;

struct file        *file;
    struct sock        *sk;
    const struct proto_ops    *ops;
};

代码中的注释对于每一个变量说的都很清楚——看到这里,我先感叹一下,linux2.6的结构体的注释比老版本要清楚的多。到目前为止,我所看到的关键的结构体,都有清晰的注释。我们可以看出struct socket中的sock变量,是socket变量的工作核心。

那么现在跳转到struct sock的定义处。由于struct sock的定义过长,所以只展示一部分。

struct sock {
    /*
     * Now struct inet_timewait_sock also uses sock_common, so please just
     * don't add nothing before this first member (__sk_common) --acme
     */
    struct sock_common    __sk_common;
    /* skip some codes */
    int sk_rcvbuf;
    /* skip some codes */
    int sk_sndbuf;
    struct sk_buff_head    sk_receive_queue;
    struct sk_buff_head    sk_write_queue;

};

其中,sk_rcvbuf和sk_sendbuf分别是接收和发送缓存的字节数。

而struct sk_buff_head的定义如下:

struct sk_buff_head {
    /* These two members must be first. */
    struct sk_buff    *next;
    struct sk_buff    *prev;

__u32        qlen;
    spinlock_t    lock;
};

可以看出socket的接收和发送缓存是使用一个双链表将sk_buff组织起来的。

struct sk_buff与struct socket及struct sock 结构体分析相关推荐

  1. 网络协议栈3:sock结构体

     sock结构体是我们在网络编程中遇到的第一个庞大的结构体 struct sock {   struct options      *opt;/*IP选项缓存于此处*/   volatile unsi ...

  2. 三、初识Socket套接字结构体

    一.初识Socket套接字结构体 1.通用套接字结构体类型 struct sockaddr{sa_family_t sa_family; //协议簇char sa_data[14]; //协议簇数据} ...

  3. linux sock结构体,struct socket结构体详解

    在内核中为什么要有struct socket结构体呢? struct socket结构体的作用是什么? 下面这个图,我觉得可以回答以上两个问题.  由这个图可知,内核中的进程可以通过使用struct ...

  4. C语言 泛型链表 如何计算(结构体中各元素)相对内存地址?(字节对齐,结构体对齐)offsetof()函数 ( (struct X*)0 ) -> Y)语法(匿名结构体)

    示例: typedef struct _user {char name[20];char sex[20];int age;struct list_head mylist;//自定义结构体里保存双向循环 ...

  5. socket编程之addrinfo结构体与getaddrinfo函数

    1. 概述 IPv4中使用gethostbyname()函数完成主机名到地址解析,这个函数仅仅支持IPv4,且不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储IPv4地址的空间.IP ...

  6. C# Socket 入门5 UPD 结构体 与 C++ 通信

    这篇文章本来是星期五晚写好了, 因6日去旅游了, 没来得急发上来 1. 同样, 我们先看看这一个比简单的 结构体 代码 using System; using System.Collections.G ...

  7. struct sk_buff结构体详解

    struct sk_buff是linux网络系统中的核心结构体,linux网络中的所有数据包的封装以及解封装都是在这个结构体的基础上进行. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

  8. 非常详细的详谈struct sk_buff

    非常详细的详谈struct sk_buff 排版太慢 难看的话可以下载WOR文档 专门详解struct_sk_buff 链接: http://pan.baidu.com/s/1gf8VNKR 密码: ...

  9. 内核中用于数据接收的结构体struct msghdr以及iovec介绍

    我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构.在我们的虚拟机上发送icmp回显请求包,ping另一台主机172.16.48.1.我们使用系统调用send ...

最新文章

  1. Strategy_Level1
  2. VC++ 单文档的状态栏编程、CEditView类实现编辑器功能、编辑框显示行号列号
  3. 外国人居留证办理手续
  4. mysql udf提权_三分钟解析postgresql提权
  5. 河南省多校连萌(一) E题【kruskal】
  6. BZOJ 1901 Zju2112 Dynamic Rankings 题解
  7. 同济版《线性代数》引争议,从清华改用MIT数学课程看中美数学教育差距!
  8. [经验教程]Windows电脑上移动电信联通光宽带如何测速电信光纤200m宽带测速多少正常?
  9. ubuntu下使用CPU频率控制
  10. 【调剂】长江大学张菲菲教授招收硕士生
  11. go语言命令入门之env(操作环境信息)
  12. Parsed mapper file:项目启动不起来
  13. android微信认证失败怎么办,微信登陆好友头像验证失败该怎么办?
  14. springBoot redis开发的Java快递代拿系统(含人脸识别,验证码登录)
  15. 天津理工大学计算机最牛导师,孟祥太_天津理工大学研究生导师信息
  16. MySQL-实操:部门、员工信息与管理
  17. 计算机编程语言及C语言简介,编程语言基础:C语言
  18. 单片机教学打铃控制器C语言
  19. 文件未上传成功再次点击上传报错问题处理
  20. Google新动作频出 Google Trends发布

热门文章

  1. torchvision resize 指定生成图片的尺寸
  2. 解决seaborn绘制热力图使用科学记数法
  3. 复制网页中的表格格式后导入到excel、markdown、数据库、json中,并转换表格格式
  4. python 数组打包_Python:打包多字节数组
  5. [洛谷P3292] [SCOI2016]幸运数字
  6. 《神经网络和深度学习》系列文章五:用简单的网络结构解决手写数字识别
  7. Hibernate学习笔记--映射配置文件详解
  8. HTC ThunderBolt无法打开3G问题解决方法
  9. 在WinForm中使用Web Service来实现软件自动升级
  10. ArcGIS的BLOB字段与Access数据库BLOB字段的交换