linux策略路由iproute2

策略性路由

  策略性是指對於IP包的路由是以網絡管理員根據須要定下的一些策略爲主要依據進行路由的。例如咱們能夠有這樣的策略:「全部來直自網A的包,選擇X路徑;其餘選擇Y路徑」,或者是「全部TOS爲A的包選擇路徑F;其餘選者路徑K」。
  Cisco 的網絡操做系統 (Cisco IOS) 從11.0開始就採用新的策略性路由機制。而Linux是在內核2.1開始採用策略性路由機制的。策略性路由機制與傳統的路由算法相比主要是引入了多路由表以及規則的概念。node

多路由表(multiple Routing Tables)

  傳統的路由算法是僅使用一張路由表的。可是在有些情形底下,咱們是須要使用多路由表的。例如一個子網經過一個路由器與外界相連,路由器與外界有兩條線路相連,其中一條的速度比較快,一條的速度比較慢。對於子網內的大多數用戶來講對速度並無特殊的要求,因此可讓他們用比較慢的路由;可是子網內有一些特殊的用戶倒是對速度的要求比較苛刻,因此他們須要使用速度比較快的路由。若是使用一張路由表上述要求是沒法實現的,而若是根據源地址或其它參數,對不一樣的用戶使用不一樣的路由表,這樣就能夠大大提升路由器的性能。linux

規則(rule)

  規則是策略性的關鍵性的新的概念。咱們能夠用天然語言這樣描述規則,例如我門能夠指定這樣的規則:
  規則一:「全部來自192.16.152.24的IP包,使用路由表10, 本規則的優先級別是1500」
  規則二:「全部的包,使用路由表253,本規則的優先級別是32767」算法

  咱們能夠看到,規則包含3個要素:
  什麼樣的包,將應用本規則(所謂的SELECTOR,多是filter更能反映其做用);
  符合本規則的包將對其採起什麼動做(ACTION),例如用那個表;
  本規則的優先級別。優先級別越高的規則越先匹配(數值越小優先級別越高)。數組

策略性路由的配置方法

  傳統的linux下配置路由的工具是route,而實現策略性路由配置的工具是iproute2工具包。這個軟件包是由Alexey Kuznetsov開發的,軟件包所在的主要網址爲ftp://ftp.inr.ac.ru/ip-routing/。
這裏簡單介紹策略性路由的配置方法,以便能更好理解第二部分的內容。詳細的使用方法請參考Alexey Kuznetsov寫的 ip-cfref文檔。策略性路由的配置主要包括接口地址的配置、路由的配置、規則的配置。緩存

接口地址的配置IP Addr

對於接口的配置能夠用下面的命令進行:
 網絡

Usage: ip addr [ add | del ] IFADDR dev STRING數據結構


  例如:
併發

router># ip addr add 192.168.0.1/24 broadcast 192.168.0.255 label eth0 dev eth0app


  上面表示,給接口eth0賦予地址192.168.0.1 掩碼是255.255.255.0(24表明掩碼中1的個數),廣播地址是192.168.0.255框架

 

路由的配置IP Route

  Linux最多能夠支持255張路由表,其中有3張表是內置的:
  表255 本地路由表(Local table) 本地接口地址,廣播地址,已及NAT地址都放在這個表。該路由表由系統自動維護,管理員不能直接修改。
  表254 主路由表(Main table) 若是沒有指明路由所屬的表,全部的路由都默認都放在這個表裏,通常來講,舊的路由工具(如route)所添加的路由都會加到這個表。通常是普通的路由。
  表253 默認路由表 (Default table) 通常來講默認的路由都放在這張表,可是若是特別指明放的也能夠是全部的網關路由。
  表 0 保留

  路由配置命令的格式以下:
 

Usage: ip route list SELECTOR
ip route { change | del | add | append | replace | monitor } ROUTE


  若是想查看路由表的內容,能夠經過命令:

  ip route list table table_number


  對於路由的操做包括change、del、add 、append 、replace 、 monitor這些。例如添加路由能夠用:

