文章

RootlessRouter(Fin): UML版本上線啦!

圖片
前篇:  RootlessRouter(Part:5) 完結 最後,RootlessRouter終於上線了! 完結灑花! 在放棄VPP以後,最初我的計劃長這樣: 自己刻一個Simple Router代替原本的VPP,大致架構不變 原本VPP的LD_PRELIAD的kernel bypass部分拿掉,改成端口轉發。把遠端端口179轉發到localhist:10079 然後BIRD就和localhost:10079 建立session,同時把遠端發往SimpleRouter的179端口轉發到localhost:179 同時也不忘看看 這裡 一些其他選項,在我看UML的時候,其中一句話吸引了我: You can get extremely high performance for anything which is a “kernel specific task” such as forwarding, firewalling, etc while still being isolated from the host kernel. 我決定相信他所謂的 extremely high performance。而且BIRD正好不怎麼fork,完美適合UML發揮的場景! 於是我決定把計畫更名,從RootlessRouter改成RootlessRouter-UML,和以前做出區別 現在的架構長這樣:   BIRD是運作在UML裡面的,圖片沒畫好又有點懶得改,附註一下 經過半年,這個計畫終於搞定了! 所有元件都在用戶態執行,甚至連root權限都不需要! 現在節點也上線了,處於beta測試階段。現有10個節點可供peer,列表如下 https://dn42usw.azurewebsites.net https://dn42use.azurewebsites.net https://dn42hk.azurewebsites.net https://dn42jpe.azurewebsites.net https://dn42sg.azurewebsites.net https://dn42au.azurewebsites.net https://dn42fr.azurewebsites.net https://dn42br.azurewebsites.net https://dn42c

三分鐘搞懂DN42 wiki裡面的BIRD2範例設定檔

當初知道DN42的時候,還什麼都不懂 只會抄配置,抄來了也不懂意思。經過了好幾個月,才搞懂他到底在幹嘛 本文假定你至少會一種 procedural programming languages 相信學程式語言的都有這種感覺,懂了一種,其他的也很好懂。 因為他們只是token不一樣,但是語法邏輯都非常相似。頂多多一些專有特性額外要背 不是procedural programming的另當別論,functional/return oriented當我沒說 雖說大多BIRD的評價都是「很像程式語言」 但我也不是沒寫過程式,為啥我都看不懂在幹嘛呢? 因為我雖然會寫程式,但是我當初的癥結點,是卡在「 不知道他的交互對象 」 一旦搞懂這些,剩下的就迎刃而解了。 但我當初不知道,摸了很久才發現這點。 所以想花三分種講給你聽 不管是語法,還是操作,都可以之後在搞懂 但是,首先要搞清的是「你在和誰打交道」 只要這個搞懂了,就算沒學過他的語法,看過別人的範例,加上以前程式語言的經驗,很快就搞懂了 只要這個沒搞懂,看了在多與法定義,也還是搞不懂 路由是一個長類似這樣的資料結構 [1] 192.168.1.0/24 → 192.168.0.1 (加上一些額外標記) [2] 192.168.2.0/26 → 1.1.1.1 (加上一些額外標記) Kernel收到一個封包,DstIP=192.168.1.9。 查詢到路由表裡的 [1],就會把這個封包送往192.168.0.1 這就是路由表 首先,BIRD有2張路由表,叫做master4和master6 ,分別存放ipv4和ipv6路由。 以下只會提到master4,但ipv6的東西會放master6,但我省略了 這個是wiki裡面的BIRD範例設定檔: https://wiki.dn42.dev/howto/Bird2 首先,每個protocol都是一個打交道的對象。 import代表「對面發給我的東西,塞去master4」 export代表「把master4裡面的東西,丟給對面」 第一段 protocol static { route OWNNET reject; ipv4 { import all; export none; }; } route OWNNET reject:

RootlessRouter(Part:5) 完結

前篇:  RootlessRouter(Part: 4): 被VPP Host Stack衝康 先說結論: 失敗了 唉,忙了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-Based-Optimization-for-NGINX

