核心 TLS 解除安裝

核心 TLS 操作

Linux 核心提供 TLS 連線解除安裝基礎設施。一旦 TCP 連線處於 ESTABLISHED 狀態,使用者空間就可以啟用 TLS 上層協議 (ULP) 並安裝加密連線狀態。有關使用者介面介面的詳細資訊,請參閱 Documentation/networking/tls.rst 中的 TLS 文件。

ktls 可以以三種模式執行

  • 軟體加密模式 (TLS_SW) - CPU 處理加密。在最基本的情況下,只能使用與 CPU 同步的加密操作,但根據呼叫上下文,CPU 可能會利用非同步加密加速器。加速器的使用會增加套接字讀取時的額外延遲(解密僅在發出讀取系統呼叫時開始)以及系統上的額外 I/O 負載。

  • 基於包的 NIC 解除安裝模式 (TLS_HW) - NIC 以逐包方式處理加密,前提是包按順序到達。此模式與核心堆疊整合最佳,並在此文件的剩餘部分詳細描述(ethtool 標誌 tls-hw-tx-offloadtls-hw-rx-offload)。

  • 完整 TCP NIC 解除安裝模式 (TLS_HW_RECORD) - NIC 驅動程式和韌體用自己的 TCP 處理取代核心網路堆疊的操作模式,它不適用於利用 Linux 網路堆疊的生產環境,例如任何防火牆功能或 QoS 和包排程(ethtool 標誌 tls-hw-record)。

操作模式根據裝置配置自動選擇,目前不支援按連線選擇性解除安裝或不解除安裝。

TX

從高層次來看,使用者寫入請求被轉換為分散列表,TLS ULP 攔截它們,插入記錄幀,執行加密(在 TLS_SW 模式下),然後將修改後的分散列表交給 TCP 層。從這一點開始,TCP 堆疊正常進行。

TLS_HW 模式下,加密不在 TLS ULP 中執行。相反,資料包到達裝置驅動程式,驅動程式將根據資料包附加到的套接字標記資料包進行加密解除安裝,並將其傳送到裝置進行加密和傳輸。

RX

在接收端,如果裝置成功處理瞭解密和認證,驅動程式將在相關的 struct sk_buff 中設定解密位。資料包到達 TCP 堆疊並正常處理。ktls 在資料排隊到套接字時得到通知,並使用 strparser 機制來劃分記錄。在讀取請求時,從套接字檢索記錄並傳遞給解密例程。如果裝置解密了記錄的所有分段,則跳過解密,否則軟體路徑處理解密。

TLS offload layers

核心 TLS 堆疊層

裝置配置

在驅動程式初始化期間,裝置設定 NETIF_F_HW_TLS_RXNETIF_F_HW_TLS_TX 特性,並在 struct net_devicetlsdev_ops 成員中安裝其 struct tlsdev_ops 指標。

當 TLS 加密連線狀態安裝在 ktls 套接字上時(請注意,它被執行兩次,一次用於 RX 方向,一次用於 TX 方向,兩者完全獨立),核心會檢查底層網路裝置是否支援解除安裝並嘗試解除安裝。如果解除安裝失敗,連線將完全透過軟體處理,機制與從未嘗試解除安裝的情況相同。

解除安裝請求透過 struct tlsdev_opstls_dev_add 回撥函式執行

int (*tls_dev_add)(struct net_device *netdev, struct sock *sk,
                   enum tls_offload_ctx_dir direction,
                   struct tls_crypto_info *crypto_info,
                   u32 start_offload_tcp_sn);

direction 指示加密資訊是用於接收還是傳輸的資料包。驅動程式使用 sk 引數檢索連線的五元組和套接字族(IPv4 或 IPv6)。crypto_info 中的加密資訊包括金鑰、IV、鹽以及 TLS 記錄序列號。start_offload_tcp_sn 指示哪個 TCP 序列號對應於序列號來自 crypto_info 的記錄的開始。驅動程式可以在核心結構體的末尾新增其狀態(參見 include/net/tls.h 中的 driver_state 成員)以避免額外的記憶體分配和指標解引用。

