sk_buff結構分析

 

原文出處:http://www.cnblogs.com/iceocean/articles/1594160.htmlhtml

前言:linux

如下是根據《深刻理解Linux網絡技術內幕》對sk_buff的相關總結,因爲是剛剛看這本書(太厚了),難免在前期出現錯誤,隨着對此書的深刻我會在修改前面的錯誤,也但願各位牛人給予指點。幫助我成長。網絡

sk_buff分析:數據結構

sk_buff是Linux網絡代碼中最重要的結構體之一。它是Linux在其協議棧裏傳送的結構體,也就是所謂的「包」,在他裏面包含了各層協議的頭部,好比ethernet, ip ,tcp ,udp等等。也有相關的操做等。熟悉他是進一步瞭解Linux網絡協議棧的基礎。併發

      此結構定義在<include/linux/skbuff.h>頭文件中,結構體佈局大體可分爲如下四部分:tcp

l       佈局(layout)模塊化

l       通用(general)函數

l       功能專用(feature-specific)佈局

l       管理函數(management functions)atom

網絡選項以及內核結構

      咱們能夠看到在此結構體裏有不少預處理,他是在須要指定相應功能時才起做用,咱們在這裏先對通用的做出分析。

佈局字段:

      sk_buff是一個複雜的雙向鏈表,在他結構中有next和prev指針,分別指向鏈表的下一個節點和前一個節點。而且爲了某些需求(不知道是哪些目前)須要很快定位到鏈表頭部,因此還有一個指向鏈表頭部的指針list(我在2.6.25內核沒有發現這個指針)。

sk_buff_head結構是:

struct sk_buff_head {

      /* These twomembers must be first. */

      structsk_buff *next;

      structsk_buff *prev;

     __u32       qlen; //表明元素節點數目

     spinlock_t      lock; //加鎖,防止對錶的併發訪問

};

 

  

 

struct sock *sk

這個指針指向一個套接字sock數據結構。當數據在本地產生或者本地進程接受時,須要這個指針;裏面的數據會有tcp/udp和用戶態程序使用。若是是轉發此指針爲NULL

unsigned int len

緩衝區中數據塊大小。長度包括:主要緩衝區(head所指)的數據以及一些片段(fragment)的數據。當包在協議棧向上或向下走時,其大小會變,由於有頭部的丟棄和添加。

unsigned int data_len

片斷中數據大小

unsigned int mac_len

mac包頭大小

atomic_t users

      引用計數,使用這個sk_buff的使用者的數目,可能有多個函數要使用同一個sk_buff因此防止提早釋放掉,設置此計數

unsigned int truesize

      此緩衝區總大小,包括sk_buff。sk_buff只不過是個指針的集合,他所指的纔是真正的數據區,因此是兩部分。(見下圖)

sk_buff_data_t         tail;

sk_buff_data_t         end;

unsigned char     *head, *data;

      這些指針很重要,他們指向的是真正的數據區,他們的邊界。head和end指向的是數據區的開端和尾端(注意和data,tail區別)以下圖,data和tail指向的是實際數據的開頭和結尾。

      由於數據區在協議棧走的時候要一層層添加或去掉一些數據(好比報頭)因此申請一塊大的足夠的內存,而後在往裏放東西。真實的實際數據可能用不了這麼多,因此用data,tail指向真實的,head,tail指向邊界。剛開始沒填充數據時前三個指針指向的是一個地方。

 

               

void (*destructor) (…….)

      此函數指針被初始化一個函數,當此緩衝區刪除時,完成某些工做。

通用字段

struct timeval stamp(2.6.25沒有,估計是ktime_t tstamp)

      時間戳,表示什麼時候被接受或有時表示包預約的傳輸時間

struct net_device *dev

      描述一個網絡設備,我會之後分析他。

sk_buff_data_t         transport_header; //L4

sk_buff_data_t         network_header; //L3

sk_buff_data_t         mac_header; //L2

這些指針分別指向報文頭部,和2.4版本比較有了變化,再也不是聯合體,使用更加方便了,Linux給出了很方便的函數直接定位到各層的頭部。下圖是2.4版本的,只是說明一下。

 

 

struct dst_entry dst

      路由子系統使用。目前不知道怎麼回事呢。聽說比較複雜。

char cb[40]

      緩衝控制區,用來存儲私有信息的空間。好比tcp用這個空間存儲一個結構體tcp_skb_cb ,能夠用宏TCP_SKB_CB(__skb)定位到他,而後使用裏面的變量。

ip_summed:2

__wsum   csum;

      校驗和

unsigned char pkt_type

      根據L2層幀的目的地址進行類型劃分。

unsigned char cloned

      表示該結構是另外一個sk_buff克隆的。

__u32           priority;

      QoS等級

__be16               protocol;

      從L2層設備驅動看使用在下一個較高層的協議。

功能專用字段

Linux是模塊化的,你編譯時能夠帶上特定功能,好比netfilter等,相應的字段纔會生效。應該是那些預約義控制的。

 

管理函數

下面這個圖是:(a*)skb_put; (b*) skb_push; (c*) skb_pull (d*)skb_reserve的使用,主要是對skb_buf所指向的數據區的指針移動。(數據預留以及對齊)

 

 

 

下圖是用skb_reserve函數,把一個14字節的ethernet幀拷貝到緩衝區。skb_reserve(skb, 2), 2表示16字節對齊。14+2=16

 

 

下圖是穿過協議棧從tcp層向下到鏈路層的過程

 

 

 

分配內存:

alloc_skb 分配緩衝區和一個sk_buff結構

dev_alloc_skb 設備驅動程序使用的緩衝區分配函數

釋放內存:

kfree_skb 只有skb->users計數器爲1時才釋放

dev_kfree_skb

緩衝區克隆函數 skb_clone

 

列表管理函數:

skb_queue_head_init

      隊列初始化

skb_queue_head , skb_queue_tail

      把一個緩衝區添加到隊列頭或尾

skb_dequeue, skb_dequeue_tail

      從頭或尾去掉

skb_queue_purge

      把隊列變空

skb_queue_walk

      循環隊列每一個元素

相關文章
相關標籤/搜索