FreeBSD 上的 nginx kTLS 支持

• 本文约 832 字,阅读大致需要 2 分钟 | Security | #SSL | #OpenSSL | #FreeBSD | #kTLS | #nginx | #Performance | #Networking | #TLS

昨天,FreeBSD 13.2正式发布了kTLS 是在FreeBSD 13.0中由Netflix赞助的新功能,过去,TLS/SSL应用程序对于通讯内容的加解密通常是在用户态进行的,这样一来,系统在读取出数据和发出数据之前需要进行额外的上下文切换,并在内核和用户地址空间之间来回复制缓冲区来满足加解密的需要。有了kTLS之后,内核可以在 sendfile(2) 时直接在内核上下文中完成加密和填充到网络协议栈的操作,从而减少了上下文切换和不必要的复制操作。

在进行加密和解密操作时,kTLS假定内核有直接映射 (direct map) 支持。在这些平台中,内核直接将物理内存全部「直接」映射到内核地址空间,这样一来,在内核需要访问某一物理地址时,其 pmap_map 实现便完全无需操作页表,因此可以大幅提高性能。FreeBSD支持的主流64位平台均支持这一特性(参见平台对应的pmap_map实现)。

FreeBSD附带的OpenSSL在arm64/aarch64和amd64/amd64平台上默认启用了 WITH_OPENSSL_KTLS,无需重新编译即可使用。

整体上,FreeBSD的kTLS提供了三种模式:软件(software),网卡(ifnet) 和TOE。软件模式中,kTLS会使用软件加密(这包括加速指令如AES-NI,也包括协处理器如 qat(4) 等等)在socket缓冲区层进行加解密。网卡ifnet模式中,加解密操作是由网卡完成的,一些比较贵的网卡,如 mlx5en(4)cxgbe(4) T6上集成了相关功能,其中前者同时支持发送和接收。而TOE(TCP卸载引擎,由网卡完成完整的TCP/IP操作)模式中,网卡除了完成加解密之外也负责TCP。

我个人的网站使用了AES256-GCM,在FreeBSD 13.2中加入了收发的支持,因此这次升级完系统之后打算试一试。由于我没有使用高端的网卡,加上这个网站反正流量也不大,因此我使用软件模式,首先是加载 ktls_ocf 内核模块:

kldload ktls_ocf

/etc/rc.conf 中加入: kld_list="ktls_ocf" 令下次启动时也启用它。

此处 ocf 是指内核的OpenCrypto Framework,它会自行决定是否使用类似aesni这样的加速机制。

然后是启用kTLS支持:

echo "kern.ipc.tls.enable=1" >> /etc/sysctl.conf
service sysctl start

接下来是告诉nginx可以用kTLS了。在nginx配置中的server小节中添加:

ssl_conf_command Options KTLS;

然后重启nginx。此后,在 sysctl kern.ipc.tls.stats 中可以观察到由OCF完成的加密解密。