Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1214559
  • 博文数量: 122
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4004
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-20 08:27
文章分类
文章存档

2016年(1)

2015年(21)

2014年(100)

分类: LINUX

2014-03-11 14:32:39

sk_buff数据结构定义:

点击(此处)折叠或打开

  1. struct sk_buff {
  2.     /* These two members must be first. */
  3.     // 用于将该skb链入到双向链表中
  4.     struct sk_buff        *next;
  5.     struct sk_buff        *prev;

  6.     /*接收或发送时间戳,通常在netif_receive_skb()或netif_rx()中设置*/
  7.     ktime_t            tstamp;
  8.     /*
  9.      * skb的宿主传输控制块(sock结构),仅当网络报文由本地发送或接收时
  10.      * 才有效,使传输控制块与套接口(socket)及应用程序相关。当该skb仅在
  11.      * L2或L3进行转发时(即src和dst ip都不是本机地址),该指针为空。
  12.      */
  13.     struct sock        *sk;
  14.     /*
  15.      * 网络设备指针。在接收时指向收到网络包的网络设备(net_device结构)
  16.      * 发送时指向输出包的网络设备,如果是虚拟网卡,则指向该虚拟网卡,
  17.      * 在发送包时,虚拟设备驱动会在一组设备中选择合适的物理设备,并将
  18.      * dev指针改写为该设备的net_device结构;在收包时物理设备驱动会根据一定
  19.      * 策略选择合适的虚拟网络设备,并激dev指针改写。在某些情况下,该指针
  20.      * 会在包处理过程中改变。
  21.      */
  22.     struct net_device    *dev;

  23.     /*
  24.      * This is the control buffer. It is free to use for every
  25.      * layer. Please put your private variables there. If you
  26.      * want to keep them across layers you have to do a skb_clone()
  27.      * first. This is owned by whoever has the skb queued ATM.
  28.      */
  29.     // 控制缓存,各层均可使用,存放私有数据的地方,8字节对齐
  30.     char            cb[48] __aligned(8);

  31.     unsigned long        _skb_refdst;
  32. #ifdef CONFIG_XFRM
  33.     struct    sec_path    *sp;
  34. #endif
  35.     /*
  36.      * skb中的数据长度,包括线性区(data指向)的数据长度和SG模式下各frag
  37.      * 的数据长度,注意:仅包括数据的长度,并不是分配的数据区的长度。
  38.      * 该长度随skb的传递而改变,因为各层的头部数据的添加或剥离。
  39.      * len中包含了协议首部的长度。
  40.         */
  41.     unsigned int        len,
  42.                 data_len;/*SG类型和Fraglist类型聚合分散IO存储区中的数据长度*/
  43.     // L2首部长度
  44.     __u16            mac_len,
  45.                 hdr_len;
  46.     /*
  47.      * 校验和相关,当校验状态为CHECKSUM_NONE时,csum中存放skb中数据部分
  48.      * 的校验和,当校验状态为CHECKSUM_PARTIAL时,csum_offset记录传输层首部中
  49.      * 的校验和字段的偏移,两种状态互斥,所以用联合体节省空间
  50.      */
  51.     union {
  52.         __wsum        csum;
  53.         struct {
  54.             __u16    csum_start;
  55.             __u16    csum_offset;
  56.         };
  57.     };
  58.     /*QoS流控使用*/
  59.     __u32            priority;
  60.     kmemcheck_bitfield_begin(flags1);
  61.     /*节省空间,按位利用*/
  62.     /*标记该skb是否运行在本地分片*/
  63.     __u8            local_df:1,
  64.     /*标记该skb是否已被克隆*/
  65.                 cloned:1,
  66.                 ip_summed:2,
  67.     /*标记payload是否被单独使用,如果不是则不能再修改协议首部,也不能通过skb->data访问协议首部*/
  68.                 nohdr:1,
  69.                 nfctinfo:3;
  70.     /*帧类型,由L2的目的地址(mac地址)决定*/
  71.     __u8            pkt_type:3,
  72.     /*当前克隆状态*/
  73.                 fclone:2,
  74.                 ipvs_property:1,
  75.                 peeked:1,
  76.                 nf_trace:1;
  77.     kmemcheck_bitfield_end(flags1);
  78.     /*从L2设备角度看到的上层协议(L3),典型的包括IP/IPv6/ARP*/
  79.     __be16            protocol;
  80.     /*
  81.      * skb析构函数指针,在释放skb时调用,释放后该skb不再属于相应的传输控制块(sock)
  82.         * 因此需要根据被释放的skb->truesize来调整sock的接收和发送缓存区大小(sk_rmem_alloc和sk_wmem_alloc)
  83.         */
  84.     void            (*destructor)(struct sk_buff *skb);
  85.     /*netfilter相关*/
  86. #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
  87.     struct nf_conntrack    *nfct;
  88. #endif
  89. #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
  90.     struct sk_buff        *nfct_reasm;
  91. #endif
  92. #ifdef CONFIG_BRIDGE_NETFILTER
  93.     struct nf_bridge_info    *nf_bridge;
  94. #endif

  95.     int            skb_iif;

  96.     __u32            rxhash;

  97.     __be16            vlan_proto;
  98.     __u16            vlan_tci;
  99. /*tc流控相关*/
  100. #ifdef CONFIG_NET_SCHED
  101.     __u16            tc_index;    /* traffic control index */
  102. #ifdef CONFIG_NET_CLS_ACT
  103.     __u16            tc_verd;    /* traffic control verdict */
  104. #endif
  105. #endif

  106.     __u16            queue_mapping;
  107.     kmemcheck_bitfield_begin(flags2);
  108. #ifdef CONFIG_IPV6_NDISC_NODETYPE
  109.     __u8            ndisc_nodetype:2;
  110. #endif
  111.     __u8            pfmemalloc:1;
  112.     __u8            ooo_okay:1;
  113.     __u8            l4_rxhash:1;
  114.     __u8            wifi_acked_valid:1;
  115.     __u8            wifi_acked:1;
  116.     __u8            no_fcs:1;
  117.     __u8            head_frag:1;
  118.     /* Encapsulation protocol and NIC drivers should use
  119.      * this flag to indicate to each other if the skb contains
  120.      * encapsulated packet or not and maybe use the inner packet
  121.      * headers if needed
  122.      */
  123.     __u8            encapsulation:1;
  124.     /* 7/9 bit hole (depending on ndisc_nodetype presence) */
  125.     kmemcheck_bitfield_end(flags2);

  126. #if defined CONFIG_NET_DMA || defined CONFIG_NET_LL_RX_POLL
  127.     union {
  128.         unsigned int    napi_id;
  129.         dma_cookie_t    dma_cookie;
  130.     };
  131. #endif
  132. #ifdef CONFIG_NETWORK_SECMARK
  133.     __u32            secmark;
  134. #endif
  135.     union {
  136.         __u32        mark;
  137.         __u32        dropcount;
  138.         __u32        reserved_tailroom;
  139.     };

  140.     __be16            inner_protocol;
  141.     __u16            inner_transport_header;
  142.     __u16            inner_network_header;
  143.     __u16            inner_mac_header;
  144.     __u16            transport_header;
  145.     __u16            network_header;
  146.     __u16            mac_header;

  147.     /* RHEL SPECIFIC
  148.      *
  149.      * The following padding has been inserted before ABI freeze to
  150.      * allow extending the structure while preserve ABI. Feel free
  151.      * to replace reserved slots with required structure field
  152.      * additions of your backport.
  153.      */
  154. #ifndef __GENKSYMS__
  155.     u32            rh_reserved1;
  156.     u32            rh_reserved2;
  157.     u32            rh_reserved3;
  158.     u32            rh_reserved4;
  159. #endif

  160.     /* These elements must be at the end, see alloc_skb() for details. */
  161.     /*线性区中数据结束的地方,tail和end之间可以添加数据*/
  162.     sk_buff_data_t        tail;
  163.     /*
  164.      * 线性区的尾部,end之后紧接着存放skb_shared_info数据结构
  165.      * 用于存放SG相关的信息,如分片(frag)信息
  166.      */
  167.     sk_buff_data_t        end;
  168.     /*线性区的头部,发送时,每一层的协议在head和data之间填充协议首部*/
  169.     unsigned char        *head,
  170.                 *data;/*线性区中数据开始的地方*/
  171.     /*
  172.      * sk_buff数据结构长度+len(数据长度)
  173.      */
  174.     unsigned int        truesize;
  175.     /*引用计数,标识引用该skb的数量,在释放时判断,只有在其为0时才真正释放*/
  176.     atomic_t        users;
  177. };



