LINUX內(nèi)核網(wǎng)卡驅(qū)動解析_第1頁
LINUX內(nèi)核網(wǎng)卡驅(qū)動解析_第2頁
LINUX內(nèi)核網(wǎng)卡驅(qū)動解析_第3頁
LINUX內(nèi)核網(wǎng)卡驅(qū)動解析_第4頁
LINUX內(nèi)核網(wǎng)卡驅(qū)動解析_第5頁
已閱讀5頁,還剩68頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、Linux具有作為網(wǎng)絡(luò)操作系統(tǒng)尤其是服務(wù)器端操作系統(tǒng)的優(yōu)勢。網(wǎng)絡(luò)部分代碼量很大,TCP/IP協(xié)議本身就很復(fù)雜,因而本堂就主要介紹數(shù)據(jù)包的傳遞過程、與應(yīng)用層的接口、與底層的接口及網(wǎng)絡(luò)驅(qū)動程序的編寫。目錄【隱藏11Linux網(wǎng)絡(luò)系統(tǒng)分層結(jié)構(gòu)22數(shù)據(jù)包結(jié)構(gòu)2.1msghdr纟吉構(gòu)2.2socket結(jié)構(gòu)2.3sl:_buff結(jié)構(gòu)及管理2.31sk.buff結(jié)構(gòu)2.4sl:_buff及其鏈表的操作2.4.1(1)對或_buff對應(yīng)的數(shù)據(jù)區(qū)進(jìn)行控制2.4.2(2)對緩沖區(qū)鏈表進(jìn)行操作25sock結(jié)構(gòu)3sockfs文件系統(tǒng)4利用socket通信4.1socket層42IP層收發(fā)數(shù)據(jù)包函數(shù)421接收例程422

2、發(fā)送例程43網(wǎng)絡(luò)核心層4.3.1net.device結(jié)構(gòu)432網(wǎng)絡(luò)設(shè)備初始化43?接收數(shù)據(jù)包434包接收5網(wǎng)卡驅(qū)動程序51NAPI528139CP網(wǎng)卡驅(qū)動程序1Linux網(wǎng)絡(luò)系統(tǒng)分層結(jié)構(gòu)Linux網(wǎng)絡(luò)系統(tǒng)遵守一個四層的模型概念:應(yīng)用層、傳輸層、互聯(lián)層和網(wǎng)絡(luò)接口層。模型的基層是網(wǎng)絡(luò)接口層。負(fù)責(zé)數(shù)據(jù)幀的發(fā)送和接收.幀是獨立的網(wǎng)絡(luò)信息傳輸單元。網(wǎng)絡(luò)接口層將幀放在網(wǎng)上,或從網(wǎng)上把幀取下來。互聯(lián)協(xié)議將數(shù)據(jù)包封裝成internet數(shù)據(jù)報,并運行必要的路由算法。這里有四個互聯(lián)協(xié)議:網(wǎng)際協(xié)議IP:負(fù)責(zé)在主機和網(wǎng)絡(luò)之間尋址和路由數(shù)據(jù)包。地址解析協(xié)議ARP:獲得同一物理網(wǎng)絡(luò)中的硬件主機地址。網(wǎng)際控制消息協(xié)議ICM

3、P:發(fā)送消息.并報告有關(guān)數(shù)據(jù)包的傳送錯誤。互聯(lián)組管理協(xié)議IGMP:被IP主機拿來向本地多路廣摘路由器報告主機組成員。傳輸協(xié)議在計算機之間提供通信會話。傳輸協(xié)議的選擇根據(jù)數(shù)據(jù)傳輸方式而定。兩個傳輸協(xié)議:傳輸控制協(xié)議TCP:為應(yīng)用程序提供可靠的通信連接。適合于一次傳輸大批數(shù)扌居的情況。并適用于要求得到響應(yīng)的應(yīng)用程序。用戶數(shù)扌居報協(xié)議UDP:提供了無連接通信,且不對傳送包進(jìn)行可靠的保證。適合于一次傳輸小呈數(shù)據(jù),可靠性則由應(yīng)用層來負(fù)責(zé)。應(yīng)用層應(yīng)用程序通過這一層訪問網(wǎng)絡(luò)。網(wǎng)絡(luò)接口技術(shù)IP使用網(wǎng)絡(luò)設(shè)備接口規(guī)范NDIS向網(wǎng)絡(luò)接口層提交幀。IP支持廣域網(wǎng)和本地網(wǎng)接口技術(shù)。串行線路協(xié)議TCP/IPG一般通過in

4、ternet串行線路協(xié)議SLIP或點對點協(xié)議PPP在串行線上進(jìn)行數(shù)扌居傳送。BSDSocket接口是個通用的接口,它支持各種網(wǎng)絡(luò)工作形式。一個套接字描述一個通訊連接的一端,兩個通訊程序中各自有一個套接字來描述它們自己那一端。Linux支持多種類型的套接字。每一類型的套接字有它自己的通信尋址方法。Linux支持下列套接字地址族或域:UNIXUnix域套接字INETInternet地址族支持通過TCP/IP協(xié)議的通信AX25AmateurradioX25IPXNovellIPXAPPLETALKAppletalkDDPX25X25INETsocket層支持包括TCP/IP協(xié)議在內(nèi)的internet

