兩件很容易搞混的工作
當你抵達網路層時,你遇到一個聽起來幾乎像是一個概念被斜線劈成兩半的詞:轉送與路由。現在值得放慢腳步好好看它,因為整段這一級的內容都活在斜線的「路由」那一側。想像一間忙碌的郵件分揀中心。轉送是那位職員:瞥一眼包裹上的地址,讀一下釘在牆上的圖表,然後把它丟進正確的外送滑槽,整個動作不到一秒。路由則是規劃小組:花上數小時、數天,決定那張牆上的圖表一開始究竟該寫些什麼。
在一台路由器內部,這兩件工作以天差地遠的速度、在不同的地方運行。轉送屬於資料平面(data plane):對每一個抵達的封包,路由器從標頭裡掏出目的 IP、查一下、再把封包從它的某個介面推出去。這件事每秒必須發生數百萬次,所以它被做進快速硬體裡,並使用一張預先算好的表。路由屬於控制平面(control plane):一個較慢的背景程序,跑在軟體裡,與其他路由器交談、學出網路的形狀,然後(重新)建出那張表。那張表就是兩者之間的橋。
把網路畫成一張加權圖
為了規劃出好路徑,路由首先需要一個它能用來推理的網路模型。這個模型美妙地簡單:一張圖(graph)。把每一台路由器畫成一個點(節點),把每兩台路由器之間的直接鏈路畫成連接這兩個點的一條線(邊)。一個橫越網路的封包,就只是一枚沿著線、從點跳到點的棋子。這就是網路圖模型,而一旦你看見它,路由就不再神祕,而變成一個關於點與線的乾淨問題。
但並非所有鏈路生而平等,所以每條邊都帶著一個數字,稱為它的成本(cost,或權重)。成本可以代表這條鏈路的延遲、它頻寬的倒數(所以 1 Gbps 的鏈路比 100 Mbps 的便宜)、一個金錢價格,或者單純就是「每跳算 1」——當你只在乎封包經過幾台路由器時。由營運者決定成本代表什麼;演算法只把它當成一個沿路徑累加的數字。關鍵在於:成本低是好事,就像價格低一樣,於是路由的工作就變成:找出從這裡到各個目的地最便宜的那條路。
A small network as a weighted graph (numbers = link cost)
2 5
(A)------(B)----------(C)
| | |
1 | 3 | 1 |
| | |
(D)------(E)----------(F)
1 2
Cost of A -> B -> C = 2 + 5 = 7
Cost of A -> D -> E -> F -> C = 1+1+2+1 = 5 (cheaper!)我們真正要算的東西:最低成本路徑
有了這張圖在手,任何路由演算法的目標現在都很精確:對每一個目的地,找出最低成本路徑——從這台路由器到那個目的地、成本加總最小的那條路。注意這跟「跳數最少」並不是同一回事。在上面那張圖裡,A 用兩跳到達 C,成本是 7;用四跳卻只要成本 5。如果成本代表延遲,那條看起來更長的繞道其實真的更快。最低成本路徑正是演算法要獵捕的東西,而沿著它的第一跳,正是被寫進轉送表的內容。
有一個微妙卻可愛的事實,讓這一切變得可解,接下來兩篇的演算法都重度倚賴它。如果從 A 到 C 最便宜的路恰好經過 E,那麼這條路從 E 往後的那一段,本身就必然是從 E 到 C 最便宜的路。(因為若從 E 到 C 還有更便宜的走法,A 也會跟著用它。)用白話說:一條最佳路徑,是由一段段最佳子路徑拼出來的。這正是為什麼一台路由器只要把鄰居們早已找到的好路線組合起來,就能學出完整的好路線,而不必把整個世界從頭重算一遍。
兩種解法,兩個完整的家族
讓路由器算出這些最低成本路徑,有兩種根本不同的辦法,而每一種都錨定了一整個真實協定的家族。它們的差別落在一個決定性的問題上:每台路由器究竟能知道多少關於這張網路的事?要嘛每台路由器都學到整張地圖、獨自算出路徑;要嘛沒有任何一台路由器看得到完整地圖,它們改而向鄰居們閒聊各自的距離,直到答案塵埃落定。這一個選擇會漣漪般地影響一切:速度、訊息大小、出錯時的樣子,以及錯得有多嚴重。
第一個家族是鏈路狀態路由(link-state routing)。每台路由器只把「自己直接相連的鏈路以及它們的成本」的描述,向所有其他路由器大聲廣播,於是最終每台路由器手上都握著一份一模一樣、完整的地圖。握著整張圖,路由器接著獨自跑一個最短路徑演算法——著名的 Dijkstra 演算法——算出到各地的最低成本路徑。這是「每個人都拿到完整地圖,然後各自獨立思考」的做法。鏈路狀態路由是 OSPF 內部的引擎,OSPF 是大型企業與電信業者網路的主力協定,本級的第 2 篇就專門講它。
第二個家族是距離向量路由(distance-vector routing)。沒有任何一台路由器看得到整張地圖。每台路由器改為保有一張小表,記著自己到每個目的地目前已知的最佳成本(一個由距離組成的向量),並週期性地只告訴它的直接鄰居:「我認為每個地方離我有多遠。」每台路由器再從鄰居們回報的內容更新自己的估計,用的是 Bellman-Ford 的想法:我到某目的地的成本,是(到某鄰居的成本 + 那位鄰居回報的往後成本)之中最便宜的那一個。距離向量路由是 RIP 內部的引擎,它跑起來較簡單,卻容易犯計數至無窮的毛病,第 3 篇會把它拆開來看。
這一級會把你帶到哪裡
這裡的一切都活在單一管理網域之內——一個組織的網路,由一位掌控所有成本的營運者運行。在這樣一個網域內部負責路由的協定,稱為內部閘道協定,而 RIP 與 OSPF 就是其中兩個著名的代表。在不同組織之間、橫跨開放網際網路的路由,則是另一場把政治與金錢都揉進去的賽局;那是下一級的 BGP,我們刻意還沒走到那裡。現在,請把這條界線牢牢記住:一個網域、一套成本、彼此合作的路由器。
- 第 2 篇打造鏈路狀態的世界:路由器如何把自己本地的鏈路資訊向所有人氾流(flood)出去,再對拼好的地圖跑 Dijkstra 演算法算出最短路徑。
- 第 3 篇用 Bellman-Ford 的想法打造距離向量的世界,接著遇上計數至無窮的問題(壞消息傳得很慢)以及它的部分解藥,例如水平分割(split horizon)。
- 第 4 篇把兩種想法落實到真實的內部協定上:RIP 是簡單的距離向量老兵,OSPF 是可擴充的鏈路狀態標準。
- 第 5 篇追問這如何擴展:把網路切成區域的階層式路由,加上讓轉送表保持精簡的預設路由(default route)與路由聚合(route aggregation)。
牢牢抓住這篇的兩個錨點,這一級剩下的內容就會像是同一主題的變奏。第一,轉送是逐封包、讀一張表的本地反射,路由則是較慢、遍及全網、用來算出那張表的工作。第二,網路是一張加權圖,路由就是在其中尋找最低成本路徑——要嘛靠「人人都知道地圖」(鏈路狀態),要嘛靠「人人都閒聊距離」(距離向量)。這兩句話就是接下來一切內容的脊梁。