Linux核心分析

來源:互聯網
上載者:User

核心版本: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 plaincopy              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()繼續向上傳遞。

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中。

register_netdevice_notifier(&fib_netdev_notifier);     register_inetaddr_notifier(&fib_inetaddr_notifier);

而當在路由緩衝中沒有尋找到快取項目時,會進行路由表 查詢,還是以IP層協議中的程式碼片段為例[net/ipv4/route.c],fib_lookup()會在MAIN和LOCAL兩張表中進行尋找。

if ((err = fib_lookup(net, &fl, &res)) != 0) {         if (!IN_DEV_FORWARD(in_dev))             goto e_hostunreach;         goto no_route;     }

如果主機配置成了支援轉寄,則無論在路由表中找到與否,都會產生這次查詢的一個緩衝,包括源IP、目的IP、接收 的網卡,插入路由緩衝中:

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錯誤判文。不在路由表中的路由項也要插入路由緩衝,這可以看作路由學 習功能,下次就可以直接在路由緩衝中找到。

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.