XFRM 裝置 - 解除安裝 IPsec 計算

Shannon Nelson <shannon.nelson@oracle.com> Leon Romanovsky <leonro@nvidia.com>

概述

IPsec 是保護網路流量的有用功能,但計算成本很高:根據流量和連結配置,一個 10Gbps 的連結很容易降至 1Gbps 以下。幸運的是,有些網絡卡提供基於硬體的 IPsec 解除安裝,可以極大地提高吞吐量並降低 CPU 利用率。XFRM 裝置介面允許網絡卡驅動程式向協議棧提供對硬體解除安裝的訪問。

目前,核心支援兩種型別的硬體解除安裝。
  • IPsec 加密解除安裝: * 網絡卡執行加密/解密 * 核心執行其他所有操作

  • IPsec 資料包解除安裝: * 網絡卡執行加密/解密 * 網絡卡執行封裝 * 核心和網絡卡具有同步的 SA 和策略 * 網絡卡處理 SA 和策略狀態 * 核心與金鑰管理器通訊

使用者空間對解除安裝的訪問通常透過諸如 libreswan 或 KAME/raccoon 之類的系統,但是 iproute2 ‘ip xfrm’ 命令集在實驗時非常方便。以下是一個加密解除安裝的示例命令:

ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport

reqid 0x07 replay-window 32 aead ‘rfc4106(gcm(aes))’ 0x44434241343332312423222114131211f4f3f2f1 128 sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp offload dev eth4 dir in

以及資料包解除安裝:

ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport

reqid 0x07 replay-window 32 aead ‘rfc4106(gcm(aes))’ 0x44434241343332312423222114131211f4f3f2f1 128 sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp offload packet dev eth4 dir in

ip x p add src 14.0.0.70 dst 14.0.0.52 offload packet dev eth4 dir in tmpl src 14.0.0.70 dst 14.0.0.52 proto esp reqid 10000 mode transport

是的,這很醜陋,但這就是 shell 指令碼和/或 libreswan 的用途。

要實現的的回撥

/* from include/linux/netdevice.h */
struct xfrmdev_ops {
      /* Crypto and Packet offload callbacks */
      int     (*xdo_dev_state_add)(struct net_device *dev,
                                   struct xfrm_state *x,
                                   struct netlink_ext_ack *extack);
      void    (*xdo_dev_state_delete)(struct net_device *dev,
                                      struct xfrm_state *x);
      void    (*xdo_dev_state_free)(struct net_device *dev,
                                    struct xfrm_state *x);
      bool    (*xdo_dev_offload_ok) (struct sk_buff *skb,
                                     struct xfrm_state *x);
      void    (*xdo_dev_state_advance_esn) (struct xfrm_state *x);
      void    (*xdo_dev_state_update_stats) (struct xfrm_state *x);

      /* Solely packet offload callbacks */
      int     (*xdo_dev_policy_add) (struct xfrm_policy *x, struct netlink_ext_ack *extack);
      void    (*xdo_dev_policy_delete) (struct xfrm_policy *x);
      void    (*xdo_dev_policy_free) (struct xfrm_policy *x);
};

提供 ipsec 解除安裝的網絡卡驅動程式將需要實現與支援的解除安裝相關的回撥,以使解除安裝可用於網路棧的 XFRM 子系統。此外,特徵位 NETIF_F_HW_ESP 和 NETIF_F_HW_ESP_TX_CSUM 將表明解除安裝的可用性。

流程

在探測時以及呼叫 register_netdev() 之前,驅動程式應設定本地資料結構和 XFRM 回撥,並設定特徵位。XFRM 程式碼的偵聽器將在 NETDEV_REGISTER 上完成設定。

adapter->netdev->xfrmdev_ops = &ixgbe_xfrmdev_ops;
adapter->netdev->features |= NETIF_F_HW_ESP;
adapter->netdev->hw_enc_features |= NETIF_F_HW_ESP;

