0%

周谈(58)- 内核IPSec丢包问题

前言

不知道什么情况,最近支持的客户越来越多了。前人欠的债,后人帮忙还。

最近有个客户使用了公司的产品,通过strongSwan配置了IPSec通路,使用了内核的xfrm框架实现数据包的加解密。为了提升吞吐量,需要使用到内置密码引擎功能。

然后在使用iperf进行流量测试时,发现存在丢包的问题。反馈到了技术支持,最终落到了我的头上。

这个驱动是历史产物了,也算是公司第一代的产品。一直也没有什么客户在用,也就一直没有收到市场的问题,给人一种产品很好的错觉。领导也经常引以为傲哈。

但实际情况是我已经填了不下10个坑。

问题现象

客户使用strongSwan搭建了IPsec环境,并使用iperf进行带宽测试,收发两端都使用我司产品,加载了密码引擎驱动。配置IPsec策略使用cbc(sm4)加密,hmac(sm3)做认证。现象:
1.单向发送iperf流量时,iperf计数正常,几乎不丢包。
2.单向发送iper流量,同时反向使用ping包,iperf出现丢包。

问题复现

报案了,咱们开始破案吧。首先,还原现场,根据客户描述搭建环境。

问题在于我对业务不熟悉,也就是不知道怎么搭建这个IPSec环境。利用之前的经验,使用ip xfrm命令配置了静态的环境,可就是死活配置不了那个sm4算法。

1
2
3
~ # ip xfrm state add src 192.168.0.1 dst 192.168.0.2 proto esp spi 0x00000301 mode tunnel auth sm3 0x96358c90783bbfa3d7b196ceabe0536b enc sm4 0xf6ddb555acfd9d77b03ea3843f2653255afe8eb5573965df
RTNETLINK answers: Invalid argument

这个ip xfrm的提示很明显了,我愣是没看出啥问题,参数太多了。

只能先凑合着用hmac(sm3)+cbc(des3_ede)。主要命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
=====================sm3 + cbc(des3_ede) ============================
PC1: //192.168.0.1
ip xfrm state add src 192.168.0.1 dst 192.168.0.2 proto esp spi 0x00000301 mode tunnel auth sm3 0x96358c90783bbfa3d7b196ceabe0536b enc sm4 0xf6ddb555acfd9d77b03ea3843f2653255afe8eb5573965df
ip xfrm state add src 192.168.0.2 dst 192.168.0.1 proto esp spi 0x00000302 mode tunnel auth sm3 0x99358c90783bbfa3d7b196ceabe0536b enc des3_ede 0xffddb555acfd9d77b03ea3843f2653255afe8eb5573965df

ip xfrm policy add src 192.168.0.1 dst 192.168.0.2 dir out ptype main tmpl src 192.168.0.1 dst 192.168.0.2 proto esp mode tunnel
ip xfrm policy add src 192.168.0.2 dst 192.168.0.1 dir in ptype main tmpl src 192.168.0.2 dst 192.168.0.1 proto esp mode tunnel

PC2:// 192.168.0.2
ip xfrm state add src 192.168.0.1 dst 192.168.0.2 proto esp spi 0x00000301 mode tunnel auth sm3 0x96358c90783bbfa3d7b196ceabe0536b enc des3_ede 0xf6ddb555acfd9d77b03ea3843f2653255afe8eb5573965df
ip xfrm state add src 192.168.0.2 dst 192.168.0.1 proto esp spi 0x00000302 mode tunnel auth sm3 0x99358c90783bbfa3d7b196ceabe0536b enc des3_ede 0xffddb555acfd9d77b03ea3843f2653255afe8eb5573965df

ip xfrm policy add src 192.168.0.1 dst 192.168.0.2 dir in ptype main tmpl src 192.168.0.1 dst 192.168.0.2 proto esp mode tunnel
ip xfrm policy add src 192.168.0.2 dst 192.168.0.1 dir out ptype main tmpl src 192.168.0.2 dst 192.168.0.1 proto esp mode tunnel

# 删除xfrm配置的命令
ip xfrm state deleteall
ip xfrm policy deleteall

iperf3 -c 192.168.0.2 -u -i 10 -t 20 -b 300M -l 1024

# 查看配置
ip xfrm state
ip xfrm policy

自测时发现是存在少量的丢包,但是也没有客户反馈的那么严重。

问题定位

  1. 同时客户还反馈使用内核自带的软算法没有问题。基本可以确认就是驱动的问题了。

  2. 根据描述的场景,考虑可能存在多线程加解密。所以我就增加了多线程同时进行加解密的操作的测试,每个线程分别进行计算,结果和软算法进行比较,结果都正确,没有发现问题。

  3. 继续分析代码,把代码中可能存在脏值的内存都清零了,继续测试,问题现象依然存在。

  4. 给力的客户,也同时在分析我们的代码进行测试,通过对sm3算法处理逻辑加锁,发现丢包的数目减少了

  5. 大概判断是多线程处理导致的问题,最大的可能就是共用了临界区,但是保护措施还是不到位。

  6. 确认现场配置使用的是同一条IPSec策略,在本地配置了sm3+des3的IPSec环境,在sm3的加密函数中添加WARN_ON查看调用栈:

