Keep learning, keep living...

0%

关于/etc/sysctl.conf生效时机

Linux内核提供了sysctl机制用于动态配置内核及内核模块的参数, 每个参数对应/proc/sys/下的一个文件,可以通过sysctl命令或直接操作/proc/sys/下的文件对参数进行读写。比如,net.ipv4.ip_forward对应文件/proc/sys/net/ipv4/ip_forwardsysctl命令实际是是对/proc/sys/操作的封装。

如果需要将sysctl参数持久化,可以将参数写入文件/etc/sysctl.conf文件中,这样参数在系统重启后依然生效。这是如何实现的呢?实际是由systemd-sysctl(或其他类似功能的服务)在系统完成内核模块的加载后,再来加载/etc/sysctl.conf里的参数。

如果需要立即生效/etc/sysctl.conf中的参数,可以执行sysctl -p。但如果此时内核模块未并加载,由于/proc/sys/目录下并不存在对应的参数文件,因而执行会失败。尽管这种场景下sysctl -p执行失败,但通过modprobe命令加载内核模块完成后,查看对应的sysctl参数,却发现sysctl参数已经生效。那这种场景下是如何令/etc/sysctl.conf中的参数生效的呢?

我们来做实验。

/etc/sysctl.conf中添加如下内容:

1
net.netfilter.nf_conntrack_max = 1234567

确保此时系统尚未加载nf_conntrack模块, 并执行sysctl -p命令, 可以看到执行失败了。

1
2
3
[root@one ~]# lsmod |grep nf_conntrack
[root@one ~]# sysctl -p
sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory

使用modprobe加载nf_conntrack模块, 并查看nf_conntrack_max参数:

1
2
3
4
[root@one ~]# modprobe nf_conntrack
[root@one ~]# sysctl -a |grep nf_conntrack_max
net.netfilter.nf_conntrack_max = 1234567
net.nf_conntrack_max = 1234567

可以看到在/etc/sysctl.conf中设置的参数值生效了。

再将nf_conntrack模块卸载,再使用insmod命令来加载模块:

1
2
3
4
5
[root@one ~]# rmmod nf_conntrack
[root@one ~]# insmod /lib/modules/3.10.0-957.el7.x86_64/kernel/net/netfilter/nf_conntrack.ko.xz
[root@one ~]# sysctl -a |grep nf_conntrack_max
net.netfilter.nf_conntrack_max = 262144
net.nf_conntrack_max = 262144

可以看到,使用insmod加载内核模块,并没有调整sysctl参数。

因而可以猜想,参数的设置是由modprobe实现。实际上,/etc/modprobe.d/目录中的配置可以自定义模块加载时的行为,例如设置模块参数、定义模块别名、禁止加载特定模块等。具体可以通过man modprobe.d查看。

/etc/modprobe.d/firewalld-sysctls.conf文件里有这样的配置:

1
install nf_conntrack /usr/sbin/modprobe --ignore-install nf_conntrack $CMDLINE_OPTS && /usr/sbin/sysctl --quiet --pattern 'net[.]netfilter[.]nf_conntrack.*' --system

表示当加载nf_conntrack模块时在加载完成后,还要再执行sysctl命令完成参数调整。

以上可知,因为sysctl变量基于/proc/sys/目录实现,在内核模块加载后,才会在/proc/sys/目录下创建相应的文件,内核模块的sysctl参数的动态调整是置后于模块加载的。如果内核模块中通过sysctl变量来实现功能开关逻辑控制,那么默认值最好设置为关闭,依赖后续的参数动态调整来开启参数。