當使用“offload”特性請求設定新的 SA 時,驅動程式的 xdo_dev_state_add() 將被賦予要解除安裝的新 SA,並指示它是用於 Rx 還是 Tx。 驅動程式應該:

  • 驗證演算法是否支援解除安裝

  • 儲存 SA 資訊(金鑰、salt、目標 IP、協議等)

  • 啟用 SA 的 HW 解除安裝

  • 返回狀態值

    0

    成功

    -EOPNETSUPP

    不支援解除安裝,請嘗試 SW IPsec,不適用於資料包解除安裝模式

    其他

    請求失敗

驅動程式還可以在 SA 中設定一個 offload_handle,這是一個不透明的 void 指標,可用於將上下文傳遞到快速路徑解除安裝請求中

xs->xso.offload_handle = context;

當網路棧為已設定為解除安裝的 SA 準備 IPsec 資料包時,它首先使用 skb 和預期的解除安裝狀態呼叫 xdo_dev_offload_ok(),以詢問驅動程式解除安裝是否可用。這可以檢查資料包資訊以確保可以支援解除安裝(例如,IPv4 或 IPv6,沒有 IPv4 選項等),並返回 true 或 false 來表示其支援。如果驅動程式未實現此回撥,則協議棧會提供合理的預設值。

加密解除安裝模式:準備好傳送時,驅動程式需要檢查 Tx 資料包的解除安裝資訊,包括不透明的上下文,並相應地設定資料包傳送。

xs = xfrm_input_state(skb);
context = xs->xso.offload_handle;
set up HW for send

協議棧已將適當的 IPsec 標頭插入資料包資料中,解除安裝只需進行加密並修復標頭值即可。

當收到資料包並且 HW 指示已解除安裝解密時,驅動程式需要在資料包的 skb 中新增對解碼的 SA 的引用。 此時,資料應該被解密,但 IPsec 標頭仍在資料包資料中;它們稍後在 xfrm_input() 中被從協議棧中移除。

查詢並持有用於 Rx skb 的 SA

get spi, protocol, and destination IP from packet headers
xs = find xs from (spi, protocol, dest_IP)
xfrm_state_hold(xs);

將狀態資訊儲存到 skb 中

sp = secpath_set(skb);
if (!sp) return;
sp->xvec[sp->len++] = xs;
sp->olen++;

指示解除安裝的成功和/或錯誤狀態

xo = xfrm_offload(skb);
xo->flags = CRYPTO_DONE;
xo->status = crypto_status;

像往常一樣將資料包傳遞給 napi_gro_receive()

在 ESN 模式下,從 xfrm_replay_advance_esn() 為 RX 呼叫 xdo_dev_state_advance_esn(),為 TX 呼叫 xfrm_replay_overflow_offload_esn。 驅動程式將檢查資料包序列號,並在需要時更新 HW ESN 狀態機。

資料包解除安裝模式:HW 新增和刪除 XFRM 標頭。 因此,在 RX 路徑中,如果 HW 報告成功,則繞過 XFRM 協議棧。 在 TX 路徑中,資料包離開核心時沒有額外的標頭並且未加密,HW 負責執行此操作。

當用戶刪除 SA 時,驅動程式的 xdo_dev_state_delete() 和 xdo_dev_policy_delete() 被要求停用解除安裝。 稍後,在刪除對狀態和策略的所有引用計數後,以及可以清除任何剩餘資源以進行解除安裝狀態後,從垃圾收集例程中呼叫 xdo_dev_state_free() 和 xdo_dev_policy_free()。 驅動程式如何使用這些將取決於特定的硬體需求。

當 netdev 設定為 DOWN 時,XFRM 協議棧的 netdev 偵聽器將對任何剩餘的解除安裝狀態呼叫 xdo_dev_state_delete()、xdo_dev_policy_delete()、xdo_dev_state_free() 和 xdo_dev_policy_free()。

HW 處理資料包的結果是,XFRM 核心無法計算硬限制、軟限制。 HW/驅動程式負責執行此操作,並在呼叫 xdo_dev_state_update_stats() 時提供準確的資料。 如果發生其中一個限制,驅動程式需要呼叫 xfrm_state_check_expire() 以確保 XFRM 執行重新金鑰序列。