Linux核心分析

來源:互聯網
上載者:User

核心版本:2.6.34

這部分的重點是三個核心的資料結構-鄰居表、鄰居緩衝、代理鄰居表,以及NUD狀態轉移圖。

總的來說,要成功添加一條鄰居表項,需要滿足兩個條件:1. 本機使用該表項;2. 對方主機進行了確認。同時,表項的添加 引入了NUD(Neighbour Unreachability Detection)機制,從建立NUD_NONE到可用NUD_REACHABLE需要經曆一系列狀態轉移,而根 據達到兩個條件順序的不同,可以分為兩條路線:

先引用再確認- NUD_NONE -> NUD_INCOMPLETE -> NUD_REACHABLE

先確認再引用- NUD_NONE -> NUD_STALE -> NUD_DELAY -> NUD_PROBE -> NUD_REACHABLE

下面還是從接收函數入手,當匹配號協議號是0x0806,會調用ARP模組的接收函數arp_rcv()。

arp_rcv() ARP接收函數

首先是對arp協議頭進行檢查,比如大小是否足夠,頭部各數值是否正確等,這裡略過代碼,直 接向下看。每個協議處理都一樣,如果被多個協議佔有,則拷貝一份。

if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)      goto out_of_mem;

NEIGH_CB(skb)實際就是skb->cb,在skb聲明為u8 char[48],它用作每個協議模組的私人資料 區(control buffer),每個協議模組可以根據自身需求在其中儲存私人資料。而arp模組就利用了它儲存控制結構neighbour_cb ,它聲明如下,佔8位元組。這個控制結構在代理ARP中使用工作隊列時會發揮作用,sched_next代表下次被調度的時間,flags是 標誌。

memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));     struct neighbour_cb {      unsigned long sched_next;      unsigned int flags;     };

函數最後調用arp_process,其間插入netfilter(關於netfilter,參見前篇:http://hi.csdn.net/link.php? url=http://blog.csdn.net%2Fqy532846454),作為開始處理ARP報文的起點。

return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);

arp_process()

這個函數開始對報 文進行處理,首先會從skb中取出arp前序部分的資訊,如sha, sip, tha, tip等,這部分可查閱代碼,這裡略過。ARP不會查詢 環路地址和組播地址,因為它們沒有對應的mac地址,因此遇到這兩類地址,直接退出。

if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))      goto out;

如果收到的是重複地址檢測報文,並且本機佔用了檢測了地址,則調用arp_send發送響應。對於重複地址 檢測報文(ARP報文中源IP為全0),它所帶有的鄰居表項資訊還沒通過檢測,此時緩衝它顯然沒有意義,也許下一刻就有其它主機 聲明它非法,因此,重複地址檢測報文中的資訊不會加入鄰居表中。

if (sip == 0) {      if (arp->ar_op == htons(ARPOP_REQUEST) &&       inet_addr_type(net, tip) == RTN_LOCAL &&       !arp_ignore(in_dev, sip, tip))       arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha);      goto out;     }

下面要處理的位址解析報文,並且要解析的地址在路由表中存在

if (arp->ar_op == htons(ARPOP_REQUEST) &&      ip_route_input(skb, tip, sip, 0, dev) == 0)

第一種情況,如果要解析的是本機地址,則調用neigh_event_ns() ,並根據查到的鄰居表項n發送ARP響應報文。這裡neigh_event_ns的功能是在arp_tbl中尋找是否已含有對方主機的地址資訊, 如果沒有,則進行建立,然後會調用neigh_update來更新狀態。收到對方主機的請求報文,會導致狀態遷移到NUD_STALE。

if (addr_type == RTN_LOCAL) {      ……      if (!dont_send) {       n = neigh_event_ns(&arp_tbl, sha, &sip, dev);       if (n) {        arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);        neigh_release(n);       }      }      goto out;     }

#NUD_INCOMPLETE也遷移到NUD_STALE,作何解釋?

第二種情況,如果要解析的不是本機地址,則要判斷是否支援 轉寄,是否支援代理ARP(代理ARP是陸由器的功能,因此能轉寄是先決條件),如果滿足條件,那麼按照代理ARP流程處理。首先 無論如何,主機得通了存在這樣一個鄰居,因此要在在arp_tbl中尋找並(如果不存在)建立相應鄰居表項;然後,對於代理ARP, 這個流程實際上會執行兩遍,第一遍走else部分,第二遍走if部分。第一次的else程式碼片段會觸發定時器,通過定時器引發報文重 新執行arp_process函數,並走if部分。

-第一遍的else部分:調用pneigh_enqueue()將報文skb加入tbl->proxy_queue隊 列,同時設定NEIGH_CB(skb)的值,具體可看後見的代理表項處理。

-第二遍的if部分,發送ARP響應報文,行使代理ARP的功 能。

else if (IN_DEV_FORWARD(in_dev)) {      if (addr_type == RTN_UNICAST  &&       (arp_fwd_proxy(in_dev, dev, rt) ||       arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||       pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))      {       n = neigh_event_ns(&arp_tbl, sha, &sip, dev);       if (n)        neigh_release(n);                if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||        skb->pkt_type == PACKET_HOST ||        in_dev->arp_parms->proxy_delay == 0) {        arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);       } else {        pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);        in_dev_put(in_dev);        return 0;       }       goto out;      }     }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.