5、地址族。這些協(xié)議是分層的,一個協(xié)議使用另一個協(xié)議的服務(wù)。它與BSDsocket層的接口要通過一系列Internet地址族socket操作,這一操作是在網(wǎng)絡(luò)初始化時就已經(jīng)注冊到BSDsocket層的。為了不把BSDsocket與TCP/IP的特定信息搞混,INETsocket層使用它自己的數(shù)據(jù)結(jié)構(gòu)sock,它與BSDsocket結(jié)構(gòu)相連。Linux網(wǎng)絡(luò)層次圖2數(shù)據(jù)包結(jié)構(gòu)結(jié)構(gòu)sockjocb是socket的I/O控制塊.用來進(jìn)行socket的I/O異步處理,它是網(wǎng)絡(luò)傳輸?shù)囊粋€總的控制結(jié)構(gòu),結(jié)構(gòu)sockjocb列出如下(在include/net/sock.h中):structsock_iocblis

6、t;structlist_headintflags;intsize;structsocket*sock;structsock*sk;structscm_cookie*scm;structmsghdr*msg,async_msg;structiovecasync_iov;structkiocb*kiocb;;在內(nèi)核中的BSDSocket層使用msghdr結(jié)構(gòu)來存儲數(shù)據(jù)包,使用socket結(jié)構(gòu)來字處理控制socket.在INETSocket以下層中使用sk_buff結(jié)構(gòu)來存儲數(shù)扌居包。使用sock結(jié)構(gòu)來管理數(shù)據(jù)包存放和調(diào)度。下面這兩個結(jié)構(gòu)分別進(jìn)行討論。msghdr結(jié)構(gòu)linux/socket.hs

