• Linux内核网络协议栈深入分析(一)与sk_buff有关的几个重要的数据结构


    本文分析基于Linux Kernel 3.2.1

    原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7971463

    更多请查看专栏http://blog.csdn.net/column/details/linux-kernel-net.html

    作者:闫明


    几个月之前做了关于Linux内核版本1.2.13网络栈的结构框架分析并实现了基于Netfilter的包过滤防火墙,这里以内核3.2.1内核为例来进一步分析,更全面的分析网络栈的结构。


    1、先说一下sk_buff结构体

    这个结构体是套接字的缓冲区,详细记录了一个数据包的组成,时间、网络设备、各层的首部及首部长度和数据的首尾指针。

    下面是他的定义,挺长

    1. struct sk_buff {  
    2.     /* These two members must be first. */  
    3.     struct sk_buff      *next;  
    4.     struct sk_buff      *prev;  
    5.   
    6.     ktime_t         tstamp;  
    7.   
    8.     struct sock     *sk;  
    9.     struct net_device   *dev;  
    10.   
    11.     /* 
    12.      * This is the control buffer. It is free to use for every 
    13.      * layer. Please put your private variables there. If you 
    14.      * want to keep them across layers you have to do a skb_clone() 
    15.      * first. This is owned by whoever has the skb queued ATM. 
    16.      */  
    17.     char            cb[48] __aligned(8);  
    18.   
    19.     unsigned long       _skb_refdst;  
    20. #ifdef CONFIG_XFRM  
    21.     struct  sec_path    *sp;  
    22. #endif  
    23.     unsigned int        len,  
    24.                 data_len;  
    25.     __u16           mac_len,  
    26.                 hdr_len;  
    27.     union {  
    28.         __wsum      csum;  
    29.         struct {  
    30.             __u16   csum_start;  
    31.             __u16   csum_offset;  
    32.         };  
    33.     };  
    34.     __u32           priority;  
    35.     kmemcheck_bitfield_begin(flags1);  
    36.     __u8            local_df:1,  
    37.                 cloned:1,  
    38.                 ip_summed:2,  
    39.                 nohdr:1,  
    40.                 nfctinfo:3;  
    41.     __u8            pkt_type:3,  
    42.                 fclone:2,  
    43.                 ipvs_property:1,  
    44.                 peeked:1,  
    45.                 nf_trace:1;  
    46.     kmemcheck_bitfield_end(flags1);  
    47.     __be16          protocol;  
    48.   
    49.     void            (*destructor)(struct sk_buff *skb);  
    50. #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)  
    51.     struct nf_conntrack *nfct;  
    52. #endif  
    53. #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED  
    54.     struct sk_buff      *nfct_reasm;  
    55. #endif  
    56. #ifdef CONFIG_BRIDGE_NETFILTER  
    57.     struct nf_bridge_info   *nf_bridge;  
    58. #endif  
    59.   
    60.     int         skb_iif;  
    61. #ifdef CONFIG_NET_SCHED  
    62.     __u16           tc_index;   /* traffic control index */  
    63. #ifdef CONFIG_NET_CLS_ACT  
    64.     __u16           tc_verd;    /* traffic control verdict */  
    65. #endif  
    66. #endif  
    67.   
    68.     __u32           rxhash;  
    69.   
    70.     __u16           queue_mapping;  
    71.     kmemcheck_bitfield_begin(flags2);  
    72. #ifdef CONFIG_IPV6_NDISC_NODETYPE  
    73.     __u8            ndisc_nodetype:2;  
    74. #endif  
    75.     __u8            ooo_okay:1;  
    76.     __u8            l4_rxhash:1;  
    77.     kmemcheck_bitfield_end(flags2);  
    78.   
    79.     /* 0/13 bit hole */  
    80.   
    81. #ifdef CONFIG_NET_DMA  
    82.     dma_cookie_t        dma_cookie;  
    83. #endif  
    84. #ifdef CONFIG_NETWORK_SECMARK  
    85.     __u32           secmark;  
    86. #endif  
    87.     union {  
    88.         __u32       mark;  
    89.         __u32       dropcount;  
    90.     };  
    91.   
    92.     __u16           vlan_tci;  
    93.   
    94.     sk_buff_data_t      transport_header;  
    95.     sk_buff_data_t      network_header;  
    96.     sk_buff_data_t      mac_header;  
    97.     /* These elements must be at the end, see alloc_skb() for details.  */  
    98.     sk_buff_data_t      tail;  
    99.     sk_buff_data_t      end;  
    100.     unsigned char       *head,  
    101.                 *data;  
    102.     unsigned int        truesize;  
    103.     atomic_t        users;  
    104. };  
    可以看到新版本内核中发生了很多变化,其中数据包的首部在早期版本是以union的形式定义的,例如mac_header的定义方式如下:

    1. union{  
    2.     struct ethhdr *ethernet;  
    3.     unsigned char *raw;  
    4. }mac;  

    这里是以指针的形式给出的

    1. #ifdef NET_SKBUFF_DATA_USES_OFFSET  
    2. typedef unsigned int sk_buff_data_t;  
    3. #else  
    4. typedef unsigned char *sk_buff_data_t;  
    5. #endif  

    这里主要说明下后面几个后面的四个属性的含义head、data、tail、end

    head是缓冲区的头指针,data是数据的起始地址,tail是数据的结束地址,end是缓冲区的结束地址。


    char cb[48] __aligned(8);中的48个字节是控制字段,配合各层协议工作,为每层存储必要的控制信息。


    2、sk_buff_head结构体

    1. struct sk_buff_head {  
    2.     /* These two members must be first. */  
    3.     struct sk_buff  *next;  
    4.     struct sk_buff  *prev;  
    5.   
    6.     __u32       qlen;  
    7.     spinlock_t  lock;  
    8. };  

    这个结构体比较简单,前面两个指针是用于和sk_buff结构串成双向链表,用于管理sk_buff双链表,qlen属性表示该链表中sk_buff的数目,lock是自旋锁。


    3、skb_shared_info结构体

    1. struct skb_shared_info {  
    2.     unsigned short  nr_frags;  
    3.     unsigned short  gso_size;//尺寸  
    4.     /* Warning: this field is not always filled in (UFO)! */  
    5.     unsigned short  gso_segs;//顺序  
    6.     unsigned short  gso_type;  
    7.     __be32          ip6_frag_id;  
    8.     __u8        tx_flags;  
    9.     struct sk_buff  *frag_list;//分片的sk_buff列表  
    10.     struct skb_shared_hwtstamps hwtstamps;//硬件时间戳  
    11.   
    12.     /* 
    13.      * Warning : all fields before dataref are cleared in __alloc_skb() 
    14.      */  
    15.     atomic_t    dataref;//使用计数  
    16.   
    17.     /* Intermediate layers must ensure that destructor_arg 
    18.      * remains valid until skb destructor */  
    19.     void *      destructor_arg;  
    20.   
    21.     /* must be last field, see pskb_expand_head() */  
    22.     skb_frag_t  frags[MAX_SKB_FRAGS];  
    23. };  


    该类型用来管理数据包分片信息,通过宏可以表示与skb的关系

    1. #define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))  

    1. #ifdef NET_SKBUFF_DATA_USES_OFFSET  
    2. static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)  
    3. {  
    4.     return skb->head + skb->end;  
    5. }  
    6. #else  
    7. static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)  
    8. {  
    9.     return skb->end;  
    10. }  
    11. #endif  

    可以看到如果用户没有自己使用偏移量,就是skb的end属性指针,也就是该信息存储在缓冲区之后。


    下篇将看有关sk_buff的操作函数的实现。

  • 相关阅读:
    window 安装使用npm
    php 身份证验证类
    php nl2br 将 变成<br />
    win10 system guard运行时监视器,关闭服务
    PHP7 引入的“??” 和“?:”的区别
    git 本地删除修改文件后从远程拉取
    深入解读阿里云Redis开发规范
    阿里云Redis开发规范
    Centos7 安装docker
    api-doc-php
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332906.html
Copyright © 2020-2023  润新知