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变量来实现功能开关逻辑控制,那么默认值最好设置为关闭,依赖后续的参数动态调整来开启参数。