7、tructmsghdrvoid*intstructiovecmsg_name;msg_namelen;msg_iov;_kernel_size_tmsgiovlen;void*msg_controt;/Socket名字/名字長度/數(shù)據(jù)塊/數(shù)據(jù)塊個數(shù)/各個協(xié)議的magic(如8SQ文件描述子_kernel_size_tmsg_controllen;/*Lengthofcmsglist*/unsignedmsgjlags;/保存接收數(shù)據(jù)的時候使用的控制標(biāo)志;linux/uio.hstructiovecvoid_user*iov_base;/數(shù)據(jù)緩存區(qū)地址_kernel_size_tiov_len;

8、/數(shù)據(jù)長度;socket結(jié)構(gòu)Linux應(yīng)用層的程序使用的是標(biāo)準(zhǔn)的BSDSocket接口.BSDSocket層管理多種地址簇。socket結(jié)構(gòu)是BSDSocket層的socket控制結(jié)構(gòu),在應(yīng)用程序中通過使用一個socket文件描述符與一個socket相對應(yīng)。include/linux/net.hstructsocketsocketstateunsignedlongstructproto_opsstate;/socket狀態(tài)flags;/如SOCKSYNCJJOSPACE的標(biāo)識*ops;/協(xié)議特定的socket操作structstructstructfasync_structasync_list

9、;/異步喚程隊列/回指向file的指針*sk;/指向下一層協(xié)議中的sock結(jié)構(gòu)wait;/等待在這個socket上的任務(wù)列衷filesockwait_queue_head_tshortunsignedcharPF_LOCAL;type;/數(shù)據(jù)包的類型passered;/credentials(usedonlyinUnixSockets(akasocket結(jié)構(gòu)中的state狀態(tài)值如下枚舉結(jié)構(gòu),主要的有SSJJNCONNECTED和SS_CONNECTEDr這個結(jié)構(gòu)列出如TtypedefenumSS_FREE=0,SSJJNCONNECTED,SS_CONNECTINGZSS_CONNECTED,

10、SS_DISCONNECTINGsocket_state;/不允許的狀態(tài)/沒連接到任何socket/在連接中/已連接到socket/連接正在斷開中Linux系統(tǒng)調(diào)用建立新的套接字時.需要傳遞套接字的地址族標(biāo)識符、套接字類型以及協(xié)議。內(nèi)核套接字分配新的socket數(shù)據(jù)結(jié)構(gòu)。Socket數(shù)據(jù)結(jié)構(gòu)實際是VFS索引節(jié)點數(shù)據(jù)結(jié)構(gòu)的一部分.分配新的socket數(shù)扌居結(jié)構(gòu)實際就是分配新的VFS索引節(jié)點。socket在文件系統(tǒng)位萱如下圖所示:Filesjtrudfib圖socket在文件系統(tǒng)inode中的位吉sk_buff結(jié)構(gòu)及管理sk_buff結(jié)構(gòu)Linux網(wǎng)絡(luò)層采用統(tǒng)一的緩沖區(qū)結(jié)構(gòu)skbuff,一個個單獨

11、的sKbuff被組織成雙向鏈衷的形式。網(wǎng)卡接收到數(shù)據(jù)幀后,系統(tǒng)內(nèi)核為接收到的數(shù)據(jù)幀放在skbuff結(jié)構(gòu)管理的緩沖區(qū)內(nèi)。在網(wǎng)絡(luò)協(xié)議處理的時候數(shù)據(jù)均以skbuff的形式在各層之間傳遞、處理。sk_buff提供了眾多指針,可以快速的定位協(xié)議頭位筈.它同時保留了許多數(shù)據(jù)包信息(如使用的網(wǎng)絡(luò)設(shè)備等),以便協(xié)議層根據(jù)需要靈活應(yīng)用。下面套接字緩沖區(qū)流程圖說明了skbuff流動的過程。在源主機上.INETsocket層創(chuàng)建了skbuff緩沖區(qū),它沿網(wǎng)絡(luò)自上而下傳遞.它先在協(xié)議層流動.最后在物理層消失。同時把它所帶的數(shù)據(jù)傳遞給目標(biāo)主機的物理層的套接字緩沖區(qū).該綜沖區(qū)自下而上傳遞到目標(biāo)主機的春接字,并把數(shù)據(jù)傳遞給

12、用戶進(jìn)程.目標(biāo)主機的套接字緩沖區(qū)也同時消失。當(dāng)套接字綜沖區(qū)在協(xié)議層流動過程中.毎個協(xié)議都在發(fā)送數(shù)據(jù)區(qū)添加自己的協(xié)議頭和協(xié)議尾,而在接收數(shù)據(jù)時去掉這些協(xié)議頭和協(xié)議尾。設(shè)Ssk_buff數(shù)據(jù)結(jié)構(gòu)的主要目的就是為網(wǎng)絡(luò)提供一種統(tǒng)一有效的緩沖區(qū)操作方法。冬技字層(M)(脫Mg職)MSMSBEfesg4性4in發(fā)fiffi圖套接字緩沖區(qū)流程圖在linux/skbuff.h中有sk_buff結(jié)構(gòu)的定義,說明如下:structskbuffheadstructsk_buffstructsk_buff_u32spinlock_t;/*Thesetwomembersmustbefirst*/next;+prev;q

13、len;/鏈衷節(jié)點的個數(shù)lock;structsk_buff/*Thesetwomembersmustbefirst*/structsk_buffstructsk_buff*next;*prev;structsk_buff_head示在哪個鏈表上structsock*sk;/被哪個socket擁有structtimevalstamp;/數(shù)據(jù)包到達(dá)的時間structnet_device*dev;/數(shù)據(jù)包經(jīng)過的網(wǎng)絡(luò)i殳備structnet_device*input_dev;/數(shù)據(jù)包到達(dá)的設(shè)備structnet_device*real_dev;/數(shù)據(jù)包正在使用的設(shè)備unionstructtcphdr

14、structudphdr*th;/TCP傳輸層頭*uh;/UDP頭structicmphdr*icmph;structigmphdr*igmph;structiphdr*ipiph;structipv6hdr*ipv6h;unsignedchar*raw;/h;*iph;/IP層頭*ipv6h;*arph;*raw;unionstructiphdrstructipv6hdrstructarphdrunsignedcharnh;*raw;unionunsignedcharmac;/M4C層即數(shù)據(jù)鏈路層頭structdstentrystructsec_path*dst;/發(fā)送到的目標(biāo)地址描述+sp

15、;charcb40;/控制buffer9毎層自由使用,存放個人鑿數(shù),/如果你想在層間保持這些數(shù)據(jù),你得先做skbclonef)操作。unsignedintIenz/實際的數(shù)據(jù)長度data.len,/數(shù)據(jù)長度macjen,/鏈路層頭的長度csum;/校驗結(jié)構(gòu)unsignedcharlocal_df,/cloned,/指這個sk_buff結(jié)構(gòu)是否克隆過pkt_type,ip_summed;_u32priority;/數(shù)據(jù)包排列優(yōu)先級unsignedshortprotocol,/etherneti辦議的類型security;/數(shù)據(jù)包的安全保密級別void#ifdefCONFIGNETFILTERun

16、signedlong_u32(destructor)(structsk_buff:+;skb);/釋放函數(shù)/與包過濾相關(guān)的成員nfmark;/nfcache;_u32nfctinfo;structnf_conntrack*nfct;#ifdefCONFIGNETFILTERDEBUGunsignedmtnf_debug;#endif#lfdefCONFIGBRIDGE_NETFILTERstructnf_bridge_info*nf_bridge;#endif#endif/*CONFIGNETFILTER/#ifdefined(CONFIG_HIPPI)union_u32ifield;priv

17、ate;#endif#lfdefCONFIG_NET_SCHED/*trafficcontrolindex/*trafficcontrolverdict*/*trafficcontrolclassic/*/_u32tc_index;#lfdefCONFIG_NET_CLS_ACT_u32tc_verd;_u32tc_classid;#endif#endif/*Theseelementsmustbeattheend,seealloc_skb()fordetails/unsignedinttruesize;/buffer大小atonnc_tusers;unsignedchar*head,/buff

18、er頭指針*data,/數(shù)據(jù)頭指針數(shù)據(jù)尾指針性nd;/結(jié)束指針;sk_buff結(jié)構(gòu)與它管理的數(shù)據(jù)區(qū)的關(guān)系如下圖所示.數(shù)據(jù)區(qū)是由sk.buff結(jié)構(gòu)中的幾個指針及長度來定義的。Skbuff圖:sk_buff結(jié)構(gòu)sk_buff有兩個非常垂要長度字段,len和truesize,分別描述當(dāng)前協(xié)議數(shù)據(jù)包的長度和數(shù)扌居緩沖區(qū)的實際長度。skbjnit函數(shù)創(chuàng)建了sk_buff的對象緩存,由全局變$skbuff_head_cache指向這個緩存,函數(shù)列出如下(在net/core/skbuff.c):statickmem_cache_t*skbuff_head_cache;void_initskb_init(vo

19、id)skbuff_head_cache=kmem_cache_create(skbuff_head_cache,1zsizeof(structskbuff),0,SLABHWCACHEALIGN,NULL,NULL);if(!skbuff_he3d_cache)panic(cannotcreateskbuffcache);sk_buff及其鏈表的操作在傳輸過程中,存在若多個套接緩沖區(qū).這些緩沖區(qū)組成一個氈衷。毎個鏈表都有一個鏈衷頭sk_buff_headr鏈衷中每個節(jié)點分別對應(yīng)內(nèi)存中的一塊的數(shù)據(jù)區(qū)。對它的操作有兩種基本方式:第一種是對緩沖區(qū)鏈衷進(jìn)行操作,第二種是對緩沖區(qū)對應(yīng)的數(shù)據(jù)區(qū)進(jìn)行控制。

20、(1)對sk.buff對應(yīng)的數(shù)據(jù)區(qū)進(jìn)行控制操作sk_buff對應(yīng)的數(shù)據(jù)區(qū)函數(shù)的作用說明如下圖:sRebuffskbuff_head_cache或上uff結(jié)構(gòu)管理的數(shù)據(jù)區(qū)skbheadroomO數(shù)據(jù)區(qū)size有效數(shù)據(jù)dataskbJailroomOheadfskb_pu5h(datai4skbpullQ*5kb_trim()endsk_buff結(jié)構(gòu)及數(shù)據(jù)區(qū)的操作創(chuàng)建或取消一個緩沖區(qū)結(jié)構(gòu)函數(shù)創(chuàng)建或取消一個緩沖區(qū)結(jié)構(gòu)函數(shù)說明如下(在net/core/skbuff.c中):structsk_buff*alloc_skb(intsize,intpriority)分iEsk_buff對象緩存t分配size

21、大小的數(shù)據(jù)區(qū).將sk_buff結(jié)構(gòu)的指針head,data等指向數(shù)據(jù)區(qū)。voidkfree_skb(structsk_buffskb,intrw)釋放一個skb_buffostuctsk_buff*skb_clone(structsk_buff*old,intpriority)復(fù)制一個sk_buff,但不復(fù)制數(shù)據(jù)部分。structsk_buff*skb_copy(structsk_buff*skb)完全復(fù)制一個sk_buff0對sk_buff結(jié)構(gòu)數(shù)扌居區(qū)的操作函數(shù)對sk_buff結(jié)構(gòu)數(shù)據(jù)區(qū)的操作函數(shù)說明如下(在include/linux/skbuff.h中):unsignedchar*skb_

22、headroom(structsk_buff*skb)返回緩沖區(qū)頭部為skb_push預(yù)留的空間的字節(jié)數(shù)大小。unsignedchar*skb_pull(structsk_buff*len)該函數(shù)將data指針向數(shù)據(jù)區(qū)的末尾移動.減少了len字段的長度。該函數(shù)可用于從接收到的數(shù)據(jù)頭上移動數(shù)扌居或協(xié)議頭。unsignedchar*skb_push(structsk_buff*skb,intlen)該函數(shù)將data指針向數(shù)據(jù)區(qū)的前端移動.增加了len字段的長度。在發(fā)送數(shù)據(jù)的過程中,利用該函數(shù)可在數(shù)扌居的前端添加數(shù)據(jù)或協(xié)議頭。unsignedchar*skb_put(structsk_

23、buff*skb?intlen)該函數(shù)將tail指針向數(shù)據(jù)區(qū)的末尾移動,堵加了len字段的長度。在發(fā)送數(shù)據(jù)的過程中,利用該函數(shù)可在數(shù)扌居的末端添加數(shù)據(jù)或協(xié)議尾。unsignedchar*skb_reserve(structsk_buff*skb,intlen)該函數(shù)在緩沖區(qū)頭部創(chuàng)建一塊額外的空間,這塊空間在skb_push添加數(shù)據(jù)時使用。因為套接字連立時并沒有為skb_push預(yù)留空間。它也可以用于在緩沖區(qū)的頭部墳加一塊空白區(qū)域,從而調(diào)整緩沖區(qū)的大小使緩沖區(qū)的長度統(tǒng)一。這個函數(shù)對一個空的緩沖區(qū)才能使用。unsignedchar*skb_tailroom(structsk_buffPkb)返回緩

24、沖區(qū)尾部為skb_put預(yù)留的空間的字節(jié)數(shù)大小。unsignedchar*skb_trim(structsk_buff*len)該函數(shù)和put函數(shù)的功能相反,它將tail指針向數(shù)扌居區(qū)的前端移動.減小了len字段的長度。該函數(shù)可用于從接收到的數(shù)據(jù)尾上移去數(shù)據(jù)或協(xié)議尾。如果緩沖區(qū)的長度比“l(fā)en”還長.那么它就通過移去緩沖區(qū)尾部若干字節(jié),把緩沖區(qū)的大小縮減到”lerT長度。還有一些其它的對sk.buff結(jié)構(gòu)及數(shù)據(jù)區(qū)的操作函數(shù).另外還有各種對sk.buff結(jié)構(gòu)雙向鏈衷的操作函數(shù).這里不作說明了。(2)對緩沖區(qū)鏈衷進(jìn)行操作sK_buff鏈衷是一個雙向鏈衷.它包括一個鏈衷頭而且毎一個緩沖

25、區(qū)都有一個prev和next指針,指向鏈衷中前一個和后一個緩沖區(qū)結(jié)點。對鏈衷的操作函數(shù)說明如下(在net/core/skbuff.c中):structsk_buff*skb_dequeue(structskb_buff_headlist)這個函數(shù)作用是把第一個緩沖區(qū)從鏈衷中移走。返回取出的sk.buff,如果隊列為空,就返回空指針。添加緩沖區(qū)用到skb_queue_head和skb_queuejail兩個例程。intskb_peek(structsk_buff_headJist)返回指向緩沖區(qū)鏈衷第一個節(jié)點的指針。intskb_queue_empty(structsk_buff_head*li

26、st)如果鏈衷為空,返回true。voidskb_queue_head(structsk_buff_head*skb)在鏈衷頭部添加一個緩沖區(qū)。voidskb_queue_head_init(structsk_buff_head*list)初始化sk_buff_head結(jié)構(gòu)。_u32skb_queueen(structsk_buff_head*list)返回隊列中排隊的緩沖區(qū)的數(shù)目。voidskb_queuejqil(structsk_buff*skb)在鏈衷的尾部添加一個緩沖區(qū)。voidskb_unlink(structsk_buff*skb)這個函數(shù)從鏈衷中移去一個緩沖區(qū),它只是將緩沖區(qū)從

27、鏈衷中移去.但并不釋放它。voidskb_append(structsk_buff*entry?structsk_buff*new_entry)voidskb_insert(structsk_buff*entry,structsk_buff*new_entry)它們可以使用戶把一個緩沖區(qū)放在鏈衷中任何一個位萱。sock結(jié)構(gòu)INET是Linux的TCP/IP協(xié)議簇的應(yīng)用,在INETSocket層中管理數(shù)據(jù)包存放和調(diào)度的數(shù)據(jù)結(jié)構(gòu)是sock,sock是socket的網(wǎng)絡(luò)層代衷。include/net/sock.h這是socket在小型網(wǎng)絡(luò)層的代舉,是sock結(jié)構(gòu)及tcp_tw_bucket結(jié)構(gòu)的頭。

28、skc_family;/網(wǎng)絡(luò)地址簇skc_state;/連接狀態(tài)skc_reuse;/%SOREUSEADDR設(shè)運skc_bound_dev_if;/綁定設(shè)備的序號structsock_commonunsignedshortvolatileunsignedcharunsignedcharintstructhlist_nodestructhlist_nodeatomic_t;skc.node;/各種協(xié)議查找表的主加s/)鏈接skc_bind_node;/各種協(xié)議查找衷的bindhash連接skc_refcnt;/引用計數(shù)socket的網(wǎng)絡(luò)層代衷structsock/*sock_common結(jié)構(gòu)是

29、tcp_tw_bucket結(jié)構(gòu)的共享設(shè)計現(xiàn)在tcp_tw_bucket電結(jié)構(gòu)也用到sock_common結(jié)構(gòu).因而sockcommon結(jié)構(gòu)必須作為第一個成員*/structsock_common_sk_common;#definesk_famity_sk_commonskc_famity#definesk_state_sk_commonskc_state#definesk_reuse_sk_commonskc_reuse#definesk_bound_dev_if_sk_commonskc_bound_dev_if#definesk_node_sk_commonskc_node#defines

30、k_bind_node_sk_commonskc_bind_node#definesk_refcnt_sk_commonskc_refentvolatileunsignedcharsk_zapped;/ax25&ipxmeans!linked/maskof%SEND_SHUTDOWNand/orRCV_SHUTDOWNunsignedcharskshutdown;unsignedcharsk_use_write_queue;unsignedcharsk_userlocks;/SONDBUF和socket_lock_tsk_lock;/同步鎖intskcvbuf;/接收buffer的大?。ㄗ止?jié)為

31、單位)wait_queue_head_t*sk_sleep;/sock等待隊列structdst_entry*sk_dst_cache;/目的地cacherwlock_tsk_dst_lock;/目的地cached寫鎖structxfrm_policy*sk_policy2;/flowpolicyatomic_tsk_rmem_alloc;/提交接收隊列字節(jié)數(shù)structsk_buff_headsk_receive_queue;/正進(jìn)來的包atomic_tsk_wmem_alloc;/提交傳輸隊列字節(jié)數(shù)structsk_buff_headsk_write_queue;/包正送向隊列atomic

32、_tsk_omem_alloc;/oBis11option9or11otherintsk_wmem_queued;/persistentqueuesizeintsk_forward_alloc;/向前分配的空間unsignedintsk_allocation;/分配的模式intsksndbuf;發(fā)送buffer大小,以字節(jié)為單位unsignedlongsk_flags;/%SO_LINGER(lonoff),%SO_BROADCAST,/SOEEPALIVE,SOJJOBINLINEcharsk_no_check;/SOJIOCHECK設(shè)畫unsignedcharsk_debug;/%SO_D

33、EBUGunsignedcharskcvtstamp;/SOIMESTAMP設(shè)直unsignedcharsk_no_l3rgesend;/是否送大片段intsk_route_caps;/路由能力如%NETIF_FJS0等unsignedlongsk_lingertime;/%SO_LINGER設(shè)吉intsk_hashent;/幾個衷的hashentry如tcp_ehash/backlog隊列是特殊的structstructsk_buff*head;structsk_buff*tail;sk.backlog;/與每socket持有的自旋鎖一起使用.要求較小的訪問延遲rwlock_tsk_call

34、b3ck_lock;/這個結(jié)構(gòu)尾部回調(diào)用函數(shù)使用structsk_buff_headsk_errorequeue;/很少用的錯i吳隊列structproto*sk_prot;/網(wǎng)絡(luò)簇內(nèi)的協(xié)議句柄intsk_err,/K后的錯謀sk_err_soft;/不引起失敗的裙誤但它是永久失敗的原因unsignedshortsk_3ck_b3cklog;/當(dāng)前l(fā)istenbacklogunsignedshortsk_max_ack_backlog;_u32sk_pnLority/%SO_PRTORT設(shè)酋unsignedshortsk_type;/socket類型如SOCK_S77?EAM等unsigned

35、charsk_localroute;/僅當(dāng)?shù)芈酚桑?J)ONTROUTE設(shè)酋unsignedcharskprotocol;/socket協(xié)議屈于這個網(wǎng)絡(luò)簇structucredskpeercred;/%SO_PEERCRED設(shè)吉intskcvlowat;/SORCVLOWAT設(shè)迓longskcvtimeo;/%SO_RCVTIME0設(shè)吉longsk_sndtimeo;/SONDTIMEO設(shè)吉structsk_fiIter*sk_fliter;/socket過濾操作void*sk_protmfo;/私有區(qū)域,當(dāng)不用slab時的輕定net簇kmem_cache_t*sk_slab;/分配這個soc

