1. 程式人生 > >如何旁路內核協議棧

如何旁路內核協議棧

-c const .html word 我們 mmap 完整 sym 瓶頸

如何旁路內核協議棧

時間 2017-01-15 原文 http://blog.csdn.net/liukun321/article/details/54564798

此文轉自:http://blog.csdn.net/wwh578867817/article/details/50139819

在前兩篇文章中,我們討論了如何每秒接收 1M UDP 數據包 以及 如何減少往返時間 。我們在 Linux 上做試驗,因為它是一個性能非常好的通用操作系統。

不幸的是,對於一些更加專業的工作,Vanilla Linux(譯者註:Linux 的內核版本,代號“香草”) 內核的網絡速度是不夠的。舉個例子,在 CloudFlare,我們持續地處理洪水般的數據包。 Vanilla Linux 處理速度僅能達到約 1M pps (譯者註:單位 packet per seconds),這在我們的工作環境下是不夠的,特別是網卡有能力處理大量的數據包。現代 10Gbps 網卡的處理能力通常至少達到 10M pps 。

技術分享圖片

內核不給力

我們做一個小實驗來說明修改 Linux 確實是有必要的。我們看看理想狀態下內核能處理多少數據包。把數據包傳遞到用戶空間的代價是高昂的,讓我們嘗試一下在網絡驅動程序收到數據包後就立刻丟棄它們。據我所知,Linux 上不修改內核丟棄數據包最快的方法是在 PREROUTING iptables 上設置一些丟棄規則。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
$ sudo iptables -t raw -I PREROUTING -p udp --dport 4321 --dst 192.168.254.1 -j DROP $ sudo ethtool -X eth2 weight 1 $ watch ‘ethtool -S eth2|grep rx‘ rx_packets: 12.2m/s rx-0.rx_packets: 1.4m/s rx-1.rx_packets: 0/s ...

如上所示, Ethtool(譯者註:Ethtool 是 Linux 下用於查詢及設置網卡參數的命令)的統計顯示,網卡能達到每秒接收 12M 數據包的速度。通過 ethtool -X 來操作網卡上的間接表,可以將所有的數據包引向 0 號 RX 隊列。正如我們看到的,在一顆 CPU 上,內核處理隊列的速度可以達到 1.4M pps。

在單核上能達到 1.4M pps 是一個相當不錯的結果,但不幸的是協議棧卻不能擴展。當數據包被分配到多核上,這個成績會急劇下降。讓我們看看把數據包分到 4 個 RX 隊列的結果。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
$ sudo ethtool -X eth2 weight 1 1 1 1 $ watch ‘ethtool -S eth2|grep rx‘ rx_packets: 12.1m/s rx-0.rx_packets: 477.8k/s rx-1.rx_packets: 447.5k/s rx-2.rx_packets: 482.6k/s rx-3.rx_packets: 455.9k/s

此時每個核的處理速度是 480k pps。這是個糟糕的消息。即使樂觀地假設增加多個核心不會進一步地造成性能的下降,處理數據包的核心也要多達 20 個才能達到線速度。所以內核是不起作用的。

內核旁路前來救駕

技術分享圖片

關於 Linux 內核網絡性能的局限早已不是什麽新鮮事了。在過去的幾年中,人們多次嘗試解決這個問題。最常用的技術包括創建特別的 API,來幫助高速環境下的硬件去接收數據包。不幸的是,這些技術總是在變動,至今沒有出現一個被廣泛采用的技術。

這裏列出一些廣為人知的內核旁路技術。

PACKET_MMAP

Packet mmap 是 Linux 上的API,用來實現數據包快速嗅探。然而它不是嚴格意義上的內核旁路技術,它是技術列表中的一個特例 —— 可以在 Vanilla 內核上使用。

PF_RING

PF_RING 是另一個已知的技術,用來提升捕獲數據包的速度。不像 packet_mmap,PF_RING 不在內核主線中,需要一些特殊模塊。通過 ZC 驅動和把模式設置成 transparent_mode = 2(譯者註:是 PF_RING 的一種模式),只把數據包傳遞給 PF_RING 客戶端,而不會經過內核網絡協議棧。由於內核比較緩慢,這樣可以確保高速運轉。

Snabbswitch

