![linux-sk-buff-完全剖析與理解_第1頁](http://file4.renrendoc.com/view/163fa9cfe2dd1f9f289b284991288b28/163fa9cfe2dd1f9f289b284991288b281.gif)
![linux-sk-buff-完全剖析與理解_第2頁](http://file4.renrendoc.com/view/163fa9cfe2dd1f9f289b284991288b28/163fa9cfe2dd1f9f289b284991288b282.gif)
![linux-sk-buff-完全剖析與理解_第3頁](http://file4.renrendoc.com/view/163fa9cfe2dd1f9f289b284991288b28/163fa9cfe2dd1f9f289b284991288b283.gif)
![linux-sk-buff-完全剖析與理解_第4頁](http://file4.renrendoc.com/view/163fa9cfe2dd1f9f289b284991288b28/163fa9cfe2dd1f9f289b284991288b284.gif)
![linux-sk-buff-完全剖析與理解_第5頁](http://file4.renrendoc.com/view/163fa9cfe2dd1f9f289b284991288b28/163fa9cfe2dd1f9f289b284991288b285.gif)
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
sk_buff目錄1sk_buff介紹2sk_buff組成3structsk_buff結構體4sk_buff成員變量4.1Layout布局4.2General通用4.3Feature-specific功能相關5sk_buff管理和操作函數5.1緩沖區(qū)操作函數skb_reserveskb_putskb_pushskb_pull5.2發(fā)送tcp報文示例5.3緩沖區(qū)分配、克隆和釋放函數alloc_skbskb_clonepskb_copyskb_copykfree_skb1sk_buff介紹sk_buff(socketbuffer)結構是linux網絡代碼中重要的數據結構,它管理和控制接收或發(fā)送數據包的信息。2sk_buff組成Packetdata:通過網卡收發(fā)的報文,包括鏈路層、網絡層、傳輸層的協議頭和攜帶的應用數據,包括headroom,data,tailroom三部分。skb_shared_info作為packetdata的補充,用于存儲ip分片,其中sk_buff*frag_list是一系列子skbuff鏈表,而frag[]是由一組單獨的page組成的數據緩沖區(qū)。Databuffer:用于存儲packetdata的緩沖區(qū),分為以上兩部分。Sk_buff:緩沖區(qū)控制結構sk_buff。整個sk_buff結構圖如圖1。headheaddatatailendHeadroomDATATailroom…frag_listfrags[0]frags[1]…PacketdataDataBuffersk_bufffrags[MAX_SKB..]skb_shared_info分片1分片2頁碎片圖1sk_buff結構圖3structsk_buff結構體/*structsk_buff-socketbuffer*/structsk_buff{/*Thesetwomembersmustbefirst.*/structsk_buff *next;structsk_buff *prev;structsock *sk;structskb_timeval tstamp;/*Timewearrived,記錄接收或發(fā)送報文的時間戳*/structnet_device *dev;/*通過該設備接收或發(fā)送,記錄網絡接口的信息和完成操作structnet_device *input_dev;/*接收數據的網絡設備structnet_device *curlayer_input_dev;structnet_device *l2tp_input_dev;union{structtcphdr *th;structudphdr *uh;structicmphdr *icmph;structigmphdr *igmph;structiphdr *ipiph;structipv6hdr *ipv6h;unsignedchar *raw;}h;//傳輸層報頭union{structiphdr *iph;structipv6hdr *ipv6h;structarphdr *arph;unsignedchar *raw;}nh;//網絡層報頭union{unsignedchar *raw;}mac;//鏈路層報頭...unsignedint len,//len緩沖區(qū)中數據部分的長度。data_len,//data_len只計算分片中數據的長度mac_len,//mac頭的長度csum;//校驗和__u32 priority;__u8 local_df:1,cloned:1,//表示該結構是另一個sk_buff克隆的ip_summed:2,nohdr:1,nfctinfo:3;__u8 pkt_type:3,fclone:2,ipvs_property:1;__be16 protocol;__u32flag;/*packetflags*/.../*Theseelementsmustbeattheend,seealloc_skb()fordetails.*/unsignedint truesize;//這是緩沖區(qū)的總長度,包括sk_buff結構和數據部分atomic_t users;unsignedchar *head,//指向緩沖區(qū)的頭部*data,//指向實際數據的頭部*tail,//指向實際數據的尾部*end;//指向緩沖區(qū)的尾部};4sk_buff成員變量Sk_buff成員變量主要包括以下3類1Layout布局2General通用3Feature-specific功能相關4.1Layout布局1structsk_buff*next,structsk_buff*prev有些sk_buff成員變量的作用是方便查找,或者是連接數據結構本身.內核可以把sk_buff組織成一個雙向鏈表。當然,這個鏈表的結構要比常見的雙向鏈表的結構復雜一點。就像任何一個雙向鏈表一樣,sk_buff中有兩個指針next和prev,其中,next指向下一個節(jié)點,而prev指向上一個節(jié)點。但是,這個鏈表還有另一個需求:每個sk_buff結構都必須能夠很快找到鏈表頭節(jié)點。為了滿足這個需求,在第一個節(jié)點前面會插入另一個結構sk_buff_head,這是一個輔助節(jié)點,它的定義如下sk_buff和sk_buff_head的前兩個元素是一樣的:next和prev指針。這使得它們可以放到同一個鏈表中,盡管sk_buff_head要比sk_buff小得多。另外,相同的函數可以同樣應用于sk_buff和sk_buff_head。圖22structsock*sk這是一個指向擁有這個sk_buff的sock結構的指針。這個指針在網絡包由本機發(fā)出或者由本機進程接收時有效,因為插口相關的信息被L4(TCP或UDP)或者用戶空間程序使用。如果sk_buff只在轉發(fā)中使用(這意味著,源地址和目的地址都不是本機地址),這個指針是NULL。3unsignedintlen這是緩沖區(qū)中數據部分的長度。它包括主緩沖區(qū)中的數據長度(data指針指向它)和分片中的數據長度。它的值在緩沖區(qū)從一個層向另一個層傳遞時改變,因為往上層傳遞,舊的頭部就沒有用了,而往下層傳遞,需要添加本層的頭部。len同樣包含了協議頭的長度。4unsignedintdata_len和len不同,data_len只計算分片中數據的長度。5unsignedintmac_len這是mac頭的長度。6atomic_tusers這是一個引用計數,用于計算有多少實體引用了這個sk_buff緩沖區(qū)。它的主要用途是防止釋放sk_buff后,還有其他實體引用這個sk_buff。因此,每個引用這個緩沖區(qū)的實體都必須在適當的時候增加或減小這個變量。這個計數器只保護sk_buff結構本身,而緩沖區(qū)的數據部分由類似的計數器(dataref)來保護。有時可以用atomic_inc和atomic_dec函數來直接增加或減小users,但是,通常還是使用函數skb_get和kfree_skb來操作這個變量。7unsignedinttruesize這是緩沖區(qū)的總長度,包括sk_buff結構和數據部分。如果申請一個len字節(jié)的緩沖區(qū),alloc_skb函數會把它初始化成len+sizeof(sk_buff)。8unsignedchar*head,*end,*data,*tail它們表示緩沖區(qū)和數據部分的邊界。在每一層申請緩沖區(qū)時,它會分配比協議頭或協議數據大的空間。head和end指向緩沖區(qū)的頭部和尾部,而data和tail指向實際數據的頭部和尾部,參見圖3。每一層會在head和data之間填充協議頭,或者在tail和end之間添加新的協議數據。圖3中右邊數據部分會在尾部包含一個附加的頭部。圖39void(*destructor)(...)這個函數指針可以初始化成一個在緩沖區(qū)釋放時完成某些動作的函數。如果緩沖區(qū)不屬于一個socket,這個函數指針通常是不會被賦值的。如果緩沖區(qū)屬于一個socket,這個函數指針會被賦值為sock_rfree或sock_wfree(分別由skb_set_owner_r或skb_set_owner_w函數初始化)。這兩個sock_xxx函數用于更新socket隊列中的內存容量。4.2General通用本節(jié)描述sk_buff的主要成員變量,這些成員變量與特定的內核功能無關。1structtimevaltstamp這個變量只對接收到的包有意義。它代表包接收時的時間戳,或者有時代表包準備發(fā)出時的時間戳。它在netif_rx里面由函數net_timestamp設置,而netif_rx是設備驅動收到一個包后調用的函數。2structnet_device*dev這個變量的類型是net_device,net_device它代表一個網絡設備。dev的作用與這個包是準備發(fā)出的包,還是剛接收的包有關。當收到一個包時,設備驅動會把sk_buff的dev指針指向收到這個包的設備的數據結構,就像下面的vortex_rx里的一段代碼所做的一樣,這個函數屬于3c59x系列以太網卡驅動,用于接收一個幀。(drivers/net/3c59x.c):當一個包被發(fā)送時,這個變量代表將要發(fā)送這個包的設備。在發(fā)送網絡包時設置這個值的代碼要比接收網絡包時設置這個值的代碼復雜。有些網絡功能可以把多個網絡設備組成一個虛擬的網絡設備(也就是說,這些設備沒有和物理設備直接關聯),并由一個虛擬網絡設備驅動管理。當虛擬設備被使用時,dev指針指向虛擬設備的net_device結構。而虛擬設備驅動會在一組設備中選擇一個設備并把dev指針修改為這個設備的net_device結構。因此,在某些情況下,指向傳輸設備的指針會在包處理過程中被改變。3structnet_device*input_dev這是收到包的網絡設備的指針。如果包是本地生成的,這個值為NULL。對以太網設備來說,這個值由eth_type_trans初始化,它主要被流量控制代碼使用。4structnet_device*real_dev這個變量只對虛擬設備有意義,它代表與虛擬設備關聯的真實設備。例如,Bonding和VLAN設備都使用它來指向收到包的真實設備。5union{...}hunion{...}nhunion{...}mac這些是指向TCP/IP各層協議頭的指針:h指向L4,nh指向L3,mac指向L2。每個指針的類型都是一個聯合,包含多個數據結構,每一個數據結構都表示內核在這一層可以解析的協議。例如,h是一個包含內核所能解析的L4協議的數據結構的聯合。每一個聯合都有一個raw變量用于初始化,后續(xù)的訪問都是通過協議相關的變量進行的。當接收一個包時,處理n層協議頭的函數從n-1層收到一個緩沖區(qū),它的skb->data指向n層協議的頭。處理n層協議的函數把本層的指針(例如,L3對應的是skb->nh指針)初始化為skb->data,因為這個指針的值會在處理下一層協議時改變(skb->data將被初始化成緩沖區(qū)里的其他地址)。在處理n層協議的函數結束時,在把包傳遞給n+1層的處理函數前,它會把skb->data指針指向n層協議頭的末尾,這正好是n+1層協議的協議頭(參見圖4)。發(fā)送包的過程與此相反,但是由于要為每一層添加新的協議頭,這個過程要比接收包的過程復雜。圖46structdst_entrydst這個變量在路由子系統中使用。7charcb[40]這是一個控制緩存,或者說是一個私有信息的存儲空間,由每一層自己維護并使用。它在分配sk_buff結構時分配(它目前的大小是40字節(jié),已經足夠為每一層存儲必要的私有信息了)。在每一層中,訪問這個變量的代碼通常用宏實現,以增強代碼的可讀性。例如,TCP用這個變量存儲tcp_skb_cb結構,這個結構在include/net/tcp.h中定義:下面這個宏被TCP代碼用來訪問cb變量。在這個宏里面,有一個簡單的類型轉換:#defineTCP_SKB_CB(__skb)((structtcp_skb_cb*)&((__skb)->cb[0]))下面的例子是TCP子系統在收到一個分段時填充相關數據結構的代碼:inttcp_v4_rcv(structsk_buff*skb)8unsignedintcsumunsignedcharip_summed表示校驗和以及相關狀態(tài)標記。unsignedcharcloned一個布爾標記,當被設置時,表示這個結構是另一個sk_buff的克隆。9unsignedcharpkt_type這個變量表示幀的類型,分類是由L2的目的地址來決定的??赡艿娜≈刀荚趇nclude/linux/if_packet.h中定義。對以太網設備來說,這個變量由eth_type_trans函數初始化。10__u32priority這個變量描述發(fā)送或轉發(fā)包的QoS類別。如果包是本地生成的,socket層會設置priority變量。如果包是將要被轉發(fā)的,rt_tos2priority函數會根據ip頭中的Tos域來計算賦給這個變量的值。這個變量的值與DSCP(DiffServCodePoint)沒有任何關系。unsignedshortprotocol這個變量是高層協議從二層設備的角度所看到的協議。典型的協議包括IP,IPV6和ARP。完整的列表在include/linux/if_ether.h中。由于每個協議都有自己的協議處理函數來處理接收到的包,因此,這個域被設備驅動用于通知上層調用哪個協議處理函數。每個網絡驅動都調用netif_rx來通知上層網絡協議的協議處理函數,因此protocol變量必須在這些協議處理函數調用之前初始化。unsignedshortsecurity這是包的安全級別。這個變量最初由IPSec子系統使用,但現在已經作廢了。4.3Feature-specific功能相關linux內核是模塊化的,你可以選擇包含或者刪除某些功能。因此,sk_buff結構里面的一些成員變量只有在內核選擇支持某些功能時才有效,比如防火墻(netfilter)或者qos:1unsignedlongnfmark__u32nfcache__u32nfctinfostructnf_conntrack*nfctunsignedintnfdebugstructnf_bridge_info*nf_bridge這些變量被netfilter使用(防火墻代碼),內核編譯選項是“DeviceDrivers->Networkingsupport->Networkingoptions->Networkpacketfiltering”和兩個子選項“Networkpacketfilteringdebugging”和“BridgedIP/ARPpacketsfiltering”2union{...}private這個聯合結構被高性能并行接口(HIPPI)使用。相應的內核編譯選項是“Device->Drivers->Networkingsupport->Networkdevicesupport->HIPPIdriversupport”3__u32tc_index__u32tc_verd__u32tc_classid這些變量被流量控制代碼使用,內核編譯選項是“DeviceDrivers->Networking->support->Networkingoptions->QoSand/orfairqueueing”和它的子選項“PacketclassifierAPI”4structsec_path*sp這個變量被IPSec協議用于跟蹤傳輸的信息。5sk_buff管理和操作函數5.1緩沖區(qū)操作函數有很多函數,通常都比較短小而且簡單,內核用這些函數操作sk_buff的成員變量或者sk_buff鏈表。首先來看分配和釋放緩沖區(qū)的函數,然后是一些通過移動指針在緩沖區(qū)的頭部或尾部預留空間的函數。如果你看過include/linux/skbuff.h和net/core/skbuff.c中的函數,你會發(fā)現,基本上每個函數都有兩個版本,名字分別是do_something和__do_something。通常第一種函數是一個包裝函數,它會在第二種函數的基礎上增加合法性檢查或者鎖。一般來說,類似__do_something的函數不能被直接調用(除非滿足特定的條件,比如說鎖)。那些違反這條規(guī)則而直接引用這些函數的不良代碼會最終被更正。各操作函數緩沖區(qū)與移動指針變化如圖5所示。圖5操作前與操作后指針變化圖:(a)skb_put,(b)skb_push,(c)skb_pull,and(d)skb_reserve1unsignedchar*skb_put(structsk_buff*skb,unsignedintlen)在緩沖區(qū)的尾部空間擴充len字節(jié)數據區(qū)l,將tail指針下移,并增加skb的len值。data和tail之間的空間就是可以存放網絡報文的空間。這個操作增加了可以存儲網絡報文的空間,但是增加不能使tail的值大于end的值,skb的len值大于truesize的值。2unsignedchar*skb_push(structsk_buff*skb,unsignedintlen)在緩沖區(qū)的頭部空間擴充len字節(jié)的數據區(qū)。將data指針上移,并增加skb的len值。這個操作在存儲空間的頭部增加了一段可以存儲網絡報文的空間,但是增加不能使data的值小于head的值,skb的len值大于truesize的值。3unsignedchar*skb_pull(structsk_buff*skb,unsignedintlen)從緩沖區(qū)的數據區(qū)刪除len字節(jié),把騰出的內存歸還給頭部空間。將data指針下移,并減小skb的len值。這個操作使data指針指向下一層網絡報文的頭部。4voidskb_reserve(structsk_buff*skb,unsignedintlen)從空白緩沖區(qū)中分配len字節(jié)的數據區(qū),通過減少尾部空間,增加一個空&sk_buff的首部空間,將data指針和tail指針同時下移。這個操作在存儲空間的頭部預留len長度的空隙。如果查看某個以太網設備驅動的收包函數(例如,drivers/net/3c59x.c中的vortex_rx),你就會發(fā)現它在分配緩沖區(qū)之后,在向緩沖區(qū)中填充數據之前,會調用下面的函數:由于以太網幀的頭部長度是14個八位組,這個函數把緩沖區(qū)的頭部指針向后移動了2個字節(jié)。這樣,緊跟在以太網頭部之后的IP頭部在緩沖區(qū)中存儲時就可以在16字節(jié)的邊界上對齊。如圖6所示。圖6(a)skb_reserve開始前,(b)skb_reserve后(c)復制數據到緩沖區(qū)5.2發(fā)送tcp報文示例發(fā)送報文時,在不同協議層處理數據時,該數據要添加相應的協議頭。因此,最高層添加數據和自身的協議頭。alloc_skb用來申請一個sk_buff。skb_reserve用來創(chuàng)建頭空間。skb_put用來創(chuàng)建用戶數據空間,用戶數據復制到sk->data指向的數據區(qū)。接下來使用skb_push是在用戶數據的前面加上各層協議頭。圖7是發(fā)送tcp報文的整個過程示意圖。1)當TCP發(fā)送數據時,它根據一些條件分配一個緩沖區(qū)(比如,TCP的最大分段長度(mss),是否支持散讀散寫I/O等2)TCP在緩沖區(qū)的頭部預留足夠的空間(用skb_reserve)用于填充各層的頭部(如TCP,IP,鏈路層等)。MAX_TCP_HEADER參數是各層頭部長度的總和,它考慮了最壞的情況:由于tcp層不知道將要用哪個接口發(fā)送包,它為每一層預留了最大的頭部長度。它甚至考慮了出現多個IP頭的可能性(如果內核編譯支持IPoverIP,我們就會遇到多個IP頭的情況)。3)把TCP的負載拷貝到緩沖區(qū)(用skb_put,復制數據)。需要注意的是:圖7只是一個例子。TCP的負載可能會被組織成其他形式。例如它可以存儲到分片中。4)TCP層添加自己的頭部(用skb_push)。5)TCP層把緩沖區(qū)傳遞給IP層,IP層同樣添加自己的頭部(用skb_push)。6)IP層把緩沖區(qū)傳遞給鄰居層,鄰居層添加鏈路層頭部(用skb_push)。Tcp報文發(fā)送過程如圖6所示。接收報文時:當緩沖區(qū)在協議棧中向下層傳遞時,每一層都把skb->data指針向下移動,然后拷貝自己的頭部,同時更新skb->len。圖7tcp報文發(fā)送過程5.3緩沖區(qū)分配、克隆和釋放函數分析1alloc_skballoc_skb是net/core/skbuff.c里面定義的,用于分配緩沖區(qū)的函數。我們已經知道,數據緩沖區(qū)和緩沖區(qū)的描述結構(sk_buff結構)是兩種不同的實體,這就意味著,在分配一個緩沖區(qū)時,需要分配兩塊內存(一個是緩沖區(qū),一個是緩沖區(qū)的描述結構sk_buff)。alloc_skb函數起始可以看作三部分,第一部分是從cache中分配內存,第二部分是初始化分配的skb的相關域。第三部分是處理fclone。1)分配內存首先調用函數kmem_cache_alloc從緩存中獲取一個sk_buff結構,然后調用kmalloc_cachhe_alloc_node分配緩沖區(qū)(如果有緩存的話,它同樣從緩存中獲取內存)。2)初始化在調用kmalloc前,size參數通過SKB_DATA_ALIGN宏強制對齊。在函數返回前,它會初始化結構中的一些變量。3)處理fclone每次skb_clone一個skb的時候,都是要調用kmem_cache_alloc從cache中alloc一塊新的內存。而現在當我們擁有了fastclone之后,通過調用alloc_skb_fclone函數來分配一塊大于sizeof(structsk_buff)的內存,也就是在這次請求的skb的下方多申請了一些內存,然后返回的時候設置返回的skb的fclone標記為SKB_FCLONE_ORIG,而多申請的那塊內存的sk_buff的fclone為SKB_FCLONE_UNAVAILABLE,這樣當我們調用skb_clone克隆這個skb的時候看到fclone的標記就可以直接將skb的指針+1,而不需要從cache中取了。這樣的話節(jié)省了一次內存存取,提高了clone的效率,不過調用flcone一般都是我們確定接下來這個skb會被clone很多次。4)skb指針狀態(tài)alloc_skb之后的skb的指針的狀態(tài)如圖8所示。在圖7右邊所示的內存塊的底部,可以能看到對齊操作所帶來的填充區(qū)域(padding)。圖8skb指針狀態(tài)2克隆skb_clone如果一個緩沖區(qū)需要被不同的用戶獨立地操作,而這些用戶可能會修改sk_buff中某些變量的值(比如h和nh值),內核沒有必要為每個用戶復制一份完整的sk_buff以及相應的緩沖區(qū)。相反,為提高性能,內核克隆一個緩沖區(qū)。克隆過程只復制sk_buff結構,同時修改緩沖區(qū)的引用計數以避免共享的數據被提前釋放??寺【彌_區(qū)使用skb_clone函數。一個
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年揭陽貨運從業(yè)資格證考題
- 2025年德州下載b2貨運從業(yè)資格證模擬考試考試
- 2025年商丘駕??荚囏涍\從業(yè)資格證模擬考試
- 電視臺合同范本(2篇)
- 電力服務績效合同(2篇)
- 山西省陽曲縣八年級地理上冊 第二章 自然環(huán)境 我們賴以生存的基本條件說課稿 晉教版
- 2024-2025學年五年級語文上冊第二單元5裝滿昆蟲的衣袋教案設計蘇教版
- 2024-2025學年高中歷史第四單元中國社會主義建設發(fā)展道路的探索第19課經濟體制改革教案含解析岳麓版必修2
- 馬栗種子提取物片說明書
- 湘教版地理八年級下冊:9 建設《永續(xù)發(fā)展的美麗中國》 聽課評課記錄
- 對違反政治紀律行為的處分心得體會
- 大學生職業(yè)生涯發(fā)展與規(guī)劃(第二版)PPT完整全套教學課件
- 《深度學習革命》讀書筆記思維導圖PPT模板下載
- SAP可配置產品學習課件
- 傳統運動療法易筋經教案5
- GB/T 8014.1-2005鋁及鋁合金陽極氧化氧化膜厚度的測量方法第1部分:測量原則
- 股票基礎知識(入市必讀)-PPT
- 雅思閱讀題型與技巧課件
- 招商銀行房地產貸款壓力測試
- 公文與公文寫作課件
- 車削成形面和表面修飾加工課件
評論
0/150
提交評論