前言
在網絡安全領域中數(shù)據(jù)包捕獲技術的應用十分廣 泛,在當前高速網絡環(huán)境中系羞,如何實時柒竞、高效政供、完整、快速捕獲數(shù)據(jù)包是能否準確分析網絡數(shù)據(jù)的基礎和網絡安全防護系統(tǒng)的關鍵技術能犯。目前已經有從硬件/軟件/軟硬結合多種解決方案被不斷的提出鲫骗,用于提升數(shù)據(jù)包轉發(fā)與捕獲的性能。
本文主要目的從原理上分析比較目前主流的數(shù)據(jù)包捕獲技術踩晶。寫作思路:
- 介紹傳統(tǒng)數(shù)據(jù)包捕獲技術-->分析其原理-->指出其存在的問題
- 針對傳統(tǒng)數(shù)據(jù)包捕獲技術存在的問題給出解決方法-->介紹幾種改善的數(shù)據(jù)包捕獲技術
傳統(tǒng)Linux數(shù)據(jù)包捕獲技術流程和性能分析
傳統(tǒng)Linux數(shù)據(jù)包捕獲技術流程
傳統(tǒng)的數(shù)據(jù)包捕獲技術(典型的libpcap)是利用linux協(xié)議棧在數(shù)據(jù)鏈路層增加一個旁路處理执泰,不干擾系統(tǒng)自身的網路協(xié)議棧的處理,對發(fā)送和接收的數(shù)據(jù)包通過Linux內核做過濾和緩沖處理渡蜻,最后直接傳遞給上層應用程序术吝。
流程:
數(shù)據(jù)包到達網卡設備计济。網卡設備(NIC)依據(jù)配置進行DMA操作。( 「第1次拷貝」 :網卡寄存器->內核為網卡分配的緩沖區(qū)ring buffer)
第一次cpy完成后排苍,網卡發(fā)送中斷沦寂,喚醒處理器。網卡驅動程序通過 NAPI機制 從ring buffer中讀取淘衙,填充內核skbuff結構( 「第2次拷貝」 :內核網卡緩沖區(qū)ring buffer->內核專用數(shù)據(jù)結構skbuff)
網卡驅動觸發(fā)軟中斷調用netif_receive_skb來處理數(shù)據(jù)包:
3.1 遍歷嗅探器ptype_all传藏,如果有注冊抓包程序,由網絡分接口進入BPF過濾器彤守,將規(guī)則匹配的報文拷貝到系統(tǒng)內核緩存 ( 「第3次拷貝」 )毯侦。BPF為每一個要求服務的抓包程序關聯(lián)一個filter和兩個buffer。BPF分配buffer 且通常情況下它的額度是4KB the store buffer 被使用來接收來自適配器的數(shù)據(jù)具垫;the hold buffer被使用來拷貝包到應用程序侈离。
3.2 調用handle_bridge處理網橋。
3.3 調用handle_macvlan處理vlan筝蚕。
3.4 根據(jù)skb->protocol字段確定上層協(xié)議并提交給網絡層處理卦碾,進入網絡協(xié)議棧,進行高層處理起宽。libpcap繞過了Linux內核收包流程中協(xié)議棧部分的處理洲胖,使得用戶空間API可以直接調用套接字PF_PACKET從鏈路層驅動程序中獲得數(shù)據(jù)報文的拷貝,將其從內核緩沖區(qū)拷貝至用戶空間緩沖區(qū)( 「第4次拷貝」 )
傳統(tǒng)Linux數(shù)據(jù)包捕獲技術性能分析
研究者們發(fā)現(xiàn)燎含,Linux內核協(xié)議棧在數(shù)據(jù)包的收發(fā)過程中宾濒,內存拷貝操作的時間開銷占了整個處理過程時間開銷的65%腿短,此外層間傳遞的系統(tǒng)調用時間也占據(jù)了8%~10%屏箍。
協(xié)議棧的主要問題:
針對單個數(shù)據(jù)包級別的頻繁的資源分配和釋放。
每當一個數(shù)據(jù)包到達網卡橘忱,系統(tǒng)就會分配一個分組描述符用于存儲數(shù)據(jù)包的信息和頭部赴魁,直到分組傳送到用戶態(tài)空間,其描述符才被釋放钝诚。此外颖御,sk_buff龐大的數(shù)據(jù)結構中的大部分信息對于大多數(shù)網絡任務而言都是無用的。分配和釋放描述符的過程在高達 14.88Mpps 環(huán)境下是一個顯著的時間上的開銷凝颇。此外潘拱,sk_buff龐大的數(shù)據(jù)結構中的大部分信息對于大多數(shù)網絡 任務而言都 是無用的。每個分組的sk_buff的分配消耗近1200個CPU 周期拧略,而釋放需要1100個周期芦岂。事實上,對于一個大小為64B的分組垫蛆,sk_buff相關操作消耗了整個接收處理的 CPU 利用率的63%禽最。-
流量的串行訪問腺怯。
現(xiàn)代網卡包括多個硬件的接收端擴展(receiver-side scaling, RSS)隊列可以將分組按照五元組散列函數(shù)分配到不同的接收隊列。使用這種技術川无,分組的捕獲過程可以被并行化呛占,因為每個RSS隊列可以映射到一個特定的CPU核,并且可以對應相應的NAPI線程懦趋。這樣整個捕獲過程就可以做到并行化晾虑。
但是問題出現(xiàn)在之上的層次,Linux中的協(xié)議棧在網絡層和傳輸層需要分析合并的所有數(shù)據(jù)包:
①所有流量在一個單一模塊中被處理仅叫,產生性能瓶頸走贪;
②用戶進程不能夠從一個單一的RSS隊列接收消息。
這就造成了上層應用無法利用現(xiàn)代硬件的并行化處理能力惑芭,這種在用戶態(tài)分配流量先后序列的過程降低了系統(tǒng)的性能坠狡,丟失了驅動層面所獲得的加速。此外遂跟,從不同隊列合并的流量可能會產生額外的亂序分組逃沿。
從驅動到用戶態(tài)的數(shù)據(jù)拷貝。
從網卡收到數(shù)據(jù)包到應用取走數(shù)據(jù)的一次 DMA 過程中幻锁,存在至少2次數(shù)據(jù)包的復制:從驅動中 DMA 的訪問內存到內核的數(shù)據(jù)包緩存凯亮,以及從內核數(shù)據(jù)包緩存到應用程序。一次復制操作的消耗取決于數(shù)據(jù)包長度哄尔,一般為500~2〖傧000個 CPU 周期之間。上述過程中更糟糕的是岭接,當數(shù)據(jù)包很小時富拗,逐包復制的效率更加低下,這是由于每個操作恒定的開銷引起的鸣戴。內核到用戶空間的上下文切換啃沪。
從應用程序的視角來看,它需要執(zhí)行系統(tǒng)調用來接收每個分組.每個系統(tǒng)調用包含一次從用戶態(tài)到內核態(tài)的上下文切換窄锅,隨之而來的是大量的CPU時間消耗创千。在每個數(shù)據(jù)包上執(zhí)行系統(tǒng)調用時產生的上下文切換可能消耗近1 000個CPU周期。跨內存訪問入偷。
例如追驴,當接收一個64 B分組時,cache未命中造成了額外13.8%的CPU周期的消耗疏之。另外殿雪,在一個基于NUMA的系統(tǒng)中,內存訪問的時間取決于訪問的存儲節(jié)點体捏。因此冠摄,cache未命中在跨內存塊訪問環(huán)境下會產生更大的內存訪問延遲糯崎,從而導致性能下降。
提高捕獲效率的技術
目前高性能報文捕獲引擎中常用的提高捕獲效率的技術
- 預分配和重用內存資源河泳。
開始分組接收之前沃呢,預先分配好將要到達的數(shù)據(jù)包所需的內存空間用來存儲數(shù)據(jù)和元數(shù)據(jù)(分組描述符)。尤其在加載網卡驅動程序時就分配好 N 個描述符隊列(每個硬件隊列和設備一個)拆挥。
同樣薄霜,當一個數(shù)據(jù)包被傳送到用戶空間,其對應的描述符也不會被釋放纸兔,而是重新用于存儲新到達的分組.得益于這一策略惰瓜,在每個數(shù)據(jù)包分配/釋放所產生的性能瓶頸得到了消除.此外,也可以通過簡化sk_buff的數(shù)據(jù)結構來減少內存開銷汉矿。 - 數(shù)據(jù)包采用并行直接通道傳遞崎坊。
為了解決序列化的訪問流量,需要建立從RSS隊列到應用之間的直接并行數(shù)據(jù)通道洲拇。這種技術通過特定的RSS隊列奈揍、特定的CPU核和應用三者的綁定來實現(xiàn)性能的提升。Intel XL710 NIC 可以選用對稱哈希赋续,保證同一條流的往返數(shù)據(jù)包被分配到相同的CPU核上時男翰,避免造成低效的跨核訪問。 - 內存映射纽乱。
使用這種方法蛾绎,應用程序的內存區(qū)域可以映射到內核態(tài)的內存區(qū)域,應用能夠在沒有中間副本的情況下讀寫這片內存區(qū)域鸦列。用這種方式我們可以使應用直接訪問網卡的DMA內存區(qū)域租冠,這種技術被稱為零拷貝.但零拷貝也存在潛在的安全問題,向應用暴露出網卡環(huán)形隊列和寄存器會影響系統(tǒng)的安全性和穩(wěn)定性 敛熬。 - 數(shù)據(jù)包的批處理肺稀。
為了避免對每個數(shù)據(jù)包的重復操作的開銷第股,可以使用對數(shù)據(jù)包的批量處理应民。這個策略將數(shù)據(jù)包劃分為組,按組分配緩沖區(qū)夕吻,將它們一起復制到內核/用戶內存.運用這種技術減少了系統(tǒng)調用以及隨之而來的上下文切換的次數(shù);同時也減少了拷貝的次數(shù)诲锹,從而減少了平攤到處理和復制每個數(shù)據(jù)包的開銷。但由于分組必須等到一個批次已滿或定時器期滿才會遞交給上層涉馅,批處理技術的主要問題是延遲抖動以及接收報文時間戳誤差的增加归园。 - 親和性與預取。
由于程序運行的局部性原理稚矿,為進程分配的內存必須與正在執(zhí)行它的處理器操作的內存塊一致庸诱,這種技術被稱為內存的親和性捻浦。CPU親和性是一種技術,它允許進程或線程在指定的處理器核心上運行桥爽。在內核與驅動層面朱灿,軟件和硬件中斷可以用同樣的方法指定具體的CPU核或處理器來處理,稱為中斷親和力钠四。每當一個線程希望訪問所接收的數(shù)據(jù)盗扒,如果先前這些數(shù)據(jù)已被分配到相同CPU核的中斷處理程序接收,則它們在本地cache能夠更容易被訪問到缀去。
目前幾種高性能報文捕獲引擎
- libpcap-mmap
libpcap-mmap是對舊的libpcap實現(xiàn)的改進侣灶,新版本的libpcap基本都采用packet_mmap機制。PACKET_MMAP通過mmap缕碎,減少一次內存拷貝( 「第4次拷貝沒有了」 )褥影,減少了頻繁的系統(tǒng)調用,大大提高了報文捕獲的效率咏雌。 - PF_RING
我們看到之前l(fā)ibpcap有4次內存拷貝伪阶。libpcap_mmap有3次內存拷貝。PF_RING提出的核心解決方案便是減少報文在傳輸過程中的拷貝次數(shù)处嫌。我們可以看到栅贴,相對與libpcap_mmap來說,pfring允許用戶空間內存直接和rx_buffer做mmap熏迹。這又減少了一次拷貝 ( 「libpcap_mmap的第2次拷貝」 :rx_buffer->skb)檐薯。
PF-RING ZC實現(xiàn)了DNA(Direct NIC Access 直接網卡訪問)技術,將用戶內存空間映射到驅動的內存空間注暗,使用戶的應用可以直接訪問網卡的寄存器和數(shù)據(jù)坛缕。通過這樣的方式,避免了在內核對數(shù)據(jù)包緩存捆昏,減少了一次拷貝( 「libpcap的第1次拷貝」 赚楚,DMA到內核緩沖區(qū)的拷貝)。這就是完全的零拷貝骗卜。其缺點是宠页,只有一個 應用可以在某個時間打開DMA ring(請注意,現(xiàn)在的網卡可以具有多個RX / TX隊列寇仓,從而就可以在每個隊列上同時一個應用程序)举户,換而言之,用戶態(tài)的多個應用需要彼此溝通才能分發(fā)數(shù)據(jù)包遍烦。 - DPDK
pf-ring zc和dpdk均可以實現(xiàn)數(shù)據(jù)包的零拷貝俭嘁,兩者均旁路了內核,但是實現(xiàn)原理略有不同服猪。pf-ring zc通過zc驅動(也在應用層)接管數(shù)據(jù)包供填,dpdk基于UIO實現(xiàn)拐云。
3.1 UIO+mmap 實現(xiàn)零拷貝(zero copy)
UIO(Userspace I/O)是運行在用戶空間的I/O技術。Linux系統(tǒng)中一般的驅動設備都是運行在內核空間近她,而在用戶空間用應用程序調用即可慨丐,而UIO則是將驅動的很少一部分運行在內核空間,而在用戶空間實現(xiàn)驅動的絕大多數(shù)功能泄私。采用Linux提供UIO機制房揭,可以旁路Kernel,將所有報文處理的工作在用戶空間完成晌端。
3.2 UIO+PMD 減少中斷和CPU上下文切換
DPDK的UIO驅動屏蔽了硬件發(fā)出中斷捅暴,然后在用戶態(tài)采用主動輪詢的方式,這種模式被稱為PMD(Poll Mode Driver)咧纠。
與DPDK相比蓬痒,pf-ring(no zc)使用的是NAPI polling和應用層polling,而pf-ring zc與DPDK類似漆羔,僅使用應用層polling梧奢。
3.3 HugePages 減少TLB miss
在操作系統(tǒng)引入MMU(Memory Management Unit)后,CPU讀取內存的數(shù)據(jù)需要兩次訪問內存演痒。第一次要查詢頁表將邏輯地址轉換為物理地址亲轨,然后訪問該物理地址讀取數(shù)據(jù)或指令。
為了減少頁數(shù)過多鸟顺,頁表過大而導致的查詢時間過長的問題惦蚊,便引入了TLB(Translation Lookaside Buffer),可翻譯為地址轉換緩沖器讯嫂。TLB是一個內存管理單元蹦锋,一般存儲在寄存器中,里面存儲了當前最可能被訪問到的一小部分頁表項欧芽。
引入TLB后莉掂,CPU會首先去TLB中尋址,由于TLB存放在寄存器中千扔,且其只包含一小部分頁表項憎妙,因此查詢速度非常快昏鹃。若TLB中尋址成功(TLB hit)尚氛,則無需再去RAM中查詢頁表;若TLB中尋址失敹床场(TLB miss),則需要去RAM中查詢頁表属瓣,查詢到后载迄,會將該頁更新至TLB中讯柔。
而DPDK采用HugePages ,在x86-64下支持2MB护昧、1GB的頁大小魂迄,大大降低了總頁個數(shù)和頁表的大小,從而大大降低TLB miss的幾率惋耙,提升CPU尋址性能捣炬。
3.4 其它優(yōu)化
SNA(Shared-nothing Architecture),軟件架構去中心化绽榛,盡量避免全局共享湿酸,帶來全局競爭,失去橫向擴展的能力灭美。NUMA體系下不跨Node遠程使用內存推溃。
SIMD(Single Instruction Multiple Data),從最早的mmx/sse到最新的avx2届腐,SIMD的能力一直在增強铁坎。DPDK采用批量同時處理多個包,再用向量編程犁苏,一個周期內對所有包進行處理硬萍。比如,memcpy就使用SIMD來提高速度围详。
cpu affinity:即 CPU 親和性襟铭。
3.5 DPDK VS PF-RING
PF-RING的DNA工作方式下,網卡驅動NAPI的整體流程基本沒變短曾,依舊是由報文觸發(fā)硬中斷寒砖,軟中斷進行輪詢收包,但DNA工作方式下嫉拐,網卡的DMA緩沖被映射到了內核中PF-RING的環(huán)形緩沖上哩都,而改環(huán)形緩沖又被映射到了用戶態(tài),故用戶態(tài)應用程序可直接讀取到網卡的報文婉徘。在本工作方式下漠嵌,直接避免了報文的拷貝。在中斷方面盖呼,PF-RING整體收包的流程依然采取報文觸發(fā)硬中斷儒鹿,隨后軟中斷進行輪詢收包的方式。在始終維持大量報文到來的高速網絡環(huán)境中几晤,這種基于NAPI的異步中斷式收包
仍然會帶來中斷活鎖以及較高的中斷上下文切換開銷约炎。在系統(tǒng)調用方面,PF-RING的環(huán)形緩沖存在于內核態(tài),當應用程序讀取報文時需依賴系統(tǒng)調用從用戶態(tài)讀取內核態(tài)中的數(shù)據(jù)圾浅,故PF-RING存在系統(tǒng)調用的開銷掠手。DPDK開源時間較短,但是目前當下最熱的數(shù)據(jù)轉發(fā)技術狸捕,商用案例多且得到主流設備廠家的應用喷鸽,有良好的產業(yè)生態(tài)鏈。DPDK借助于用戶態(tài)I0灸拍,使輪詢模式的網卡驅動運行在用戶態(tài)接收報文做祝,一切數(shù)據(jù)操作都發(fā)生在用戶態(tài),故與其他兩種技術相比鸡岗,基本避免了系統(tǒng)調用的使用以及用戶態(tài)內核態(tài)上下文切換的開銷混槐。與NAPI即異步中斷模式相比,在本驅動模式下纤房,網卡的一切中斷被關閉纵隔,由此消除了中斷上下文的切換。每當網卡接收隊列填滿報文之后填寫接收描述符炮姨,CPU只需輪詢該描述符即可感知是否進行報文處理捌刮,該機制保證CPU只專注于對報文的輪詢I/O與處理,提高了報文的接收與處理效率舒岸。在報文拷貝與存儲方面绅作,DPDK通過用戶態(tài)核心庫的緩沖區(qū)管理功能在用戶態(tài)為報文存儲提供了預分配內存緩沖區(qū),再者通過環(huán)境抽象層EAL直接與硬件資源交互蛾派,將預分配內存緩沖區(qū)的地址直接寫入到網卡寄存器中俄认。由此,網卡將接收到的報文直接存儲到了用戶態(tài)的內存緩沖區(qū)中洪乍,實現(xiàn)了報文的零拷貝眯杏。PF-RINGDNA與DPDK都實現(xiàn)了真正的零拷貝,單純就拷貝這一行為來說壳澳,二者的優(yōu)化達到了同一程度岂贩。但是值得注意的是,由于捕獲的報文進行入侵檢測分析巷波,故在后期會對存儲報文內存進行頻繁的讀取萎津,相比于PF-RTNG使用常規(guī)內存分頁技術,DPDK在預分配內存時使用的Hugepage技術抹镊,在后期數(shù)據(jù)處理階段中锉屈,可顯著提高內存的訪問效率。 - Netmap
4.1 Netmap是一個高性能收發(fā)原始數(shù)據(jù)包的框架垮耳,由Luigi Rizzo等人開發(fā)完成徘禁,其包含了內核模塊以及用戶態(tài)庫函數(shù)。其目標是,不修改現(xiàn)有操作系統(tǒng)軟件以及不需要特殊硬件支持,實現(xiàn)用戶態(tài)和網卡之間數(shù)據(jù)包的高性能傳遞尽楔。數(shù)據(jù)包不經過操作系統(tǒng)內核進行處理,用戶空間程序收發(fā)數(shù)據(jù)包時丰介,直接與網卡進行通信呀打。在Netmap框架下,內核擁有數(shù)據(jù)包池豌研,發(fā)送環(huán)接收環(huán)上的數(shù)據(jù)包不需要動態(tài)申請妹田,有數(shù)據(jù)到達網卡時,當有數(shù)據(jù)到達后鹃共,直接從數(shù)據(jù)包池中取出一個數(shù)據(jù)包鬼佣,然后將數(shù)據(jù)放入此數(shù)據(jù)包中,再將數(shù)據(jù)包的描述符放入接收環(huán)中霜浴。內核中的數(shù)據(jù)包池晶衷,通過mmap技術映射到用戶空間。用戶態(tài)程序最終通過netmap_if獲取接收發(fā)送環(huán)netmap_ring阴孟,進行數(shù)據(jù)包的獲取發(fā)送晌纫。
與硬件解耦 ,只需要對網卡驅動程序稍微做點修改就可以使用此框架(幾十行行)永丝,傳統(tǒng)網卡驅動將數(shù)據(jù)包傳遞給操作系統(tǒng)內核中協(xié)議棧锹漱,而修改后的數(shù)據(jù)包直接放入Netmap_ring供用戶使用。 虛擬交換機場景下慕嚷,使用Netmap可以實現(xiàn)不同網卡間高效數(shù)據(jù)轉發(fā)哥牍,將一個網卡的數(shù)據(jù)放到另外一個網卡上時,只需要將接收環(huán)中的packet的描述符放入發(fā)送環(huán)喝检,不需要拷貝數(shù)據(jù)嗅辣,實現(xiàn)數(shù)據(jù)包的零拷貝。
4.2 簡單 對比 netmap 和 DPDK挠说。
可能唯一相同之處就是: 將 NIC 的 rx_ring_buffer 和 tx_ring_buffer澡谭,映射到 user-level,直接在 user-level 進行 packet RX/TX纺涤。- 相比 DPDK 來說译暂,netmap 并不能算作一個豐富的SDK。
- 使用netmap撩炊,需要很多手動操作的細節(jié)外永,比如說 手動修改 netmap_shadow_ring,不是很方便
- rx_/tx_ring_buffer 都是由 netmap.ko 預分配拧咳,user-level application 不能動態(tài)分配伯顶,只能使用,而已。
- netmap 并不是在 user-level 實現(xiàn) driver (__ DPDK 的 PMD 是在 user-level )祭衩。 而是灶体,在原本的 kernel driver 上打 patch,加入 netmap 自定義的邏輯掐暮。Linux 中仍然會有 "ethX" 這樣的 "net_device"蝎抽。 只不過 Linux stack 無法直接向其收發(fā)packet,罷了路克。但是 "ifconfig" 之類的東西樟结,還是可以用的。
- 仍然會有 中斷精算。對于 packet RX瓢宦,仍然是 RX IRQ handler -> BH napi_rx_poll(),對于 packet TX灰羽,仍然是 TX-DONE IRQ handler -> BH napi_tx_done_poll()驮履。 只不過,netmap 會在 poll() 中加入自定義的邏輯廉嚼,替換掉driver 原本的邏輯玫镐。
- netmap 只是將 ring_buffer 映射到user-level。但并不將 NIC hw_ring_descriptors 映射到 user-level前鹅。 每種不同的NIC 的 descriptor 格式摘悴,都不一樣。因為設計上的考慮舰绘,想要對user-level application表現(xiàn)得common 和 generic 蹂喻,就不能映射。 幾乎全部 NIC HW offload features捂寿,比如說 VLAN offload, checksum offload, TSO, 等口四,都需要特別設置 hw_ring_descriptors 的一些fields。netmap 完全不考慮這些 NIC HW offload features秦陋。
- netmap 也沒有像 DPDK 那樣規(guī)定 lcore thread model 和 進行packet RX/TX時的 multi-thread best practice蔓彩。對于 netmap來說,thread, priority, CPU affinity, 等等驳概,都不是 netmap 本身規(guī)定的內容赤嚼,而完全由 使用netmap的 programmer 來控制。
-
netmap 只是進行最簡單的 packet RX/TX顺又。沒有其他任何對 packet 進行處理的 library更卒。比如說,DPDK 提供了對 packet data 進行處理的 GRO, GSO, IP分片/重組稚照,QoS蹂空,加解密俯萌,等等等 library。 但是上枕,這些都不是 netmap 的內容咐熙。
綜上所述,DPDK高速報文捕獲技術更加適合于作為高速報文捕獲機制的基礎解決方案辨萍。
參考:
https://blog.csdn.net/gengzhikui1992/article/details/103142848
https://blog.csdn.net/xzhao28/article/details/109112898