router># ip route add 0/0 via 192.168.0.4 table main
router># ip route add 192.168.3.0/24 via 192.168.0.3 table 1


  第一條命令是向主路由表(main table)即表254添加一條路由,路由的內容是設置192.168.0.4成爲網關。
  第二條命令表明向路由表1添加一條路由,子網192.168.3.0(子網掩碼是255.255.255.0)的網關是192.168.0.3。

 

  在多路由表的路由體系裏,全部的路由的操做,例如網路由表添加路由,或者在路由表裏尋找特定的路由,須要指明要操做的路由表,全部沒有指明路由表,默認是對主路由表(表254)進行操做。而在單表體系裏,路由的操做是不用指明路由表的。

規則的配置IP Rule

  在Linux裏,總共能夠定義 個優先級的規則,一個優先級別只能有一條規則,即理論上總共能夠有 條規則。其中有3個規則是默認的。命令用法以下:
 

Usage: ip rule [ list | add | del ] SELECTOR ACTION
SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ]
[ dev STRING ] [ pref NUMBER ]
ACTION := [ table TABLE_ID ] [ nat ADDRESS ]
[ prohibit | reject | unreachable ]
[ flowid CLASSID ]
TABLE_ID := [ local | main | default | new | NUMBER


  首先咱們能夠看看路由表默認的全部規則:

root@netmonster# ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
<code>
  規則0,它是優先級別最高的規則,規則規定,全部的包,都必須首先使用local表(254)進行路由。本規則不能被更改和刪除。
  規則32766,規定全部的包,使用表main進行路由。本規則能夠被更改和刪除。
  規則32767,規定全部的包,使用表default進行路由。本規則能夠被更改和刪除。

  在默認狀況下進行路由時,首先會根據規則0在本地路由表裏尋找路由,若是目的地址是本網絡,或是廣播地址的話,在這裏就能夠找到合適的路由;若是路由失敗,就會匹配下一個不空的規則,在這裏只有32766規則,在這裏將會在主路由表裏尋找路由;若是失敗,就會匹配32767規則,即尋找默認路由表。若是失敗,路由將失敗。重這裏能夠看出,策略性路由是往前兼容的。

  還能夠添加規則:
<code>
router># ip rule add [from 0/0] table 1 pref 32800
router >#ip rule add from 192.168.3.112/32 [tos 0x10] table 2 pref 1500 prohibit


  第一條命令將向規則鏈增長一條規則,規則匹配的對象是全部的數據包,動做是選用路由表1的路由,這條規則的優先級是32800。
  第二條命令將向規則鏈增長一條規則,規則匹配的對象是IP爲192.168.3.112,tos等於0x10的包,使用路由表2,這條規則的優先級是1500,動做是prohibit。添加之後,咱們能夠看看系統規則的變化。

router># ip rule
0: from all lookup local
1500 from 192.168.3.112/32 [tos 0x10] lookup 2
32766: from all lookup main
32767: from all lookup default
32800: from all lookup 1


  上面的規則是以源地址爲關鍵字,做爲是否匹配的依據的。除了源地址外,還能夠用如下的信息:
  From -- 源地址
  To -- 目的地址(這裏是選擇規則時使用,查找路由表時也使用)
  Tos -- IP包頭的TOS(type of sevice)域
  Dev -- 物理接口
  Fwmark -- 防火牆參數

 

  採起的動做除了指定表,還能夠指定下面的動做:
   Table 指明所使用的表
   Nat 透明網關
   Action prohibit 丟棄該包,併發送 COMM.ADM.PROHIITED的ICMP信息
   Reject 單純丟棄該包
   Unreachable丟棄該包, 併發送 NET UNREACHABLE的ICMP信息

策略性路由的應用

  基於源地址選路( Source-Sensitive Routing)
  若是一個網絡經過兩條線路接入互聯網,一條是比較快的ADSL,另一條是比較慢的普通的調制解調器。這樣的話,網絡管理員既能夠提供無差異的路由服務,也能夠根據源地址的不一樣,使一些特定的地址使用較快的線路,而普通用戶則使用較慢的線路,即基於源址的選路。

  根據服務級別選路(Quality of Service)
  網絡管理員能夠根據IP報頭的服務級別域,對於不一樣的服務要求能夠分別對待對於傳送速率、吞吐量以及可靠性的有不一樣要求的數據報根據網絡的情況進行不一樣的路由。

  節省費用的應用
  網絡管理員能夠根據通訊的情況,讓一些比較大的陣發性通訊使用一些帶寬比較高可是比較貴的路徑一段短的時間,而後讓基本的通訊繼續使用原來比較便宜的基本線路。例如,管理員知道,某一臺主機與一個特定的地址通訊一般是伴隨着大量的陣發性通訊的,那麼網絡管理員能夠安排一些策略,使得這些主機使用特別的路由,這些路由是按需撥號,帶寬比較高的線路,通訊完成之後就中止使用,而普通的通訊則不受影響。這樣既提升網絡的性能,又能節省費用。

  負載平衡(Load Sharing)
  根據網絡交通的特徵,網絡管理員能夠在不一樣的路徑之間分配負荷實現負載平衡。

Linux下策略性路由的實現--RPDB(Routing Policy DataBase)

  在Linux下,策略性路由是由RPDB實現的。對於RPDB的內部機制的理解,能夠加深對於策略性路由使用的理解。這裏分析的是linux 2.4.18的RPDB實現的細節。主要的實現文件包括:
 

fib_hash.c
fib_rules.c
fib_sematic
fib_frontend.c
route.c


  RDPB主要由多路由表和規則組成。路由表以及對其的操做和其對外的接口是整個RPDB的核心部分。路由表主要由table,zone,node這些主要的數據結構構成。對路由表的操做主要包含物理的操做以及語義的操做。路由表除了向IP層提供路由尋找的接口之外還必須與幾個元素提供接口:與用戶的接口(即更改路由)、proc的接口、IP層控制接口、以及和硬件的接口(網絡接口的改變會致使路由表內容的改變)。處在RDPB的中心的規則,由規則選取表。IP層並不直接使用路由表,而是經過一個路由適配層,路由適配層提供爲IP層提供高性能的路由服務。

 

路由表(Fib Table)

  數據結構:
  在整個策略性路由的框架裏,路由表是最重要的的數據結構,咱們在上面以及對路由表的概念和結構進行了清楚的說明。Linux裏經過下面這些主要的數據結構進行實現的。
 

主要的數據結構 做用 位置
struct fib_table 路由表 ip_fib.h 116
struct fn_hash 路由表的哈希數據 fib_hash.c 104
struct fn_zone zone域 fib_hash.c 85
struct fib_node 路由節點 fib_hash.c 68
struct fib_info 路由信息 ip_fib.h 57
struct fib_result 路由結果 ip_fib.h 86


數據結構之間的主要關係以下。路由表由路由表號以及路由表的操做函數指針還有表數據組成。這裏須要注意的是,路由表結構裏並不直接定義zone域,而是經過一個數據指針指向fn_hash。只有當zone裏有數據纔會鏈接到fn_zone_list裏。(如圖)
系統的全部的路由表由數組變量*fib_tables[RT_TABLE_MAX+1]維護,其中系統定義RT_TABLE_MAX爲254,也就是說系統最大的路由表爲255張,全部的路由表的操做都是對這個數組進行的。。同時系統還定義了三長路由表*local_table; *main_table。

 

路由表的操做:

  Linux策略路由代碼的主要部分是對路由表的操做。對於路由表的操做,物理操做是直觀的和易於理解的。對於表的操做不外乎就是添加、刪除、更新等的操做。還有一種操做,是所謂的語義操做,語義操做主要是指諸如計算下一條的地址,把節點轉換爲路由項,尋找指定信息的路由等。

  一、物理操做(operation):
  路由表的物理操做主要包括以下這些函數:
 

路由標操做 實現函數 位置
新建路由表
刪除路由表
搜索路由 fn_hash_lookup fib_hash.c 269
插入路由到路由表 fn_hash_insert fib_hash.c 341
刪除路由表的路由 fn_hash_delete
fn_hash_dump
fib_hash.c 433
fib_hash.c 614
更新路由表的路由 fn_hash_flush fib_hash.c 729
顯示路由表的路由信息 fn_hash_get_info fib_hash.c 750
選擇默認路由 fn_hash_select_default fib_hash.c 842


  二、語義操做(semantics operation):
  語義操做並不涉及路由表總體框架的理解,並且,函數名也是不言自明的,因此請你們參考fib_semantics.c。

 

  三、接口(front end)
  對於路由表接口的理解,關鍵在於理解那裏有

  IP
  首先是路由表於IP層的接口。路由在目前linux的意義上來講,最主要的仍是IP層的路由,因此和IP層的的接口是最主要的接口。和ip層的銜接主要是向IP層提供尋找路由、路由控制、尋找指定ip的接口。
 

Fil_lookup
ip_rt_ioctl fib_frontend.c 286;" f
ip_dev_find 145


  Inet
  路由表還必須提供配置接口,即用戶直接操做路由的接口,例如增長和刪除一條路由。固然在策略性路由裏,還有規則的添加和刪除。

inet_rtm_delroute 351
inet_rtm_newroute 366
inet_check_attr 335


  proc
  在/proc/net/route裏顯示路由信息。
  fib_get_procinfo

 

  四、網絡設備(net dev event)
  路由是和硬件關聯的,當網絡設備啓動或關閉的時候,必須通知路由表的管理程序,更新路由表的信息。
 

fib_disable_ip 567
fib_inetaddr_event 575
fib_netdev_event


  五、內部維護( magic)
  上面咱們提到,本地路由表(local table)的維護是由系統自動進行的。也就是說當用戶爲硬件設置IP地址等的時候,系統自動在本地路由表裏添加本地接口地址以及廣播地址。

fib_magic 417
fib_add_ifaddr 459
fib_del_ifaddr 498

 

Rule

  一、數據結構
  規則在fib_rules.c的52行裏定義爲 struct fib_rule。而RPDB裏全部的路由是保存在101行的變量fib_rules裏的,注意這個變量很關鍵,它掌管着全部的規則,規則的添加和刪除都是對這個變量進行的。

  二、系統定義規則:
  fib_rules被定義之後被賦予了三條默認的規則:默認規則,本地規則以及主規則。
 

u 本地規則local_rule
94 static struct fib_rule local_rule = {
r_next: &main_rule, /*下一條規則是主規則*/
r_clntref: ATOMIC_INIT(2),
r_table: RT_TABLE_LOCAL, /*指向本地路由表*/
r_action: RTN_UNICAST, /*動做是返回路由*/
};


u 主規則main_rule
86 static struct fib_rule main_rule = {
r_next: &default_rule,/*下一條規則是默認規則*/
r_clntref: ATOMIC_INIT(2),
r_preference: 0x7FFE, /*默認規則的優先級32766*/
r_table: RT_TABLE_MAIN, /*指向主路由表*/
r_action: RTN_UNICAST, /*動做是返回路由*/
};


u 默認規則default rule
79 static struct fib_rule default_rule = {
r_clntref: ATOMIC_INIT(2),
r_preference: 0x7FFF,/*默認規則的優先級32767*/
r_table: RT_TABLE_DEFAULT,/*指默認路由表*/
r_action: RTN_UNICAST,/*動做是返回路由*/
};


  規則鏈的鏈頭指向本地規則。

 

RPDB的中心函數fib_lookup

  如今到了討論RPDB的實現的的中心函數fib_lookup了。RPDB經過提供接口函數fib_lookup,做爲尋找路由的入口點,在這裏有必要詳細討論這個函數,下面是源代碼:
 

310 int fib_lookup(const struct rt_key *key, struct fib_result *res)
311 {
312 int err;
313 struct fib_rule *r, *policy;
314 struct fib_table *tb;
315
316 u32 daddr = key->dst;
317 u32 saddr = key->src;
318
321 read_lock(&fib_rules_lock);
322 for (r = fib_rules; r; r=r->r_next) {/*掃描規則鏈fib_rules裏的每一條規則直到匹配爲止*/
323 if (((saddr^r->r_src) & r->r_srcmask) ||
324 ((daddr^r->r_dst) & r->r_dstmask) ||
325 #ifdef CONFIG_IP_ROUTE_TOS
326 (r->r_tos && r->r_tos != key->tos) ||
327 #endif
328 #ifdef CONFIG_IP_ROUTE_FWMARK
329 (r->r_fwmark && r->r_fwmark != key->fwmark) ||
330 #endif
331 (r->r_ifindex && r->r_ifindex != key->iif))
332 continue;/*以上爲判斷規則是否匹配,若是不匹配則掃描下一條規則,不然繼續*/

335 switch (r->r_action) {/*好了,開始處理動做了*/
336 case RTN_UNICAST:/*沒有設置動做*/
337 case RTN_NAT: /*動做nat ADDRESS*/
338 policy = r;
339 break;
340 case RTN_UNREACHABLE: /*動做unreachable*/
341 read_unlock(&fib_rules_lock);
342 return -ENETUNREACH;
343 default:
344 case RTN_BLACKHOLE:/* 動做reject */
345 read_unlock(&fib_rules_lock);
346 return -EINVAL;
347 case RTN_PROHIBIT:/* 動做prohibit */
348 read_unlock(&fib_rules_lock);
349 return -EACCES;
350 }
351 /*選擇路由表*/
352 if ((tb = fib_get_table(r->r_table)) == NULL)
353 continue;
/*在路由表裏尋找指定的路由*/
354 err = tb->tb_lookup(tb, key, res);
355 if (err == 0) {/*命中目標*/
356 res->r = policy;
357 if (policy)
358 atomic_inc(&policy->r_clntref);
359 read_unlock(&fib_rules_lock);
360 return 0;
361 }
362 if (err < 0 && err != -EAGAIN) {/*路由失敗*/
363 read_unlock(&fib_rules_lock);
364 return err;
365 }
366 }
368 read_unlock(&fib_rules_lock);
369 return -ENETUNREACH;
370 }


  上面的這段代碼的思路是很是的清晰的。首先程序從優先級高到低掃描全部的規則,若是規則匹配,處理該規則的動做。若是是普通的路由尋址或者是nat地址轉換的換,首先從規則獲得路由表,而後對該路由表進行操做。這樣RPDB終於清晰的顯現出來了。

 

IP層路由適配(IP route)

  路由表以及規則組成的系統,能夠完成路由的管理以及查找的工做,可是爲了使得IP層的路由工做更加的高效,linux的路由體系裏,route.c裏完成大多數IP層與RPDB的適配工做,以及路由緩衝(route cache)的功能。

調用接口

  IP層的路由接口分爲發送路由接口以及接收路由接口:

發送路由接口

  IP層在發送數據時若是須要進行路由工做的時候,就會調用ip_route_out函數。這個函數在完成一些鍵值的簡單轉換之後,就會調用 ip_route_output_key函數,這個函數首先在緩存裏尋找路由,若是失敗就會調用 ip_route_output_slow,ip_route_output_slow裏調用fib_lookup在路由表裏尋找路由,若是命中,首先在緩存裏添加這個路由,而後返回結果。
 

ip_route_out route.h
ip_route_output_key route.c 1984;
ip_route_output_slow route.c 1690;"

 

接收路由接口

  IP層接到一個數據包之後,若是須要進行路由,就調用函數ip_route_input,ip_route_input如今緩存裏尋找,若是失敗則 ip_route_inpu調用ip_route_input_slow, ip_route_input_slow裏調用fib_lookup在路由表裏尋找路由,若是命中,首先在緩存裏添加這個路由,而後返回結果。
 

ip_route_input_slow route.c 1312;" f
ip_route_input route.c 1622;" f

 

cache

  路由緩存保存的是最近使用的路由。當IP在路由表進行路由之後,若是命中就會在路由緩存裏增長該路由。同時系統還會定時檢查路由緩存裏的項目是否失效,若是失效則清除。

相關文章
相關標籤/搜索