齊戰(zhàn)勝 林立友
廈門市美亞柏科信息股份有限公司北京分公司 北京 100025
一個好的包捕獲系統(tǒng)應該盡可能少的丟包,實時捕獲流經(jīng)系統(tǒng)的所有數(shù)據(jù)包,而且應該較少地占用CPU資源,使得系統(tǒng)擁有更多的時間來對數(shù)據(jù)包內(nèi)容的進行處理。
在包捕獲硬件方面,當前市場上有很多千兆以太網(wǎng)報文處理網(wǎng)卡,如Endace 公司生產(chǎn)的DAG網(wǎng)卡、Liberouter及SCAMPI項目開發(fā)的COMBO網(wǎng)卡等。由于基于硬件的捕包方式價格比較昂貴,而且系統(tǒng)缺乏一定的靈活性,難以適應當今瞬息萬變的網(wǎng)絡發(fā)展現(xiàn)狀與具體的流量分析需求。
在包捕獲軟件方面,設計了很多優(yōu)秀的包捕獲函數(shù)庫如Libpcap、nCap、DMA-Ring和PF_RING等。Libpcap是一個優(yōu)秀的數(shù)據(jù)包捕獲函數(shù)庫,由網(wǎng)卡驅(qū)動、操作系統(tǒng)內(nèi)核協(xié)議棧以及套接字接口三個部分組成,由于消耗了較高的CPU資源、引入了較高的包傳輸延時等問題,效率較低。為了提高包捕獲的效率,很多研究人員已經(jīng)做了大量的工作,包括從操作系統(tǒng)和應用軟件兩個方面進行優(yōu)化。在操作系統(tǒng)方面:由于很多網(wǎng)絡應用都有實時性的要求,增加了一些實時的內(nèi)核來提高網(wǎng)絡的實時性;為了避免頻繁的中斷造成的中斷活鎖現(xiàn)象,Linux內(nèi)核中引入了一些新的 API函數(shù),簡稱NAPI(NewAPI),通過在重負載的情況下采用輪詢的方式來提高包捕獲系統(tǒng)的性能。在應用軟件方面:一種方式是減少內(nèi)存拷貝次數(shù),Libpcap-mmap、nCap、DMA-RING和PF_RING都采用了這種方式;第二種方式是減少系統(tǒng)調(diào)用的次數(shù)。
綜合分析以上包捕獲技術,發(fā)現(xiàn)以上沒有任何一種包捕獲接口的速度能達到千兆線速的處理目標,即使它們的設計目標是這樣;第二,都是基于單核的系統(tǒng)來進行設計,沒有考慮到發(fā)揮多核平臺和多收發(fā)隊列網(wǎng)卡的優(yōu)勢來增加系統(tǒng)的吞吐量。
本文在基于PCI-E總線的 Intel X86 多核平臺下,通過充分利用RPS和RFS的包分發(fā)技術、PF_RING的零拷貝技術和多核CPU的計算資源,解決了 Gbit 及其以上鏈路帶寬下的包捕獲問題。
多核處理器是指在一枚處理器中集成兩個或多個完整的計算引擎(內(nèi)核)。操作系統(tǒng)通過在多個執(zhí)行內(nèi)核之間劃分任務,多核處理器可在特定的時鐘周期內(nèi)執(zhí)行更多的任務。
多隊列網(wǎng)卡是一種技術,最初是用來解決網(wǎng)絡 IO QoS問題的,后來隨著網(wǎng)絡IO的帶寬的不斷提升,單核CPU不能完全處滿足網(wǎng)卡的需求,通過多隊列網(wǎng)卡驅(qū)動的支持,將各個隊列通過中斷綁定到不同的核上,以滿足網(wǎng)卡的需求。常見的有Intel的 82575、82576、82599、82580,Boardcom的57711等。
為了充分利用多核處理器的計算資源和多隊列網(wǎng)卡的吞吐能力,本文提出了以下包捕獲模型,如圖1所示。
圖1 包捕獲模型
此模型中采用的是Intel 82576多隊列網(wǎng)卡,模型工作流程如下:
(1) 數(shù)據(jù)包到達網(wǎng)卡后,產(chǎn)生硬中斷,網(wǎng)卡RSS根據(jù)數(shù)據(jù)包的IP和端口計算出hash值,hash值跟中斷個數(shù)取模后,分成若干個接收隊列。
(2) 為了保證分發(fā)到每個包處理線程的數(shù)據(jù)鏈的完整性(一個鏈接上的上行和下行數(shù)據(jù)都分發(fā)到一個包處理線程),所以這里需要利用RPS和RFS技術對數(shù)據(jù)包進行重新計算Hash值,然后取模分發(fā)到相應的CPU核心上。
(3) 改進后的PF_RING為每一個接收隊列創(chuàng)建一個虛擬的網(wǎng)絡接口,通過在內(nèi)核注冊的函數(shù)接收RFS分發(fā)下來的數(shù)據(jù)包,然后送到相應的虛擬網(wǎng)絡接口。
(4) 用戶空間的包處理線程通過PF_RING的虛擬網(wǎng)絡接口讀取數(shù)據(jù)包并處理。
多隊列數(shù)據(jù)包分發(fā)技術接收方擴展 (RSS,Receive Side Scaling)。目前的NICs支持多個接收和傳輸隊列,即多隊列。接收的時候,一個網(wǎng)卡能夠發(fā)送不同的包到不同的隊列,為了在不同的CPU之間分散處理。NIC針對每一個包,通過一個過濾器來指定這個包屬于少數(shù)幾個流中的一個流。每個流中的數(shù)據(jù)包被控制在一個單獨的接收隊列中,而隊列輪回的被CPU進行處理。這種機制就叫做RSS。RSS的目標和其他控制技術目的都是為了提高數(shù)據(jù)吞吐性能。
RSS中的過濾器是一個基于L3和L4層頭部的hash函數(shù)。例如,基于IP地址和TCP端口的4元組的hash函數(shù)。最常見的RSS硬件實現(xiàn)中,使用了128個間接表,其中每個表存儲一個隊列號(注,網(wǎng)卡的隊列數(shù)比較少,比如igb是8個,bnx2是5個)。針對某個包而言,使用這個包計算出的hash值(hash是Toeplitz算法)的低7位先確定間接表,再從間接表中的值訪問隊列。
多隊列網(wǎng)卡的驅(qū)動提供了一個內(nèi)核模塊參數(shù),用來指定硬件隊列個數(shù)。一個典型的RSS配置中,最好的是一個CPU對應一個接收隊列。每個接收隊列有一個單獨的IRQ,即中斷號。NIC通過IRQ來通知CPU什么時候新的數(shù)據(jù)包到達了指定的隊列。有效的隊列到IRQ的映射是由/proc/interrupts來指定的。一些系統(tǒng)會運行 irqbalance服務,這個服務會動態(tài)的優(yōu)化IRQ的親和性。
RPS(Receive Packet Steering) 邏輯上是一種以軟件的方式來實現(xiàn)RSS。在數(shù)據(jù)包被從網(wǎng)卡驅(qū)動傳向網(wǎng)絡協(xié)議棧時,RPS在底半環(huán)境(通過軟中斷來實現(xiàn)的,在硬中斷處理函數(shù)之后)中被調(diào)用。通過把數(shù)據(jù)包放在目標CPU的backlog隊列,并喚醒CPU來處理,之后隊列中數(shù)據(jù)包被發(fā)送到網(wǎng)絡協(xié)議棧進行處理。
RPS相比RSS有幾個好處:
(1) RPS能夠被任何NIC使用。
(2) 軟件過濾器能夠輕易的被添加,用來hash新的協(xié)議。
(3) 它不會增加硬件設備的中斷。
決定目標CPU的第一步是基于包的地址和端口(有的協(xié)議是2元組,有的協(xié)議是4元組)來計算hash值。這個值與這個包的流保持一致。這個hash值要么是由硬件來提供的,要么是由協(xié)議棧來計算的。每一個接收硬件隊列有一個相關的CPU列表,RPS可以將包放到這個隊列中進行處理。對于每一個接收到的包,指向這個列表的索引是通過流hash值對列表大小取模來計算的。被指向的 CPU是處理包的目標CPU,并且這個包被加到CPU的backlog隊列的尾部。經(jīng)過底半處理后,IPI被發(fā)送到這個包所插到的那個CPU。IPI喚醒遠程CPU來處理backlog隊列,之后隊列中數(shù)據(jù)包被發(fā)送到網(wǎng)絡協(xié)議棧進行處理。
RPS要求內(nèi)核編譯了CONFIG_RPS選項(SMP上默認是打開的)。盡管編譯到內(nèi)核,直到被配置了才能啟用。對于某個接收隊列,RPS可以轉(zhuǎn)發(fā)流量到哪個 CPU,是由/sys/class/net/queues/rx-/rps_cpus來控制的。這個文件實現(xiàn)了CPU的位圖。默認,當值是0,RPS是無效的,數(shù)據(jù)包是由中斷的CPU來處理的。
RFS(Receive Flow Steering),RPS只依靠hash來控制數(shù)據(jù)包,提供了好的負載平衡,但是它沒有考慮應用程序的位置(注:這個位置是指程序在哪個 cpu上執(zhí)行)。RFS則考慮到了應用程序的位置。RFS的目標是通過指派應用線程正在運行的CPU來進行數(shù)據(jù)包處理,以此來增加數(shù)據(jù)緩存的命中率。RFS依靠RPS的機制插入數(shù)據(jù)包到指定CPU的backlog隊列,并喚醒那個CPU來執(zhí)行。
RFS中,數(shù)據(jù)包并不會直接的通過數(shù)據(jù)包的hash值被轉(zhuǎn)發(fā),但是hash值將會作為流查詢表的索引。這個表映射數(shù)據(jù)流與處理這個流的CPU。這個數(shù)據(jù)流的hash值(就是這個流中的數(shù)據(jù)包的 hash值)將被用來計算這個表的索引。流查詢表的每條記錄中所記錄的CPU是上次處理數(shù)據(jù)流的CPU。如果記錄中沒有CPU,那么數(shù)據(jù)包將會使用RPS來處理。多個記錄會指向相同的CPU。確實,當流很多而CPU很少時,很有可能一個應用線程處理多個不同hash值的數(shù)據(jù)流。
RFS需要內(nèi)核編譯 CONFIG_RPS選項,直到明顯的配置,RFS才起作用。全局數(shù)據(jù)流表(rps_sock_flow_table)的總數(shù)可以通過下面的參數(shù)來設置:/proc/sys/net/core/rps_sock_flow_entries每個隊列的數(shù)據(jù)流表總數(shù)可以通過下面的參數(shù)來設置:/sys/class/net//queues/rx-/rps_flow_cnt。
通過調(diào)用 SetThreadAffinityMask,就能為各個線程設置親緣性屏蔽:
該函數(shù)中的 hThread參數(shù)用于指明要限制哪個線程,dwThreadAffinityMask用于指明該線程能夠在哪個CPU上運行。dwThreadAffinityMask必須是進程的親緣性屏蔽的相應子集。返回值是線程的前一個親緣性屏蔽。
例如,可能有一個包含4個線程的進程,它們在擁有4個CPU的計算機上運行。如果這些線程中的一個線程正在執(zhí)行非常重要的操作,而你想增加某個CPU始終可供它使用的可能性,為此你對其他3個線程進行了限制,使它們不能在CPU 0上運行,而只能在CPU 1、2和3上運行。因此,若要將3個線程限制到CPU 1、2和3上去運行,可以這樣操作:
2.5.1 PF_RING技術簡介
PF_RING是Luca研究出來的基于Linux內(nèi)核級的高效數(shù)據(jù)包捕獲技術。PF_RING基本原理是將網(wǎng)卡接收的數(shù)據(jù)包存儲在一個環(huán)狀緩存,這也是為什么叫RING的原因,這個環(huán)狀緩存有兩個接口,一個供網(wǎng)卡向其中寫數(shù)據(jù)包,另一個為應用層程序提供讀取數(shù)據(jù)包的接口,讀取數(shù)據(jù)包的接口通過 mmap函數(shù)(將一個文件或其它對象映射進內(nèi)存)實現(xiàn)的。圖2顯示了PF_RING的工作原理。
圖2 PF_RING
2.5.2 PF_RING技術優(yōu)化
由于 PF_RING需要定制的網(wǎng)卡驅(qū)動的支持,并且PF_RING的虛擬網(wǎng)絡接口目前僅支持 DNA(Direct NIC Access)模式,所以為了適應本模型的需要,本文做了以下優(yōu)化:
(1) 修改PF_RING定制的網(wǎng)卡驅(qū)動,開啟網(wǎng)卡多接收隊列的功能;
(2) 把PF_RING的DNA模塊的虛擬網(wǎng)絡接口功能移植到NAPI模式下。
圖3顯示了測試環(huán)境的部署情況。
圖3 測試環(huán)境
測試服務器,i3 CPU 2.93GHZ,4G內(nèi)存,2塊Intel 82576千兆網(wǎng)卡,Red Hat Enterprise 6.0系統(tǒng)(內(nèi)核已升級為2.6.39),
網(wǎng)絡流量發(fā)生儀,基于 Intel IXP2400 的網(wǎng)絡處理器,用于產(chǎn)生測試的流量。
控制端是普通的PC機,用來控制流量的組織、發(fā)送和控制。
3.2.1 捕包性能測試與分析
控制端控制流量發(fā)生儀發(fā)送 1000Mbit,長度分別為128、512 和 1024 字節(jié)的數(shù)據(jù)包,在被測試主機上分別采用 Libpcap,PF_RING和本文捕包模型接收測試流量。圖4顯示了當丟包數(shù)為零時各個包捕獲方式可以接收的最大流速率。
圖4 吞吐率對比測試圖
分析圖4的結(jié)果可以得出:在 1024 字節(jié)、512字節(jié)和128字節(jié),1000Mbit 的鏈路環(huán)境下,Multi-PF_RING和PF_RING 接收速率沒有什么區(qū)別。
3.2.2 CPU使用率測試與分析
CPU 空閑率是衡量包捕獲接口的重要指標,空閑率高的CPU 可以有更多的時間用來做與應用更加相關的工作,控制端控制流量發(fā)生儀發(fā)送 100Mbit 至 1000Mbit,字節(jié)長度為512字節(jié)的鏈路流量。
圖5 CPU使用率對比圖
分析圖 5結(jié)果可以得出:同等接收速率下,Multi-PF_RING的CPU使用率最低。即使在1000Mbit/s時,CPU仍然有 70%左右的空閑率,可以讓 CPU有足夠的計算資源對數(shù)據(jù)包進行處理。
控制端控制流量發(fā)生儀發(fā)送 IP 包頭地址輪轉(zhuǎn)變化的IP 包,在測試服務器端觀察 Multi-PF_RING接收數(shù)據(jù)包的情況,發(fā)現(xiàn)測試服務器接收的 IP 包與流量發(fā)生儀發(fā)送的 IP包內(nèi)容一致,驗證了程序的正確性;每個核心收到的鏈路數(shù)據(jù)是完整的,驗證了程序?qū)?shù)據(jù)包的分發(fā)是符合應用邏輯的。
本文首先提出了一種基于多核架構和多收發(fā)隊列的包捕獲模型,然后對包捕獲模型中涉及的核心技術進行了詳細介紹和分析,并結(jié)合本模型捕包的需要對 PF_RING的接口進行了優(yōu)化。實驗結(jié)果表明,本文設計的 Multi-PF_RING 模型在保持高吞吐量的同時,具有更低的CPU使用率,給CPU留出了足夠的資源進行數(shù)據(jù)包的處理,并且保證了同一鏈接的數(shù)據(jù)始終被分發(fā)到一個CPU核心上。本文的不足之處是沒有考慮負載均衡的情況,當鏈接數(shù)目較少或者同一鏈接數(shù)據(jù)超多的情況下,會造成個別CPU核心超負荷運轉(zhuǎn)而其它核心閑置的情況,后期會進一步研究負載均衡的問題。
[1]張顯,黎文偉.基于多核平臺的數(shù)據(jù)包捕獲方法性能評估[J].計算機應用研究.2011.
[2]孫江.基于多核處理器的普適性報文捕獲技術研究[D].解放軍信息工程大學.2011.
[3]笱程成.基于多核架構的高速 IP包捕獲技術研究[D].解放軍信息工程大學.2010.
[4]http://www.ntop.org/products/pf_ring.
http://code.google.com/p/kernel/wiki/NetScalingGuide.