zoukankan      html  css  js  c++  java
  • 套接字缓存之sk_buff结构

    sk_buff结构用来描述已接收或者待发送的数据报文信息;skb在不同网络协议层之间传递,可被用于不同网络协议,如二层的以太网协议,三层的ip协议,四层的tcp或者udp协议,其中某些成员变量会在该结构从一层向另一层传递时发生改变,从上层向下层传递需要添加首部,从下层向上层传递需要移除首部;

    多个skb通过sk_buff_head表头部结构的next和prev指针连接成双向链表;头部还包含了链表中skb节点的总数量;

     1 /* skb头结构 */
     2 struct sk_buff_head {
     3     /* These two members must be first. */
     4     /* 通过下面两个指针成员将skb连接成双向链表 */
     5     struct sk_buff    *next; /* 指向后一个skb */
     6     struct sk_buff    *prev; /* 指向前一个skb */
     7 
     8     __u32        qlen; /* 链表中元素个数 */
     9     spinlock_t    lock; /* 自旋锁 */
    10 };

    下面为具体的sk_buff结构,部分成员加了注释,在后续代码阅读过程中会持续更新该结构注释;

      1 /* skb结构 */
      2 struct sk_buff {
      3     union {
      4         struct {
      5             /* These two members must be first. */
      6             struct sk_buff        *next;
      7             struct sk_buff        *prev;
      8 
      9             /* 报文到达或者离开的时间戳 */
     10             union {
     11                 ktime_t        tstamp;
     12                 struct skb_mstamp skb_mstamp;
     13             };
     14         };
     15         /* 红黑树的节点,用在netem和tcp协议栈 */
     16         struct rb_node    rbnode; /* used in netem & tcp stack */
     17     };
     18     
     19     /* 
     20         指向缓冲区的套接字sock数据结构。当数据在本地产生或者正由本地进程接收时,
     21         该数据以及套接字相关信息会被L4(tcp或者udp)以及用户应用程序使用
     22         当缓冲区只是被转发时(本地机器不是来源也不是目的地),该指针为NULL
     23     */
     24     struct sock        *sk;
     25 
     26     union {
     27         /* 报文到达或者离开时的网络设备 */
     28         struct net_device    *dev;
     29         /* Some protocols might use this space to store information,
     30          * while device pointer would be NULL.
     31          * UDP receive path is one user.
     32          */
     33         unsigned long        dev_scratch;
     34     };
     35     /*
     36      * This is the control buffer. It is free to use for every
     37      * layer. Please put your private variables there. If you
     38      * want to keep them across layers you have to do a skb_clone()
     39      * first. This is owned by whoever has the skb queued ATM.
     40      */
     41     /*
     42         控制缓冲区,用于存储私有信息,每层协议自己维护并使用,
     43         并且只在本层有有效
     44     */
     45     char            cb[48] __aligned(8);
     46 
     47     /* 路由缓存,输入或者输出报文都要查询到目的路由缓存项,才能确定流向 */
     48     unsigned long        _skb_refdst;
     49     
     50     /* 
     51         当缓冲区被删除时,可以完成某些清理工作
     52         当缓冲区不属于一个套接字时,该函数通常不被初始化
     53         属于一个套接字时,通常设置为sock_rfree或sock_wfree
     54         sock_xxx函数用于更新套接字队列中所持有的内存
     55     */
     56     void            (*destructor)(struct sk_buff *skb);
     57 #ifdef CONFIG_XFRM
     58     /* ipsec用于跟踪传输信息 */
     59     struct    sec_path    *sp;
     60 #endif
     61 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
     62     /* 连接跟踪 */
     63     unsigned long         _nfct;
     64 #endif
     65 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
     66     /* 桥接帧的相关信息 */
     67     struct nf_bridge_info    *nf_bridge;
     68 #endif
     69     /* 
     70         缓冲区的数据区块大小,该长度包括主缓冲区(head指针指向)的数据
     71         以及一些片段(fragment)的数据,当缓冲区从一个网络分层移动到下一个
     72         网络分层时,该值会发生变化,因为在协议栈中向上层移动时报头会被丢弃
     73         向下层移动时报头会添加,len也会把协议报头算在内,与"数据预留和对齐"操作
     74     */
     75     unsigned int        len,
     76     /* 片段(fragment)中的数据大小 */
     77                 data_len;
     78     /* mac报头大小 */
     79     __u16            mac_len,
     80     /* 克隆skb时可写报文头部长度 */
     81                 hdr_len;
     82 
     83     /* Following fields are _not_ copied in __copy_skb_header()
     84      * Note that queue_mapping is here mostly to fill a hole.
     85      */
     86     kmemcheck_bitfield_begin(flags1);
     87     /* 多设备的队列映射 */
     88     __u16            queue_mapping;
     89 
     90 /* if you move cloned around you also must adapt those constants */
     91 #ifdef __BIG_ENDIAN_BITFIELD
     92 #define CLONED_MASK    (1 << 7)
     93 #else
     94 #define CLONED_MASK    1
     95 #endif
     96 #define CLONED_OFFSET()        offsetof(struct sk_buff, __cloned_offset)
     97 
     98     __u8            __cloned_offset[0];
     99     /* 表示该skb是另外一个skb的克隆 */
    100     __u8            cloned:1,
    101                 /* 
    102                     payload是否被单独引用,不存在协议首部,如果被引用,则不能修改协议首部,
    103                     也不能通过skb->data来访问协议首部 
    104                 */
    105                 nohdr:1,
    106                 /*
    107                     当前克隆状态
    108                     SKB_FCLONE_UNAVAILABLE-skb未被克隆
    109                     SKB_FCLONE_ORIG-在skbuff_fclone_cache分配的父skb,可以被克隆
    110                     SKB_FCLONE_CLONE-在skbuff_fclone_cache分配的子skb,从父skb克隆得到
    111                 */
    112                 fclone:2,
    113                 peeked:1,
    114                 /* 通过page_fragment_alloc分配内存 */
    115                 head_frag:1,
    116                 xmit_more:1,
    117                 __unused:1; /* one bit hole */
    118     kmemcheck_bitfield_end(flags1);
    119 
    120     /* fields enclosed in headers_start/headers_end are copied
    121      * using a single memcpy() in __copy_skb_header()
    122      */
    123     /* private: */
    124     __u32            headers_start[0];
    125     /* public: */
    126 
    127 /* if you move pkt_type around you also must adapt those constants */
    128 #ifdef __BIG_ENDIAN_BITFIELD
    129 #define PKT_TYPE_MAX    (7 << 5)
    130 #else
    131 #define PKT_TYPE_MAX    7
    132 #endif
    133 #define PKT_TYPE_OFFSET()    offsetof(struct sk_buff, __pkt_type_offset)
    134 
    135     __u8            __pkt_type_offset[0];
    136     /*
    137         此字段根据l2的目的地址进行划分
    138         PACKET_HOST-mac地址与接收设备mac地址相等,说明是发给该主机的
    139         PACKET_BROADCAST-mac地址是接收设备的广播地址
    140         PACKET_MULTICAST-mac地址接收改设备注册的多播地址之一
    141         PACKET_OTHERHOST-mac地址不属于接收设备的地址,启用转发则转发,否则丢弃
    142         PACKET_OUTGOING-数据包将被发出,用到这个标记的功能包括decnet,或者为每个
    143         网络tab都复制一份发出包的函数
    144         PACKET_LOOPBACK-数据包发往回环设备,有此标识,处理回环设备时,
    145         可以跳过一些真实设备所需的操作
    146         PACKET_USER-发送到用户空间,netlink使用
    147         PACKET_KERNEL-发送到内核空间,netlink使用
    148         PACKET_FASTROUTE-未使用
    149     */
    150     __u8            pkt_type:3;
    151     /* PFMEMALLOC内存分配标记 */
    152     __u8            pfmemalloc:1;
    153     __u8            ignore_df:1;
    154 
    155     __u8            nf_trace:1;
    156     /*
    157         CHECKSUM_NONE-硬件不支持,完全由软件执行校验和
    158         CHECKSUM_PARTIAL-由硬件来执行校验和
    159         CHECKSUM_UNNECESSARY-没必要执行校验和
    160         CHECKSUM_COMPLETE-已完成执行校验和
    161     */
    162     __u8            ip_summed:2;
    163     __u8            ooo_okay:1;
    164     __u8            l4_hash:1;
    165     __u8            sw_hash:1;
    166     __u8            wifi_acked_valid:1;
    167     __u8            wifi_acked:1;
    168 
    169     __u8            no_fcs:1;
    170     /* Indicates the inner headers are valid in the skbuff. */
    171     __u8            encapsulation:1;
    172     __u8            encap_hdr_csum:1;
    173     __u8            csum_valid:1;
    174     __u8            csum_complete_sw:1;
    175     __u8            csum_level:2;
    176     __u8            csum_bad:1;
    177 
    178     __u8            dst_pending_confirm:1;
    179 #ifdef CONFIG_IPV6_NDISC_NODETYPE
    180     __u8            ndisc_nodetype:2;
    181 #endif
    182     __u8            ipvs_property:1;
    183     __u8            inner_protocol_type:1;
    184     __u8            remcsum_offload:1;
    185 #ifdef CONFIG_NET_SWITCHDEV
    186     __u8            offload_fwd_mark:1;
    187 #endif
    188 #ifdef CONFIG_NET_CLS_ACT
    189     __u8            tc_skip_classify:1;
    190     __u8            tc_at_ingress:1;
    191     __u8            tc_redirected:1;
    192     __u8            tc_from_ingress:1;
    193 #endif
    194 
    195 #ifdef CONFIG_NET_SCHED
    196     __u16            tc_index;    /* traffic control index */
    197 #endif
    198 
    199     union {
    200         /* 校验和,必须包含csum_start和csum_offset */
    201         __wsum        csum;
    202         struct {
    203             /* 校验开始位置,相对于header */
    204             __u16    csum_start;
    205             /* 校验和存储位置,相对于csum_start */
    206             __u16    csum_offset;
    207         };
    208     };
    209     /* 
    210         正在被传输的数据包QoS等级
    211         数据包由本地产生,套接字会定义优先级的值
    212         数据包在被转发,则在调用ip_forward函数时,会根据
    213         ip头本身的ToS字段定义该值
    214     */
    215     __u32            priority;
    216     /* 数据包接收时的网络设备索引号 */
    217     int            skb_iif;
    218     /* 数据包的hash值 */
    219     __u32            hash;
    220     /* vlan封装协议 */
    221     __be16            vlan_proto;
    222     /* vlan标签控制信息 */
    223     __u16            vlan_tci;
    224 #if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)
    225     union {
    226         unsigned int    napi_id;
    227         unsigned int    sender_cpu;
    228     };
    229 #endif
    230 #ifdef CONFIG_NETWORK_SECMARK
    231     __u32        secmark;
    232 #endif
    233 
    234     union {
    235         __u32        mark;
    236         __u32        reserved_tailroom;
    237     };
    238 
    239     /* 封装的协议 */
    240     union {
    241         __be16        inner_protocol;
    242         __u8        inner_ipproto;
    243     };
    244     /* 封装的传输层头部相对于head的偏移 */
    245     __u16            inner_transport_header;
    246     /* 封装的网络层头部相对于head的偏移 */
    247     __u16            inner_network_header;
    248     /* 封装的链路层头部相对于head的偏移 */
    249     __u16            inner_mac_header;
    250 
    251     /* 
    252         l3层协议值
    253         如ETH_P_IP-ipv4报文
    254         ETH_P_ARP-arp报文等
    255     */
    256     __be16            protocol;
    257     /* 传输层头部相对于head的偏移 */
    258     __u16            transport_header;
    259     /* 网络层头部相对于head的偏移 */
    260     __u16            network_header;
    261     /* 链路层头部相对于head的偏移 */
    262     __u16            mac_header;
    263 
    264     /* private: */
    265     __u32            headers_end[0];
    266     /* public: */
    267 
    268     /* These elements must be at the end, see alloc_skb() for details.  */
    269     /* 实际数据的尾部 */
    270     sk_buff_data_t        tail;
    271     /* 缓冲区的尾部 */
    272     sk_buff_data_t        end;
    273     /* 缓冲区的头部 */
    274     unsigned char        *head,
    275     /* 实际数据的头部 */
    276                 *data;
    277     /*
    278         缓冲区的总大小,包括skb本身和实际数据len大小,alloc_skb函数将
    279         该字段设置为len+sizeof(sk_buff)
    280         每当len值更新,该值也要对应更新
    281     */
    282     unsigned int        truesize;
    283     
    284     /* 
    285         引用计数,在使用该skb缓冲区的实例个数,当引用计数为0时,skb才能被释放
    286         skb_get()获取操作中会增加引用计数,kfree_skb释放过程中检查引用计数,
    287         引用计数为0时,才真正释放skb
    288         该计数器只计算sk_buff结构引用计数,缓冲区包含的实际数据由
    289         skb_shared_info->dataref字段记录
    290     */
    291     atomic_t        users;
    292 };
  • 相关阅读:
    运维ipvsadm配置负载均衡
    vue--存储
    vue--v-model表单控件绑定
    CSS--外发光与内阴影
    vue运行报错--preventDefault
    vue运行报错--dependency
    vue--移动端兼容问题
    vue--生命周期
    vue--vuex
    Vue--vux组件库
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7529486.html
Copyright © 2011-2022 走看看