Rootless Router(Part: 5): 完結

RootlessRouter系列:
  1. Rootless Router(Part: 0): 用戶態DN42節點
  2. Rootless Router(Part: 1): wggo-vpp
  3. Rootless Router(Re: 0): VPP Host stack
  4. Rootless Router(Part: 2): BIRD-vpp
  5. Rootless Router(Part: 3): EtherGuard
  6. Rootless Router(Extra):蒐集的Userspace 網路棧
  7. Rootless Router(Part: 4): 被VPP Host Stack衝康
  8. Rootless Router(Part: 5): 完結
  9. Rootless Router(Fin): UML版本上線啦!
  10. Rootless Router(Afterword): Azure App Service真的很靈
先說結論:失敗了

唉,忙了5個月,結果一場空。真的是很難過

本地最終測試

大部分的拼圖都造好了,我又花了一個月把這些拼圖拼再一起
總時間花了5個月的RootlessRouter總算能運作上線了
在本地測試,BGP session起來了,路由有廣播出去,也有收到外面的路由

上線後遇到第一個麻煩,赫然發現CPU占用率居然是100% !

才想起來,VPP為了性能,採用的是輪詢模式,而不是中斷模式。所以會直接佔用一顆CPU 100%。因為本地是多核心,所以沒發現。但是雲端上是一核心,直接卡死

首先我想到的是cpulimit。我限制成1%,用了以後CPU降到剩下10%。但是有很大的問題,就是ping超級不穩定。因為她的細粒度太低了,跑0.1秒,卡0.9秒。所以部分ping值直接跳上900

後來找到這篇,解決了VPP CPU 100%的問題。
但是又發現,怎麼換成BIRD的cpu 卡100%了?
然後又找上海交大的這篇,經過一番修改,總算是壓住CPU使用率了
在他的輪巡迴圈裡面加上sleep,解決100%的問題。
我是usleep(1000),延遲還算勉強可用,idle狀態壓在3%左右
我做的修改: https://github.com/KusakabeSi/vpp/commit/73ee9164f8a7c4c65ced4aa61ab865878b2e5d3a

部屬上線

之後我就開始部屬到azure app service的免費容器裡面
一開始的確正常運作,session建立,路由正確
但是時間一長,bgp session開始中斷。
ping測試,網路一切正常。可是BGP session就是開始出事
要嘛Hold time expired,要嘛Ceased

之前我在本地已經測試過無數次了,我在本地又重新測試。
但是這次不一樣的點是,我放著讓他長時間跑。果然,問題出現了

一開始都正常,能ping通外面,looking glass能查到路由。但是時間拉長以後,BGP session就沒了
之後我又用沒有patch的版本,也就是會占用100% CPU的全性能版本,問題依舊,所以不是我的patch出問題

網路品質一定沒問題,都在我內網測試,docker的區網裡面,應該不太會丟封包。
所以可以推斷,一定是VPP Host stack的問題。

放棄VPP

這個問題,就真的很難診斷了。不知道又要讀多少程式碼,才能修好這個問題。
天知道問題是出在他的TCP狀態機維護,還是session讀寫鎖出錯,還是哪邊有別的問題
VPP Host stack那個複雜程度,我也實在沒有信心可以看完他呀.....

再加上幾天前才被他的 Host Stack坑到對VPP Host stack已經有點沒信心了

讓我決定放棄的最後一根稻草,是這3%的CPU占用。
就算沒有任何活動,還是要不斷占用3%的CPU
而且這已經是我sleep加到極限,性能已經很差了。usleep(5000)就不太能看了
雖然VPP就是主打輪巡代替中斷,取得更好的性能。但是和我的應用場景就不合了
idle狀態下的CPU高占用,說不定哪天被判定挖礦
這一點讓我決定要改變做法了,不再使用VPP了

有那麼多的網路虛擬化方案,最當初,我為什麼這麼堅持要選擇VPP呢?
因為不同的虛擬化方案基於不同的技術。
linux上主流的是network ns / tun tap / veth / ptrace / ld_preload 。
但是除了ptrace / ld_preload,其他的都要Root! 而我想做的是 Rooeless Router
一切處理都在用戶態,不借助kernel的幫忙

最好可以包成容器,docker run,一台BGP Router就起來了。
而且不用 --privileged ,就是普通的docker container

而ptrace預設關閉,那麼我只剩ld_preload這個選項了

我到快弄完的時候才知道,kernel 4.8以後,docker裡面ptrace就可以用了。
但是因為沉沒成本效應,所以想說VPP弄到底吧

最後的結果...如你所見,翻車了。

在最後紀念一下,為了這個RootlessRouter計畫,我所造的拼圖片們吧

  1. https://github.com/KusakabeSi/EtherGuard-VPN
  2. https://github.com/KusakabeSi/wireguard-go-vpp
  3. https://github.com/KusakabeSi/DN42-AutoPeer-vpp
  4. https://github.com/KusakabeSi/bird-vpp-route-syncer
  5. https://github.com/KusakabeSi/bird-lg-go
  6. https://github.com/KusakabeSi/vpp
  7. https://github.com/KusakabeSi/BIRD-vpp
  8. https://github.com/KusakabeSi/RootlessRouterDocker
  9. https://github.com/KusakabeSi/RootlessRouter
  10. https://github.com/KusakabeSi/RRstate

結論

之後再考慮另起爐灶吧。解鎖了ptrace 選項,選擇就多很多了。
目前我UML是我心目中的候選人,或是gvisor。

這個userspace network stack必須要有3個功能。

  1. 提供 bind() listen() 之類的API,維護tcp state machine,做L3-L4的轉換,讓BIRD接入
  2. 動態新增虛擬網路裝置
  3. 提供路由表功能。能寫入CIDR/device對應表,能正確把風包發項正確的裝置
還有一個選項,就是不走kernel bypass。而是把socket forward出來,讓bird去連線127.0.0.1的某個port。架構有些想法,但是短期內應該不會跑去實作了

畢竟忙了5個月,結果一場空。真的是很難過,需要點時間平復心情

留言

張貼留言