Snabbswitch 是一個 Lua 網絡框架,主要用來寫 L2 應用。它可以完全接管一個網卡,並且在用戶空間實現硬件驅動。它在一個 PCI 設備上實現了用戶空間 IO(UIO),把設備寄存器映射到 sysfs 上(譯者註:sysfs 是 Linux 內核中設計較新的一種虛擬的基於內存的文件系統) 。這樣就可以非常快地操作,但是這意味著數據包完全跳過了內核網絡協議棧。

DPDK

DPDK 是一個用 C 語言實現的網絡框架,專門為 Intel 芯片創建。它本質上和 snabbswitch 類似,因為它也是一個基於UIO 的完整框架。

Netmap

Netmap 也是一個豐富的網絡框架,但是和 UIO 技術不同,它是由幾個內核模塊來實現的。為了和網絡硬件集成在一起,用戶需要給內核網絡驅動打補丁。增加復雜性的最大好處是有一個詳細文檔說明的、設備廠商無關的和清晰的 API。

由於內核旁路技術的目的是不再讓內核處理數據包,所以我們排除了 packet_mmap。因為它不能接收數據包 —— 它只是一個嗅探數據包的快速接口。同樣,沒有 ZC 模塊的 PF_RING 也沒有什麽吸引力,因為它的主要目標是加速 libpcap(譯者註:libpcap是unix/linux平臺下的網絡數據包捕獲函數包,大多數網絡監控軟件都以它為基礎)。

我們已經排除了兩種技術,但很不幸的是,在余下的解決方案中,也沒有我們能夠使用的!

讓我告訴你原因。為了用 剩下的技術 實現內核旁路技術:Snabbswitch、DPDK 和 netmap 會接管整個網卡,不允許網卡的任何流量經過內核。我們在 CloudFlare,根本不可能讓一個分擔負載的應用程序獨占整個網卡。

話說回來,很多人使用上面的技術。在其他環境中占用一個網卡,來實現旁路也許是可以接受的。

Solarflare 上的 EF_VI

雖然上面列出的技術需要占用整個網卡,但還有其它的選擇。

技術分享圖片

Solarflare 網卡支持 OpenOnload,一個神奇的網卡加速器。它通過如下方式來實現內核旁路,在用戶空間實現網絡協議棧,並使用 LD_PRELOAD 覆蓋目標程序的網絡系統調用。在底層訪問網卡時依靠 “EF_VI” 庫。這個庫可以直接使用並且有很好的說明文檔。

EF_VI 作為一個專用庫,僅能用在 Solarflare 網卡上,你可能想知道它實際是如何工作的。 EF_VI 是以一種非常聰明的方式重新使用網卡的通用功能。

在底層,每個 EF_VI 程序可以訪問一條特定的 RX 隊列,這條 RX 隊列對內核不可見的。默認情況下,這個隊列不接收數據,直到你創建了一個 EF_VI “過濾器”。這個過濾器只是一個隱藏的流控制規則。你用 ethtool -n 也看不到,但實際上這個規則已經存在網卡中了。對於 EF_VI 來說,除了分配 RX 隊列並且管理流控制規則,剩下的任務就是提供一個API 讓用戶空間可以訪問這個隊列。

分叉驅動

技術分享圖片

雖然 EF_VI 是 Solarflare 所特有的,其他網卡還是可以復制這個技術。首先我們需要一個支持多隊列的網卡,同時它還支持流控制和操作間接表。

有了這些功能,我們可以:

  • 正常啟動網卡,讓內核來管理一切。

  • 修改間接表以確保沒有數據包流向任一 RX 隊列。比如說我們選擇

  • 16 號 RX 隊列。

  • 通過流控制規則將一個特定的網絡流引到 16號 RX 隊列。

完成這些,剩下的步驟就是提供一個用戶空間的 API ,從 16 號 RX 隊列上接收數據包,並且不會影響其他任何隊列。

這個想法在 DPDK 社區被稱為“分叉驅動”。它們打算在 2014 年創建分叉驅動,不幸的是 這個補丁 還沒進入內核的主線。

虛擬化方法

針對 intel 82599 還有另外一種選擇。我們可以利用網卡上的虛擬化功能來實現內核旁路,而不需要通過分叉驅動程序。

