[openssl] intel qat場景下的openssl框架


源代碼

[classic_tong:https://www.cnblogs.com/hugetong/p/14363775.html]

 

我們使用openssl版本1.1.1的源代碼進行安裝與實驗. 目前已經有了3.0.0的alpha版本.

源碼下載在這里: https://www.openssl.org/source/

git在這里:git@github.com:openssl/openssl.git

編譯與安裝

使用如下命令即可方便的完成編譯與安裝

./Configure --prefix=/root/debug/  LDFLAGS="-Wl,-rpath,/root/debug/lib"  linux-x86_64
make
make install

如下是安裝后的交付物.

[root@T9 OUTPUT_openssl_bare]# tree -L 3
.
├── bin
│   ├── c_rehash
│   └── openssl
├── certs
├── ct_log_list.cnf
├── ct_log_list.cnf.dist
├── include
│   └── openssl
│       ├── ...
│       └── x509_vfy.h
├── lib
│   ├── engines-1.1
│   │   ├── capi.so
│   │   └── padlock.so
│   ├── libcrypto.a
│   ├── libcrypto.so -> libcrypto.so.1.1
│   ├── libcrypto.so.1.1
│   ├── libssl.a
│   ├── libssl.so -> libssl.so.1.1
│   ├── libssl.so.1.1
│   └── pkgconfig
│       ├── libcrypto.pc
│       ├── libssl.pc
│       └── openssl.pc
├── misc
│   ├── CA.pl
│   ├── tsget -> tsget.pl
│   └── tsget.pl
├── openssl.cnf
├── openssl.cnf.dist
├── private
└── share
    ├── doc
    │   └── openssl
    └── man
        ├── ...
        └── man7

17 directories, 124 files

 

openssl框架

邏輯結構

在這里,我們偷兩張官網的圖, 然后通過這兩張圖進行更直觀的講解.

       

 

 

兩個圖通過不同的維度表達了同樣的事情, 我們這里只關注左圖, 右圖用來自學補充.

通過左圖,我們能看見openssl由四組件構成, 分別是APP, TLS, CRYPTO, ENGINE

ENGINE是提供加密能力的一組引擎,  插件式整合在框架內. 在使用中可以對不同的算法指定不同的加密引擎.

CRYPTO是加密組件的的集合, 對加密邏輯的抽象, 使用ENGINE中的能力完成密碼功能, 其中兩個重要的核心組件分別是EVP(envelope)和BIO(BASIC INPUT OUTPUT)

TLS表現為一組API用於操作SSL socket. TLS庫是對CRYPTO的封裝,使用EVP接口, EVP模塊使用BIO接口.

APP就是一組命令行工具, 他們被集成在二進制文件/bin/openssl中, 可以通過不同的參數進行調用.  APP主要是對TLS與CRYPTO的使用.

 

物理結構

物理結構並不准確, 實際上就是想說一下交付物的結構, 見前面的第一小節, 剔除不重要的(我們不關心的)之后, 是如下這樣:

├── bin
│   ├── c_rehash
│   └── openssl
├── lib
│   ├── engines-1.1
│   │   ├── capi.so
│   │   └── padlock.so
│   ├── libcrypto.a
│   ├── libcrypto.so -> libcrypto.so.1.1
│   ├── libcrypto.so.1.1
│   ├── libssl.a
│   ├── libssl.so -> libssl.so.1.1
│   └── libssl.so.1.1
├── openssl.cnf
├── private
└── certs

現在對應上前文講到的邏輯結構,  bin目錄下的openssl就是component APP,  lib目錄下面的libcrypto是component CRYPTO,  libssl是component SSL, lib/engines-1.1目錄下面的所有so文件都是一個engine, 

engines是在運行是dlopen動態加載上去的, 下文提到的qatengine在安裝之后, 也會放置在這個目錄下面以供openssl使用.

private和certs是兩個給app使用的兩個空目錄,  分別用於存放用戶的私鑰和證書文件.  我們在討論結構話題的當前, 可以不去關心它.

最后一個, 十分重要. 是配置文件. openssl.cnf, 這個文件是openssl的默認配置文件, 前文提到的所有使用openssl的APP都被這個配置文件控制, 

另外一個需要注意的是以庫的形式使用openssl的應用程序, 也可以通過api的方式, 讓openssl被該配置文件的內容約束行為, 比如nginx程序便采用了這樣的設置, 這個API是這樣的:

OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL)               // 使用ssl的應用程序
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, &settings)    // 使用crypto的應用程序

第二個參數如果指定了NULL將使用默認配置文件, 否則使用被設置的內容.

 

qat場景下openssl的框架

  

Intel的QAT卡, 推薦了一個典型的應用場景, 並且開源了代碼, 這組代碼包含四部分,

1.  nginx的patch,https://github.com/intel/asynch_mode_nginx

2.  openssl新增的async mode,已經合並到了openssl的主分支。

3   一個openssl engine叫qatengine 詳見: https://github.com/intel/QAT_Engine

 一個跟隨硬件發布的驅動程序,可以在intel網站下載

qatengine安裝成功后, 在前文提到的目錄下將能夠看見它的so: openssl/lib/engines-1.1/qat.so

