linux协议栈之链路层上的数据传输-----sk_buff结构分析

时间:2021-12-28 11:03:25

出处:http://ericxiao.cublog.cn/

------------------------------------------

sk_buff结构分析

sk_buff是我们遇到的第二个重要的结构,在内核中经常被缩写成skb.linux 2.6.21它被定义成:

struct sk_buff {

         //指向下一个skb

struct sk_buff               *next;

//上一个skb

         struct sk_buff               *prev;

 

         struct sk_buf0f_head   *list;

         //对应的sock。这也是个重要的结构,在传输层的时候我们再来分析

         struct sock          *sk;

         //接收或者发送时间戳

         struct timeval               stamp;

         //接收或者发送时对应的net_device

         struct net_device *dev;

         //接收的net_device

         struct net_device *input_dev;

         //数据包对应的真实net_device.关于虚拟设备可以在之后的网桥模式分析中讨论

         struct net_device *real_dev;

         //ip层的相关信息

         union {

                   struct tcphdr       *th;

                   struct udphdr      *uh;

                   struct icmphdr    *icmph;

                   struct igmphdr    *igmph;

                   struct iphdr         *ipiph;

                   struct ipv6hdr     *ipv6h;

                   unsigned char      *raw;

         } h;

         //协议层的相关信息

         union {

                   struct iphdr         *iph;

                   struct ipv6hdr     *ipv6h;

                   struct arphdr       *arph;

                   unsigned char      *raw;

         } nh;

         //链路层的相关信息

         union {

                unsigned char     *raw;

         } mac;

         //在路由子系统中再来分析这一结构

         struct  dst_entry        *dst;

         struct         sec_path    *sp;

 

         /*

          * 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[40];

         //各层的数据长度

         unsigned int                  len,

                                     data_len,

                                     mac_len,

                                     csum;

         unsigned char                local_df,

                                     cloned,

                                     pkt_type,

                                     ip_summed;

         __u32                           priority;

         unsigned short              protocol,

                                     security;

 

         void                     (*destructor)(struct sk_buff *skb);

#ifdef CONFIG_NETFILTER

        unsigned long                  nfmark;

         __u32                           nfcache;

         __u32                           nfctinfo;

         struct nf_conntrack      *nfct;

#ifdef CONFIG_NETFILTER_DEBUG

        unsigned int           nf_debug;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

         struct nf_bridge_info    *nf_bridge;

#endif

#endif /* CONFIG_NETFILTER */

#if defined(CONFIG_HIPPI)

         union {

                   __u32                  ifield;

         } private;

#endif

#ifdef CONFIG_NET_SCHED

       __u32                       tc_index;        /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

         __u32           tc_verd;               /* traffic control verdict */

         __u32           tc_classid;            /* traffic control classid */

#endif

 

#endif

 

 

         /* These elements must be at the end, see alloc_skb() for details.  */

         unsigned int                  truesize;

         //引用计数

         atomic_t              users;

         //存储空间的起始地址

         unsigned char      *head,

         //网络数据的起始起址

                                     *data,

         //存放网络数据的结束地址

                                     *tail,

         //存储空间的结束地址

                                     *end;

}

对应我们上面的网卡驱动分析。接收到的数据是存放在datatail之间的区域。

Skb通常还有常用的几个函数,一一列举分析如下:

struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)

分配存储空间为sixeskb,内存分配级别为gfp_mask.注意这里的存储空间的含义,即为skb->dataskb->tail的区域

struct sk_buff *skb_clone(struct sk_buff *skb, int priority)

克隆出的skb指向同一个结构,同时会增加skb的引用计数

struct sk_buff *skb_copy(const struct sk_buff *skb, int priority)

复制一个全新的skb

void kfree_skb(struct sk_buff *skb)

skb的引用计数为1的时候,释放此skb

unsigned char *skb_put(struct sk_buff *skb, unsigned int len)

使skb的存储空间扩大len.即使tail指针下移

unsigned char *skb_push(struct sk_buff *skb, unsigned int len)

push,即推出一段数据,使data指针下层。

void skb_reserve(struct sk_buff *skb, unsigned int len)

该操作使data指针跟tail指针同时下移,即扩大存储区域之前的空间

int skb_headroom(const struct sk_buff *skb)

返回data之前可用的空间数量

int skb_tailroom(const struct sk_buff *skb)

返回缓存区中可用的空间大小