高速網路下的 Netmap 單 RX 佇列核心旁路技術

夏了夏天發表於2016-12-29

在前一篇《如何實現核心旁路(Kernel bypass)?》 中,我們討論了 Linux 核心網路協議棧的效能瓶頸。我們詳細說明了如何利用核心旁路(kenerl bypass)技術,讓使用者空間程式可以接收大量的資料包。遺憾的是,沒有開源解決方案討論過這個問題,來滿足我們的需求。為了改善現狀,我們決定為 Netmap 專案 做點貢獻。在本篇文章中將描述我們提出的改動。

Binary Koala 拍攝,CC BY-SA 2.0 

我們的需求

在 CloudFlare,我們經常處理洶湧的資料流量。我們的網路經常會接收到很多的資料包,它們總是來自大量的同步攻擊。事實上此刻僅是這篇文章所在的伺服器,都完全有可能每秒鐘處理數百萬的資料包。

因為 Linux 核心實際上不能真正處理大量的資料包,我們需要想辦法解決這個問題。在洪水攻擊期間,我們將選定的網路流量解除安裝到使用者空間程式。這個應用程式以非常高的速度過濾資料包。大部分資料包被丟棄了,因為它們屬於洪水攻擊。少量“有效”的資料包被重新返回核心並且以正常流量的方式處理。

需要重點強調的是核心旁路技術只針對選定的流,這意味著所有其它的資料包都像往常一樣經過核心。

這個工作完美地建立在基於 Solarflare 網路卡的伺服器上 —— 我們可以使用 ef_vi API 來實現核心旁路技術。不幸的是,我們沒有在基於Intel IXGBE 網路卡的伺服器上實現這個功能。

直到 Netmap 出現。

Netmap

過去的幾個月裡,我們一直認真地思考如何在非 Solarflare 網路卡上旁路選定的資料流(又叫做:分叉驅動)。

我們考慮過 PF_RING,DPDK 和其他一些定製的解決方案,但不幸的是所有這些方案都應用在整個網路卡上(譯者注:即不能在選定的資料流上操作),最後我們決定最好的方式就是根據我們需要的功能給 Netmap 打補丁。

我們選擇 Netmap 是因為:
  • 它完全開源並且基於 BSD 許可釋出。
  • 它可以很好得支援網路卡無關 API。
  • 它非常快:很容易滿足線路速率的要求。
  • 這個專案維護得很好並且相當成熟。
  • 程式碼的質量非常高。
  • 對特定驅動的修改很小:大多數神奇的事都發生在共享的 Netmap 模組,很容易對新增的新硬體提供支援。

單 RX 佇列模組介紹

通常當一個網路卡進入 Netmap 模式,所有的 RX 佇列都會從核心中分離出來並用於 Netmap 的應用程式。

我們不希望這樣。我們想讓大部分 RX 佇列留在核心模式中,僅僅在選定的 RX 佇列上採用 Netmap 模式,我們把這個功能稱為:“單 RX 佇列模式”。

其目的是暴露一個簡單的 API,它可以:
  • 在“單 RX 佇列模式”下開啟一個網路介面。
  • 這將允許 Netmap 應用從特定的 RX 佇列上接收資料包。
  • 其他所有佇列都被繫結在主機網路協議棧上。
  • 按需新增或刪除“單 RX 佇列模式”下的 RX 佇列。
  • 最後從 Netmap 模式上移除這個介面,並將 RX 佇列重新繫結到主機協議棧上。

這個 Netmap 的補丁正在等待程式碼審查,可以在這裡找到它:

一個從 eth3 的 RX 4 號佇列上接收資料包的小程式看起來像這樣:

這段程式碼非常接近 Netmap 的示例程式。事實上唯一區別在於 nm_open() 呼叫,它使用了新的語法,netmap:ifname~queue_number。

再次,當執行這段程式碼時只要資料包到達 4 號 RX 佇列就會進入 netmap 程式,所有其他的 RX 和 TX 佇列將被 Linux 核心網路協議棧處理。

你可以在這裡找到更多完整的例子:

獨立一個佇列

由於 RSS(譯者注:Receive Side Scaling,由微軟提出,通過這項技術能夠將網路流量分散到多個 cpu 上,降低單個 cpu 的佔用率) 的存在,多佇列網路卡上的一個資料包可以出現在任意一個 RX 佇列上。這是為什麼開啟單 RX 模式時,必須確保只有選定的流才可以進入 Netmap 佇列。

這些是必須做的:

  • 修改間接表以確保沒有 RSS 雜湊的資料包到達這裡。
  • 使用流控制技術專門引導資料流到達獨立的佇列中。
  • 用 RFS(譯者注:Receive Flow Steering,接收流控制)方法解決  —— 確保即將執行 Netmap 的 CPU 上沒有其他程式執行。

舉個例子:

這裡我們設定間接表以阻止前往 4 號 RX 佇列的流量,接著我們使用流控制技術,將所有目的埠是 53 的 UDP 流量引導向 4 號佇列。

嘗試一下

以下是如何在 IXGBE 網路卡上執行這項技術。首先獲取原始碼:

載入 Netmap 補丁模組並設定介面:

現在我們開始以 6 M UDP 資料包來填充這個介面,htop 命令顯示伺服器此刻完全忙於處理大量的資料包:

為了應對大流量,我們啟動 Netmap。首先我們需要編輯間接表,挑選出 4 號 RX 佇列:

這導致所有的資料包都去往 4 號 RX 佇列。

在 Netmap 設定介面前,必須關閉硬體解除安裝的功能:

最後我們啟動 netmap 解除安裝功能:

正如你看到的,基於單 RX 佇列的 netmap 程式大約收到 5.8M 資料包。

為了完整性,這有一個僅執行在單核下的 netmap 的 htop 展示:

感謝

我要感謝 Pavel Odintsov,是他提出了使用 Netmap 這種方式的可能性。他還做了初步的修改,使得我們在基礎上進行開發。

我也要感謝 Luigi Rizzo,為他對 Netmap 所做的工作和對我們補丁提出很棒的意見。

結束語

在 CloudFalre ,我們應用程式協議棧是以開源軟體為基礎的。我們對開源工作者所做出的卓越工作表示感激,無論何時我們會盡力回報社群 —— 我們希望 “單 RX 佇列 Netmap 模式”對其他人能有所幫助。

你可以在 這裡 找到更多關於 CloudFlare 的開原始碼。

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

高速網路下的 Netmap 單 RX 佇列核心旁路技術 高速網路下的 Netmap 單 RX 佇列核心旁路技術

相關文章