圖片
本文轉載自:  https://sdic.sjtu.edu.cn/wp-content/uploads/2019/10/VPP-Based-Optimization-for-NGINX.pdf Background 1. Session lock and session lock table in VPP 在VPP里,一个VPP session可以是一个网络流,可以将这个session理解为原来Linux内核的一个socket。为了处理多线程应用场景中多线程应用竞争socket的情况,Linux内核为socket引入了socket lock来解决socket竞争问题。而VPP将自己的网络协议栈实现在用户态的同时,也将原来Linux内核中的socket lock拿到了用户态去实现。VPP在用户态实现的这个lock就是VPP session lock。 在多线程应用的每个线程使用一个VPP session之前,线程需要首先获得相应的session lock。因此为了让所有线程都能访问到session lock,VPP就将所有的session lock放到线程均能访问到的共享内存中进行管理。而在共享内存中存储VPP session lock的数据结构,就是VPP session lock table。  如下图。应用线程使用的FD(文件描述符)整数,实际上代表的是session lock table中一个表项的索引值。session lock table中的一个表项供一个VPP session使用,存放了该session的session index和session lock。Session lock table的访问通过lock table read/write lock(读写锁)进行管理。  当一个线程使用listen session时,它会首先去获取lock table的read lock。然后根据listenFD从lock table中获取listen session的表项,从表项中拿到listen session lock并加锁。加锁后就可以从表项中读出listen session index,并释放lock table的read lock。线程根据获取的listen session index从唯一的一个accept event FIFO中accept一个新的连

RootlessRouter(Part: 4): 被VPP Host Stack衝康

前篇:  Rootless Router(Part: 3) EtherGuard 當你以為快要搞定,卻突然被衝康,真的不是普通的難受 被vpp host stack衝康了。之前BIRD運作正常,我就接著弄這些 wggo-vpp搞定 eggo-vpp搞定 bird-vpp搞定 bird-vpp-route-sync搞定 結果發現session又不能建立了 測試一番,發現VPP host stack底下,當server沒問題,但是當client大有問題 vpp side: nc -l 8888 linux side: nc 10.127.111.1 8888 連線完全正常 linux side: nc -l 8888 vpp side: nc 172.22.77.33 8888 連線失敗! 之前BIRD正常運作,因為他可以listen 當server,另一邊(linux)連過來,session建立 所以我一直以為它的功能是好的,就接著弄了。 但是當兩邊都是vpp,一定要有一邊當client,就出問題了! 現在終於快搞定的時候,發現這個大問題 如果這個不能解決,真就只能換一個network stack了 記得從6月開始弄這個。在我以為快弄完的時候,發現以前的功夫可能白費,真的...難過... 下一個network stack群友有什麼推薦嗎?我有看到這些候選 1. 用gVisor (基於ptrace) 2. 用gVisor (以socks proxy方式提供,BIRD透過L4 proxy連線wg加入DN42網路) 3. User mode linux (基於ptrace,聽說性能堪慮。因為他提供的API太全了,kernel bypass耗費太多性能。我只要bypass網路相關的就好) 4. LKL (重新編譯,覆寫掉網路相關system call,改走LKL的stack) 5. 其他,大家推薦下? 09/26/2021 Update 問題解決 問題解決了,不要用release分支,直接用最新的原始碼編譯就好了 由此確認,確實是VPP Host stack的問題 雖然偶爾會出現address boundary error ,至少BIRD session能建立了 下一篇: RootlessRouter(Part:5) 完結

蒐集的Userspace 網路棧

