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