歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

Linux內核sk_buff的結構分析

我看的Linux內核版本是2.6.32.

在內核中sk_buff表示一個網絡數據包,它是一個雙向鏈表,而鏈表頭就是sk_buff_head,在老的內核裡面sk_buff會有一個list域直接指向sk_buff_head也就是鏈表頭,現在在2.6.32裡面這個域已經被刪除了。

而sk_buff的內存布局可以分作3個段,第一個就是sk_buff自身,第二個是linear-data buff,第三個是paged-data buff(也就是skb_shared_info)。

ok.我們先來看sk_buff_head的結構。它也就是所有sk_buff的頭。

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

 __u32  qlen;
 spinlock_t lock;
};

這裡可以看到前兩個域是和sk_buff一致的,而且內核的注釋是必須放到最前面。這裡的原因是:

這使得兩個不同的結構可以放到同一個鏈表中,盡管sk_buff_head要比sk_buff小巧的多。另外,相同的函數可以同樣應用於sk_buff和sk_buff_head。

然後qlen域表示了當前的sk_buff鏈上包含多少個skb。

lock域是自旋鎖。

然後我們來看sk_buff,下面就是skb的結構:

我這裡注釋了一些簡單的域,復雜的域下面會單獨解釋。


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

//表示從屬於那個socket,主要是被4層用到。
 struct sock  *sk;
//表示這個skb被接收的時間。
 ktime_t   tstamp;
//這個表示一個網絡設備,當skb為輸出時它表示skb將要輸出的設備,當接收時,它表示輸入設備。要注意,這個設備有可能會是虛擬設備(在3層以上看來)
 struct net_device *dev;
///這裡其實應該是dst_entry類型,不知道為什麼內核要改為ul。這個域主要用於路由子系統。這個數據結構保存了一些路由相關信息
 unsigned long  _skb_dst;
#ifdef CONFIG_XFRM
 struct sec_path *sp;
#endif
///這個域很重要,我們下面會詳細說明。這裡只需要知道這個域是保存每層的控制信息的就夠了。
 char   cb[48];
///這個長度表示當前的skb中的數據的長度,這個長度即包括buf中的數據也包括切片的數據,也就是保存在skb_shared_info中的數據。這個值是會隨著從一層到另一層而改變的。下面我們會對比這幾個長度的。
 unsigned int  len,
///這個長度只表示切片數據的長度,也就是skb_shared_info中的長度。
    data_len;
///這個長度表示mac頭的長度(2層的頭的長度)
 __u16   mac_len,
///這個主要用於clone的時候,它表示clone的skb的頭的長度。
    hdr_len;

///接下來是校驗相關的域。
 union {
  __wsum  csum;
  struct {
   __u16 csum_start;
   __u16 csum_offset;
  };
 };
///優先級,主要用於QOS。
 __u32   priority;
 kmemcheck_bitfield_begin(flags1);
///接下來是一些標志位。
//首先是是否可以本地切片的標志。
 __u8   local_df:1,
///為1說明頭可能被clone。
    cloned:1,
///這個表示校驗相關的一個標記,表示硬件驅動是否為我們已經進行了校驗(前面的blog有介紹)
    ip_summed:2,
///這個域如果為1,則說明這個skb的頭域指針已經分配完畢,因此這個時候計算頭的長度只需要head和data的差就可以了。
    nohdr:1,
///這個域不太理解什麼意思。
    nfctinfo:3;

///pkt_type主要是表示數據包的類型,比如多播,單播,回環等等。
 __u8   pkt_type:3,
///這個域是一個clone標記。主要是在fast clone中被設置,我們後面講到fast clone時會詳細介紹這個域。
    fclone:2,
///ipvs擁有的域。
    ipvs_property:1,
///這個域應該是udp使用的一個域。表示只是查看數據。
    peeked:1,
///netfilter使用的域。是一個trace 標記
    nf_trace:1;
///這個表示L3層的協議。比如IP,IPV6等等。
 __be16   protocol:16;
 kmemcheck_bitfield_end(flags1);
///skb的析構函數,一般都是設置為sock_rfree或者sock_wfree.
 void   (*destructor)(struct sk_buff *skb);

///netfilter相關的域。
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 struct nf_conntrack *nfct;
 struct sk_buff  *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
 struct nf_bridge_info *nf_bridge;
#endif

///接收設備的index。
 int   iif;

///流量控制的相關域。
#ifdef CONFIG_NET_SCHED
 __u16   tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
 __u16   tc_verd; /* traffic control verdict */
#endif
#endif

 kmemcheck_bitfield_begin(flags2);
///多隊列設備的映射,也就是說映射到那個隊列。
 __u16   queue_mapping:16;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
 __u8   ndisc_nodetype:2;
#endif
 kmemcheck_bitfield_end(flags2);

 /* 0/14 bit hole */

#ifdef CONFIG_NET_DMA
 dma_cookie_t  dma_cookie;
#endif
#ifdef CONFIG_NETWORK_SECMARK
 __u32   secmark;
#endif
///skb的標記。
 __u32   mark;

///vlan的控制tag。
 __u16   vlan_tci;

///傳輸層的頭
 sk_buff_data_t  transport_header;
///網絡層的頭
 sk_buff_data_t  network_header;
///鏈路層的頭。
 sk_buff_data_t  mac_header;
///接下來就是幾個操作skb數據的指針。下面會詳細介紹。
 sk_buff_data_t  tail;
 sk_buff_data_t  end;
 unsigned char  *head,
    *data;
///這個表示整個skb的大小,包括skb本身,以及數據。
 unsigned int  truesize;
///skb的引用計數
 atomic_t  users;
};

Copyright © Linux教程網 All Rights Reserved