TX

安裝 TX 狀態後,堆疊保證流的第一個段將從 start_offload_tcp_sn 序列號開始,從而簡化 TCP 序列號匹配。

TX 解除安裝完全初始化並不意味著所有透過驅動程式並屬於解除安裝套接字的段都將在預期序列號之後,並且具有核心記錄資訊。特別是,已加密的資料可能在核心中安裝連線狀態之前已排隊到套接字。

RX

在 RX 方向,本地網路堆疊對分段的控制很少,因此初始記錄的 TCP 序列號可能位於分段的任何位置。

正常操作

裝置至少為每個連線在每個方向上維護以下狀態

  • 加密金鑰 (key, iv, salt)

  • 加密處理狀態(部分塊,部分認證標籤等)

  • 記錄元資料(序列號、處理偏移量和長度)

  • 預期 TCP 序列號

對記錄長度或記錄分段沒有保證。特別是,分段可能在記錄的任何點開始,幷包含任意數量的記錄。假設分段按順序接收,裝置應該能夠執行加密操作和認證,無論分段如何。為了實現這一點,裝置必須保留少量分段到分段的狀態。這至少包括

  • 部分報頭(如果分段僅攜帶了 TLS 報頭的一部分)

  • 部分資料塊

  • 部分認證標籤(所有資料都已看到,但部分認證標籤必須寫入或從後續分段讀取)

TLS 解除安裝不需要記錄重組。如果資料包按順序到達,裝置應該能夠單獨處理它們並向前推進。

TX

核心堆疊執行記錄成幀,保留認證標籤的空間,並填充所有其他 TLS 報頭和尾部欄位。

由於可能存在重傳以及資料包到達裝置後缺乏軟體回退機制,裝置和驅動程式都維護預期的 TCP 序列號。對於按順序傳遞的分段,驅動程式使用連線識別符號標記資料包(請注意,五元組查詢不足以識別需要硬體解除安裝的資料包,請參閱五元組匹配限制部分),並將其交給裝置。裝置將資料包識別為需要 TLS 處理,並確認序列號與預期匹配。裝置執行記錄資料的加密和認證。它用正確的值替換認證標籤和 TCP 校驗和。

RX

在資料包 DMA 到主機之前(但在 NIC 的嵌入式交換和資料包轉換功能之後),裝置驗證第 4 層校驗和並執行五元組查詢,以查詢資料包可能屬於的任何 TLS 連線(技術上,四元組查詢就足夠了——IP 地址和 TCP 埠號,因為協議始終是 TCP)。如果資料包與某個連線匹配,裝置會確認 TCP 序列號是否為預期值,然後繼續進行 TLS 處理(記錄劃分、解密、資料包中每個記錄的認證)。裝置保持記錄幀不變,堆疊負責記錄解封裝。裝置在傳遞給主機的每包上下文(描述符)中指示 TLS 解除安裝的成功處理。

接收到 TLS 解除安裝的資料包後,驅動程式在對應於分段的 struct sk_buff 中設定 decrypted 標記。網路堆疊確保解密和未解密的分段不會合並(例如,透過 GRO 或套接字層),並處理部分解密。

重新同步處理

在存在資料包丟失或網路資料包重排序的情況下,裝置可能會失去與 TLS 流的同步,並需要與核心的 TCP 堆疊重新同步。

請注意,重新同步僅針對已成功新增到裝置表且處於 TLS_HW 模式的連線進行嘗試。例如,如果在核心中安裝加密狀態時表已滿,則此類連線將永遠不會被解除安裝。因此,重新同步請求不攜帶任何加密連線狀態。

TX

從解除安裝套接字傳輸的分段可能會以與接收側重傳類似的方式不同步——可能發生本地丟包,儘管不會發生網路重排序。目前有兩種機制來處理亂序分段。

加密狀態重建