首先我簡單說下背景。有結果證明,在虛擬化世界中將數據包從主機傳遞到客戶機,虛擬機通常是瓶頸。因此,這些年對虛擬化性能的需求與日俱增,通過軟件模擬網絡硬件的仿真技術成為了影響性能的主要障礙。

網卡廠商增加一些特性來加速虛擬客戶端。其中一項虛擬化技術,要求網卡虛擬成多個 PCI 設備。虛擬客戶端可以操作這些虛擬接口,無需與主機操作系統進行任何合作。我演示一下它是如何工作的。舉個例子,這是我本機上的 82599 網卡。這個“真實的”設備被稱為 PF(物理功能)接口:

  • 1
  • 2
  • 1
  • 2
$ lspci 04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)

我們要求這個設備創建一個 VF(虛擬功能)設備:

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
$ echo 1 > /sys/class/net/eth3/device/sriov_numvfs $ lspci 04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01) 04:10.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)

比如說一個 KVM 客戶端很容易使用這個假的 PCI 設備。同時,我們還是能夠使用主機環境。要做到這些僅需要加載 “ixgbevf” 內核模塊,之後會出現另一個 “ethX” 接口。

你或許想知道內核旁路技術幹了什麽。內核沒有利用“ixgbevf”設備正常聯網,我們可以把它專門用在內核旁路上。這樣看起來可以在 “ixgbevf” 設備運行 DPDK。

概括來說:這個想法可以讓 PF 設備正常處理內核工作,而 VF 接口專門用在內核旁路技術上。由於 VF 是專用的,所以我們可以運行“接管整個網卡”的技術。

這聽起來似乎不錯,實際上卻沒那麽簡單。首先,只有 DPDK 支持“ixgbevf”設備,netmap,snabbswtich 和 PF_RING 是不支持的。默認情況下, VF 接口不能接收任何數據包。若通過 PF 發送數據給 VF ,你需要給 ixgbe 打上這個補丁。有了它,你可以對 VF 進行尋址,即在ethtool中對“活動”“隊列號的高位進行編碼。

  • 1
  • 1
$ ethtool -N eth3 flow-type tcp4 dst-ip 192.168.254.30 dst-port 80 action 4294967296

最後一個障礙出現了,在 82599 芯片上啟用 VF 功能,RSS 組的最大規模變小了(譯者註:Really Simple Syndication,簡易信息聚合)。沒有虛擬化時,82599 可以在 16 個 CPU 核上進行 RSS 。但隨著 VF 的啟用,這個數量卻變成了 4。如果 PF 上的流量比較低,只使用 4 個核來發布可能還好。不幸的是,我們在 Cloudflare 需要處理大規模的 RSS 組。

結束語

完成內核旁路技術沒有那麽簡單。雖然存在很多開源的技術,但它們看起來都需要一塊專用的的網卡。這裏我們展示了 3 個可以選擇的框架:

  • 類似 EF_VI, 隱藏 RX 隊列
  • DPDK 分叉驅動
  • VF 技術

不幸的是,在我們的環境下,這麽多技術中能起作用的似乎只有 EF_VI。我們祈禱開源的內核旁路 API 趕緊出現,唯一的要求是不需要一塊專用的網卡。

相關文章
  • 1. 如何實現內核旁路(Kernel bypass)?
  • 2. linux內核協議棧
  • 3. linux 內核協議棧
  • 4. tcp/ip協議棧 -- linux內核
  • 5. linux 內核網絡協議棧
  • 6. Android5.0——Linux內核存儲協議棧圖
  • 7. Linux內核網絡協議棧筆記
  • 8. 內核tcp協議棧SACK的處理
  • 9. Linux內核網絡協議棧
  • 10. linux網絡協議棧內核分析
  • 更多相關文章...
相關標簽/搜索 內核協議棧
內核協議
linux內核協議棧
內置協議棧
zigbee協議棧
lwip協議棧
PPP協議棧
zstack協議棧
協議棧
ip 協議棧
內核協議棧內核協議棧
內核協議棧
linux內核協議棧
linux內核協議棧
linux內核協議
協議棧
UIP協議棧
SIP協議棧
BLE協議棧
內置協議棧cc2530協議棧
cc2650SDK協議棧
mqtt協議棧
MQTT協議棧
lorawan協議棧
cc2541 協議棧
mqtt 協議棧
如何理解BLE協議棧內置協議棧 外置協議棧 區別

如何旁路內核協議棧