1.sk_buff是linux 網路核心裡面最終要的資料結構了.存放要發送和接收的資料.標頭檔 linux/skbuff.h
2.主要成員以及相關結構函數分為以下幾類
a.layout
struct sk_buff *next;
struct sk_buff *prev;
struct sk_buff_head* list; 方便找到表頭
__u32 qlen; 雙鏈表裡sk_buff結構的數量
spinlock_t lock; 保證操作鏈結表安全
struct sock *sock; 指向tcp udp socket結構,如果資料被轉寄的話,該指標為NULL
unsigned int len; 整個sk_buff鏈data_len的總和
unsigned int data_len; 當前sk_buff的資料長度.包含協議頭部內容.各層傳輸時大小會變化
unsigned int mac_len; mac頭部大小
atomic_t users; 引用計數.(skb_get kfree_skb改變)
unsigned int truesize; data大小 + sizeof(sk_buff)
unsigned char *head;
unsigned char *data;
unsigned char *tail;
unsigned char *end; 以上都是資料區段的指標
void (*destructor)(...) 當sk_buff某個socket的時候被初始化,通常執行sock_rfree或者sock_wfree
b.general
struct tim stamp; 接收到資料時時間
struct net_device *dev; 網路裝置,也很重要
struct net_device *input_dev; 輸入裝置
struct net_device *real_dev; 可用於虛擬設備
union
{
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct spxhdr *spxh;
unsigned char *raw;
} h;
union
{
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
struct ipxhdr *ipxh;
unsigned char *raw;
} nh;
union
{
struct ethhdr *ethernet;
unsigned char *raw;
} mac;
struct dst_entry dst; 路由子系統使用,複雜
char cb[40]; 控制緩衝區或者存放隱私資訊,例如tcp用它來存放一個struct_skb_cb的結構體
struct tcp_skb_cb {
... ... ...
_ _u32 seq;
_ _u32 end_seq;
_ _u32 when;
_ _u8 flags;
... ... ...
};
unsigned int csum;
unsigned char ip_summed;
unsigned char cloned; 該sk_buff是否複製的
unsigned char pkt_type; 根據L2層的目的地址判斷,該資料包的類型,原生,多播,廣播,其他主機
__u32 priority; 發送和轉寄的QoS
unsigned short protocol; L2層的協議類型.通常是ip ip6 arp rarp
unsigned short security; IPSec,未使用
c.feature-specific
unsigned long nfmark;
__u32 nfcache;
__u32 nfctinfo;
struct nf_conntrack *nfct;
unsigned int nfdebug;
struct nf_bridge_info *nf_bridge;
以上欄位netfilter模組使用.
union {...} private HIPPI使用
__u32 tc_index;
__u32 tc_verd;
__u32 tc_classid;
以上欄位用於traffic control
struct sec_path *sp; 用於IPSec跟蹤傳輸
d.manegement functions
sk_put L2層接收資料時,將除了資料幀頭部(已經拷貝)的內容包考到sk_buff資料緩衝區
sk_push 發送資料時,高層->低層添加頭部(data指標改變)
sk_pull 接收資料時,低層->高層去迴轉部(data指標改變)
sk_reserve L2層開始接收資料前,保持4位元組對齊,data += 2 alloc_skb dev_alloc_skb 分配空間函數,預設用dev_alloc_skb.分配的空間包括兩次,第一個是struct sk_buff,第二個是data_size + sizeof(struct skb_shared_info)
kfree_skb dev_kfree_skb 釋放sk_buff記憶體
struct skb_shared_info { 緊跟著data緩衝區後面,儲存data緩衝區的相關資訊的結構體
atomic_t dataref;
unsigned int nr_frags;
unsigned short tso_size;
unsigned short tso_seqs;
unsigned sk_buff *frag_list;
skb_frag_t frags[MAX_SKB_FRAGS];
};
clone和copy
clone:資料需要給其他的使用者時候(不會改變資料內容),會採用clone.分配一個新的sk_buff,並且 cloned屬性為1,users屬性為1,保證不要的時候釋放記憶體.head data等仍然指向以前的data緩衝區.但是 儲存data緩衝區的
struct skb_shared_info的dataref需要加一.
copy:其他使用者需要改變data緩衝區的資料的時候使用.分配兩塊新的記憶體.不會設定clone位
相關函數:skb_clone pskb_copy(拷貝當前data緩衝區) skb_copy(拷貝所有data緩衝區)
skb_queue_head_init 初始化一個空鏈表
skb_queue_head skb_queue_tail 添加sk_buff到鏈表
skb_dequeue skb_dequeue_tail 刪除sk_buff從鏈表
skb_queue_purge 清空sk_buff鏈表
skb_queue_walk 迴圈鏈表
進行這些函數的時候需要使用 :
unsigned long flags;
spin_lock_irqsave(...);
function();
spin_unlock_irqrestore(...);
spin的作用在單一處理器上,關中斷.多處理器上, 通過一個原子變數,保證函數的執行安全.