36、k實例的slabcachestructtimer_listsk_timer;/sock淸除定時器structtimevalsk_stamp;/最后包接收的時間戳structsocket*sk_socket;/Identdandreporting10signalsvoid*sk_userdata;/RPC層私有數(shù)據(jù)structmodule*sk_owner;擁有這個socker的模塊structpage*sk_sndmsgjDage;/發(fā)送消息的緩存頁_u32sk_sndmsg_off;/發(fā)送消息的緩存偏移structsk_buff+sk_send_head;/frontofstufftotra

37、nsmitintsk_write_pending;/寫到流中的socker等待開始void*sk_security;/_u8sk_queue_shrunk;/寫隊列晟近被縮小/*threebyteshole,trytopack*/指示sock狀態(tài)變化的回調(diào)函數(shù)void(:+:sk_statexchange)(structsock*sk);/數(shù)據(jù)準(zhǔn)備好將要處理的回調(diào)函數(shù)void(;+:sk_data_ready)(structsock*sk,intbytes);/指示有可用的緩存發(fā)送空間回調(diào)函數(shù)void(*sk_write_spmce)(structsock+sk);/指示如皆IS6玄RRQUE

38、UE的錯誤發(fā)生的回調(diào)函數(shù)void(*sk_error_report)(structsock*sk);/處理backlog的回調(diào)函數(shù)int(*sk_backlog_rev)(structsock+sk,structsk_buff*skb);/當(dāng)所有的refent=sock釋放的時刻調(diào)用的函數(shù)void(*sk_destruct)(structsock*sk);結(jié)構(gòu)proto_ops是BSDSocket層的socket結(jié)構(gòu)中定義的操作函數(shù)結(jié)構(gòu)。這個結(jié)構(gòu)的實現(xiàn)函數(shù)都工作在INETSocket層,即指向INETSocket層的具體函數(shù),例如:連接方式是SOCK.STREAM時,就初始化為inet_str

