linux内核的邻居表,Linux内核报文收发-L3 - Section 3. IP协议、邻居子系统主要是接收、转发和发送三部分...
版本說明
Linux版本: 3.10.103
網(wǎng)卡驅(qū)動(dòng): ixgbe
網(wǎng)絡(luò)協(xié)議注冊(cè)
inet_init主要是注冊(cè)各種協(xié)議
注冊(cè)TCP協(xié)議proto_register(&tcp_prot, 1)
繼續(xù)注冊(cè)UDP、RAW、PING
arp_init, ip_init, tcp_init, udp_init, ping_init, icmp_init
dev_add_pack(&ip_packet_type)主要是注冊(cè)ip報(bào)文處理函數(shù)ip_rcv到pttype_base。
arp_init-->dev_add_pack(&arp_packet_type)主要是注冊(cè)arp報(bào)文處理函數(shù)arp_rcv到pttype_base。
報(bào)文處理
網(wǎng)卡調(diào)用__netif_receivve_skb_core后,會(huì)調(diào)用deliver_skb(skb, pt_prev, orig_dev)處理對(duì)應(yīng)的3層協(xié)議函數(shù)。
ip協(xié)議
ip_rcv主要獲取報(bào)文頭,報(bào)文健康檢查,最后進(jìn)入NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,...,ip_rcv_finish)。
ip_rcv_finish進(jìn)行路由查找,ip_route_input_noref-->ip_route_input_slow進(jìn)行慢速路由判定。
ip_route_input_slow判定報(bào)文是本地的話,就給input裝載ip_local_deliver函數(shù),如果不是本地繼續(xù)調(diào)用ip_mkroute_input-->__mkroute_input查找路由,并且給input裝載ip_forward函數(shù),output裝載ip_output。
ip_local_deliver函數(shù)直接進(jìn)入NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,..., ip_local_deliver_finish)。
ip_local_deliver_finish調(diào)用ipprot->handler進(jìn)入4層的協(xié)議處理函數(shù)。
ip_forward進(jìn)入NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,..., ip_forward_finish)。
ip_forward_finish調(diào)用output裝載的ip_output。
ip_output進(jìn)入NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING,...,ip_finish_output)
ip_finish_output進(jìn)行分片的判斷和操作,此處涉及到GSO的判定,最后調(diào)用ip_finish_output2。
ip_finish_output2調(diào)用__ipv4_neigh_lookup_noref進(jìn)行鄰居子系統(tǒng)的表查找,ipv4主要是arp表,查找到arp表,則調(diào)用dst_neigh_output-->neigh_hh_output-->dev_queue_xmit進(jìn)行報(bào)文發(fā)送。
如果沒有查找到,則調(diào)用__neigh_create-->arp_constructor進(jìn)行發(fā)送等函數(shù)的裝載,最后也調(diào)用dst_neigh_output,然后也調(diào)用裝載的發(fā)送函數(shù),將報(bào)文修改為request,調(diào)用dev_queue_xmit進(jìn)行發(fā)送。
arp協(xié)議
arp_rcv健康檢查后,進(jìn)入NF_HOOK(NFPROTO_ARP, NF_ARP_IN, ..., arp_process)
arp_process完成了所有的處理操作,包括是reply報(bào)文則更新arp表;如果是request本地的話,則更新或者創(chuàng)建arp表,并且調(diào)用arp_send回復(fù)arp報(bào)文;如果不是本地不支持arp proxy的話,丟棄報(bào)文;支持的話轉(zhuǎn)發(fā)報(bào)文。
arp_send調(diào)用arp_create創(chuàng)建報(bào)文,并且調(diào)用arp_xmit發(fā)送報(bào)文。
arp_xmit進(jìn)入NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, ..., dev_queue_xmit_sk),最后調(diào)用dev_queue_xmit發(fā)送報(bào)文。
轉(zhuǎn)發(fā)流程
鄰居子系統(tǒng)
Generic neighbouring interface(VFT),為上層協(xié)議提供了一個(gè)統(tǒng)一的輸出接口neigh->output()。
Generic neighbouring interface,為下層提供的也是一個(gè)統(tǒng)一的接口dev_queue_xmit()。
ARP是為IPV4設(shè)計(jì)的地址解析協(xié)議,而ND(neighbour detect)則是為IPv6設(shè)計(jì)的。這些地址解析協(xié)議可以說是“嵌入”在鄰居子系統(tǒng)里面,但是又可以自由靈活的拆卸,非常方便。
為了加速數(shù)據(jù)包的發(fā)送速度,會(huì)將路由表和鄰居緩存進(jìn)行綁定,這個(gè)綁定其實(shí)就是把鄰居緩存中的每個(gè)項(xiàng)的結(jié)構(gòu)體嵌入路由表中的一個(gè)路由項(xiàng)中,這樣報(bào)文在查找到路由以后,其實(shí)也相當(dāng)于已經(jīng)在鄰居子系統(tǒng)中查到了緩存,減少了查找的次數(shù)。這樣在進(jìn)入鄰居子系統(tǒng)后的處理流程就很短。
struct neigh_table :鄰居表,每個(gè)地址解析協(xié)議就會(huì)創(chuàng)建這樣的一個(gè)表(比如arp)
struct neighbour :鄰居項(xiàng)代表一個(gè)鄰居。鄰居項(xiàng)用哈希表+鏈表鏈的組織方式
struct hh_cache :這個(gè)字段存的就是封裝好的二層協(xié)議頭部,每個(gè)報(bào)文在進(jìn)入鄰居子系統(tǒng)前都會(huì)查找路由,路由項(xiàng)中就會(huì)包含這hh_cache這個(gè)結(jié)構(gòu)
狀態(tài)機(jī)
鄰居項(xiàng)存在一種狀態(tài)機(jī),鄰居項(xiàng)都有一個(gè)對(duì)于管理和維護(hù)鄰居表來說非常重要的成員,nud_state,用來表示該鄰居項(xiàng)當(dāng)前所處的狀態(tài)。下面依依介紹這幾個(gè)狀態(tài):
NUD_NONE:鄰居項(xiàng)剛建立時(shí)處于的狀態(tài),在該狀態(tài)下,還沒有硬件地址可以用,所以還不能發(fā)送請(qǐng)求報(bào)文。一旦有報(bào)文要輸出到該鄰居,便會(huì)出發(fā)對(duì)該鄰居硬件地址的請(qǐng)求,進(jìn)入NUD_INCOMPLETE狀態(tài),并緩存發(fā)送的報(bào)文。
NUD_INCOMPLETE:該狀態(tài)是請(qǐng)求報(bào)文已發(fā)送,但尚未收到應(yīng)答的狀態(tài)。該狀態(tài)下還沒解析到硬件地址,因此尚無可用硬件地址,如果有報(bào)文要輸出到該鄰居,會(huì)將其緩存起來。這個(gè)狀態(tài)會(huì)啟動(dòng)一個(gè)定時(shí)器,如果在定時(shí)器到期時(shí)還沒有接收到鄰居的回應(yīng),則會(huì)重復(fù)發(fā)送請(qǐng)求報(bào)文,否則發(fā)送請(qǐng)求報(bào)文的次數(shù)打到上限,便會(huì)進(jìn)入NUD_FAILED。
NUD_REACHABLE:該狀態(tài)以及得到并緩存了鄰居的硬件地址。進(jìn)入該狀態(tài)首先設(shè)置鄰居項(xiàng)相關(guān)的output函數(shù)(該狀態(tài)使用neighbors_ops結(jié)構(gòu)的connectd_outpt),然后查看是否存在要發(fā)送給該鄰居的報(bào)文。如果在該狀態(tài)下閑置時(shí)間達(dá)到上限,便會(huì)進(jìn)入NUD_STATLE。
NUD_STATLE:該狀態(tài)一旦有報(bào)文要輸出到該鄰居,則會(huì)進(jìn)入NUD_DELAY并將該報(bào)文輸出。如果在該狀態(tài)下閑置時(shí)間達(dá)到上限,且此時(shí)的引用計(jì)數(shù)為1,則通過垃圾回收機(jī)制將其刪除,在該狀態(tài)下,報(bào)文的輸出不收限制,使用慢速發(fā)送過程。
NUD_DELAY:該狀態(tài)下表示NUD_STATE狀態(tài)下發(fā)送的報(bào)文已經(jīng)發(fā)出,需得到鄰居的可達(dá)性確認(rèn)的狀態(tài)。在為接收到鄰居的應(yīng)答或確認(rèn)時(shí)也會(huì)定時(shí)地重發(fā)請(qǐng)求,如果發(fā)送請(qǐng)求報(bào)文的次數(shù)到上限,如果收到鄰居的應(yīng)答,進(jìn)入NUD_REACHABLE,否則進(jìn)入NUD_FAILED,在該狀態(tài)下,報(bào)文的輸出不收限制,使用慢速發(fā)送過程。
操作
neigh_create:
創(chuàng)建一個(gè)neighbour項(xiàng)結(jié)構(gòu),當(dāng)以下情況發(fā)生:
傳輸請(qǐng)求:向一臺(tái)L2地址未知的主機(jī)傳輸請(qǐng)求,就需要對(duì)這個(gè)地址進(jìn)行解析。
收到solicitation請(qǐng)求:收到這個(gè)請(qǐng)求的主機(jī)會(huì)假定兩個(gè)系統(tǒng)有通信發(fā)生,會(huì)創(chuàng)建一個(gè)緩存項(xiàng)。
手工添加:手工添加一個(gè)鄰居緩存項(xiàng)。
neigh_release:
這個(gè)函數(shù)會(huì)減少neighbour的引用計(jì)數(shù),當(dāng)引用計(jì)數(shù)為0時(shí),才真正刪除neighbour結(jié)構(gòu),這個(gè)函數(shù)真正調(diào)用neigh_destroy。以下是函數(shù)調(diào)用的原因:
內(nèi)核企圖向一個(gè)不可到達(dá)的主機(jī)發(fā)送報(bào)文。
與這個(gè)鄰居結(jié)構(gòu)相關(guān)的L2地址改變了。
鄰居結(jié)構(gòu)存在的時(shí)間太長(zhǎng),內(nèi)核需要它占用的內(nèi)存。
neigh_update:
更新neighbour狀態(tài)和鏈路層地址。流程如下:
更新狀態(tài)不是NUD_VALID態(tài)的鄰居發(fā)生的變化,主要是狀態(tài)機(jī)和neigh->output。
更新L2地址,給狀態(tài)不是NUD_VALID態(tài)的鄰居使用。
設(shè)置一個(gè)新的鏈路層地址。
改變NUD狀態(tài)。
處理arp_queue隊(duì)列。
arp例子
總結(jié)
以上是生活随笔為你收集整理的linux内核的邻居表,Linux内核报文收发-L3 - Section 3. IP协议、邻居子系统主要是接收、转发和发送三部分...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我国再减持6百多亿美国国债,还持有7万多
- 下一篇: 英国之后德国也栽了,二季度GDP同比大跌