之前在 這篇 提到我蒐集到的Userspace network stack,想說獨立一篇出來好了。之後有查到新東西直接加進來 目前我找到的提供網路隔離的程式列表,以及他們kernel bypass所用的技術 基於LD_PRELOAD VPP (我用起來相容性不好。後來發現BIRD能用) NUSE (聽說bug很多) The shadow simulator (很新的專案,資料蠻少的) 基於ptrace gVisor UML(User Mode Linux) (就是linux的網路棧) The shadow simulator (好像兩個一起用,增加穩定度) 重新編譯原始碼 LKL(Linux Kernel Library) (C/C++版本,也是linux的網路棧) LKL.js (javascript版本的LKL,可以在瀏覽器上執行!) F-Stack 基於network namespace (只是用了linux的ns隔離,本質上還是跑在kernel) mininet 沒有kernel bypass功能,依賴tun/tap RARE/freertr ns3 什麼是kernel bypass? 和網路隔離有什麼關係? 一般情況,我們程式想要監聽port,多半會呼叫bind()這個系統呼叫。 想要連線,就會呼叫socket()這個系統呼叫。 如果呼叫成功,就會拿到一個file descriptor,是一個整數 之後呼叫Read/Write function時,傳入fd,OS就會把資料弄去buffer了 這一切,OS會在背後幫我們處理。從網路堆疊複製東西/tcp狀態機的維護之類 當我們想要隔離的網路,有很多技術。像是 network namespace : 我們呼叫linux kernel的socket()這個系統呼叫。但是kernel維護不只一個網路堆疊。kernel會根據你的namespace,決定要和哪個堆疊作互動 LD_PRELOAD 和 ptrace : 則是劫持現有程式內部的系統呼叫。 以VPP為例,VCL負責劫持程式的bind()/socket()系統呼叫,並且轉交給VPP。和VPP維護的網路堆疊作互動 這個列表是被VPP劫持了的系統呼叫: https://github.com/KusakabeSi/RootlessRouter/blob/main/mis

Rootless Router(Part: 3) EtherGuard

圖片
前篇:  Rootless Router (Part2): BIRD-vpp 前情提要: 總之BIRD確定了要用python糊以後,我就來決定來搞多節點互連了 Mesh VPN 我決定弄一個layer 2 的mesh VPN,用於我之後會架設的多個節點之間的互聯。 至於為什麼我要自己弄這個VPN呢?  首先,因為幾乎沒見到別的VPN軟體支援VPP VPP雖然有內建VPN,但是沒有一個支援udp打洞 我想要有一個VPN能夠用在VPP上,又能夠udp打洞,似乎只能些修改/重寫了 比較過幾個,最後還是決定以go語言為基礎 因為之前弄 wireguard-go-vpp 的時候,go語言下的libmemif環境都弄好了 如果要基於C++的改成memif後端,不知道環境又要搞多久 順帶一提,go語言的環境設計,真的太神了,不得不吹 不像C++有各種路徑要設定,ld_library_path,還有gcc加上LDFLAGS之類的設定 還有namespace的問題,C++的include真的就只是單純把那段code貼到#include的地方 這個設計,簡單是很簡單,但是各種變數汙染也是不好弄 go語言就方便多了。go get XXX,go mod vender,所有需要的檔案通通搬去vender子資料夾 mod之間也不會互相汙染,真是太神奇了! go語言萬歲! EtherGuard 花了半個月,我終於寫完了! 最後我決定把新弄得VPN取名叫做Etherguard。為什麼叫做Etherguard呢? 是因為code是從wireguard-go改來的,所以加密方法,header之類都和wireguard一樣,就取guard部分 又是二層VPN,layer 2又叫Ethernet。就取Etger的部分。組合再一起變成Etherguard 而且我想順便引入單向延遲選路的功能 OSPF能夠根據cost自動選路 但是實際上,我們偶爾會遇到去程/回程不對等的問題 之前我就在想,能不能根據單向延遲選路呢? 例如我有2條線路,一條去程快,一條回程快。就自動過去回來各自走快的? 而且市面上也完全沒有類似的VPN軟體能做到這點(或是我不知道) 因為這個我開始擔心了。因為 測量單向延遲是不可能的 。 難道要做出有上述效果(根據單向延遲選路)的VPN是不可能的? 單向延遲選路 於是我又在想了,有時鐘誤差下的單