39、eam_ops;如果連接方式是SOCK_DGRAMt則初始化為inet_dgram_ops0結(jié)構(gòu)proto是INETSocket層的控制函數(shù),它定義不同的協(xié)議簇,如對于TCP,則為tcp_prot;對于UDP協(xié)議,則為udpjDrot,sockfs文件系統(tǒng)通過sockfs文件系統(tǒng)的操作也可實現(xiàn)對socket的操作.sockfs文件系統(tǒng)通過操作函數(shù)指針轉(zhuǎn)接.最終調(diào)用了socket的操作函數(shù)集來完成對sockfs文件系統(tǒng)中的文件操作。sockjnit函數(shù)在init進(jìn)程中的main函數(shù)被調(diào)用.它初始化協(xié)議簇、建立socket緩存、建立socketfs文件系統(tǒng)和建立用于包過濾的nLhooks鏈衷數(shù)組。

40、函數(shù)列出如F(在在net/socket.c中):void_initsock_init(void)inti;/初始化地址(協(xié)議)簇for(i=0;iki_dtor=sock_aio_dtor;iocb沖rivate=x;xkiocb=iocb;/得到socket結(jié)構(gòu)sock=SOCKET_I(iocb-ki_fiIp-f_dentry-d_inode);/初始化xxasync_msgmsg_name=NULL;xasync_msgrnsg_namelen=0;xasync_msgmsg_:LOv=&xasync_iov;xasync_msgmsg_:LOvlen=1;xasync_msgmsg_

41、control=NULL;xasync_msgmsg_controlien=0;x-async_msg.msg_flags=!(iocb-ki_filp-f_flags&0_N0NBL0CK)?0:MSG_DONTWAIT;if(sock-type=SOCKSEQPACKET)x-async_msg.msg_flags|=MSG_E0R;xasync_iov.iov_base=(void_user*)ubuf;xasync_iov.iov_len二size;_sock_sendmsg(iocb,sock,&x-async_msg,size);staticinlineint_socksendms

42、g(structkiocb*iocb,structsocketsock,structmsghdr+msg,size_tsize)structsock_iocb*si=kiocb_to_siocb(iocb);interr;siAsock=sock;siAscm=NULL;simsg=msg;siAsize=size;/進(jìn)行安全檢查err=security_socket_sendmsg(sock,msg,size);if(err)returnerr;/調(diào)用socket的操作函數(shù)發(fā)送消息returnsockopssendmsg(iocb,sock,msg,size);利用socket通信socke

43、t對連接控制及數(shù)據(jù)信息進(jìn)行管理,從用戶的角度看,網(wǎng)絡(luò)通信就是創(chuàng)建socket和使用socket的過程。一個socket映射到一個文件,對這個文件的讀寫,就相當(dāng)于對socket進(jìn)行操作.也就相當(dāng)于接收和發(fā)送網(wǎng)絡(luò)數(shù)據(jù)。Linux網(wǎng)絡(luò)收發(fā)數(shù)據(jù)有兩種發(fā)送數(shù)據(jù)的方式:一是通過文件系統(tǒng)中的write系統(tǒng)調(diào)用,將需要發(fā)送的數(shù)扌居寫入socket文件描述符;另一種通過sys_send系統(tǒng)調(diào)用完成。同樣.接收數(shù)據(jù)可以通過文件系統(tǒng)中的read系統(tǒng)調(diào)用或通過sys.recv系統(tǒng)調(diào)用來接收數(shù)據(jù),這兩種發(fā)送和接收數(shù)據(jù)方式,經(jīng)過形式處理后統(tǒng)一到函數(shù)sock_readv_writev函數(shù)上。整個網(wǎng)絡(luò)層的流程如下(以兩個進(jìn)程

44、通過TCP/IP進(jìn)行通信為例):在IP協(xié)議層有三個關(guān)鍵函數(shù):ipcv()、ipjorward()、ip_output(),分別處理IP層的接收、轉(zhuǎn)發(fā)和發(fā)送工作。防火墻的功能函數(shù)將在此三個函數(shù)中調(diào)用。硬件Linux網(wǎng)絡(luò)收發(fā)數(shù)據(jù)流程圖從Linux網(wǎng)絡(luò)收發(fā)數(shù)據(jù)流程圖中可將程序分為第一層是驅(qū)動程序?qū)?第二層是協(xié)議無關(guān)層,第三層是IP層.第四層是socket層。socket層sys_socketcall函數(shù)是網(wǎng)絡(luò)通信的系統(tǒng)調(diào)用.應(yīng)用程序通過對這個函數(shù)的調(diào)用建立socket,并利用socket進(jìn)行網(wǎng)絡(luò)通信。這個函數(shù)把用戶空間的擊數(shù)args分解成地址簇、協(xié)議類型等,根扌居擊數(shù)call選擇不同的函數(shù)進(jìn)行網(wǎng)絡(luò)操

