BGP 網路架構 BIRD 路由協定 IXP

BIRD 2 撐到 1000 個 peer 就開始噴:BIRD 3 用協同多執行緒把單機 BGP 拉到 5000 peer 以上

BIRD 從 1998 年寫到現在,核心一直是單執行緒事件驅動。IXP route server 起機要跑 20 分鐘的問題在 BIRD 3 才被真正解決。這篇拆解協同多執行緒的設計、從 BIRD 2 遷移過去要注意的組態變化,以及 3.2 版把 AS Set 當作 malformed 的預設變更。

跑自己 ASN 的團隊,這幾年大概都經歷過同一件事:BGP session 數量一多,BIRD 的 CPU 使用率就開始往上飄;把 route table dump 出來要等好幾秒;改一次 filter 重載組態,整臺 route server 的收斂時間可以拉到十幾分鐘起跳。這不是設定失誤,是 BIRD 從 1998 年寫下第一行程式開始,核心就是單執行緒事件驅動——route 選擇、filter 執行、鄰居狀態機、table 維護全部塞在同一個 event loop 裡輪流跑。BIRD 3 在 2024 年 12 月發布首個多執行緒重寫版本,2025 到 2026 年一路推到 3.2 版,這個歷史包袱終於被拆掉。

CZ.NIC 公開的資料上,BIRD 2 在 IXP route server 情境大約撐 1000 個 BGP peer 就開始明顯掉速,BIRD 3 在同一臺機器上跑到 5000 個 peer 依然游刃有餘。這不是換演算法帶來的加速,是把整個 event loop 改成協同多執行緒之後的結構性提升。對正在營運 BGP、跑 IX 路由伺服器、或準備擴充 transit 上游數量的網路,這個版本值得認真評估遷移路徑。

為什麼 BIRD 2 一過 1000 peer 就撐不住

BIRD 從一開始就選擇事件驅動,這在 1998 年是正確決策——當年 Linux kernel 對 pthread 的支援還在成熟階段,一個 process 內做多執行緒協作反而容易踩到細節 bug。單執行緒 event loop 把所有 I/O、timer、訊息通通排進一個 queue 依序處理,行為可預期、除錯容易、跨平臺移植也乾淨。

問題在於這條路的天花板來得很清楚。BGP session 開太多,光是每個 peer 的 keepalive、update、withdraw 訊息就會塞爆事件佇列。更糟的是 route selection 這種本質上就 CPU 密集的計算,一旦某個大 peer 送來幾十萬條路由的初始 dump,整個 event loop 都在跑那份 dump 的 best-path 選擇,其他所有 peer 全部被排在後面。CZ.NIC 官方 blog 的測試數據顯示,大型 IXP route server 冷啟動時完整收斂要超過 20 分鐘,而且處理速度會隨時間下降——單一 event loop 撐不住之後,每秒能處理的路由變化甚至掉到個位數。

實務上這件事對 IX 路由伺服器的影響最直接,但對一般 transit 骨幹也不能忽略。多個上游 full table peer 加上內部 iBGP mesh,很快就會逼近單執行緒的頻寬上限。想跨過去只能起第二個 BIRD process,靠 iBGP session 互相同步——設定複雜、故障處理麻煩,收斂時間反而更難掌握。

協同多執行緒不是「加一顆 pthread」那麼簡單

BIRD 3 的多執行緒設計刻意避開了共用記憶體加鎖的路子。作者 Maria Matejka 在幾份公開簡報裡強調過,走傳統 mutex 路線要改動的地方會炸開,而且鎖競爭本身在高並行下就是新的瓶頸。BIRD 3 選擇的是訊息傳遞為主、極小範圍鎖為輔的協同模型。

實際運作方式是這樣:每個 BGP protocol instance、每個 RPKI/Pipe/BMP/MRT protocol、每張路由表都會被指派到一個 worker thread 上執行。thread 之間透過訊息 queue 溝通,例如某個 BGP session 收到 update 需要寫進 RIB,就把訊息丟到那張路由表所屬的 thread 去處理,自己繼續讀下一份 packet。route selection、table maintenance、filter 執行都在對應的 thread 內部完成,彼此之間不共用可寫記憶體。

CZ.NIC 的說法是「幾乎全部 lockless,例外是 ROA 檢查跟 nexthop 解析」。這兩個例外是因為它們需要跨表查詢——ROA 資料可能在別的 thread 掌管的 table 裡,nexthop resolution 也需要查另一張路由表。這些場景走了細粒度鎖,但因為只在寫入點短暫持有,實務上對吞吐量影響有限。

這個設計叫「協同多執行緒」是因為 thread 之間互相協作,不是搶著跑同一段程式碼。每一個 thread 有自己的職責邊界,訊息 queue 是唯一的協同機制。CZ.NIC 8 核心(16 hyperthread)機器上的公開 benchmark,BIRD 3.0-alpha0 相對 2.0.8 的處理時間降到約 1/8,接近核心數的理論上限。

組態該怎麼開始改

從 BIRD 2 升級到 3,最關鍵的組態變化其實只有一行。全域區塊裡加一個 threads N 就會啟動 N 個 worker thread:

1
threads 6;

CZ.NIC 建議 N 設成 CPU 核心數扣掉一到兩顆——留給 kernel 和其他系統程序。8 vCPU 的 VPS 設 6 是合理起點;跑 IXP route server 這種對延遲敏感的角色,可以先開 4 觀察一週再往上調。預設值是單執行緒,等於 BIRD 2 的行為,所以升級後不改組態也不會炸——只是完全沒享受到 3.0 的紅利。