每當亂序分段被傳輸時,驅動程式都會向裝置提供足夠的資訊來執行加密操作。這很可能意味著記錄中當前分段之前的部分必須作為資料包上下文的一部分傳遞給裝置,連同其 TCP 序列號和 TLS 記錄號。然後裝置可以初始化其加密狀態,處理並丟棄先前的資料(以便能夠插入認證標籤),然後繼續處理實際資料包。

在此模式下,根據實現的不同,驅動程式可以要求使用加密狀態和新序列號繼續(下一個預期段是亂序段之後的那個),或者繼續使用先前的流狀態——假設亂序段只是一個重傳。前者更簡單,並且不需要重傳檢測,因此在證明其效率低下之前,它是推薦的方法。

下一個記錄同步

每當檢測到亂序分段時,驅動程式會請求 ktls 軟體回退程式碼對其進行加密。如果分段的序列號低於預期,驅動程式假定是重傳,並且不更改裝置狀態。如果分段是未來的,這可能意味著本地丟包,驅動程式要求堆疊將裝置同步到下一個記錄狀態並回退到軟體。

重新同步請求透過以下方式指示

void tls_offload_tx_resync_request(struct sock *sk, u32 got_seq, u32 exp_seq)

在重新同步完成之前,驅動程式不應訪問其預期的 TCP 序列號(因為它將從不同的上下文中更新)。應使用以下輔助函式來測試重新同步是否完成

bool tls_offload_tx_resync_pending(struct sock *sk)

下一次 ktls 推送記錄時,它會首先將其 TCP 序列號和 TLS 記錄號傳送給驅動程式。堆疊還將確保新記錄將在分段邊界處開始(就像連線最初新增時一樣)。

RX

少量 RX 重排序事件可能不需要完全重新同步。特別是,當記錄邊界可以恢復時,裝置不應失去同步

reorder of non-header segment

非報頭分段的重排序

綠色分段已成功解密,藍色分段按線速接收,紅色條紋標記新記錄的開始。

在上述情況下,分段 1 被成功接收和解密。分段 2 被丟棄,因此分段 3 亂序到達。裝置根據分段 1 中的記錄長度知道下一個記錄從分段 3 內部開始。分段 3 未經觸動地傳遞,因為由於缺少分段 2 的資料,分段 3 中先前記錄的剩餘部分無法處理。然而,裝置可以從分段 3 中新記錄收集認證演算法的狀態和部分塊,當分段 4 和 5 到達時繼續解密。最後,當分段 2 到達時,它完全超出了裝置的預期視窗,因此它按原樣傳遞,沒有特殊處理。ktls 軟體回退處理跨越分段 1、2 和 3 的記錄的解密。即使有兩個分段未解密,裝置也沒有失去同步。

如果丟失的分段包含記錄頭,並且在下一個記錄頭已經透過之後到達,則可能需要核心同步

reorder of header segment

包含 TLS 報頭的分段的重排序

在此示例中,分段 2 被丟棄,並且它包含一個記錄頭。裝置只有在知道分段 2 中先前記錄的長度後,才能檢測到分段 4 也包含 TLS 頭。在這種情況下,裝置將失去與流的同步。

流掃描重新同步

當裝置失去同步,且流的 TCP 序列號超過預期 TCP 序列號最大記錄大小後,裝置開始掃描已知報頭模式。例如,對於 TLS 1.2 和 TLS 1.3,值 0x03 0x03 的後續位元組出現在報頭的 SSL/TLS 版本欄位中。一旦模式匹配,裝置繼續嘗試在預期位置(根據猜測位置的長度欄位)解析報頭。每當預期位置不包含有效報頭時,掃描就會重新開始。

當報頭匹配時,裝置向核心傳送確認請求,詢問猜測的位置是否正確(如果 TLS 記錄確實從那裡開始),以及給定報頭是哪個記錄序列號。核心確認猜測的位置正確,並告訴裝置記錄序列號。同時,裝置一直在解析和計數自剛剛確認的記錄以來的所有記錄,它將其看到的記錄數量新增到核心提供的記錄號。此時,裝置處於同步狀態,可以在下一個分段邊界恢復解密。