45、作。如偵聽、傳送、接收等。這個函數(shù)在下面只列出部分操作函數(shù).其它擊看源代碼。這個函數(shù)如卞(在neVsocketx中):/協(xié)議列舉.每個協(xié)議注冊在這里,NPROTO缺省定義為staticstructnet_proto_family*net_familiesNPROTO;asmlinkagelongsys_socketcall(intcall,unsignedlong_user*args)unsignedlonga6;unsignedlongaO,al;interr;if(callSYS_RECVMSG)returnEINVAL;/*copy_from_usershouldbeSMPsafe*/i

46、f(copy_from_user(azargs,nargscall)returnAULT;aO=aO;al=al;switch(call)caseSYS_SOCKET:err=sys_socket(aOzal,a2);break;caseSYS_BIND:err=sys_bmd(aOz(structsockaddr_user*)al,a2);break;caseSYS_CONNECT:err=sys_connect(aOz(structsockaddr_user*)al#a2);break;caseSYS_LISTEN:err=sys_listen(aOzal);break;caseSYS_A

47、CCEPT:err=sysaccept(aO,(structsockaddr_user*)al,(int_user*)a2);break;err;下面對函數(shù)sys_socket進(jìn)行分析.函數(shù)sys_socket調(diào)用層次圖如下:函數(shù)sys_socket調(diào)用層次圖系統(tǒng)調(diào)用sys.socket創(chuàng)建一個socket,對不同的協(xié)議族調(diào)用不再聽創(chuàng)建函數(shù).例如,對于IPV6來說.晟終通過調(diào)用函數(shù)inet_create來創(chuàng)建socket系統(tǒng)調(diào)用sys_socket列出如下(在net/socket.c中):asmlinkagelongsys_socket(intfamily,mttype,:i.ntprotoc

48、ol)retval;structsocket*sock;retval=sock_create(familyztype,protocol,&sock);if(retval0)gotoout;retval=sock_map_fd(sock);if(retvalcreate(sock,protocol)type)answer=list_entr*y(p,structinet_protosw,list);/檢查協(xié)議是否匹配及是否為IPPROTOJPif(protocol=answer沖rotocol)if(protocol!=IPPROTO_IP)break;else/*Checkforthetwow

49、ildcases/if(IPPROTO_IP=protocol)protocol=answer-protocol;break;if(IPPROTO_IP=answer-沖rotocol)break;answer=NULL;/得到協(xié)議對應(yīng)的操作函數(shù)集結(jié)構(gòu)sockops=answer-ops;answer_prot=answerprot;answer_no_check=answerno_check;answer_flags=answerflags;rcu_read_unlock();BUG_TRAP(answer_prot-slab!=MJLL);rc=ENOBUFS;/分配新的sock結(jié)構(gòu)sk=

50、sk_aUoc(PF_INET6fGFP_K曰NEL,answerj)rotslab_obj_siNe,answerj)rotslab);if(sk=NULL)gotoout;/將sock與sk用指針關(guān)聯(lián)起來,初始化sksock_init_data(sock,sk);sk_set_owner(sk,THIS_MODULE);/ski殳苣rc=0;/sk設(shè)遠(yuǎn)協(xié)議的控制操作函數(shù)集sksk_prot=answer_prot;sksk_no_check=answer_no_check;if(INET_PROTOSW_REUSE&answer_flags)sk-sk_reuse=1;/得到對應(yīng)協(xié)議的in

51、et_opt結(jié)構(gòu)./inetopt結(jié)構(gòu)包含了對收到的包進(jìn)行socket解復(fù)用比較的數(shù)據(jù)inet=inet_sk(sk);if(SOCK_RAW=sock-type)inetnum=protocol;if(IPPROTO_RAW=protocol)inet-hdrincl=1;sksk_destruct=inet6_sock_destruct;sk-sk_famity=PF_INET6;sksk_protocol=protocol;sksk_backlog_rcv=answeprotbacklog_rcv;tcp6sk=(structtcp6_sock*)sk;tcp6sk-pinet6二np=

52、inet6_sk_generic(sk);/設(shè)SIPV6私有信息nphop_limitnpmcast_hopsnpmc_loopnppmtudisc=-1;=-1;=1;=IPV6_PMTUDISCWANT;np:*ipv6only二sysctl_ipv6_bindv6only;/初始化在socket中的ipv4部分.因為有socket因IPV4而使用TPIZ6的APTinetuc_ttl=J;mc_loopmc_ttlmc_indexinetmclist=1;=1;=o;=NULL;if(ipv4_conf1g.no_pmtu_disc)inet-沖mtudisc=IP_PMTUDISC_D

53、ONT;elseinet-沖mtudisc=IP_PMFUDISC_WANT;#ifdefINETRHPhfTDEBUGatomic_inc(&inet6_sock_nr);atomic_inc(&inet_sock_nr);#endifif(inet-num)/假定允許用戶在socket創(chuàng)建時指定一個數(shù)的任何協(xié)議共享inet:*sport=ntohs(inetnum);sk-sk_prot-hash(sk);if(sksk_protinit)rc=sk-sk_prot-init(sk);if(rc)sk_comnon_release(sk);gotoout;out:returnrc;out_

54、rcu_uniock:rcu_read_unlock();gotoout;函數(shù)sock_alloc分配一個新inode和socket對象,兩者綁在一起并初始化。接若這個socket被返回。如果超出了inodes個數(shù).返回NULL。structsocket*sockalloc(void)structinode*inode;structsocket*sock;inode=new_inode(sock_mnt=mnt_sb);if(!inode)returnNLLL;/得到socket結(jié)構(gòu)sock=SOCKET(inode);inode-i_mode=S_IFSOCK|S_IFWXUGO;inode

55、i_sock=1;inodei_ujLd=currentfsuid;inodei_giLd=currentfsgid;get_cpu_var(sockets_in_use)+;put_cpu_var(sockets_in_use);returnsock;函數(shù)sock.mapjd獲得第一個可用文件描述子,并連立成可用的。這個函數(shù)創(chuàng)建文件結(jié)構(gòu)并把它映射到當(dāng)前進(jìn)程的fd空間。如果成功返回文件描述子.并且把文件結(jié)構(gòu)存在sock-file中??趇ntsock_map_fd(structsocket*sock)intfd;structqstrthis;charname32;/分配一個空閑的fdfd=get

56、_unused_fd();if(fd=0)/分配對象緩存并初始化filestructfile來file=get_empty_filp();if(!file)put_unused_fd(fd);fd=BMFILE;gotoout;sprintf(name,SOCK_INODE(sock)-i_ino);thisname=name;thislen=strlen(name);this.hash=SOCK_INODE(sock)-i_ino;/分配dentry9將其掛接在文件系統(tǒng)sockfs的根目錄卞。filef_dentry=d_alloc(sock_mntmnt_sbs_root,&this);i

57、f(!file-f_dentry)put_filp(file);put_unused_fd(fd);fd=-BMOMEM;gotoout;/賦上目錄操作函數(shù)集filef_dentryd_op=&sockfs_dentry_operations;/加上sock的節(jié)點d_add(file-f_dentryzSOCK_INODE(sock);filef_vfsmnt=mntget(sock_mnt);filefmapping=fi*le-f_dentryd_inodeimapping;sockfile=file;/加上文件操作函數(shù)集filef_op=SOCK_INODE(sock)-i_fop=&s

58、ocket_file_ops;file-f_mode=FMODE_READ|FMODE_WRITE;file-f_flags=O_RCWR;file:*f_pos=0;/將fd與file連接起來fd_install(fdzfile);out:fd;系統(tǒng)調(diào)用connect將一個和socket結(jié)構(gòu)關(guān)聯(lián)的文件描述符和一個sockaddr結(jié)構(gòu)的地址對應(yīng)的遠(yuǎn)程機器相關(guān)聯(lián),并且調(diào)用各個協(xié)議自己對應(yīng)的connect連接函數(shù)。入口參數(shù)sockfd是通過socket系統(tǒng)調(diào)用創(chuàng)建的socket文件描述符,serv_addr包括了需要連接的遠(yuǎn)程主機的IP地址,addrlenR示了serv_addr的長度。函數(shù)sys

59、_connect列出如下(在net/socket.c中):asmlinkagelongsys_connect(intfd,structsockaddr_user:+:uservaddr,intaddrlen)structsocket*sock;charaddressMAX_SOCK_ADDR;interr;/查找socketsock=sockfd_lookup(fd,&err);if(!sock)gotoout;/調(diào)用copy_from_user函數(shù)將用戶空間的uservaddr拷貝到內(nèi)核空間address中err=move_addr_to_kernel(uservaddrzaddrlen,a

60、ddress);if(erropsconnect(sock,(structsockaddr*)address,addrlen,sockfilef_flags);out_put:sockfd_put(sock);out:returnerr;IP層收發(fā)數(shù)據(jù)包函數(shù)在數(shù)據(jù)包進(jìn)入IP層時,有個數(shù)據(jù)包隊列sk_bacXlog.在數(shù)據(jù)包從IP層進(jìn)入TCP層時有包隊列sk_receive_queuer它們都是結(jié)構(gòu)sock的成員變瓦它們可用軟中斷來實現(xiàn)接收。接收例程接收操作從底層發(fā)起,因而,接收例程從底層向上層進(jìn)行分析。下面分桁接收例程的函數(shù)。函數(shù)ip_rcv()調(diào)用層次圖函數(shù)ip_rcv()在neVipv4/

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論