版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、網(wǎng)絡(luò)代碼分析第二部分網(wǎng)絡(luò)子系統(tǒng)在IP層的收發(fā)過(guò)程剖析R.wen( HYPERLINK mailto:)、IP層數(shù)據(jù)包處理全景hlFPJtAL_OUT0000prolocolSl:TC#.UDP/RAWIP/.)MtfmNFIPIKALINNFIPFORWARDINGNFP_mi_ROUTIN(iPREROUTINGTrjffi(ondiulsubitem圖1.1*|-Hlp_erwdit.inpirt虛i輩didin*kb-dstoutputipfragmpiil*ip_fijihh_outpwt2MLsunjniit)1、接收的全過(guò)程在上一節(jié)可以看到,鏈路層將數(shù)據(jù)包上傳到IP層時(shí),由IP層相
2、關(guān)協(xié)議的處理例程處理。對(duì)于IP協(xié)議,這個(gè)注冊(cè)的處理例程是ip_rcv(),它處理完成后交給NETFILTE(PRE-ROUTING)R過(guò)濾,再上遞給ip_rcv_finish(),這個(gè)函數(shù)根據(jù)skb包中的路由信息,決定這個(gè)數(shù)據(jù)包是轉(zhuǎn)發(fā)還是上交給本機(jī),由此產(chǎn)生兩條路徑,一為ip_local_deliver(),它首先檢查這個(gè)包是否是一個(gè)分片包,如果是,它要調(diào)動(dòng)ip_defrag()將分片重裝,然后再次將包將給NETFILTER(LOCAL_IN)過(guò)濾后,再由ipocal_deliver_finish()將數(shù)據(jù)上傳到L4層,這樣就完成了IP層的處理;它負(fù)責(zé)將數(shù)據(jù)上傳,另一路徑為ip_forward
3、(),它負(fù)責(zé)將數(shù)據(jù)轉(zhuǎn)發(fā),經(jīng)由NETFILTER(FORWARD)過(guò)濾后將給ip_forward_finish(),然后調(diào)用dst_output()將數(shù)據(jù)包發(fā)送出去。2、發(fā)送全過(guò)程由上圖可以看到,當(dāng)L4層有數(shù)據(jù)包待發(fā)送時(shí),它將調(diào)用ip_append_data/ip_push_pending_frams(udp,icmp,RawIP),或ip_append_page(UDP),ip_queue_xmit(TCP,SCTP),或者raw_send_hdrinc(RawIP,IGMP),它們將這些包交由NETFILTER(LOLACL_OUT)處理后,然后交給dst_output,這會(huì)根據(jù)是多播或單播
4、選擇合適的發(fā)送函數(shù)。如果是單播,它會(huì)調(diào)用ip_output(),然后是ip_finish_output(),這個(gè)函數(shù)主要是檢查待發(fā)送的數(shù)據(jù)包大小是否超過(guò)MTU,如果是,則要首先調(diào)用ip_fragment()將其分片,然后再傳給ip_finish_output2(),由它交給鏈路層處理了。二、接收的詳細(xì)過(guò)程1、我們已經(jīng)知道,鏈路層首先將數(shù)據(jù)包上傳給IP層的ip_rcv()函數(shù),這個(gè)函數(shù)主要做一些檢查工作:首先,這個(gè)函數(shù)不會(huì)接收不是發(fā)給這個(gè)主機(jī)的數(shù)據(jù)包,如果主機(jī)是工作在混雜模式,這個(gè)數(shù)據(jù)包已經(jīng)由netif_receive_skb()去完成處理了。注意,這里所說(shuō)的“不屬于”這個(gè)主機(jī),是指在這個(gè)包目標(biāo)
5、主機(jī)的MAC地址不是本機(jī),而不是L3層的ip地址。所以,它不包括路由的包。if(skb-pkt_type=PACKET_OTHERHOST)gotodrop;接下來(lái)是一個(gè)共享的檢查,如果是共享的數(shù)據(jù)包,因?yàn)樗赡苄枰薷膕kb中的信息,所以要先復(fù)制一個(gè)副本,再作進(jìn)一步的處理。if(skb=skb_share_check(skb,GFP_ATOMIC)=NULL)IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);gotoout;再下來(lái)就是檢查首部的長(zhǎng)度是否夠長(zhǎng),校檢和等等:if(!pskb_may_pull(skb,sizeof(structiphdr)gotoin
6、hdr_error;去掉padded部分的長(zhǎng)度:len=ntohs(iph-tot_len);/*Ourtransportmediummayhavepaddedthebufferout.NowweknowitisIPwecantrimtothetruelengthoftheframe.Notethisnowmeansskb-lenholdsntohs(iph-tot_len).*/if(pskb_trim_rcsum(skb,len)IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);gotodrop;returnNF_HOOK(PF_INET,NF_IP_PRE_
7、ROUTING,skb,dev,NULL,ip_rcv_finish);2、ip_rcv_finish()ip_rcv將數(shù)據(jù)傳給ip_rcv_finish()繼續(xù)處理,這個(gè)函數(shù)工作也比較簡(jiǎn)單:它首先查找路由信息,在這里先忽略這部分:if(skb-dst=NULL)interr=ip_route_input(skb,iph-daddr,iph-saddr,iph-tos,skb-dev);然后就是對(duì)IP頭選項(xiàng)部分的處理了:if(iph-ihl5&ip_rcv_options(skb)gotodrop;最后就是dst_input了:returndst_input(skb);dst_input的工作
8、更為簡(jiǎn)單,它只是根據(jù)skb的路由信息調(diào)用相應(yīng)的input函數(shù)了:skb-dst-input(skb);由全景圖可以看到,這個(gè)input有可能是ipocal_deliver()或ip_forward()。3、ip_forward()檢查skb是否共享,或是否頭部預(yù)留的空間是否足夠存放L2的頭部,因?yàn)樵谵D(zhuǎn)發(fā)這個(gè)數(shù)據(jù)包的時(shí)候要將L2的頭部拷貝進(jìn)去。/*Weareabouttomanglepacket.Copyit!*/if(skb_cow(skb,LL_RESERVED_SPACE(rt-u.dst.dev)+rt-u.dst.header_len)gotodrop;接著就是ip_forward_f
9、inish()了。returnNF_HOOK(PF_INET,NF_IP_FORWARD,skb,skb-dev,rt-u.dst.dev,ip_forward_finish);ip_forward_finish:首先處理未處理的頭部if(unlikely(opt-optlen)ip_forward_options(skb);然后就是dst_output:returndst_output(skb);這個(gè)已經(jīng)是發(fā)送部分所做的工作了,我們將在下一部分討論它。4、ipocal_deliver()首先,確定接收到的包是不是分片,如果是,則要將分片重裝成一個(gè)完整的IP包再上傳給L4層。if(skb-nh
10、.iph-frag_off&htons(IP_MF|IP_OFFSET)skb=ip_defrag(skb,IP_DEFRAG_LOCAL_DELIVER);然后就是ip_local_deliver_finish:returnNF_HOOK(PF_INET,NF_IP_LOCAL_IN,skb,skb-dev,NULL,ip_local_deliver_finish);5、ip_local_deliver_finish至此,已經(jīng)確定將這個(gè)數(shù)據(jù)包傳送給L4層,而L3層的頭已沒有作用,所以,先去掉L3的頭部:intihl=skb-nh.iph-ihl*4;_skb_pull(skb,ihl);將s
11、kb-data指向L4的頭部/*PointintotheIPdatagram,justpasttheheader.*/skb-h.raw=skb-data;/重新設(shè)備skb-h.raw值,它在receive_skb()中被置為L(zhǎng)3層頭部的位置。接下來(lái)就要處理與L4層相關(guān)的協(xié)議了,首先處理的是RawIP,它先查看raw_v4_htable有沒有注冊(cè)到這個(gè)L4協(xié)議的RawIP:hash=protocol&(MAX_INET_PROTOS-1);raw_sk=sk_head(&raw_v4_htablehash);如果有,則要執(zhí)行raw_v4_input(),為其提交一份副本:if(raw_sk&!
12、raw_v4_input(skb,skb-nh.iph,hash)raw_sk=NULL;如何處理接收所有協(xié)議的RawIP?當(dāng)socket(AF_INET,SOCK_RAW,IPPROTO_RAW)時(shí),它會(huì)接收所有協(xié)議的數(shù)據(jù)包,并且IP_HDRINCL是默認(rèn)打開的,即是說(shuō)應(yīng)用層要提供L3和L4層的頭。再如,如果是IPPROTO_TCP時(shí),它只接收到TCP包。而IP_HDRINCL是默認(rèn)不打開的,即系統(tǒng)會(huì)處理L3的頭部。接著就是對(duì)特定L4協(xié)議的處理:if(ipprot=rcu_dereference(inet_protoshash)!=NULL)intret;ret=ipprot-handler
13、(skb);它首先查找inet_protos數(shù)組,看有沒有相關(guān)的注冊(cè)的協(xié)議,如果有,則執(zhí)行它的處理例程。6、協(xié)議的注冊(cè)在inet_init()的時(shí)候,系統(tǒng)會(huì)注冊(cè)幾個(gè)常用的L4層協(xié)議:if(inet_add_protocol(&icmp_protocol,IPPROTO_ICMP)0)printk(KERN_CRITinet_init:CannotaddICMPprotocoln);if(inet_add_protocol(&udp_protocol,IPPROTO_UDP)0)printk(KERN_CRITinet_init:CannotaddUDPprotocoln);if(inet_ad
14、d_protocol(&tcp_protocol,IPPROTO_TCP)dst;if(rt!=NULL)gotopacket_routed;如果還沒有,它則要在路由表中查找相關(guān)的rt,但我們這里不關(guān)心路由部分。填充IP頭信息,這里用skb_push為IP頭留出空間/*OK,weknowwheretosendit,allocateandbuildIPheader.*/iph=(structiphdr*)skb_push(skb,sizeof(structiphdr)+(opt?opt-optlen:0);*(_ul6*)iph)=htons(412)I(5tos&0 xff);iph-tot_
15、len=htons(skb-len);if(ip_dont_fragment(sk,&rt-u.dst)&!ipfragok)iph-frag_off=htons(IP_DF);elseiph-frag_off=0;iph-ttl=ip_select_ttl(inet,&rt-u.dst);iph-protocol=sk-sk_protocol;iph-saddr=rt-rt_src;iph-daddr=rt-rt_dst;skb-nh.iph=iph;/*Transportlayersetskb-h.fooitself.*/b.創(chuàng)建選項(xiàng)部分和計(jì)算校檢:if(opt&opt-optlen)ip
16、h-ihl+=opt-optlen2;ip_options_build(skb,opt,inet-daddr,rt,0);設(shè)置包頭的ID域ip_select_ident_more(iph,&rt-u.dst,sk,(skb_shinfo(skb)-gso_segs?:1)-1);/*AddanIPchecksum.*/ip_send_check(iph);最后就是調(diào)用dst_output了。1.2、ip_append_data(ip_append_page)/ip_push_pending_frames這是一對(duì)由UDP等協(xié)議使用的一對(duì)函數(shù),ip_append_data是一個(gè)比較復(fù)雜的函數(shù),它主
17、要將收到的大數(shù)據(jù)包分成多個(gè)小于MTU(1500)的$*4為L(zhǎng)3層要實(shí)現(xiàn)的IP分片做準(zhǔn)備。例如如果待發(fā)送的數(shù)據(jù)包大小為4000字節(jié),假設(shè)先前sock中的隊(duì)列又非空(sk-sk_write_queue!=NULL),(因?yàn)閕p_append_data可以被L4層多次調(diào)用,用于添加數(shù)據(jù)。)并且之前一個(gè)skb還沒填滿,剩余大小為500字節(jié)。這時(shí),當(dāng)L4層調(diào)用ip_append_data時(shí),它首先將這個(gè)剩余的skb填滿,這里還有一個(gè)問(wèn)題就是關(guān)于scatter/gatherIO的,當(dāng)NIC不支持時(shí),它會(huì)直接將數(shù)據(jù)寫到這個(gè)skb-tail處,但是,如果NIC支持這種IO,它便會(huì)將數(shù)據(jù)寫到frags所指向的指
18、針中,如果相關(guān)的page已經(jīng)填滿,它會(huì)再分配一個(gè)新的page用于這個(gè)skb。這一步完成之后,ip_append_data再次進(jìn)入下三次循環(huán),每次循環(huán)都分配一個(gè)skb,并將數(shù)據(jù)通過(guò)getfrag從L4層復(fù)制下來(lái)。在循環(huán)結(jié)束之前,它通過(guò)_skb_queue_tail(&sk-sk_write_queue,skb),將這個(gè)skb鏈入這個(gè)sock的sk_write_queue隊(duì)列中去。待到這個(gè)循環(huán)結(jié)束時(shí),所有的數(shù)staticinlinevoid_skb_queue_tail(structsk_buff_head*list,structsk_buffstructsk_buff*newsk)*prev,*
19、next;list-qlen+;next=(structsk_buff*)list;prev=next-prev;newsk-next=next;newsk-prev:=prev;next-prev=prev-next=newsk;據(jù)都從L4復(fù)制到各個(gè)skb,并鏈入了它的sk_write_queue隊(duì)列。換言之,待發(fā)送數(shù)據(jù)已經(jīng)在sk_write_queue隊(duì)列中了。它的循環(huán)過(guò)程如下,由于代碼較長(zhǎng),這里就不列出來(lái)了。圖2.1ip_append_page()跟ip_append_data()是實(shí)現(xiàn)同樣功能的函數(shù),它們的主要不同在于,ip_append_data()需要將用戶空間的數(shù)據(jù)復(fù)制到內(nèi)核空間
20、,而ip_append_page()則不需要這個(gè)復(fù)制,它直接使用用戶提供的數(shù)據(jù),從而實(shí)現(xiàn)了數(shù)據(jù)的“零拷貝”。現(xiàn)在來(lái)看一下它們之間的差別:a.分配skb空間:ip_append_data():alloclen=datalen+fragheaderlen;if(atomic_read(&sk-sk_wmem_alloc)sk_sndbuf)skb=sock_wmalloc(sk,alloclen+hh_len+15,1,sk-sk_allocation);ip_append_page():alloclen=fragheaderlen+hh_len+fraggap+15;skb=sock_wmall
21、oc(sk,alloclen,1,sk-sk_allocation);我們可以看到,這兩個(gè)函數(shù)分配的空間大小是不一樣的,對(duì)于ip_append_page(),它不為新的數(shù)據(jù)分配空間,只是分配一些頭部所需要的空間,和一個(gè)fraggap,它個(gè)值大小為17個(gè)字節(jié),是由于對(duì)齊問(wèn)題從上一個(gè)skb移動(dòng)過(guò)來(lái)的。b.ip_append_page()只能用于支持S/GIO的NIC,它只是將數(shù)據(jù)連接到frags數(shù)組中,而沒有ip_append_data()的復(fù)制數(shù)據(jù)。i=skb_shinfo(skb)-nr_frags;if(lensize)len=size;if(skb_can_coalesce(skb,i,p
22、age,offset)skb_shinfo(skb)-fragsi-l.size+=len;elseif(inetx,而是skb_shinfo(skb)-frag_list域了。(a)nextUpayload(b)L4pa/loadstructsockL4payloadheaddatatailendhead蟲“titlendstructik.buff$(ruc(5kbuff12headerIFheadertIni珀Ii圧dbyip_push_pefiding_frameiInitiali毘dbyip_push_pefidifig_framescaller5kbshinfo(skb)L2hwde
23、rIPheaderstructsk_twffLlheaderIPheaderL4payloadstructsock$k_wr映_quEue-sirurtsk_buffL2headerIPheaderL4headernextL4payloadwuusk_tuffnextL2headerIPhpadPrL4headpfL2headeriPaderL4pdylo祖sk_wriitqueuenextnext5(fufragist);/*moveskb-datatoipheaderfromextheader*/if(skb-datanh.raw)_skb_pull(skb,skb-nh.raw-skb-
24、data);while(tmp_skb=_skb_dequeue(&sk-sk_write_queue)!=NULL)_skb_pull(tmp_skb,skb-h.raw-skb-nh.raw);*tail_skbtail_skbskb-lenskb-data_lenskb-truesize=tmp_skb;=&(tmp_skb-next);+=tmp_skb-len;+=tmp_skb-len;+=tmp_skb-truesize;_sock_put(tmp_skb-sk);tmp_skb-destructor=NULL;tmp_skb-sk=NULL;接下來(lái)就是一些值的設(shè)置了,如建立IP
25、頭,IP選項(xiàng),計(jì)算校檢值等,這些跟ip_queue_xmit()所做的工作差不多。最后跟ip_queue_xmit()樣,也是調(diào)用dst_output()完成發(fā)送工作。我們看到,對(duì)于UDP,它需要調(diào)用ip_append_data/ip_append_page處理很多輔助分片的工作,而對(duì)于TCP,ip_queue_xmit()沒有做這份工作,它是由L4層去完成的,相對(duì)于ip_append_data/ip_append_page,它有tcp_sendmsg/tcp_sendpage。1.3、dst_output()由開始的全景圖可以看到,對(duì)于單播IP來(lái)說(shuō),它執(zhí)行的是ip_output():inti
26、p_output(structsk_buff*skb)structnet_device*dev=skb-dst-dev;IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);skb-dev=dev;skb-protocol=htons(ETH_P_IP);returnNF_HOOK_COND(PF_INET,NF_IP_POST_ROUTING,skb,NULL,dev,ip_finish_output,!(IPCB(skb)-flags&IPSKB_REROUTED);由上,它再執(zhí)行ip_finish_output:staticinlineintip_finish_ou
27、tput(structsk_buff*skb)if(skb-lendst_mtu(skb-dst)&!skb_is_gso(skb)returnip_fragment(skb,ip_finish_output2);elsereturnip_finish_output2(skb);由ip_finish_output可以看到,如果IP數(shù)據(jù)包的長(zhǎng)度大于MTU,它便會(huì)先將IP分成合適大小的分片,最后調(diào)用ip_finish_output2(),將這個(gè)包路由出去。三、IP的分片與重裝(ip_fragment/ip_defrag)先來(lái)看看產(chǎn)生IP分片與重裝的地方,這里只考慮主機(jī)的情況,而不關(guān)心路由。由上可以
28、看到,當(dāng)一個(gè)IP包在ip_finish_output()中被檢查到它的長(zhǎng)度大于MTU,則它要調(diào)用ip_fragment將這個(gè)IP包進(jìn)行分片。而當(dāng)IP分片由ipocal_deliver()上傳給L4層時(shí),它要將這些分片暫時(shí)保存起來(lái),一旦所有的分片都到達(dá)時(shí),它便將一個(gè)完整的IP包上傳給L4層。1、ip_fragment當(dāng)一個(gè)包由于太大而需要通過(guò)分片傳遞時(shí),它便過(guò)調(diào)用這個(gè)函數(shù)將這個(gè)大的數(shù)據(jù)包分成多個(gè)小的IP分片。由圖2.2可以看到,ip_append_data/ip_push_pending_frames為IP分片做了很多輔助工作。當(dāng)一個(gè)L4層傳遞過(guò)來(lái)的數(shù)據(jù)包經(jīng)過(guò)ip_append_data和ip_
29、push_pending_frames處理后,它得到的結(jié)果如圖2.2(b)所示,這時(shí),隊(duì)列中每個(gè)skb的大小都小于MTU減小鏈路頭部的大小(因?yàn)榘l(fā)送數(shù)據(jù)時(shí)需要加上鏈路層頭部),因些,ip_fragment只要將這些skb依照第一個(gè)skb的IP頭部為每個(gè)skb加上IP頭就完成了這個(gè)分片工作,這種分片稱為“快速分片”:structintif(skb_shinfo(skb)-frag_list)sk_buff*frag;first_len=skb_pagelen(skb);/第一個(gè)skb長(zhǎng)度erroffsetfrag/省略了一些檢查工作/*EverythingisOK.Generate!*/處理第一
30、個(gè)skb=0;=0;=skb_shinfo(skb)-frag_list;skb_shinfo(skb)-frag_list=NULL;skb-data_len=first_len-skb_headlen(skb);=first_len;=htons(first_len);skb-leniph-tot_leniph-frag_offsend_check(iph);ip_foriffrag-ip_summedfrag-h.rawfrag-nh.raw(;)/*Prepareheaderofthenextframe,*beforepreviousonewentdown.*/(frag)memcpy
31、(frag-nh.raw,iph,hlen);/=CHECKSUM_NONE;=frag-data;=_skb_push(frag,hlen);為每個(gè)分片復(fù)制一份IP頭=htons(IP_MF);iph=frag-nh.iph;iph-tot_len=htons(frag-len);ip_copy_metadata(frag,skb);/復(fù)制其它一些關(guān)于skb的設(shè)置if(offset=0)ip_options_fragment(frag);offset+=skb-len-hlen;iph-frag_off=htons(offset3);ifiph-frag_off/*(frag-next!=N
32、ULL)|=htons(IP_MF);Ready,completechecksum*/ip_send_check(iph);err=output(skb);/發(fā)送函數(shù)skbfragskb-next=frag;=skb-next;=NULL;而當(dāng)L4層傳遞過(guò)來(lái)的包沒有滿足快速分片的要求時(shí),它只能使用一般的分片辦法了,這個(gè)辦法原理很簡(jiǎn)單,假設(shè)L4傳遞過(guò)來(lái)的一個(gè)包大小為4000字節(jié),而MTU大小為1500,那這個(gè)方法就是通過(guò)一個(gè)循環(huán),每次分配一個(gè)skb,大小分別為1500,1500,1000(忽略頭部與對(duì)齊、填充等空間),然后再將原來(lái)的skb里的IP頭,部分?jǐn)?shù)據(jù)拷貝進(jìn)新分配的skb中去,直至所有的數(shù)
33、據(jù)都拷貝完成。slow_path:left=skb-len-hlen;/*Spaceperframe*/原始長(zhǎng)度ptr=raw+hlen;/*Wheretostartfrom*/offset=(ntohs(iph-frag_off)&IP_OFFSET)frag_off&htons(IP_MF);while(left0)len=left;/*IF:itdoesntfit,usemtu-thedataspaceleft*/if(lenmtu)/每次拷貝的長(zhǎng)度len=mtu;if(skb2=alloc_skb(len+hlen+ll_rs,GFP_ATOMIC)=NULL)/出錯(cuò)處理設(shè)置新的skb
34、頭與復(fù)制IP頭ip_copy_metadata(skb2,skb);skb_reserve(skb2,ll_rs);skb_put(skb2,len+hlen);skb2-nh.raw=skb2-data;skb2-h.raw=skb2-data+hlen;memcpy(skb2-nh.raw,skb-data,hlen);復(fù)制數(shù)據(jù)部分,注意不能簡(jiǎn)單的memcpy,因?yàn)閟kb中可以存在數(shù)據(jù)分片if(skb_copy_bits(skb,ptr,skb2-h.raw,len)BUG();left-=len;/*Fillinthenewheaderfields.*/iph=skb2-nh.iph;i
35、ph-frag_off=htons(offset3);if(offset=0)ip_options_fragment(skb);if(left0|not_last_frag)iph-frag_off|=htons(IP_MF);ptr+=len;offset+=len;iph-tot_len=htons(len+hlen);ip_send_check(iph);err=output(skb2);2、ip_defrag當(dāng)L3層在將數(shù)據(jù)包上傳給L4層的時(shí)候,它如果發(fā)現(xiàn)這個(gè)包只是一個(gè)IP分片,那么它將調(diào)用ip_defrag這個(gè)函數(shù),將這個(gè)分片暫時(shí)隊(duì)列起來(lái),如果所有的分片都到齊,它便將這些分片重裝成一
36、個(gè)完整的IP包再上傳給L4層。由下圖看到,系統(tǒng)為分片準(zhǔn)備了一個(gè)hash表ipq_hash,大小為64,并且每個(gè)ipq結(jié)構(gòu)代表一個(gè)被重裝成一個(gè)完成IP包的所有IP分片的隊(duì)列頭,將被重裝的skb存放在這個(gè)ipq的fragments鏈表中。注意,同一個(gè)hash鏈中的ipq結(jié)構(gòu)是相互獨(dú)立無(wú)關(guān)的,它們只是hash表的沖突鏈表。如下圖所示,ID為1234的IP包收到了2個(gè)分片,它們根據(jù)offset的值順次插入到這個(gè)ipq的fragments鏈表中。2565127&B卿IK12ST-12K圖3.1SUZSHS至ElsaddrdaddrProtocolIDFugmenwusaddrdaddrProtocolI
37、DFragments毎uttddrdaddrProtocolIDFragmentsipq.hash$Mdrddd曲ProtocolIDFragmentsBczstructipqstructipqsaddrlPldaddr=IP2pr(rtool-IPPROTOTCPid=1234len=996meat-384-fragmenisstructipqoffset25&她t=768structskbuffstructskbuff啟q備lgnh.iph;structipq*qp;structnet_device*dev;/*Startbycleaningupthememory.*/if(atomic_
38、read(&ip_frag_mem)sysctl_ipfrag_high_thresh)ip_evictor();/如果分片的數(shù)量超過(guò)了sysctl_ipfrag_high_thresh則調(diào)用這個(gè)函數(shù)釋放掉一些LRUipq。dev=skb-dev;/*Lookup(orcreate)queueheader*/if(qp=ip_find(iph,user)!=NULL)structsk_buff*ret=NULL;spin_lock(&qp-lock);ip_frag_queue(qp,skb);/將這個(gè)skb插入到qp的fragment隊(duì)列中if(qp-last_in=(FIRST_IN|LA
39、ST_IN)&qp-meat=qp-len)/所有的分片已收到ret=ip_frag_reasm(qp,dev);/將這些分片重裝spin_unlock(&qp-lock);ipq_put(qp,NULL);returnret;2.1、p_frag_queue最主要的工作就是將收到的skb插入相應(yīng)的ipq,但它比想像中要復(fù)雜,因?yàn)樗幚砗芏喑鲥e(cuò)的情況,如收到多個(gè)相同的分片,收到重疊的分片等。先來(lái)看看ipq結(jié)構(gòu):/*Describeanentryintheincompletedatagramsqueue.*/structipqstructhlist_nodelist;structlist_headlru_list;/*lruli
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 娛樂行業(yè)前臺(tái)接待工作總結(jié)
- 快遞物流行業(yè)后勤管理工作概述
- 幼兒園工作總結(jié)溫情陪伴
- 中班科學(xué)走進(jìn)家鄉(xiāng)的橋
- 床上用品行業(yè)銷售工作總結(jié)
- 如果我能看得見十篇
- 春天的花朵6篇
- 舞臺(tái)服裝設(shè)計(jì)師的職責(zé)總結(jié)
- 糖尿病護(hù)理工作總結(jié)
- 條形碼生成課程設(shè)計(jì)
- 2024北京西城初一(上)期末數(shù)學(xué)(教師版)
- 北京市朝陽(yáng)區(qū)2023-2024學(xué)年四年級(jí)上學(xué)期期末英語(yǔ)試題
- 工業(yè)機(jī)器人論文
- UC2845的應(yīng)用和PWM變壓器設(shè)計(jì)
- 螺桿空壓機(jī)操作規(guī)程完整
- 圓柱螺旋扭轉(zhuǎn)彈簧計(jì)算公式EXCEL計(jì)算
- 中南大學(xué) 信號(hào)與系統(tǒng)實(shí)驗(yàn)報(bào)告
- 在建鋼結(jié)構(gòu)工程危險(xiǎn)源辨識(shí)評(píng)價(jià).doc
- 異常子宮出血病因與治療的臨床分析
- 少數(shù)民族預(yù)科學(xué)生思想政治教育研究
- 奧林燃燒器說(shuō)明書(GP130-150H)
評(píng)論
0/150
提交評(píng)論