![ipv6初始化和處理流程分析報(bào)告_第1頁](http://file2.renrendoc.com/fileroot_temp3/2021-4/2/7f9101a7-202e-4ec5-98c9-b63ddcd6b934/7f9101a7-202e-4ec5-98c9-b63ddcd6b9341.gif)
![ipv6初始化和處理流程分析報(bào)告_第2頁](http://file2.renrendoc.com/fileroot_temp3/2021-4/2/7f9101a7-202e-4ec5-98c9-b63ddcd6b934/7f9101a7-202e-4ec5-98c9-b63ddcd6b9342.gif)
![ipv6初始化和處理流程分析報(bào)告_第3頁](http://file2.renrendoc.com/fileroot_temp3/2021-4/2/7f9101a7-202e-4ec5-98c9-b63ddcd6b934/7f9101a7-202e-4ec5-98c9-b63ddcd6b9343.gif)
![ipv6初始化和處理流程分析報(bào)告_第4頁](http://file2.renrendoc.com/fileroot_temp3/2021-4/2/7f9101a7-202e-4ec5-98c9-b63ddcd6b934/7f9101a7-202e-4ec5-98c9-b63ddcd6b9344.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Ipv6 初始化和處理流程分析一 .Ipv6 的初始化1. 網(wǎng)絡(luò)子系統(tǒng)概述Linux內(nèi)核中,與網(wǎng)絡(luò)相關(guān)的代碼是一個(gè)相對獨(dú)立的子系統(tǒng),稱為網(wǎng)絡(luò)子系統(tǒng)。網(wǎng)絡(luò)子系統(tǒng)是一個(gè)層次化的結(jié)構(gòu),可分為以下幾個(gè)層次:1)Socket 層Linux在發(fā)展過程中,采用BSD socket APIs作為自己的網(wǎng)絡(luò)相關(guān)的API接口。同時(shí), Linux 的目標(biāo)又要能支持各種不同的協(xié)議族, 而且這些協(xié)議族都可以使用 BSD socket APIs 作為應(yīng)用層的編程接口。因此,在 socket APIs 與協(xié)議族層之間抽象出一個(gè) socket 層,用于將 user space 的 socket API 調(diào)用,轉(zhuǎn)給具體的協(xié)議族
2、做處理。2)協(xié)議族層( INET 協(xié)議族、 INET6 協(xié)議族等)Linux網(wǎng)絡(luò)子系統(tǒng)功能上相當(dāng)完備, 它不僅支持 INET 協(xié)議族(也就是通常所說的 TCP/IP stack),而且還支持其它很多種協(xié)議族,如DECnet, ROSE,NETBEUI等。 INET6 就是一種新增加的協(xié)議族。對于 INET 、INET6 協(xié)議族來說,又進(jìn)一步劃分為傳輸層和網(wǎng)絡(luò)層。3)設(shè)備驅(qū)動層設(shè)備驅(qū)動層則主要將協(xié)議族層與物理的網(wǎng)絡(luò)設(shè)備隔離開。它不在本文的討論范圍之內(nèi)。下圖是 Linux網(wǎng)絡(luò)系統(tǒng)層次結(jié)構(gòu)圖。2. 網(wǎng)絡(luò)子系統(tǒng)的初始化1) Socket 層的初始化 :Init()-do_basic_setup()-s
3、ock_init()Sock_init():對 sock和 skbuff結(jié)構(gòu)進(jìn)行 SLAB 內(nèi)存的初始化工作2)各種網(wǎng)絡(luò)協(xié)議族的初始化:.Do_initcalls():對于編譯到內(nèi)核中的功能模塊 (而不是以模塊的形式動態(tài)加載) ,它的初始化函數(shù)會在這個(gè)地方被調(diào)用到。內(nèi)核映象中專門有一個(gè)初始化段,所有編譯到內(nèi)核中的功能模塊的初始化函數(shù)都會加入到這個(gè)段中; 而 do_initcalls() 就是依次執(zhí)行初始化段中的這些函數(shù)。INET 協(xié)議族通常是被編譯進(jìn)內(nèi)核的;它的模塊初始化函數(shù)是net/ipv4/af_inet.c中的 inet_init()而INET6是作為一個(gè)模塊編譯的。它的模塊初始化函數(shù)是
4、net/ipv6/af_inet6.c中的 inet6_init()3. 協(xié)議族Linux網(wǎng)絡(luò)子系統(tǒng)可以支持不同的協(xié)議族,Linux所支持的協(xié)議族定義在include/linux/socket.h1)協(xié)議族數(shù)據(jù)結(jié)構(gòu)協(xié)議族數(shù)據(jù)結(jié)構(gòu)是struct net_proto_family。structnet_proto_familyintfamily;int(*create)(structsocket*sock,intprotocol);shortauthentication;shortencryption;shortencrypt_net;structmodule*owner;這個(gè)結(jié)構(gòu)中,最重要的是 c
5、reate 函數(shù),一個(gè)新的協(xié)議族,必須提供此函數(shù)的實(shí)現(xiàn)。這是因?yàn)椋翰煌木W(wǎng)絡(luò)協(xié)議族,從user space的使用方法來說,都是一樣的,都是先調(diào)用 socket() 來創(chuàng)建一個(gè) socket fd,然后通過這個(gè)fd 發(fā)送 / 接收數(shù)據(jù)。在 user space 通過 socket()系統(tǒng)調(diào)用進(jìn)入內(nèi)核后,根據(jù)第一個(gè)參數(shù)協(xié)議族類型 ,來 調(diào)用相應(yīng) 協(xié)議族 create() 函數(shù) 。 對 INET6 來 說,這個(gè) 函數(shù) inet6_create() 。因此,要實(shí)現(xiàn)一個(gè)新的協(xié)議族,首先需要提供一個(gè) create() 的實(shí)現(xiàn)。關(guān)于 create() 里面具體做了什么,后面再敘述。Linux系統(tǒng)通過這種方式
6、, 可以很方便的支持新的網(wǎng)絡(luò)協(xié)議族,而不用修改.已有的代碼。這很好的符合了“開 - 閉原則”,對擴(kuò)展開放,對修改封閉。2)協(xié)議族注冊Linux維護(hù)一個(gè) struct net_proto_family的數(shù)組 net_families如果 要 支 持 一個(gè) 新 的 網(wǎng) 絡(luò)協(xié) 議 族 , 那 么 需 要 定 義 自 己 的 struct net_proto_family ,并且通過調(diào)用 sock_register 將它注冊到 net_families 中。4.sock 層socket層又叫 “socket access protocol layer”。它處于 BSD socketAPIs 與底層具體
7、的協(xié)議族之間。這是一個(gè)抽象層,它起著承上啟下的作用。在這一層的數(shù)據(jù)結(jié)構(gòu)也有著這種特點(diǎn)1)數(shù)據(jù)結(jié)構(gòu)在 user space ,通過 socket() 創(chuàng)建的 socket fd ,在內(nèi)核中對應(yīng)的就是一個(gè) struct socket。structsocketsocket_statestate;unsignedlongflags;structproto_ops*ops;structfasync_struct*fasync_list;structfile*file;structsock*sk;wait_queue_head_twait;shorttype;它定義于 include/linux/net.
8、h中。Structsocket的ops 域指向一個(gè)structproto_ops結(jié) 構(gòu), structproto_ops定義于 include/linux/net.h中,它是 socket層提供給上層的接口,這個(gè)結(jié)構(gòu)中,都是BSD socket API的具體實(shí)現(xiàn)的函數(shù)指針。一個(gè) socket API通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核后,首先由socket層處理。Socket 層找到對應(yīng)的 structsocket ,通過它找到 structproto_ops ,然后由它所指向的函數(shù)進(jìn)行進(jìn)一步處理。以 sendmsg()這個(gè)函數(shù)為例,從user space通過系統(tǒng)調(diào)用進(jìn)入kernel后,由 sys_sendm
9、sg() 、sock_sendmsg() 依次處理,然后交給 structproto_ops.的 sendmsg() 處理。2)sock 層和傳輸層的關(guān)聯(lián)INET 和 INET6 這兩種協(xié)議族,可以支持多種傳輸層協(xié)議, 包括 TCP、UDP、RAW,在 2.6內(nèi)核中,又增加了一種新的傳輸層協(xié)議:SCTP。從內(nèi)核角度看,要實(shí)現(xiàn)INET6協(xié)議族的某種傳輸層協(xié)議,則必須既提供socket層的 struct proto_ops的實(shí)現(xiàn),也提供struct proto的實(shí)現(xiàn)。除此之外,還需要提供一種手段, 把這兩個(gè)結(jié)構(gòu)關(guān)聯(lián)起來, 也就是把 socket 層和傳輸層關(guān)聯(lián)起來。Linux提供了一個(gè) struc
10、t inet_protosw的結(jié)構(gòu),用于 socket層與傳輸層的關(guān)聯(lián)。structinet_protoswstructlist_headlist;/*Thesetwofieldsformthelookupkey.*/unsignedshorttype;/*Thisisthe2ndargumenttosocket(2).*/intprotocol;/*ThisistheL4protocolnumber.*/structproto*prot;structproto_ops*ops;intcapability;/*Which(ifany)capabilitydo*weneedtousethisso
11、cket*interface?*/charno_check;/*checksumonrcv/xmit/none?*/unsignedcharflags;/*SeeINET_PROTOSW_*below.*/;這個(gè)結(jié)構(gòu)定義于include/net/protocol.h中,從它的命名上可以看到它屬于 INET 和 INET6 協(xié)議族,但是沒有查到資料為什么叫做protosw 。這個(gè)結(jié)構(gòu)中, ops 指向 socket層的 struct proto_ops, prot指向傳輸層的struct proto。因此,對 INET6 這種要支持多種傳輸層協(xié)議的協(xié)議族,從內(nèi)核的角度來說,只需要為每一種傳輸層協(xié)
12、議定義相應(yīng)的struct proto_ops、struct proto,然.后再定義 struct inet_protosw,并將三者關(guān)聯(lián)起來即可。以 INET6 所支持的 TCP 為例:staticstructproto_opsinet6_sockraw_ops=.family=PF_INET6,.owner=THIS_MODULE,.release=inet6_release,.bind=inet6_bind,.connect=inet_dgram_connect,/*ok*/.socketpair=sock_no_socketpair,/*adonothing*/.accept=sock
13、_no_accept,/*adonothing*/.getname=inet6_getname,.poll=datagram_poll,/*ok*/.ioctl=inet6_ioctl,/*mustchange*/.listen=sock_no_listen,/*ok*/.shutdown=inet_shutdown,/*ok*/.setsockopt=sock_common_setsockopt,/*ok*/.getsockopt=sock_common_getsockopt,/*ok*/.sendmsg=inet_sendmsg,/* ok.*/.recvmsg=sock_common_r
14、ecvmsg,/*ok*/.mmap=sock_no_mmap,.sendpage=sock_no_sendpage,;structprototcpv6_prot=.name= TCPv6,.owner= THIS_MODULE,.close= tcp_close,.connect= tcp_v6_connect,.disconnect= tcp_disconnect,.accept= inet_csk_accept,.ioctl= tcp_ioctl,.init= tcp_v6_init_sock,.destroy= tcp_v6_destroy_sock,.shutdown= tcp_sh
15、utdown,.setsockopt= tcp_setsockopt,.getsockopt=.tcp_getsockopt,.sendmsg=tcp_sendmsg,.recvmsg=tcp_recvmsg,.backlog_rcv=tcp_v6_do_rcv,.hash=tcp_v6_hash,.unhash=tcp_unhash,.get_port=tcp_v6_get_port,.enter_memory_pressure=tcp_enter_memory_pressure,.sockets_allocated=&tcp_sockets_allocated,.memory_alloca
16、ted=&tcp_memory_allocated,.memory_pressure=&tcp_memory_pressure,.orphan_count=&tcp_orphan_count,.sysctl_mem=sysctl_tcp_mem,.sysctl_wmem=sysctl_tcp_wmem,.sysctl_rmem=sysctl_tcp_rmem,.max_header=MAX_TCP_HEADER,.obj_size.=sizeof ( structtcp6_sock),.twsk_obj_size=sizeof ( structtcp6_timewait_sock),.rsk_
17、prot= &tcp6_request_sock_ops,;staticstructinet_protoswtcpv6_protosw=.type=SOCK_STREAM,.protocol=IPPROTO_TCP,.prot=&tcpv6_prot,.ops=&inet6_stream_ops,.capability=-1,.no_check=0,.flags=INET_PROTOSW_PERMANENT,;Linux為INET6 協(xié)議族 定義 一 個(gè)structinet_protosw的 鏈表數(shù)組inetsw6。要支持某種傳輸層協(xié)議, 首先實(shí)現(xiàn)相應(yīng)的structproto_ops 、str
18、uctproto ,然 后 實(shí) 現(xiàn)structinet_protosw, 將 兩 者 關(guān) 聯(lián) , 最 后 , 通 過inet6_register_protosw(),將此 struct inet_protosw注冊到 inet6_sw中。注 冊 的 時(shí) 候 , 根 據(jù)structinet_protosw的type, 將 它 放 到inet6_swtype所在的鏈表中,相同的type,不同的 protocol,會在同一個(gè)鏈表上。3)數(shù)據(jù)結(jié)構(gòu)之間的聯(lián)系從 user space角度看,要使用INET6 協(xié)議族的某種傳輸層協(xié)議,首先需要通過 socket()調(diào)用創(chuàng)建一個(gè)相應(yīng)的socketfd ,然后再
19、通過這個(gè)socketfd ,接收和發(fā)送數(shù)據(jù)。socket()的原型是:int socket(int domain, int type, int protocol);.domain 指定了協(xié)議族 .type表明在網(wǎng)絡(luò)中通信所遵循的模式。主要的值有:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等。SOCK_STREAM是面向流的通信方式, 而 SOCK_DGRAM是面向報(bào)文的通信方式。不同的通信方式,在接收數(shù)據(jù)和發(fā)送數(shù)據(jù)時(shí),具有不同的處理方式。Protocol 則指明具體的傳輸層協(xié)議。不同的傳輸層協(xié)議,可能具有相同的 type ,例如 TCP 和 SCTP 都是 SOCK_STR
20、EAM類型。以 socket(PF_INET6, SOCK_STREAM, 0) 為例,在進(jìn)入內(nèi)核空間后,根據(jù) domain ,找到 inet6_family_ops。創(chuàng)建 struct socket調(diào)用 inet6_family_opsdecreate(),也就是 inet6_create()inet6_create() 根據(jù) type 和 protocol 在 inet6_sw 中找到對應(yīng)的 struct inet_protosw ,也就是 tcpv6_protosw創(chuàng)建 struct sock,將 struct socket和 struct sock關(guān)聯(lián)起來將 structsocket和
21、 tcpv6_protosw的 ops,也就是 inet6_stream_ops關(guān)聯(lián)起來將 struct sock和 tcpv6_protosw的 prot ,也就是tcpv6_prot關(guān)聯(lián)起來。這樣, socket層和傳輸層的數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系建立起來了,此后,應(yīng)用層通過socketfd接 收 或 者 發(fā) 送 數(shù) 據(jù) 的 時(shí) 候 , 就 會 先 經(jīng) 過socket層inet6_stream_ops處理,然后經(jīng)過傳輸層的tcpv6_prot處理。二 . 網(wǎng)卡接收數(shù)據(jù)這部分是說明數(shù)據(jù)報(bào)文在在鏈路層的處理, 以及如何將報(bào)文送交給對應(yīng)的網(wǎng)絡(luò)層協(xié)議來處理。這些功能基本都是在驅(qū)動中實(shí)現(xiàn)的。1. 網(wǎng)絡(luò)中接
22、收數(shù)據(jù)報(bào)文的兩個(gè)終端:硬中斷和軟中斷(1). 硬中斷的中斷處理函數(shù)是在驅(qū)動中注冊,一般在deviceopen() 函數(shù)或者 device init() 函數(shù)中注冊,使用 request_irq() 來注冊硬中斷處理函數(shù)。當(dāng)網(wǎng)卡接收到數(shù)據(jù)的時(shí)候,就會調(diào)用這個(gè)終端處理函數(shù)來處理。比如8139too.c函數(shù)就用retval= request_irq(dev-irq,rtl8139_interrupt,SA_SHIRQ,dev-name, dev) 來注冊硬中斷處理函數(shù)。(2).軟中斷是通過NET_RX_SOFTIRQ信號來觸發(fā)的,處理函數(shù)是net_rx_action 。注冊函數(shù)是 open_soft
23、irq(NET_RX_SOFTIRQ, net_rx_action, NULL)。觸發(fā)這個(gè)中斷信號( raise irq )一般是在硬中斷處理流程中,當(dāng)硬中斷處理基本結(jié)束的時(shí)候, 通過調(diào)用 _raise_softirq_irqoff(NET_RX_SOFTIRQ) 來觸發(fā)這個(gè)中斷。2. 接收軟中斷接收軟中斷 (net_rx_action)主要還是通過調(diào)用驅(qū)動中的poll的方法進(jìn)行接收。在 poll方法中,會提取接收包,根據(jù)它所在的設(shè)備和協(xié)議類型傳遞給各自的包處理器。以rtl8139_poll為例,它會調(diào)用rtl8139_rx()來把盡可能多的數(shù)據(jù)在一次中斷處理中處理完,而不是一個(gè)軟中斷只處理一
24、個(gè)數(shù)據(jù)包,這樣可以提高效率。每個(gè)數(shù)據(jù)包都會通過netif_receive_skb()函數(shù),根據(jù)報(bào)文的協(xié)議類.型,調(diào)用上層的包處理器。如果網(wǎng)卡本身驅(qū)動沒有poll函數(shù),將是調(diào)用bakclog_dev 的 process_backlog函數(shù)。3. 包處理器注冊包處理器用dev_add_pack() 注冊 , 如果注冊的設(shè)備號是零則表明它接收所有設(shè)備的包 ,如果注冊的包類型是(ETH_P_ALL),則表示它接收所有類型的包。netif_receive_skb()函數(shù)會根 據(jù)接 受數(shù) 據(jù)的協(xié)議類型,在ptype_all和ptype_base 列表中去查找對應(yīng)的處理協(xié)議,再將數(shù)據(jù)包傳遞給對應(yīng)的協(xié)議處理函
25、數(shù)。對于ipv4, 就 是 在af_inet.c中 的inet_init()函數(shù) 中, 初始 化了ip_packet_type.func = ip_rcv,因此, ip_rcv()將接收ipv4的報(bào)文。在inet_init()中 調(diào) 用dev_add_pack(&ip_packet_type)去 在ptype_all和ptype_base 中注冊協(xié)議處理函數(shù)。 ipv4 的 IP 頭類型值是 ETH_P_IP:0x0800。對于ipv6, 則在af_inet6.c中的 inet6_init()函數(shù) 中完成 初始化,inet6_init()調(diào)用 ipv6_packet_init()來注冊協(xié)議處理
26、報(bào)文。 Ipv6 的 IP 頭類型值是 ETH_P_IPV60x86DD。其注冊的接收處理程序是ipv6_rcv()。三 . 網(wǎng)絡(luò)層的處理這部分是說明數(shù)據(jù)報(bào)文在網(wǎng)絡(luò)層的處理。 上面一部分已經(jīng)說明了在鏈路層的處理。在鏈路層的處理,基本都是在驅(qū)動中已經(jīng)實(shí)現(xiàn)了的。接著鏈路層的處理,對于 ipv6 協(xié)議,處理過程在 ipv6_recv() 中。ipv6_rcv()中,會做一些必要的檢查和更新MIB 的一些信息,接著處理hopbyhop 報(bào)頭。然后進(jìn)入NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev,NULL, ip6_rcv_finish);對于 NF_HOOK
27、的作用解釋。 如果沒有配置 netfilter,可以簡單認(rèn)為 NF_HOOK就等于直接調(diào)用ip6_rcv_finish (skb)。Ipv6_rcv()會處理 hopbyhop 報(bào)頭,在 ipv6_parse_hopopts()函數(shù)中處理。注意 ip6_parse_tlv()的處理過程,它本身只處理PAD0和 PAD1的 type ,就是rfc2460 里面最早定義的兩個(gè)選項(xiàng),其它選項(xiàng)都是通過tlvprochopopt_lst中定義的回調(diào)函數(shù)來處理的。這樣就能夠根據(jù)將來協(xié)議的發(fā)展,靈活的添加新的 hopbyhop 類型,而不需要修改這個(gè)函數(shù)本身。對于除hopbyhop 以外的擴(kuò)展報(bào)頭的處理,是
28、通過路由表來進(jìn)行的。在ip6_rcv_finish()里面,會調(diào)用ip6_route_input(skb),這個(gè)函數(shù)返回的是路由表中對應(yīng)的 fib6_node ,這個(gè)節(jié)點(diǎn)的 input函數(shù),就會根據(jù)不同的目的地調(diào)用不同的函數(shù)來處理。具體說來:(1)If the destination address matches FE80: skb-dst-input=ip6_inputskb-dst-output=ip6_output(2)Else ifthe destinationaddress s first10 bitsmatches FE80:skb-dst-input=ip6_forwardsk
29、b-dst-output=ip6_output(3)Else if the destination addresss first 8 bits matches FF00:skb-dst-input=ip6_mc_inputskb-dst-output=ip6_output(4)Else ( no match).skb-dst-input= ip6_pkt_discardskb-dst-output=ip6_pkt_discard對于 ip6_route_input(skb)函數(shù)的分析,我們后面講路由查找的時(shí)候再敘述,這里先跳過去。說明一下到本機(jī)的路由表項(xiàng)的初始化過程。到本機(jī)的路由表的初始化是在
30、給網(wǎng)卡分配 ipv6 地址的時(shí)候初始化的, 代碼在 addrconf.c中。比如當(dāng)用戶在給網(wǎng)卡手動賦ipv6地址的時(shí)候,會通過netlink接口,傳遞到內(nèi)核以后,就由rtnetlink_rcv_msg()來處理。 Rtnetlink_recv_msg()會根據(jù)family的值,在rtnetlink_linksfamily表中進(jìn)行查找,找到對應(yīng)協(xié)議簇的處理表。對于ipv6而 言 是PF_INET6 協(xié) 議 簇 , 調(diào) 用 的 是inet6_rtnetlink_table。 在inet6_rtnetlink_table表中 ,對 應(yīng)添 加網(wǎng) 卡ipv6地址 的處 理函 數(shù)是inet6_rtm_ne
31、waddr()函數(shù),因此整個(gè)處理過程是inet6_rtm_newaddr()ipv6_add_addr()addrconf_dst_alloc()rt-u.dst.input = ip6_input(),從而轉(zhuǎn)入 ip6_input()函數(shù)的處理。轉(zhuǎn)發(fā)路由表項(xiàng)的初始化和到本機(jī)的路由表的初始化過程類似。從netlink再到 ip6_route_add(),添加 ip6_forward()的處理函數(shù)。接上面第 2 點(diǎn),在 ip6_route_input(skb)函數(shù)調(diào)用中,返回的是路由表中對應(yīng)的 fib6_node 結(jié)構(gòu),它會調(diào)用 skb-dst-input() 函數(shù)。如果數(shù)據(jù)報(bào)文是到本機(jī),這個(gè)函
32、數(shù)就是 ip6_input() 函數(shù)。擴(kuò)展報(bào)頭的處理就在 ip6_input() 函數(shù)中。然后調(diào)用 ip6_input_finish()ipprot-handler(&skb), 然后調(diào)用在inet6_protos里面注冊了的 ipv6 各個(gè)擴(kuò)展報(bào)頭的處理函數(shù)。在 ipv6 協(xié)議簇中的函數(shù)調(diào)用流程如下圖所示。在 tcpv6_init()函數(shù)中,通過 inet6_add_protocol()向 inet6_protos注.冊了處理函數(shù)tcp_v6_rcv(),這樣,協(xié)議就會交給tcp_v6_rcv ()處理了。這樣就交給了傳輸層的協(xié)議棧來處理了。ICMPv6和 UPDv6協(xié)議的處理類似。這里注意
33、各個(gè)處理函數(shù)的返回值,像 icmpv6_rcv ()返回 0,表示這個(gè)數(shù)據(jù)報(bào)不再處理了,已經(jīng)處理完了。而 ipv6_destopt_rcv() 則返回 -1/1 ,-1 表示出錯(cuò)了,就不再處理; 1 表示當(dāng)前的報(bào)頭已經(jīng)處理完了,要接著處理這個(gè)數(shù)據(jù)報(bào)的下一個(gè)報(bào)頭。這樣,就把報(bào)文傳送到了傳輸層了。對于傳輸層,我們選擇一個(gè)簡單的 updv6 協(xié)議,它注冊的處理函數(shù)是 udpv6_rcv(), 這部分會在傳輸層的處理中論述。四 . 路由模塊的處理路由節(jié)點(diǎn)結(jié)構(gòu)是 fib6_node 的結(jié)構(gòu),通過這個(gè)結(jié)構(gòu)來組織成一棵路由樹。這個(gè)結(jié)構(gòu)主要是用來組織路由結(jié)構(gòu)樹的,具體的路由信息是存放在fib6_node-le
34、af結(jié)構(gòu)中,這是一個(gè)rt6_info的結(jié)構(gòu)體。每個(gè)fib6_node 伴隨著一個(gè) rt6_info。查找路由的時(shí)候,遍歷整個(gè)路由樹,根據(jù)每個(gè)fib6_node節(jié)點(diǎn)的 rt6_info信息,判斷是否是自己需要的節(jié)點(diǎn)。如果是,則返回,然后根據(jù)這個(gè)節(jié)點(diǎn)的 rt6_info信息進(jìn)行路由。路由表的組織結(jié)構(gòu)如下圖所示。這里多說兩句,定義 CONFIG_IPV6_SUBTREES情況, fib6_lookup_1 會遞歸調(diào)用,但最多只能遞歸一次 ( 因?yàn)?subtree 里不會再有 subtree) 。遞歸的那次 fib6_lookup_1 調(diào)用只對 src 進(jìn)行了匹配,因?yàn)?args1 里的 addr 是
35、 src 。下圖中的藍(lán)色部分,表示每個(gè) fib6_node 都伴隨著一個(gè) rt6_info 結(jié)構(gòu)用來攜帶具體的路由信息。ipv6 的路由表是是一個(gè) radix 樹,根對應(yīng)默認(rèn)路由,結(jié)點(diǎn)的層次和路由 prefix_len 對應(yīng)。在 fib6_lookup_1() 中下面的循環(huán)把 fn 設(shè)為葉子結(jié)點(diǎn),然后從他開始匹配,如果不符就 fn = fn-parent 。這樣就做到了最長匹配原則。for (;)structfib6_node *next;dir = addr_bit_set(args-addr, fn-fn_bit);next = dir ? fn-right : fn-left;if(ne
36、xt).fn = next;continue ;break ;關(guān)于 radix樹的介紹,可以google ,這里簡單介紹一下,參考了blog :/blog/cns!5EB4A630986C6ECC!393.entry?s a=419936170 。Radix tree 是一種搜索樹,采用二進(jìn)制數(shù)據(jù)進(jìn)行查找,但對于路由表,采用的是二叉樹的方式,只有一個(gè) Left 和 right 兩個(gè)子節(jié)點(diǎn)。(好像 fn_bit 表示的是 prefix_len ,就是路由前綴的長度,不確定?)五 . 數(shù)據(jù)包接收流程分析接收的流程為:ipv6_rcv-ip
37、v6_rcv_finish-dst_input-ip6_input- ip6_input_finish或者 ipv6_rcv-ipv6_rcv_finish-ip6_route_input或者ipv6_rcv-ipv6_rcv_finish-dst_input-ip6_forward- ip6_forward_finishstatic struct packet_type ipv6_packet_type_read_mostly = .type= cpu_to_be16(ETH_P_IPV6),.func= ipv6_rcv,.gso_send_check= ipv6_gso_send_che
38、ck,.gso_segment= ipv6_gso_segment,.gro_receive= ipv6_gro_receive,.gro_complete= ipv6_gro_complete,;/ 執(zhí)行一些檢查,判斷數(shù)據(jù)包是否轉(zhuǎn)發(fā)、有效性、正確性intipv6_rcv(structsk_buff*skb,structnet_device*dev,structpacket_type*pt,struct net_device *orig_dev).structipv6hdr *hdr;u32 pkt_len; structinet6_dev *idev;/ 獲取數(shù)據(jù)包網(wǎng)卡structnet *
39、net = dev_net(skb-dev);/ 丟棄發(fā)送給其他主機(jī)的數(shù)據(jù)包if(skb-pkt_type = PACKET_OTHERHOST) kfree_skb(skb);return0;rcu_read_lock();idev= _in6_dev_get(skb-dev);IP6_UPD_PO_STATS_BH(net,idev, IPSTATS_MIB_IN, skb-len);/if(skb = skb_share_check(skb, GFP_ATOMIC) = NULL | !idev |unlikely(idev-cnf.disable_ipv6) IP6_INC_STATS
40、_BH(net,idev,IPSTATS_MIB_INDISCARDS);gotodrop;memset(IP6CB(skb),0, sizeof(struct inet6_skb_parm);/* Store incoming device index. When the packetwill* be queued, we cannot refer to skb-devanymore.* BTW, when we send a packet forour own localaddressona.* non-loopback interface (e.g. ethX), it isbeingd
41、elivered* via the loopback interface (lo) here;skb-dev =loopback_dev.* It, however, should be considered as if itis being* arrivedvia the sending interface(ethX),becauseof the* nature of scoping architecture. -yoshfuji*/ 保存入口設(shè)備索引IP6CB(skb)-iif= skb_dst(skb) ?ip6_dst_idev(skb_dst(skb)-dev-ifindex : d
42、ev-ifindex;/ 檢查數(shù)據(jù)包長度是否為 IP 報(bào)頭的長度if(unlikely(!pskb_may_pull(skb, sizeof(*hdr)gotoerr;/ 獲取 IPv6 報(bào)頭位置hdr= ipv6_hdr(skb);/ 檢查版本是否為 IPv6if(hdr-version != 6)gotoerr;/* RFC4291 2.5.3* A packet received on an interface with adestinationaddress* of loopback must be dropped.*/ 丟棄環(huán)路數(shù)據(jù)包if(!(dev-flags & IFF_LOOP
43、BACK) &ipv6_addr_loopback(&hdr-daddr)gotoerr;.skb-transport_header= skb-network_header +sizeof(*hdr);IP6CB(skb)-nhoff= offsetof(struct ipv6hdr, nexthdr);pkt_len= ntohs(hdr-payload_len);/ 處理 Jumbo負(fù)載選項(xiàng)/*pkt_len may be zero if Jumbo payload option is present*/if(pkt_len | hdr-nexthdr != NEXTHDR_HOP) if
44、(pkt_len+ sizeof(structipv6hdr)skb-len) IP6_INC_STATS_BH(net,idev, IPSTATS_MIB_INTRUNCATEDPKTS);gotodrop;if(pskb_trim_rcsum(skb, pkt_len +sizeof(struct ipv6hdr) IP6_INC_STATS_BH(net,idev, IPSTATS_MIB_INHDRERRORS);gotodrop;hdr= ipv6_hdr(skb);if(hdr-nexthdr = NEXTHDR_HOP) if(ipv6_parse_hopopts(skb) ds
45、t-input指向的函數(shù);否則,調(diào)用ip6_rout_input函數(shù)查找路由表,返回skb-dst-input的具體內(nèi)容inlineint ip6_rcv_finish( struct sk_buff *skb)if(skb_dst(skb) = NULL)ip6_route_input(skb);returndst_input(skb);/ 獲取目的地址描述符static inlinestruct dst_entry *skb_dst(const struct sk_buff *skb).return (struct dst_entry*)skb-_skb_dst;/* Input pack
46、etfrom network to transport.將數(shù)據(jù)包從網(wǎng)絡(luò)層送到傳輸層*/static inline int dst_input(struct sk_buff *skb)return skb_dst(skb)-input(skb);/ 交給路由模塊void ip6_route_input(struct sk_buff *skb)struct ipv6hdr *iph = ipv6_hdr(skb);struct net *net = dev_net(skb-dev);int flags = RT6_LOOKUP_F_HAS_SADDR;struct flowi fl = .iif = skb-dev-ifindex,.nl_u = .ip6_u = .daddr =iph-daddr,.saddr =iph
溫馨提示
- 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 買電器押金合同范例
- 2025年監(jiān)房安全門項(xiàng)目投資可行性研究分析報(bào)告
- 軟件技術(shù)合同范本
- 2024年多媒體講臺行業(yè)投資分析及發(fā)展戰(zhàn)略研究咨詢報(bào)告
- 2025年兒科麻醉面罩行業(yè)深度研究分析報(bào)告
- 公司會計(jì)協(xié)議合同范例
- 肖像權(quán)使用合同范本
- 廠區(qū)綠化養(yǎng)護(hù)合同范本
- 2025年安全帶項(xiàng)目可行性研究報(bào)告
- 2025年度財(cái)務(wù)數(shù)據(jù)傳輸保密及安全協(xié)議
- 2025年中國電信集團(tuán)有限公司招聘筆試參考題庫含答案解析
- 2025年全國計(jì)算機(jī)二級等級考試全真模擬試卷及答案(共九套卷)
- 2024復(fù)工復(fù)產(chǎn)安全培訓(xùn)
- 2025中國南光集團(tuán)限公司校園招聘高頻重點(diǎn)提升(共500題)附帶答案詳解
- 機(jī)加工行業(yè)安全生產(chǎn)風(fēng)險(xiǎn)辨識及控制清單
- 江蘇省蘇州市2024-2025學(xué)年第一學(xué)期八年級數(shù)學(xué)期末模擬卷(一)(無答案)
- 呼吸科護(hù)理組長述職報(bào)告
- 【歷史】秦漢時(shí)期:統(tǒng)一多民族國家的建立和鞏固復(fù)習(xí)課件-2024-2025學(xué)年統(tǒng)編版七年級歷史上冊
- 社區(qū)中心及衛(wèi)生院65歲及以上老年人健康體檢分析報(bào)告模板
- 化工過程安全管理導(dǎo)則AQT 3034-2022知識培訓(xùn)
- 2024電力建設(shè)工程質(zhì)量問題通病防止手冊
評論
0/150
提交評論