摘 要:零拷貝技術是提高通用計算機報文采集性能的重要技術手段,但是目前通用的方案存在不易移植的缺點。針對這一問題,本文提出一種基于Linux系統平臺下的新型零拷貝報文捕獲技術PF_DMA。該方法通過對系統內核函數的擴展、替換,在不破壞原有網卡驅動程序結構的基礎上實現報文的零拷貝捕獲,且易于實現在不同網卡驅動程序間移植。
關鍵詞:報文捕獲流量監測零拷貝Linux系統
中圖分類號:TP393文獻標識碼:A文章編號:1674-098X(2011)08(c)-0020-03
Abstract:Zero-Copy technique has been widely used in the implementation of packed-capture algorithm.However,the present implementations need too much modifications of NIC device drivers,and can not be migrated between heterogeneous NICs.We propose a new implementation of Zero-Copy technique (PF_DMA) under Linux System.PF_DMA implements mainly in the core functions of the operating system and avoids damaging of NIC drivers.
Key words:Packet Capture;Traffic Monitoring;Zero Copy;Linux System
1 引言
隨著網絡技術的快速發展,網絡傳輸速度不斷提高,網絡監測、入侵檢測等應用系統對網絡報文捕獲技術提出了更高的性能要求,傳統的報文捕獲技術已很難滿足高速鏈路監測的需要。一些專用硬件方案可實現CPU資源主要用于報文的應用處理,避免報文捕獲的開銷,但其價格成本高昂[1]或需要復雜的硬件開發[2,3,4]。目前,已有研究[5,6]中基于通用硬件的零拷貝實現方案,通過避免頻繁的用戶態與核心態切換、數據拷貝,來提高單機的報文捕獲能力,但實現方案往往針對特定網卡和操作系統內核,或者需要對網卡驅動程序進行很大改動,難于實現不同硬件設施平臺下的移植工作,但這種方法破壞了網卡驅動原有實現結構,需要對網卡驅動程序進行較大修改。L.Deri實現的ncap[7]主要針對Intel網卡。另外一些研究則僅僅提供了設計方案,并未給出具體的實現方法[7,9,10]。作者提出一種Linux系統平臺下零拷貝報文捕獲解決方案PF_DMA,通過對內核netdev_alloc_skb()、dev_kfree_skb()等接口函數的修改、擴充,實現零拷貝報文捕獲功能。該方法不破壞網卡驅動原有結構,且易于在不同的網絡硬件平臺間進行移植。
2 PF_DMA系統結構
零拷貝報文捕獲技術的核心設計思想是在系統內核中創建一個共享緩沖區,用戶空間的報文捕獲程序通過mmap機制將共享緩沖區映射到自己的內存空間中,實現內核與應用程序的數據共享。當網卡接收到數據報文后,通過DMA方式直接將數據報文從自己的接收緩沖區隊列中傳送到對應的共享緩沖區中,報文捕獲程序發現有新的數據報文到來時,從共享緩沖區中直接讀取數據報文進行處理,從而避免不必要內存的拷貝及頻繁的用戶態與核心態切換[8,11],提高報文捕獲性能。PF_DMA沿用了零拷貝報文捕獲技術的基本思想,通過將skb_buff作為共享緩沖區的一部分,并與報文存儲區統一管理,保持網卡驅動程序對報文處理的一致性,從而避免破壞原有網卡驅動程序的實現結構。PF_DMA整體架構由內核模塊Mod_DMA和用戶態函數庫Lib_DMA構成,如圖1所示。
內核模塊Mod_DMA實現了一種新類型的Socket,用戶態的報文捕獲程序通過Socket接口與Mod_DMA進行交互,創建、映射共享緩沖區,實現內核空間與用戶空間的數據共享及訪問同步控制,同時Mod_DMA對Linux內核相關函數進行擴展,為網卡驅動程序提供統一接口函數,以便網卡驅動程序接收到數據報文后,直接通過DMA方式將數據報文傳輸到共享緩沖區中。Lib_DMA主要為報文捕獲程序提供相關調用接口,程序通過調用Lib_DMA啟動、停止報文捕獲及對接收到的數據報文進行過濾、處理,即:1)應用程序通過Lib_DMA提供的接口函數創建Socket實例,創建、映射共享緩沖區;2)從共享緩沖區中讀取報文,并根據BPF過濾規則對收到的數據報文進行過濾;3)調用應用程序提供注冊的處理函數,對符合條件的數據報文進行處理。
3 PF_DMA的實現
3.1 內核模塊Mod_DMA的實現
3.1.1 與網卡驅動程序的接口
skb_buff是Linux網絡協議棧實現中最為重要的數據結構,在Linux操作系統中網絡數據報文的接收、發送等處理都是圍繞skb_buff進行的[12,13,14]。當網卡啟用后,網卡驅動程序通過調用內核函數netdev_alloc_skb()為網卡環形接收描述符分配skb_buff,網卡關閉后,通過內核函數dev_kfree_skb()釋放相應的skb_buff。在網絡報文接收處理過程中,網卡接收到數據報文后,通過DMA方式直接將數據報文從自己的FIFO緩沖區傳送到skb_buff結構中data指向的內存區,由網卡驅動提交給上層協議棧進行處理,并通過netdev_alloc_skb()函數分配新的skb_buff,對接收描述符進行補充。為提高PF_DMA在不同網卡驅動程序間易性移植,PF_DMA在具體實現上,通過對netdev_alloc_skb()、dev_kfree_skb()等函數進行擴展、替換,將PF_DMA功能添加到現有網卡驅動程序中,從而避免破壞原有網卡驅動程序的實現結構、減少代碼修改量。Mod_DMA對網卡驅動程序提供以下統一接口:
1)netdev_skb_dma_alloc()
當網卡處于正常工作模式下,該函數直接調用內核函數netdev_alloc_skb()為網卡環形接收描述符分配skb_buff,當網卡處于報文捕獲模式下,該函數直接從對應的共享緩沖區中為網卡分配skb_buff,從而實現網卡接收到數據報文后,通過DMA方式直接將數據報文傳送到共享緩沖區中,避免不必要的拷貝。
2)dev_kfree_dma_skb()
與netdev_skb_dma_alloc類似,當網卡處于正常工作模式下,該函數直接調用內核函數dev_kfree_skb()釋放相應的skb_buff,當網卡處于報文捕獲模式下,該函數將skb_buff回收到相應的共享緩沖區中。
3)skb_handler()
主要用于網卡驅動程序在軟中斷中對數據報文的處理,當網卡處于正常工作模式下,skb_handler()調用原有內核函數將數據報文提交給上層協議棧進行處理,當網卡處于報文捕獲模式下,skb_handle()函數旁路原有網絡協議棧處理,將數據報文直接提交給Mod_DMA進行處理。
3.1.2 Socket接口實現
Linux網絡協議棧為Socket的實現定義了統一接口,向系統中增加新類型的Socket時,只需實現struct net_proto_family、struct proto_ops中定義的相關接口[12,14]。在具體實現中,PF_DMA通過bind接口,將網卡與對應的Socket的綁定,并為該網卡創建相應的共享緩沖區;在mmap接口中實現mmap機制,以便應用程序將共享緩沖區映射到自己的內存空間中;同時由于應用程序通過輪詢方式檢查共享緩沖區中是否有新的網絡報文到達,當共享緩沖區沒有新報文到達時,如果應用程序不停輪詢,則造成CPU資源的浪費,在低負載時,該問題更為突出,PF_DMA通過poll接口實現應用程序與網卡驅動的同步。
3.1.3 共享緩沖區結構與相關操作
PF_DMA共享緩沖區主要由控制區和報文存儲區兩個部分組成(圖2),控制區主要包含共享緩沖區的讀寫索引、共享緩沖區的長度及報文捕獲統計信息等,報文存儲區主要用于存儲網卡接收的網絡報文,報文存儲區被劃分成Slot,每個Slot是一個網絡報文存儲單元。在Linux操作系統中,DMA操作使用的內存區要求物理地址連續,但系統內核對可連續分配物理內存長度有限制,同時當系統長時間運行后,往往造成內存分片,申請長度較大的連續物理內存容易失敗[13]。為避免創建共享緩沖區時,內存分配申請失敗,共享緩沖區采用多個物理上不一定連續的內存面頁構建而成,同時為方便擴充控制區保存的信息,控制區獨立占有系統申請的第一個內存面頁。
在Linux操作系統中一個內存面頁長度為4096字節,而以太網報文的MTU為1522字節,因此,將一個內存頁面劃分為兩個Slot,每個Slot的長度為2048字節,并且每個Slot中都包含一個skb_buff結構,以避免skb_buff的頻繁分配與釋放[15,16]。在每個Slot中,Info成員保存了該Slot的狀態信息,如:Slot中是否存儲了網絡報文以及存儲報文的長度、接收時間;Data成員是用于存儲網絡報文的數據區,當網卡接收到數據報文后,直接將報文通過DMA方式傳送到Data中;Pad成員是為了保證Data成員起始、結束地址是Cache對齊的,并起到數據之間安全隔離,避免Cache的錯誤共享[17]。
3.1.3.1 共享緩沖區的創建與映射
用戶插入Mod_DMA模塊時,設置共享緩沖區緩存報文的最大數目,系統根據該值計算共享緩沖區的長度。當應用程序調用Socket的bind()接口時,Mod_DMA通過內核函數get_free_pages()申請所需要內存面頁、創建共享緩沖區,并在共享緩沖區創建完成后,將緩沖區長度等控制信息寫到控制區中,同時將共享緩沖區與對應的網卡綁定。為避免共享緩沖區映射到應用程序內存空間中后,被操作系統交換到磁盤上,系統通過內核函數SetPageReserved()將內存面頁鎖定。
用戶空間中應用程序通過mmap()函數將共享緩沖區映射到自己的內存空間中,在實際實現中,Lib_DMA首先將共享緩沖區的控制區映射到用戶空間中,即將共享緩沖區的第一個內存面頁映射到用戶空間,通過控制區獲得共享緩沖區的長度,以便將整個共享緩沖區映射到用戶空間。為實現mmap機制的支持,內核模塊Mod_DMA實現了Socket的mmap()接口,通過內核函數remap_pfn_range()將共享緩沖區的內存面頁順序的映射到應用程序的虛擬內存地址上。
3.1.3.2 共享緩沖區的分配與回收
當網卡工作在報文捕獲模式下,驅動程序需要為網卡接收描述符分配skb_buff時,通過調用 netdev_skb_dma_alloc()函數來實現skb_buff的分配。netdev_skb_dma_alloc()函數從網卡對應共享緩沖區的控制區中,獲得共享緩沖區的當前寫索引,并檢查對應的Slot是否為空,如果為空,1)初始化該Slot的skb_buff結構,將skb_buff的head、data等指針指向Slot的Data內存區;2)將寫索引指向下一個Slot位置,如果當寫索引指向最后一個Slot,則將寫索引指向共享緩沖區的第一個Slot;3)將已初始化完成的skb_buff返回給網卡驅動。如果Slot的狀態不為空,說明共享緩沖區已滿,網卡驅動程序申請分配skb_buff失敗。
dev_kfree_dma_skb()函數工作相對比較簡單,只需將skb_buff對應的Slot設置為指定狀態,回收到共享緩沖區中。
3.1.3.3 報文接收處理
當網卡工作在報文捕獲模式下,收到網絡報文后,通過DMA方式將報文直接傳輸到skb_buff中data指向的內存區,即是該skb_buff對應Slot的Data內存區。在軟中斷處理過程中,由網卡驅動程序將裝載數據報文的skb_buff提交給skb_handler()函數進行處理。skb_handler函數的主要處理工作:1)將skb_buff對應的Slot狀態置為已有數據;2)根據skb_buff中控制信息,設置報文捕獲長度,同時根據系統時間,設置報文捕獲時間;3)檢查等待隊列上是否有應用進程等待,如果有,通過內核函數wake_up_interruptible()將應用進程喚醒。
應用程序通過Lib_DMA庫檢查共享緩沖區當前讀索引指向的Slot狀態,如果該Slot的狀態為已有數據,則:1)調用應用進程注冊的處理函數對數據報文進行處理;2)將該Slot的狀態置為空,并檢查下一個Slot,如果當讀索引指向最后一個Slot,則將讀索引將指向共享緩沖區的第一個Slot。當Slot狀態為空時,為避免浪費CPU資源,Lib_DMA調用poll函數將應用進程放入等待隊列掛起,當內核模塊Mod_DMA接收到新報文時將應用程序喚醒。為支持該機制,Mod_DMA實現了Socket的poll接口,通過內核函數poll_wait()將應用進程放入對應等待隊列。
3.2 Lib_DMA的實現
3.2.1 報文捕獲的啟動與停止
當需要啟動報文捕獲時,Lib_DMA首先通過ioctl接口關閉網卡,讓網絡驅動程序釋放原有從內核中申請的skb_buff,然后再通過ioctl函數將網卡切換到報文捕獲模式,并啟用網卡,使得網卡驅動程序從共享緩沖區中為網卡環形接收描述符分配skb_buff,Lib_DMA具體處理流程如下:
1)通過ioctl函數關閉網卡;
2)創建Socket;
3)通過Socket的bind接口,創建共享緩沖區,并將共享緩沖區與網卡綁定;
4)通過Socket的mmap接口,將共享緩沖區映射到應用程序內存空間;
5)通過ioctl函數將網卡切換到報文捕獲模式,并啟用網卡;
6)檢查是否有捕獲到的數據報文,并進行相應處理;
當網卡從報文捕獲模式切換到正常工作模式時,Lib_DMA同樣首先關閉網卡,回收從共享緩沖區中分配的skb_buff,然后將網卡切換回正常工作模式、重新啟用,網卡驅動為網卡環形接收描述符重新從內核申請新的skb_buff。
3.2.2 應用程序調度
由于網卡通過DMA方式直接將網絡報文傳輸到共享緩沖區中,如果應用程序不能及時對接收到的數據報文進行處理,共享緩沖區可能發生溢出現象,導致網卡驅動程序為網卡分配skb_buff失敗,網卡無法接收網絡數據報文。因此,應用程序在調度上應具有一定實時性與很高的優先級,在實際實現中,應用程序采用Linux進程調度方法中的SCHED_FIFO方式,其優先級設置為99。為進一步增強整個系統的實時性,也可通過RTAI對標準Linux內核進行擴展[18]。
隨著CPU多核技術的快速發展與成熟,多核技術已成為CPU主流發展技術。在多核系統中應用程序的調度對系統性能有著重要的影響。由于網絡驅動、應用進程都需要訪問Slot的Info成員的信息,為避免Cache錯誤共享以及提高Cache命中率,可通過中斷親和性機制,將應用進程與網卡中斷綁定到同一CPU上,進一步提高整個系統的處理性能[19]。
4 PF_DMA的移植方法
從PF_DMA的實現方法可知,PF_DMA沒有破壞原有網卡驅動程序的實現結構,易于在各個不同網卡驅動程序之間的進行移植,具體移植方法如下:
將網卡驅動程序中通過netdev_skb _alloc分配接收skb buff之處,用netdev_skb_dma_alloc函數替換,同樣網卡驅動中通過dev_kfree_ skb 釋放接收skb buff之處,用dev_kfree_dma_skb函數替換;
在網卡驅動程序注冊的接收處理函數中,將提交給上層協議棧處理的函數用skb_handler替換;
在一些網卡驅動中,對小包處理進行了優化,如:E1000驅動默認對小于256字節報文,根據報文實際長度新分配一個skb_buff,將原有skb_buff中的數據拷貝到新分配的skb_buff中,提交給上層協議棧處理,并將原有skb_buff重用。因此,在移植過程中,應對驅動程序代碼進行少量修改,避免這次網絡報文的拷貝;
當網卡接收報文發生錯誤時,一些驅動程序會重用原有的skb_buff,這種情況發生將導致應用程序延遲對后續接收報文的處理,直至該skb_buff接收到數據報文。因此,在移植過程中,可以讓網卡驅動程序重新申請新的skb_buff,并將原有skb_buff通過dev_kfree_dma_skb回收到共享緩沖區中,Slot的狀態置為出錯,避免上述情況發生。
5 結語
本文提出的基于Linux 系統的零拷貝報文捕獲方案PF_DMA,易于在多種不同網卡之間進行移植,能夠有效地提高千兆小包情況下的報文捕獲能力,降低CPU利用率??梢灶A見,隨著多核CPU技術的日益成熟與發展,通過對PF_DMA在新一代卡上進行擴展,有望進一步提高PF_DMA在多核系統上的報文捕獲能力。
參考文獻
[1]DAG7.5G2/G4,http://www.endace.com/dag-network-monitoring-cards.html.
[2]V. Paxson,R.Sommer,and N.Weaver An architecture for exploiting multi-core processors to parallelize network intrusion prevention,in Sarnoff Symposium,2007 IEEE,2007,pp.1-7.
[3]Nicholas Weaver The Shunt:An FPGA-based accelerator for network intrusion prevention.In ACM Symposium on Field ProgrammableGate Arrays,February 2007.
[4]A.Das,D.Nguyen,J.Zambreno An FPGA-Based Network Intrusion Detection Architecture, Information Forensics and Security,IEEE Transactions on,vol.3,pp.118-132,2008.
[5]A. Biswas and P.Sinha,\"Efficient real-time Linux interface for PCI devices: A study on hardening a Network Intrusion Detection System,\" in 5th System Administration and Network Engineering Conference.Aula Congress Centre,Delft,The Netherlands,2006.
[6]王佰玲,方濱興,云曉春.零拷貝報文捕獲平臺的設計與實現,計算機學報,2005,28(1):46-52.
[7]L.Deri,nCap:Wire-speed Packet Capture and Transmission,IEEE/IFIP Workshop on End-to-End Monitoring Techniques and Services, Nice-Acropolis,Nice,France,2005.
[8]A.Biswas,and P.Sinha,A high performance packet capturing support for Alarm Management Systems,17th International conference on Parallel and Distributed Computing and Systems, Phoenix,2005.
[9]Mahdi Dashtbozorgi,Mohammad Abdollahi Azgomi,\"A high-performance software solution for packet capture and transmission,\"iccsit,pp.407-411,2009 2nd IEEE International Conference on Computer Science and Information Technology,2009.
[10]Mahdi Dashtbozorgi,Mohammad Abdollahi Azgomi,A scalable multi-core aware software architecture for high-performance network monitoring,Proceedings of the 2nd international conference on Security of information and networks,2009.
[11]A.Munoz,A.Ferro,F Liberal,J Lopez, “A Kernel-Level Monitor over Multiprocessor Architectures for High-Performance Network Analysis with Commodity Hardware”,Sensor Technologies and Applications,2007.
[12]klaus wehrle,frank pahlke,汪青青,盧祖英,譯,linux網絡體系結構:linux內核中網絡協議的設計與實現.清華大學出版社,2006.
[13]Jonathan Corbet,Alessandro Rubini, Greg Kroah-Hartman,Linux Device Drivers 3rd,O'Reilly Media,2005.
[14]Wolfgang Mauerer,Professional Linux Kernel Architecture,Wrox Press,2008
[15]R.Bolla,R.Bruschi,“A high-end Linux based Open Router for IP QoS networks:tuning and performance analysis with internal (profiling) and external measurement tools of the packet forwarding capabilities”,Proc.of the 3rd International Workshop on Internet Performance,Simulation,Monitoring and Measurements (IPS MoMe 2005), Warsaw,Poland,Mar.2005.
[16]Bolla,R.;Bruschi,R.,“Linux Software Router:Data Plane Optimization and Performance Evaluation,”Journal of Networks (JNW),vol.2,no.3,Academy Publisher,pp.6-11,2007.
[17]Herb Sutter,Eliminate False Sharing, http://www.drdobbs.com/go-parallel/article/showArticle.jhtml,2009.
[18]RATI,https://www.rtai.org/
[19]A.Foong,J.Fung,D.Newell,A. Lopez-Estrada,S.Abraham,and P. Irelan.,Architectural characterization of processor affinity in network processing.In ISPASS.IEEE,2005.