路由表區塊也多了幾個效能相關旗標。sorted 讓 table 內部維護排序好的資料結構,加速 longest-prefix match;trie 則是明確要求用 trie 結構儲存前綴、方便 flowspec 這類需要範圍查詢的協定。跑幾張大表、又常被 CLI query 的情境,這兩個 flag 應該開起來:

1
2
3
4
ipv4 table master4 {
sorted;
trie;
};

除錯層面,debug latency 這個全域開關會把 scheduler 內部的延遲統計輸出到 log。上線後跑幾天,觀察哪些 event 的延遲異常高、哪個 thread 常常在忙,就能決定要不要調整 thread 數或把某些協定拆到獨立 process。

3.2 版把 AS Set 當 malformed,這條變更會踩到人

2026 年 1 月釋出的 BIRD 3.2.0 帶了一個安全相關的預設變更值得單獨拉出來講:AS Path 裡出現 AS Set(也就是 AS_SET、AS_CONFED_SET 這類聚合類型)現在會被當成 malformed,預設直接拒收。

這個決定來自現實觀察——聚合宣告在現代 BGP 幾乎沒人在正確使用,反而是路由洩漏、path forgery 常見的載體。RFC 6472 早在 2011 年就建議停用 AS_SET,主要 tier-1 業者過去十年也逐步收緊策略。BIRD 3.2 把這個推向預設值。

實務影響是:極少數還在跑 AS aggregation 的老系統,會突然發現送出去的 route 被鄰居丟掉。debug 這種問題最快的方式是先在 BIRD 端把 strict as_path 關掉、確認流量正常後回頭跟對方談是不是可以清掉那份 aggregation。多數情境下這個變更是免費的安全升級。

同一個版本還把 igp_metric 屬性拆開:需要區分 IGP metric 跟區域內 metric 的情境,現在有獨立的 local_metric 可以用。這個拆分解決了 BIRD 2 時代把兩個語意不同的欄位擠在同一個名字裡的歷史問題,寫 filter 時語意更清楚,但要留意舊 filter 引用 igp_metric 的地方在特定 IBGP 情境下可能拿到跟預期不同的值。

BGP dynamic onlink、unnumbered、link-local 這幾個連線類型也在 3.2 補齊——這對跑 IPv6-only backbone、或者用 unnumbered peering 節省 IPv4 位址的網路特別有意義。

Debian 選擇了 3.1 當 LTS,這個訊號值得注意

BIRD 團隊在 3.2 發布時同步把版本分軌釐清:3.1.x 被指定為 LTS 分支,追隨 Debian Trixie 的支援週期;3.2.x 是滾動分支,會持續加入新功能但支援期短。這個分工反映了 BIRD 3 已經從實驗階段走向生產穩定——Debian 主分支要接的東西不會是玩具。

對正在部署新機的網路來說,選 3.1.x 是穩健路線:拿到多執行緒帶來的效能提升,但避開 3.2 這類正在改預設值的版本可能踩到的相容性小坑。已經在跑 BIRD 3.0/3.1 的環境,遷移到 3.1 LTS 通常是無感升級。BIRD 2.18 仍然有維護,但團隊已經明確把 3.x 定為主線;2.x 的角色更像是「不能升級 kernel 或發行版還沒跟上的環境」的保底選項。

什麼樣的網路該開始評估遷移

單臺伺服器 BGP peer 數不到 100、又沒有明顯 CPU 瓶頸的環境,實際上 BIRD 2 還能撐很久——多執行緒帶來的差異在小規模下不明顯。這種情境下的遷移動機更多是為了跟上主線、避免長期停在停止開發的 2.x。

真的該優先升的是三種情境。第一種是 IXP 路由伺服器——peer 數容易破千,收斂時間直接影響交換中心的整體品質,BIRD 3 的多執行緒基本上是免費的十倍空間。第二種是有多個 full-table transit 上游、又同時跑內部 iBGP mesh 的網路——CPU 負載會集中在 route selection,這是 BIRD 3 加速最明顯的地方。第三種是準備擴充 BGP 服務、預期 peer 數會成長的環境——在成長之前先把底層換掉,比撞牆後緊急處理來得從容。

實際遷移建議走這條路徑:先在測試環境把現有的 BIRD 2 組態原封不動搬到 BIRD 3、不加 threads 指令,確認語法相容性;再開 threads 逐步調整,用 debug latency 觀察一週;穩定後再看要不要碰 3.2 的預設變更。整個過程不需要一次到位,也不建議一次到位——BGP 是穩定性優先的協定,換版本的節奏應該匹配 change window,不是追新版本號。

BGP 這件事的價值從來就不是「跑起來」,而是「在異常發生時知道發生什麼」。多執行緒讓單機能撐更多 peer,但真正省下來的成本是不用再靠拆 process、堆機器來繞過單執行緒瓶頸。網路架構乾淨,維運工程就輕鬆。NCSE Network 提供 10M 到 100G 的 IP Transit 與 BGP peering 服務,也協助臺灣本地 ASN 規劃路由架構與 BIRD 部署,需要評估自建 route server、或把多執行緒 BIRD 3 導入現有網路的團隊,可以直接詢問技術規劃。

需要高品質的網路服務?

NCSE Network 提供 IP Transit、IP Tunnel 及 BGP 路由規劃,10M~100G 彈性頻寬,多上游備援確保穩定。

了解網路服務 →