如上圖所示, QAT卡就是一個加解密卡, 加解密卡的一般操作模型是: 1, 把待處理數據通過接口api寫入卡,  2, 卡處理. 3, 將處理好的數據在加解密卡中通過接口api讀出.

這個接口api使用qatdriver提供的, 如上圖, 符合一般的設備驅動模型分為內核態和用戶態兩部分. (可以從intel的網站進行下載, 這里是所以資料的入口:https://01.org/intel-quickassist-technology )

從框架體系上, nginx或其他任何使用openssl進行加解密操作的應用程序只需要保持與原來同樣的方式對openssl進行調用.  如果它需要使用QAT卡

進行加解密加速, 可以通過openssl的api將需要的算法指定到engine QAT上去.  在這之后 openssl 將會dlopen將qat.so動態加載進應用程序. 

至此應用程序便可以通過intel的qat卡進行加解密加速操作了. 不需要任何額外修改(但是並不能獲得最佳性能,最大效率)。

 

qatdriver

(由於時間關系, 該小節內容的理解可能不准確並且包含錯誤)

1.  從功能上,

QAT提供加解密與壓縮解壓功能, 其中加解密包含對稱與非對稱兩類, QAT卡的優勢主要體現在非對稱加密上.

2.  從結構上,

每張QAT卡包含32個獨立的BANK, 每個BANK最多支持配置2個加解密或壓縮服務. 在BANK的上一層是instance,  大概bank數乘2就是instance總數,

根據配置不同,如果poll, epoll以及功能選擇是加解密還是壓縮, instance的總數上限也有所不同,. 詳見文檔<<Programmer's Guide>> (另外,我也沒太搞懂.

3. 從代碼上, 

可以分為三塊,兩個內核模塊, 一個用戶態模塊.  因為QAT卡要支持用戶態使用同樣也要支持kernel里的加解密框架使用, 所以各有一個模塊,  剩下的一個內核模塊

是用來分配連續物理內存的. 用戶態的模塊使用UIO與連續內存直接與硬件通信, 繞過了內核訪問的開銷.

 

qatengine

如前所述, qatengine的主要作用是將“加解密操作的輸入輸出數據”在用戶應用程序與硬件卡之間進行傳遞, 主要操作就是IO的讀寫.

然后我們回顧這個模型, 在IO的寫入與讀取之間有一點時間的等待(我們也叫它IO阻塞,或者同步IO), 等待硬件卡完成操作, 這個等待與通知的處理過程, qatengine將其封裝為如下幾種方式.

(那是因為,qat卡是沒有通知機制的(對比其他硬件就有通知機制,比如網卡硬中斷。另外我也不太肯定qat卡是不是真的不能中斷。但是我們假設它沒有中斷並無大礙,因為我要引出的內容

是這個假裝之后的一個推論),但是被Engine封裝之后就有了通知。是因為它用輪訓的方式偽裝成了通知。輪休發現硬件卡計算完成時,寫一個eventfd形成通知機制。下面提到的這四個方式,

指的就是這個輪休方式。)

ENABLE_INLINE_POLLING

SET_INTERNAL_POLL_INTERVAL

ENABLE_EXTERNAL_POLLING 

ENABLE_HEURISTIC_POLLING

參考文檔:

https://github.com/intel/asynch_mode_nginx#support-for-nginx-side-polling

 代碼: 

https://github.com/intel/asynch_mode_nginx/blob/master/modules/nginx_qat_module/ngx_ssl_engine_qat_module.c::ngx_ssl_engine_qat_send_ctrl()

https://github.com/intel/QAT_Engine/blob/master/e_qat.c::qat_cmd_defns[]

 

代碼中有四種poll方式, 文檔中只推薦了externel和heuristic兩種, 這兩張都是基於timer的poll。下面我要提到的是另一種,比較特殊的inline poll模式,ENABLE_INLINE_POLLING。

這種模式,是單獨啟動一個polling線程進行輪訓的,他的特殊在於這里邊可能會有一些多線程同步讀寫的問題,不再展開。

引出了另一個我懷疑它可能存在的bug。提交在了issue里,地址如下:https://github.com/intel/QAT_Engine/issues/178 

 

性能

使用qat卡的本質需求是性能, 是解放CPU, 讓一部分原本由CPU進行的計算轉移到qat卡上進行, 在這段時間內CPU可以用來進行其他的計算工作.

所以硬件只是基礎, 提高QAT的利用率, 降低CPU的切換開銷和等待時間是性能最大化的核心工作.

這個問題, 有兩個層面.

1 多個SSL連接的並行.

對qat卡的寫->讀操作被封裝在了SSL的read或write的API內, 於是SSL的qat IO就變成了阻塞IO,  可以使用epoll將該IO變成異步IO, 主要這里epoll的是qat的fd, 與網絡socket的fd是不同的.

需要區分理解, 要想將SSL的接口變成徹底的IO異步的需要epoll socket fd的同時也epoll qat的fd. 如下圖所示:

    

 

 

 

 

 

2 單SSL連接內多個加解密操作之間的並行. 

 這部分的細節討論詳見: [openssl] openssl async模塊框架分析

 

------

第一部分完

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM