Linux核心分析 - 網路[四補]:路由表補充__Linux

來源:互聯網
上載者:User


http://blog.csdn.net/qy532846454/article/details/6726171


      核心版本:2.6.34
      前篇路由表http://blog.csdn.net/qy532846454/article/details/6423496說明了路由表的結構及路由表的建立。下面是一些路由表的使用的細枝末節,作補充說明。
      路由可以分為兩部分:路由緩衝(rt_hash_table)和路由表()
      路由緩衝顧名思義就是加速路由尋找的,路由緩衝的插入是由核心控制的,而非人為的插入,與之相對比的是路由表是人為插入的,而非核心插入的。在核心中,路由緩衝組織成rt_hash_table的結構。

      下面是一段IP層協議的程式碼片段[net/ipv4/route.c],傳入IP層的協議在尋找路由時先在路由緩衝中尋找,如果已存在,則skb_dst_set(skb, &rth->u.dst)並返回;否則在路由表中查詢。
[cpp] view plain copy hash = rt_hash(daddr, saddr, iif, rt_genid(net));      rcu_read_lock();   for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;        rth = rcu_dereference(rth->u.dst.rt_next)) {       if (((rth->fl.fl4_dst ^ daddr) |            (rth->fl.fl4_src ^ saddr) |            (rth->fl.iif ^ iif) |            rth->fl.oif |            (rth->fl.fl4_tos ^ tos)) == 0 &&           rth->fl.mark == skb->mark &&           net_eq(dev_net(rth->u.dst.dev), net) &&           !rt_is_expired(rth)) {           dst_use(&rth->u.dst, jiffies);           RT_CACHE_STAT_INC(in_hit);           rcu_read_unlock();           skb_dst_set(skb, &rth->u.dst);           return 0;       }       RT_CACHE_STAT_INC(in_hlist_search);   }   rcu_read_unlock();  

        在ip_route_input()中查詢完陸由緩衝後會處理組播地址,如果是組播地址,則下面判斷會成功:ipv4_is_multicast(daddr)。
然後執行ip_route_input_mc(),它的主要作用就是產生路由快取項目rth,並插入緩衝。rth的產生與初始化只給出了input函數的,其它略去了,可以看出組播報文會通過ip_local_deliver()繼續向上傳遞。 [cpp] view plain copy rth->u.dst.input= ip_local_deliver;   hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));   return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);  

      路由表又可以分為兩個:RT_TABLE_LOCAL和RT_TABLE_MAIN
        RT_TABLE_LOCAL儲存目的地址是原生路由表項,這些目的地址就是為各個網卡配置的IP地址;
        RT_TABLE_MAIN儲存到其它主機的路由表項;
      顯然,RT_TABLE_MAIN路由表只有當主機作為路由器時才有作用,一般主機該表是空的,因為主機不具有轉寄資料包的功能。RT_TABLE_LOCAL對主機就足夠了,為各個網卡配置的IP地址都會加入RT_TABLE_LOCAL中,如為eth1配置了1.2.3.4的地址,則RT_TABLE_LOCAL中會存在1.2.3.4的路由項。只有本地的網卡地址會被加入,比如lo、eth1。IP模組在初始化時ip_init() -> ip_rt_init() - > ip_fib_init()會註冊notifier機制,當為網卡地址配置時會執行fib_netdev_notifier和fib_inetaddr_notifier,使更改反映到RT_TABLE_LOCAL中。 [cpp] view plain copy register_netdevice_notifier(&fib_netdev_notifier);   register_inetaddr_notifier(&fib_inetaddr_notifier);  

          而當在路由緩衝中沒有尋找到快取項目時,會進行路由表查詢,還是以IP層協議中的程式碼片段為例[net/ipv4/route.c],fib_lookup()會在MAIN和LOCAL兩張表中進行尋找。 [cpp] view plain copy if ((err = fib_lookup(net, &fl, &res)) != 0) {       if (!IN_DEV_FORWARD(in_dev))           goto e_hostunreach;       goto no_route;   }  

        如果主機配置成了支援轉寄,則無論在路由表中找到與否,都會產生這次查詢的一個緩衝,包括源IP、目的IP、接收的網卡,插入路由緩衝中: [cpp] view plain copy hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));   err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);  

      不同的是,如果在路由表中查詢失敗,即資料包不是發往本機,也不能被本機轉寄,則會設定插入路由緩衝的快取項目u.dst.input=ip_error,而u.dst.input即為IP層處理完後向上傳遞的函數,而ip_error()會丟棄資料包,被發送相應的ICMP錯誤判文。不在路由表中的路由項也要插入路由緩衝,這可以看作路由學習功能,下次就可以直接在路由緩衝中找到。 [cpp] view plain copy rth->u.dst.input= ip_error;   rth->u.dst.error= -err;   rth->rt_flags    &= ~RTCF_LOCAL;  

      但如果主機不支援轉寄,即沒有路由功能,則只有在找到時才會添加路由快取項目,都不會產生路由快取項目。這是因為在LOCAL表中沒有找到,表明資料包不是發往原生,此時緩衝這樣的路由項對於主機的資料包傳輸沒有一點意義。它只需要知道哪些資料包是發給它的,其餘的一律不管。        路由查詢整合起來,就是由ip_route_input()引入,然後依次進行路由緩衝和路由表查詢,並對路由緩衝進行更新。路由緩衝在每個資料包到來時都可能發生更新,但路由表則不一樣,只能通過RTM機制更新,LOCAL表是在網卡配置時更新的,MAIN表則是由人工插入的(inet_rtm_newroute)。
       ip_route_input()
         - 路由緩衝查詢
         - 路由表查詢:ip_route_input_slow() -> fib_lookup()

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.