丁 帥,喬廬峰,陳慶華,劉 熹,鄒仕祥
(中國人民解放軍陸軍工程大學(xué),江蘇 南京 210001)
計(jì)算機(jī)系統(tǒng)中,傳輸控制協(xié)議(Transmission Control Protocol,TCP)通常集成在操作系統(tǒng)中,以軟件方式實(shí)現(xiàn)。研究表明,這種軟件實(shí)現(xiàn)的方式在協(xié)議處理、數(shù)據(jù)拷貝和中斷處理中給系統(tǒng)帶來了龐大的開銷[1]。隨著網(wǎng)絡(luò)帶寬不斷增大,對服務(wù)器能力的要求不斷增加,協(xié)議處理已經(jīng)成為服務(wù)器的主要負(fù)荷之一。為了提高服務(wù)器的處理能力,目前通常采用增大單一服務(wù)器CPU 數(shù)量和多服務(wù)器并行處理等方式。為了進(jìn)一步提高服務(wù)器同時服務(wù)的用戶數(shù)量、提高處理的數(shù)據(jù)吞吐率,采用專用的TCP協(xié)議處理電路,以全硬件方式實(shí)現(xiàn)TCP 協(xié)議處理的功能成為研究的熱點(diǎn),由此推動了TCP 協(xié)議卸載引擎(TCP Offload Engine,TOE)技術(shù)的發(fā)展。
TOE 技術(shù)的基本思想是采用專用硬件,如TOE網(wǎng)卡,實(shí)現(xiàn)原來由CPU 承擔(dān)的TCP 協(xié)議處理功能[2]。如圖1 所示,傳統(tǒng)網(wǎng)卡主要實(shí)現(xiàn)網(wǎng)絡(luò)的物理層和數(shù)據(jù)鏈路層處理功能,網(wǎng)絡(luò)層和TCP 層功能由軟件實(shí)現(xiàn)。TOE 網(wǎng)卡除實(shí)現(xiàn)傳統(tǒng)網(wǎng)卡的處理功能外,還需要實(shí)現(xiàn)TCP 層和網(wǎng)絡(luò)層協(xié)議處理功能。CPU 重點(diǎn)完成應(yīng)用層及以上處理功能,從而可以大大降低CPU 負(fù)荷。TOE 可以采用專用集成電路(Application Specific Integrated Circuit,ASIC)、嵌入式處理器和現(xiàn)場可編程門陣列(Field Programmable Gate Array,F(xiàn)PGA)實(shí)現(xiàn)。利用ASIC 實(shí)現(xiàn)時,TOE 處理能力強(qiáng),但靈活性較差;采用嵌入式處理器實(shí)現(xiàn)時,處理靈活,可拓展性強(qiáng),但是其本質(zhì)上還是以軟件方式實(shí)現(xiàn)協(xié)議處理,性能提升有限;采用FPGA 實(shí)現(xiàn)時,可以在保證處理能力的前提下,保持足夠的靈活性,且開發(fā)周期短,實(shí)現(xiàn)風(fēng)險小[3]。本文采用的是基于FPGA 的實(shí)現(xiàn)方案。
圖1 傳統(tǒng)網(wǎng)卡與TOE 網(wǎng)卡
本文設(shè)計(jì)的TCP 協(xié)議處理電路總體結(jié)構(gòu)如圖2所示,由TCP 發(fā)送控制電路、封裝電路、校驗(yàn)和生成電路、窗口管理電路、定時器管理電路、哈希查找電路、TCP 接收控制電路、包重排序電路、發(fā)送和接收緩存組成。
圖2 TCP 協(xié)議處理電路總體結(jié)構(gòu)
TCP 發(fā)送控制電路包含TCP 發(fā)送電路和重傳電路。TCP 發(fā)送電路負(fù)責(zé)根據(jù)上層應(yīng)用提供的套接字(Socket)與目的主機(jī)實(shí)現(xiàn)建立連接、數(shù)據(jù)傳輸和釋放連接的控制功能,產(chǎn)生TCP 頭部信息并交給下級電路。TCP 封裝電路根據(jù)TCP 發(fā)送電路在數(shù)據(jù)傳輸階段提供的TCP 頭和用戶數(shù)據(jù),組建完整的TCP報文段,并通過校驗(yàn)和生成電路計(jì)算位于TCP 頭部的校驗(yàn)和字段,從而生成完整的TCP 報文段并通過發(fā)送緩存交給IP 層處理電路。重傳電路利用定時器超時控制報文段重傳,同時可根據(jù)返回的確認(rèn)信息進(jìn)行發(fā)送窗口管理,實(shí)現(xiàn)TCP 流量控制的功能。TCP 接收控制電路負(fù)責(zé)接收TCP 報文段,根據(jù)報文段類別,產(chǎn)生攜帶確認(rèn)序號和接收窗口確認(rèn)分組,發(fā)送給對端。接收分組排序電路可以對非按序到達(dá)的報文段進(jìn)行本地緩沖,確保向上層按序交付數(shù)據(jù)。TCP 接收控制電路還可以利用哈希查找電路進(jìn)行業(yè)務(wù)流區(qū)分,從而以時分復(fù)用方式同時支持多個連接。
TCP 協(xié)議有復(fù)雜的狀態(tài)變遷流程,圖3 是在正常情況下,服務(wù)器和客戶機(jī)狀態(tài)的變遷,不包含同時打開、關(guān)閉連接的服務(wù)[4]。TCP 協(xié)議處理電路需要采用全硬件方式實(shí)現(xiàn)TCP 協(xié)議處理功能。
圖3 TCP 狀態(tài)變遷
TCP 協(xié)議處理電路中的緩沖區(qū)分布和實(shí)現(xiàn)控制功能的狀態(tài)機(jī)分布如圖4 所示。發(fā)送狀態(tài)機(jī)通過與前級電路的發(fā)送隊(duì)列接口,讀取待發(fā)送TCP 分段凈荷,并讀取與TCP 頭部生成有關(guān)的控制信息,然后按照給定目的IP 地址和目的端口號完成與對端服務(wù)器建立連接、發(fā)送數(shù)據(jù)和釋放連接的操作并接收對端確認(rèn)(Acknowledgment,ACK)。定時器管理電路對發(fā)送分段進(jìn)行定時,當(dāng)一個分段出現(xiàn)超時后,它會觸發(fā)該分段的重傳操作。重傳電路包含兩個狀態(tài)機(jī),一個用于接收對端ACK,根據(jù)窗口大小字段,調(diào)節(jié)發(fā)送窗口大小實(shí)現(xiàn)流量和擁塞控制功能,并能給發(fā)送狀態(tài)機(jī)提供必要的狀態(tài)字段;另一個狀態(tài)機(jī)用于數(shù)據(jù)段的超時重傳。在發(fā)送數(shù)據(jù)時,發(fā)送狀態(tài)機(jī)首先判斷與應(yīng)用層的接口數(shù)據(jù)隊(duì)列和與重傳電路的接口隊(duì)列中是否有待發(fā)送數(shù)據(jù)指針,其次優(yōu)先發(fā)送待重傳數(shù)據(jù)。接收控制電路從與前級電路的接口隊(duì)列中讀取數(shù)據(jù)包,提取TCP 頭部信息,按照給定源IP 地址和源端口號完成與客戶機(jī)建立連接、接收數(shù)據(jù)和釋放連接的操作。在數(shù)據(jù)包的接收過程中,通過應(yīng)答發(fā)送狀態(tài)機(jī)向?qū)Χ税l(fā)送相應(yīng)的ACK 應(yīng)答。包重排序狀態(tài)機(jī)根據(jù)序號對數(shù)據(jù)包進(jìn)行排序,再按序交付給應(yīng)用層。當(dāng)同時支持多個TCP 流時,哈希查找電路用于識別不同的TCP 連接,在時分復(fù)用狀態(tài)下讀取不同TCP 流的狀態(tài)信息,對不同的流進(jìn)行管理。
圖4 TCP 協(xié)議處理電路中的緩沖區(qū)和狀態(tài)機(jī)
面向多業(yè)務(wù)流的連接管理需要采用哈希查找電路進(jìn)行業(yè)務(wù)流識別,該電路位于接收控制電路端,用于識別上千條TCP 連接,并對各個連接的參數(shù)進(jìn)行維護(hù)管理。哈希查找電路的工作原理是利用哈希函數(shù)建立關(guān)鍵字到哈希表地址空間的映射,即將關(guān)鍵字進(jìn)行哈希散列運(yùn)算,得到哈希值(Hash)。這種映射是一種壓縮映射,不同的關(guān)鍵字可能會產(chǎn)生相同的Hash,從而導(dǎo)致哈希沖突。為了減少哈希沖突,可以使用多桶哈希的技術(shù),本方案采用雙桶哈希表結(jié)構(gòu)。
雙桶哈希技術(shù)通過增大哈希表的位寬,使得一個Hash 對應(yīng)的存儲空間中可以同時存儲2 個關(guān)鍵字及其對應(yīng)的結(jié)果信息來減少哈希沖突。本設(shè)計(jì)中哈希查找電路的關(guān)鍵字是當(dāng)前連接的源IP 地址、目的IP 地址、源端口號和目的端口號,標(biāo)識為一個Socket。輸出的結(jié)果信息是每個業(yè)務(wù)流對應(yīng)唯一的連接號(Connection_id)。
哈希查找電路實(shí)現(xiàn)的功能有業(yè)務(wù)流添加操作,業(yè)務(wù)流識別操作和業(yè)務(wù)流刪除操作。
業(yè)務(wù)流添加操作是在Hash 對應(yīng)的存儲中寫入當(dāng)前Socket、Connection_id 表項(xiàng)。發(fā)送電路完成建立連接的操作后,哈希查找電路會進(jìn)行業(yè)務(wù)流添加操作,利用哈希函數(shù)計(jì)算Socket 得到Hash,以Hash 為地址將Socket 和對應(yīng)的Connection_id 寫入,完成業(yè)務(wù)流添加操作。
在連接上到達(dá)報文段時,為了簡單標(biāo)識連接進(jìn)行數(shù)據(jù)傳輸,哈希查找電路根據(jù)Socket 得到Hash讀取兩個哈希桶中對應(yīng)的表項(xiàng),表項(xiàng)匹配成功,得到Connection_id 進(jìn)行連接參數(shù)維護(hù)。
在發(fā)送電路完成釋放連接的操作后,查找電路會進(jìn)行業(yè)務(wù)流刪除操作,它將根據(jù)Socket 得到Hash 讀取兩個哈希桶中對應(yīng)的表項(xiàng),將該表項(xiàng)(包括有效指示位)全部清零,完成業(yè)務(wù)流刪除操作。
TCP 發(fā)送電路的工作流程如圖5 所示。發(fā)送狀態(tài)機(jī)的初始狀態(tài)為CLOSED 狀態(tài),在此狀態(tài)下,所有寄存器的值都為初始設(shè)定值,發(fā)送狀態(tài)機(jī)會不停地檢測上層應(yīng)用是否有執(zhí)行建立連接的操作,若上層應(yīng)用要建立連接,則發(fā)送狀態(tài)機(jī)會發(fā)送一個同步序號編號(Synchronize Sequence Numbers,SYN)置1 的連接數(shù)據(jù)幀到對端,建立連接定時器就會被啟動,發(fā)送狀態(tài)機(jī)會隨即跳轉(zhuǎn)至SYN_SENT 狀態(tài)。在SYN_SENT 狀態(tài)下,發(fā)送狀態(tài)機(jī)會等待對端ACK 的到來。若在建立連接定時器超時前收到對端的確認(rèn),則發(fā)送狀態(tài)機(jī)跳轉(zhuǎn)到ESTABLISH 狀態(tài),否則重發(fā)SYN。若在3 次發(fā)送SYN 都沒有收到對端ACK,則建立連接失敗[5]。
圖5 TCP 發(fā)送電路工作流程
若上層應(yīng)用有數(shù)據(jù)待發(fā)送,則發(fā)送狀態(tài)機(jī)開始進(jìn)行數(shù)據(jù)加載操作,數(shù)據(jù)加載完成后,發(fā)送狀態(tài)機(jī)跳轉(zhuǎn)至發(fā)送數(shù)據(jù)狀態(tài)。在發(fā)送數(shù)據(jù)狀態(tài)下,封裝好的報文段被發(fā)送出去,同時啟動超時定時器,之后進(jìn)入超時檢查狀態(tài)。在檢查超時時間時,發(fā)送方會等待對端ACK 的到來,若收到了對端的應(yīng)答,且沒有超時,則按照應(yīng)答包接收窗口大小字段進(jìn)入下一批數(shù)據(jù)發(fā)送操作;否則應(yīng)進(jìn)行數(shù)據(jù)重傳,收到重傳數(shù)據(jù)的確認(rèn)后,繼續(xù)進(jìn)行下一批數(shù)據(jù)的傳輸操作。
完成數(shù)據(jù)的傳輸后,發(fā)送狀態(tài)機(jī)可根據(jù)上級電路的要求發(fā)送一個結(jié)束幀(FIN 位置1)到對端,同時啟動超時定時器,跳轉(zhuǎn)至FIN_WAIT_1 狀態(tài)。若在超時定時器超時前收到對端的確認(rèn),會進(jìn)入FIN_WAIT_2 狀態(tài),同時啟動fin_wait 定時器,否則會向?qū)Χ酥匕l(fā)FIN。若在fin_wait 定時器超時前,發(fā)送狀態(tài)機(jī)收到對端FIN,得知對端請求關(guān)閉數(shù)據(jù)傳輸連接,便會發(fā)送一個應(yīng)答包,隨后跳轉(zhuǎn)到TIME_WAIT狀態(tài)。兩倍的最大段生存時間(Maximum Segment Lifetime,MSL)后回到CLOSED 狀態(tài),否則直接關(guān)閉連接。
如圖6 所示為重傳電路存儲結(jié)構(gòu),重傳電路的存儲管理方式為自由指針隊(duì)列(Free Pointer Queue,F(xiàn)Q)、待發(fā)送指針隊(duì)列(Pending Pointer Queue,PQ)、數(shù)據(jù)存儲區(qū)SRAM 和重傳接口隊(duì)列的組合。上層應(yīng)用有數(shù)據(jù)塊要發(fā)送時,發(fā)送控制電路在將數(shù)據(jù)寫入發(fā)送隊(duì)列的同時也將數(shù)據(jù)寫入緩沖區(qū)隊(duì)列。重傳電路開始工作時,首先將FQ 初始化,若檢測到緩沖區(qū)隊(duì)列中有指針,寫入狀態(tài)機(jī)先從自由指針隊(duì)列中讀取一個自由指針;其次根據(jù)這個指針將數(shù)據(jù)塊寫入數(shù)據(jù)存儲區(qū)中,其中自由指針作為數(shù)據(jù)存儲區(qū)的基地址;最后以自由指針值為地址,將自由指針值、數(shù)據(jù)長度、起始字節(jié)編號(本地頭)和時間戳等信息寫入PQ 中。
圖6 重傳電路存儲結(jié)構(gòu)
接收狀態(tài)機(jī)在檢測ACK 接收隊(duì)列指針是否非空的同時,在間隙中掃描PQ 中的時間戳。接收狀態(tài)機(jī)如果收到對端ACK,則對ACK 包進(jìn)行解析,依次讀取PQ 隊(duì)列并與PQ 中各表項(xiàng)的本地頭比較,確定是哪一個數(shù)據(jù)包的ACK 并記錄下接收窗口大小字段,然后從PQ 隊(duì)列中讀出自由指針。以該指針為基地址將數(shù)據(jù)塊從存儲區(qū)內(nèi)釋放,將自由指針歸還給自由指針隊(duì)列,同時在PQ 中將此表項(xiàng)的有效位置0,表示該表項(xiàng)對應(yīng)的報文段被對端成功接收。如果發(fā)生超時,重傳狀態(tài)機(jī)邊開始工作,將PQ 中自由指針值讀出,以該指針為基地址將存儲區(qū)內(nèi)數(shù)據(jù)寫入重傳接口隊(duì)列中,同時將時間戳值更新。這樣便完成了ACK的接收與數(shù)據(jù)包的重傳功能。由于一個TCP 的最大報文段是1.5 KB,所以對數(shù)據(jù)包進(jìn)行存儲時可以將一個32 KB RAM 的緩存區(qū)分塊,每塊2 KB,這樣一塊RAM 可以分為16 個數(shù)據(jù)塊,每個數(shù)據(jù)塊對應(yīng)一個指針,這樣對應(yīng)一個深度為16 的自由指針隊(duì)列0~15。在初始化時,將0~15 寫入FQ 中。假設(shè)RAM 的位寬為32 位,這樣512 個32 位的存儲單元可以存儲一個2 KB 完整的數(shù)據(jù)塊。RAM 的地址除自由指針值外,還應(yīng)該加上低9 位的計(jì)數(shù)值,加在一起才是真正使用的RAM地址。
本文以Xilinx ZYNQ-7020 開發(fā)板為硬件平臺搭建TCP 處理電路,其關(guān)鍵電路的仿真波形如圖7、圖8 和圖9 所示。圖7 展示的是多連接查找電路的仿真結(jié)果,圖中標(biāo)“1”處是4 個連接的添加操作,由于電路采用雙桶Hash 技術(shù),所以對于前3 個相同Hash 的Socket 連接添加時,第3 個連接添加失敗。標(biāo)“2”處是連接查找操作,根據(jù)Socket 得到Hash 利用哈希查找電路進(jìn)行查找,第3 個連接查找失敗,其余3 個均查找成功。標(biāo)“3”處是第4 個連接的刪除操作,根據(jù)Socket 得到Hash 利用哈希電路進(jìn)行表項(xiàng)刪除,第4 個連接刪除成功;標(biāo)“4”處是連接查找操作,由于經(jīng)過第3 步的連接刪除操作,第3 和第4 個連接均查找失敗。圖8 和圖9 展示了建立連接和釋放連接仿真結(jié)果,圖中標(biāo)“1”處是第1 次建立連接操作,由于發(fā)送3 個SYN,均沒有收到對端的同步應(yīng)答幀,所以建立連接失敗。標(biāo)“2”處是第2 次建立連接操作,在發(fā)送第3 個SYN 的超時時間內(nèi)收到對端的同步應(yīng)答幀,建立連接成功。標(biāo)“3”處是拆除連接過程中發(fā)送FIN 的操作,在第2 次FIN 的超時時間內(nèi)收到對端ACK,且在一定時間內(nèi)收到對端FIN,所以發(fā)送完ACK,再等待2MSL 時間后釋放連接。標(biāo)“4”處是拆除連接過程中接收對端FIN 超時的情況,在第2 次FIN的超時時間內(nèi)收到對端ACK,但在一定時間內(nèi)沒有收到對端FIN,所以直接釋放連接。
圖7 連接查找電路仿真結(jié)果
圖8 TCP 建立連接仿真結(jié)果
圖9 TCP 釋放連接仿真結(jié)果
本文給出了多端口TCP 協(xié)議處理電路設(shè)計(jì)方案,由TCP 發(fā)送控制電路、哈希查找電路、重傳電路、定時器管理電路組成。TCP 協(xié)議處理關(guān)鍵電路在Xilinx ZYNQ-7020 開發(fā)板上進(jìn)行了設(shè)計(jì)與仿真分析,結(jié)果表明,TCP 處理電路可以以全硬件方式實(shí)現(xiàn)連接建立、數(shù)據(jù)傳輸、連接釋放和連接存儲管理,符合TCP 協(xié)議規(guī)范要求。