Linux随机数nonblocking pool快速初始化

转载:https://blog.csdn.net/bc_vnetwork/article/details/53535476

在计算节点nova-compute运行裁剪Linux虚机提供OpenVPN服务端出现无法连接成功的情况,对Linux随机数进行初步的了解以定位分析问题原因

1994 年,美国软件工程师 Theodore Y. Ts'o 第一次在 Linux 内核中实现了随机数发生器,使用 SHA-1 散列算法而非密码,提高了密码强度。

Linux 内核采用熵来描述数据的随机性,熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。内核中随机数发生器 PRNG 为一个字符设备 random,代码实现在drivers/char/random.c,该设备实现了一系列接口函数用于获取系统环境的噪声数据,并加入熵池。系统环境的噪声数据包括设备两次中断间的间隔,输入设备的操作时间间隔,连续磁盘操作的时间间隔等。对应的接口包括:

voidadd_device_randomness(const void *buf, unsigned int size);

函数用于获取系统网络设备环境的噪声数据

voidadd_input_randomness(unsigned int type, unsigned int code,

                                     unsignedint value);

函数用于获取系统输入环境的噪声数据

voidadd_interrupt_randomness(int irq, int irq_flags);

函数用于获取系统中断环境的噪声数据

voidadd_disk_randomness(struct gendisk *disk);

函数用于获取系统磁盘环境的噪声数据

内核提供了 1 个的接口来供其他内核模块使用

void get_random_bytes(void *buf, intnbytes);

该接口会返回指定字节数的随机数。random 设备了提供了 2 个字符设备供用户态进程使用——/dev/random 和/dev/urandom:

·        /dev/random 适用于对随机数质量要求比较高的请求,在熵池中数据不足时,读取 dev/random 设备时会返回小于熵池噪声总数的随机字节。/dev/random 可生成高随机性的公钥或一次性密码本。若熵池空了,对/dev/random 的读操作将会被阻塞,直到收集到了足够的环境噪声为止。这样的设计使得/dev/random 是真正的随机数发生器,提供了最大可能的随机数据熵。

·        /dev/urandom,非阻塞的随机数发生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom 的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random 的。它可以作为生成较低强度密码的伪随机数生成器,对大多数应用来说,随机性是可以接受的。

奇怪的问题:

在计算节点nova-compute运行裁剪Linux虚机提供OpenVPN服务端,在对虚机无任何操作的情况,发现OpenVPN客户端长时间无法连接成功。

直到出现random: nonblocking pool is initialized,OpenVPN客户端正常连接成功。初步分析与nonblocking pool初始化有关。


问题解决:

如何加速Linux随机数nonblocking pool初始化,解决在对虚机无任何操作的情况下OpenVPN客户端长时间无法连接的内核补丁:

https://patchwork.kernel.org/patch/6781261/

重新编译内核验证Linux随机数nonblocking pool在2s左右完成初始化, 网络初始完成OpenVPN客户端正常连接。

后续关于Linux随机数获取系统环境的噪声数据原理与实现有待分析

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下是https://patchwork.kernel.org/patch/6781261/的内容:

random: initialize pools faster

Message ID [email protected]
State New, archived
Headers show
Series
  • random: initialize pools faster
Related show

Commit Message

Jörn EngelJuly 13, 2015, 8:25 p.m. UTC

add_interrupt_randomness() can cause significant cpu overhead on
interrupt-heavy workloads.  We try to limit that overhead by bailing out
quickly once we have sampled a few bits of entropy this second.  If
there is enough entropy around it doesn't hurt to waste the excess.

However, we also waste entropy early in boot when we haven't even
initialized the pools yet.  With this patch we initialize the pools in
1-2s while it takes 10-20s without this patch.  Actual numbers depend on
hardware and fluctuate from boot to boot, but in all cases I have tested
there is a clear improvement.

Signed-off-by: Joern Engel <[email protected]>
---
 drivers/char/random.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Patch

578584diffmboxseries

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 9cd6968e2f92..514f67a98b88 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -898,7 +898,8 @@  void add_interrupt_randomness(int irq, int irq_flags)
 	add_interrupt_bench(cycles);
 
 	if ((fast_pool->count < 64) &&
-	    !time_after(now, fast_pool->last + HZ))
+	    !time_after(now, fast_pool->last + HZ) &&
+	    nonblocking_pool.initialized)
 		return;
 
 	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;

猜你喜欢

转载自blog.csdn.net/zjy900507/article/details/86145348