Linux内核提供了sysctl
机制用于动态配置内核及内核模块的参数, 每个参数对应/proc/sys/
下的一个文件,可以通过sysctl
命令或直接操作/proc/sys/
下的文件对参数进行读写。比如,net.ipv4.ip_forward
对应文件/proc/sys/net/ipv4/ip_forward
。sysctl
命令实际是是对/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 | [root@one ~]# lsmod |grep nf_conntrack |
使用modprobe
加载nf_conntrack
模块, 并查看nf_conntrack_max
参数:
1 | [root@one ~]# modprobe nf_conntrack |
可以看到在/etc/sysctl.conf
中设置的参数值生效了。
再将nf_conntrack
模块卸载,再使用insmod
命令来加载模块:
1 | [root@one ~]# rmmod nf_conntrack |
可以看到,使用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
变量来实现功能开关逻辑控制,那么默认值最好设置为关闭,依赖后续的参数动态调整来开启参数。