在病態情況下,裝置可能會鎖定一系列匹配的報頭,並且永遠不會收到核心的回覆(核心沒有否定確認)。實現可以選擇定期重新啟動掃描。然而,考慮到錯誤匹配流的可能性極低,定期重新啟動被認為沒有必要。

如果確認請求非同步傳遞到資料包流,並且記錄可能在確認請求之前由核心處理,則必須特別小心。

堆疊驅動的重新同步

驅動程式也可以在發現記錄不再被解密時,請求堆疊執行重新同步。如果連線配置為這種模式,堆疊會在收到兩個完全加密的記錄後自動排程重新同步。

堆疊等待套接字清空,並通知裝置下一個預期記錄號及其 TCP 序列號。如果記錄繼續以完全加密的方式接收,堆疊會以指數退避的方式重試同步(第一次在 2 個加密記錄後,然後是 4 個記錄後,8 個,16 個... 直到每 128 個記錄)。

錯誤處理

TX

資料包可能會被堆疊重定向或重新路由到非選定的 TLS 解除安裝裝置。堆疊將使用 sk_validate_xmit_skb() 輔助函式處理這種情況(TLS 解除安裝程式碼在此鉤子安裝 tls_validate_xmit_skb())。解除安裝維護所有記錄的資訊,直到資料完全被確認,因此如果 skbs 到達錯誤的裝置,它們可以透過軟體回退處理。

傳輸側任何裝置 TLS 解除安裝處理錯誤都必須導致資料包被丟棄。例如,如果資料包由於堆疊或裝置中的錯誤而亂序,到達裝置且無法加密,則此類資料包必須被丟棄。

RX

如果裝置在接收端遇到任何 TLS 解除安裝問題,它應將資料包按線速接收時的狀態傳遞給主機的網路堆疊。

例如,分段中任何記錄的認證失敗都應導致將未修改的資料包傳遞給軟體回退。這意味著資料包不應“就地”修改。不建議拆分分段以處理部分解密。換句話說,要麼資料包中所有記錄都已成功處理並認證,要麼資料包必須按線速狀態傳遞給主機堆疊(如果裝置提供精確錯誤,在驅動程式中恢復原始資料包就足夠了)。

Linux 網路堆疊不提供報告每包解密和認證錯誤的方法,有錯誤的資料包不得設定 decrypted 標記。

如果資料包包含不正確的校驗和,也不應由 TLS 解除安裝處理。

效能指標

TLS 解除安裝可以透過以下基本指標來表徵

  • 最大連線數

  • 連線安裝速率

  • 連線安裝延遲

  • 總加密效能

請注意,每個 TCP 連線在兩個方向都需要一個 TLS 會話,效能可以分別報告每個方向。

最大連線數

裝置可支援的連線數可透過 devlink resource API 暴露。

總加密效能

解除安裝效能可能取決於分段和記錄大小。

裝置加密子系統的過載不應對未解除安裝的流產生顯著效能影響。

統計資料

