傳統路由僅依據**目的地址**查找單一路由表,無法滿足「不同來源走不同線路」、「依服務等級分流」、「成本優化」等進階需求。Linux 核心 2.2+ 引入**策略路由**,透過**多路由表**與**規則鏈**實現靈活的封包導向決策。本文系統闡述架構設計、配置工具、應用場景及核心原始碼層級的 RPDB(Routing Policy Database)實現機制。
Linux 支援最多 255 張路由表(0-254),預設內建三張:
| 表 ID | 名稱 | 用途 | 維護方式 |
|---|---|---|---|
| 255 | local | 本地介面位址、廣播位址、NAT 位址 | 核心自動維護,管理員不可直接修改 |
| 254 | main | 主路由表,route/ip route 無指定表預設操作此表 | 管理員管理 |
| 253 | default | 預設路由表,通常放置預設閘道 | 管理員管理 |
| 0 | reserved | 保留 | - |
| 1-252 | 用戶自訂 | 策略路由專用表 | 管理員管理 |
規則定義「什麼封包用哪張表」,包含三要素:
傳統 route 無法操作策略路由,必須使用 iproute2 套件(ip 指令)。
ip addr add 192.168.0.1/24 broadcast 192.168.0.255 dev eth0 label eth0:0
# 查看指定表
ip route list table 10
# 新增路由到表 10
ip route add 192.168.3.0/24 via 192.168.0.3 table 10
# 新增預設路由到主表
ip route add default via 192.168.0.4 table main
# 查看所有規則
ip rule list
# 0: from all lookup local
# 32766: from all lookup main
# 32767: from all lookup default
# 新增規則:來源 192.168.3.112 且 TOS=0x10 使用表 2,優先序 1500
ip rule add from 192.168.3.112/32 tos 0x10 table 2 pref 1500
# 新增規則:所有封包使用表 1,優先序 32800
ip rule add from all table 1 pref 32800
# 刪除規則
ip rule del from 192.168.3.112/32 tos 0x10 table 2 pref 1500
預設規則鏈保證**向前相容**:先查 local(本地通訊),再查 main(一般路由),最後查 default(預設閘道)。
| 場景 | 策略描述 | 關鍵 Selector | 效益 |
|---|---|---|---|
| 來源位址選路 | VIP 用戶走 ADSL 快線,一般用戶走撥接慢線 | from | 差異化服務、資源保障 |
| 服務品質 (QoS) | VoIP/視訊走低延遲路徑,郵件/備份走高頻寬廉價路徑 | tos / fwmark | 業務優先級保障 |
| 成本優化 | 突發大流量走按流量計費高速線路,平時走包月專線 | fwmark / time (搭配腳本) | 頻寬成本最小化 |
| 負載均衡 | 依來源/目的 IP 雜湊分流至多條同等線路 | from / to (搭配統計模式) | 頻寬利用最大化 |
RPDB 實現分佈於 net/ipv4/fib_*.c、net/ipv4/route.c:
| 結構體 | 角色 | 定義位置 |
|---|---|---|
struct fib_table | 路由表物件,含操作函數指標、雜湊根節點 | include/net/ip_fib.h |
struct fn_hash | 路由表雜湊結構,管理 zone 陣列 | fib_hash.c |
struct fn_zone | Zone 域,依前綴長度分組節點 | fib_hash.c |
struct fib_node | 路由節點,實際儲存前綴與路由資訊 | fib_hash.c |
struct fib_info | 路由屬性:下一跳、輸出介面、度量、快取資訊 | ip_fib.h |
struct fib_result | 查找結果封裝 | ip_fib.h |
struct fib_rule | 規則節點,串聯成規則鏈 | fib_rules.c |
struct fib_table *fib_tables[RT_TABLE_MAX+1]; // 所有路由表陣列
struct fib_rule *fib_rules; // 規則鏈頭指標
fib_lookup() (route.c / fib_frontend.c)int fib_lookup(const struct rt_key *key, struct fib_result *res) {
read_lock(&fib_rules_lock);
for (r = fib_rules; r; r = r->r_next) { // 1. 依優先序掃描規則鏈
if (selector_mismatch(key, r)) continue; // Selector 不符跳過
switch (r->r_action) { // 2. 處理 Action
case RTN_UNICAST:
case RTN_NAT:
policy = r; break;
case RTN_UNREACHABLE: return -ENETUNREACH;
case RTN_PROHIBIT: return -EACCES;
case RTN_BLACKHOLE: return -EINVAL;
}
if (!(tb = fib_get_table(r->r_table))) continue; // 3. 取得路由表
err = tb->tb_lookup(tb, key, res); // 4. 在表中查找
if (err == 0) { // 5. 命中回傳
res->r = policy;
read_unlock(&fib_rules_lock);
return 0;
}
if (err < 0 && err != -EAGAIN) return err; // 6. 硬錯誤回傳
}
read_unlock(&fib_rules_lock);
return -ENETUNREACH; // 7. 全失敗
}
route.c 實作 ip_route_output_key()(發送路徑)與 ip_route_input_slow()(接收路徑),邏輯一致:
rt_cache),命中直接回傳fib_lookup() 查 RPDB快取定期由 rt_garbage_collect() 清理失效項目。
Linux 策略路由透過 **RPDB(規則鏈 + 多路由表)** 分離「分類決策」與「路徑查找」,賦予網路管理員精細的流量控制能力。iproute2 是唯一標準配置介面,掌握 ip rule、ip route table 操作是進階網管必修課。核心層面,fib_lookup() 以極簡邏輯實現高效率的「規則→表→路由」三級查找,配合路由快取機制,滿足高效能轉發需求。