perf

根据调用栈,分析esp_input函数中的加密部分代码,发现使用的aead算法,是由authenc模板组合而来。

联想使用的是同一个xfrm_state,不同报文加解密会使用不同的req,但是算法实例上下文是同一个。

  1. 考虑到内核加密是一个通过的框架,只需要对比一下和其他驱动差异,基本就确认了原因是由于驱动不支持多个请求共用同一个算法上下文。

问题修改

参照着其他驱动,同步修改一下sm3和sm4的代码,本地验证sm3是没问题了,同步代码给客户验证, 问题完美解决。

哈希使用的是 struct shash_alg同步类型,其中base.cra_ctxsize的大小存放上下文不变的内容,比如key,算法类型等。而对于每个请求相关的buffer,total_len需要放到req中去,对应的就是descsize。

1
2
3
4
5
6
7
// 不变的内容获取
crypto_shash_ctx(desc->tfm);

// 请求相关的内容获取
shash_desc_ctx(desc);

// 对应的空间框架会申请好

后续

得空了,继续看一下为啥sm4无法配置了。最终发现是由于key的长度不是16导致的。命令如下,以供需要的同学。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

=======================sm3 + cbc(sm4) ==========================

PC1: //192.168.0.1
ip xfrm state add src 192.168.0.1 dst 192.168.0.2 proto esp spi 0x00000301 mode tunnel auth sm3 0x96358c90783bbfa3d7b196ceabe0536b enc sm4 0xf6ddb555acfd9d77b03ea3843f265325
ip xfrm state add src 192.168.0.2 dst 192.168.0.1 proto esp spi 0x00000302 mode tunnel auth sm3 0x99358c90783bbfa3d7b196ceabe0536b enc sm4 0xffddb555acfd9d77b03ea3843f265325

ip xfrm policy add src 192.168.0.1 dst 192.168.0.2 dir out ptype main tmpl src 192.168.0.1 dst 192.168.0.2 proto esp mode tunnel
ip xfrm policy add src 192.168.0.2 dst 192.168.0.1 dir in ptype main tmpl src 192.168.0.2 dst 192.168.0.1 proto esp mode tunnel

PC2:// 192.168.0.2
ip xfrm state add src 192.168.0.1 dst 192.168.0.2 proto esp spi 0x00000301 mode tunnel auth sm3 0x96358c90783bbfa3d7b196ceabe0536b enc sm4 0xf6ddb555acfd9d77b03ea3843f265325
ip xfrm state add src 192.168.0.2 dst 192.168.0.1 proto esp spi 0x00000302 mode tunnel auth sm3 0x99358c90783bbfa3d7b196ceabe0536b enc sm4 0xffddb555acfd9d77b03ea3843f265325

ip xfrm policy add src 192.168.0.1 dst 192.168.0.2 dir in ptype main tmpl src 192.168.0.1 dst 192.168.0.2 proto esp mode tunnel
ip xfrm policy add src 192.168.0.2 dst 192.168.0.1 dir out ptype main tmpl src 192.168.0.2 dst 192.168.0.1 proto esp mode tunnel

# 删除xfrm配置的命令
ip xfrm state deleteall
ip xfrm policy deleteall

iperf3 -c 192.168.0.2 -u -i 10 -t 20 -b 300M -l 1024

根本原因是由于前人对业务场景不熟悉,驱动的实现没有考虑多线程使用同一个算法上下文,驱动测试用例也没有覆盖相关场景,同时内核自检模块也缺少相关的用例。

还有就是开发者没有深入框架,学习其他驱动的实现,最终只是做了一个demo,能用而已。

后面抽空再看看那个strongSwan是怎么配置的,这块需要系统一点的知识了。

这个鬼问题,从报案到结案,断断续续的差不多有一个月了吧。领导让我先搞其他的,这个问题优先级放后,又去忙其他的了。

组里的新生力量又没人搞得了,最后一周技术支持也是急了,再不解决要捅到大领导那去了,让人出差去现场搞了。

领导又赶紧把我拉来扛了,想着有点滑稽。

更多

快半年没有更新了,一直在忙着准备系分软考,业余时间过得相当的充实,周末也排的满满当当的,当然也学了许多的知识,感觉这次能过,哈哈。


行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。

欢迎关注

博客地址: https://fishmwei.github.io

掘金主页: https://juejin.cn/user/2084329776486919