驅動程式應報告以下最基本的 TLS 相關統計資訊

  • rx_tls_decrypted_packets - 成功解密的屬於 TLS 流的 RX 資料包數量。

  • rx_tls_decrypted_bytes - 成功解密的 RX 資料包中 TLS 載荷位元組數。

  • rx_tls_ctx - 新增到裝置用於解密的 TLS RX 硬體解除安裝上下文數量。

  • rx_tls_del - 從裝置刪除的 TLS RX 硬體解除安裝上下文數量(連線已完成)。

  • rx_tls_resync_req_pkt - 收到包含重新同步請求的 TLS 資料包數量。

    請求。

  • rx_tls_resync_req_start - TLS 非同步重新同步請求啟動的次數。

    已啟動。

  • rx_tls_resync_req_end - TLS 非同步重新同步請求正確結束並提供了硬體跟蹤的 tcp-seq 的次數。

    正確結束並提供了硬體跟蹤的 tcp-seq。

  • rx_tls_resync_req_skip - TLS 非同步重新同步請求過程已啟動但未正確結束的次數。

    過程已啟動但未正確結束。

  • rx_tls_resync_res_ok - TLS 重新同步響應呼叫到驅動程式已成功處理的次數。

    驅動程式已成功處理。

  • rx_tls_resync_res_skip - TLS 重新同步響應呼叫到驅動程式已非成功終止的次數。

    驅動程式已非成功終止。

  • rx_tls_err - 屬於 TLS 流但由於狀態機中發生意外錯誤而未解密的 RX 資料包數量。

  • tx_tls_encrypted_packets - 傳遞給裝置進行 TLS 載荷加密的 TX 資料包數量。

  • tx_tls_encrypted_bytes - 傳遞給裝置進行加密的 TX 資料包中 TLS 載荷位元組數。

  • tx_tls_ctx - 新增到裝置用於加密的 TLS TX 硬體解除安裝上下文數量。

  • tx_tls_ooo - 屬於 TLS 流但未按預期順序到達的 TX 資料包數量。

  • tx_tls_skip_no_sync_data - 屬於 TLS 流且亂序到達,但跳過硬體解除安裝例程並進入常規傳輸流的 TX 資料包數量,因為它們是連線握手的重傳。

  • tx_tls_drop_no_sync_data - 屬於 TLS 流的 TX 資料包數量,由於亂序到達且無法找到相關記錄而被丟棄。

  • tx_tls_drop_bypass_req - 屬於 TLS 流的 TX 資料包數量,由於既包含軟體加密的資料又包含期望硬體加密解除安裝的資料而被丟棄。

值得注意的特殊情況、異常和附加要求

五元組匹配限制

裝置只能根據套接字的五元組識別接收到的資料包。當前的 ktls 實現不會解除安裝透過隧道或虛擬網路等軟體介面路由的套接字。然而,網路堆疊執行的許多資料包轉換(最值得注意的是任何 BPF 邏輯)不需要任何中間軟體裝置,因此五元組匹配可能在裝置級別始終丟失。在這種情況下,裝置仍應能夠執行 TX 解除安裝(加密),並且應乾淨地回退到軟體解密(RX)。

亂序

在 NIC 中引入額外的處理不應導致資料包傳輸或接收亂序,例如純 ACK 資料包不應相對於資料段進行重排序。

入口重排序

裝置允許對連續的 TCP 分段進行資料包重排序(即按正確順序放置資料包),但禁止任何形式的額外緩衝。

與標準網路解除安裝功能的共存

解除安裝的 ktls 套接字應透明地支援標準 TCP 堆疊功能。啟用裝置 TLS 解除安裝不應導致線路上看到的資料包有任何差異。

傳輸層透明性

為了簡化 TLS 解除安裝,裝置不應修改任何資料包報頭。

裝置不應依賴於 TLS 解除安裝嚴格必要之外的任何資料包報頭。

分段丟失

僅在發生災難性系統錯誤時才允許丟棄資料包,並且絕不能將其用作正常操作中出現的錯誤的處理機制。換句話說,依賴 TCP 重傳來處理特殊情況是不可接受的。

TLS 裝置特性

驅動程式應忽略 TLS 裝置特性標誌的更改。這些標誌將由核心 ktls 程式碼相應地處理。TLS 裝置特性標誌只控制新 TLS 連線解除安裝的新增,舊連線在標誌被清除後仍將保持活動。

沒有校驗和計算解除安裝的裝置不能解除安裝 TLS 加密。因此,TLS TX 裝置特性標誌要求設定 TX 校驗和解除安裝。停用後者意味著清除前者。停用 TX 校驗和解除安裝不應影響舊連線,驅動程式應確保其校驗和計算不會中斷。類似地,裝置解除安裝的 TLS 解密意味著執行 RXCSUM。如果使用者不想啟用 RX 校驗和解除安裝,TLS RX 裝置特性也會被停用。