skb->data    skb的数据区开始
skb_shared_info   skb数据区的附加信息,用于分散/聚集(SG)特性(需要网卡硬件支持),放在在skb数据区的末尾,该数据结构放在skb->end指针所指的地址之后,分配skb时,会一起分配:

点击(此处)折叠或打开

  1. /**
  2.  * 分配sk_buff结构及其缓冲区。
  3.  */
  4. struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
  5. {
  6.  struct sk_buff *skb;
  7.  u8 *data;

  8.  /* Get the HEAD */
  9.  /**
  10.   * 从缓存中获取一个sk_buff结构
  11.   */
  12.  skb = kmem_cache_alloc(skbuff_head_cache,
  13.           gfp_mask & ~__GFP_DMA);
  14.  if (!skb)
  15.   goto out;

  16.  /* Get the DATA. Size must match skb_add_mtu(). */
  17.  /**
  18.   * 分配缓冲区.
  19.   * 在调用 kmalloc 前,size 参数通过 SKB_DATA_ALIGN宏强制对齐。
  20.   */
  21.  size = SKB_DATA_ALIGN(size);
  22.  /**
  23.   * skb_shared_info 块主要用来处理 IP 分片
  24.   */
  25.  data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
  26. 。。。
skb_shared_info->dataref     数据区引用计数,在skb_clone时增加
skb_shared_info在很多地方用作存放实际的数据,比如xen的pv驱动中。
skb中存放的数据分两种类型:
1、线性区数据,即skb->data指针指向的数据区,为一块连续的内存区,故称线性区。
2、SG(集合分散)IO数据区,也称分片区,或非线性区,用于SG特性下存放数据,其中的数据存放与独立的内存区域中,使用skb_shared_info->frags[]数组指向。

skb_clone    仅复制skb数据结构,并设置skb数据结构相关成员,clone的skb与原skb共享数据区(data)和skb_shared_info共享(同一份,使用指针引用),只是增加相应的引用计数而已。
当一个缓冲区需要被不同的用户独立地操作,而这些用户可能会修改sk_buff中某些变量的值(比如h和nh值)时调用。克隆过程只复制sk_buff结构,同时修改缓冲区的引用计数以避免共享的数据被提前释放.

skb_copy    复制skb数据结构和相应的数据(包括数据区(data)和skb_shared_info)
当一个函数不仅要修改sk_buff,而且要修改缓冲区内容时,就需要同时复制缓冲区。
如果所修改的数据在skb->start和skb->end之间,可以使用pskb_copy来复制这部分数据.
如果同时需要修改分片中的数据,就必须使用skb_copy。

pskb_copy    复制skb数据结构和数据区,共用skb_shared_info,当需要修改复制后的skb数据结构和数据区时,使用此接口。其作用介于skb_clone和sky_copy之间。

通常,使用skb_clone的情况比较多,由于通常的流程中,都不需要修改原skb的数据,而只是修改skb数据结构。
阅读(3662) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~