当前位置:首页 > 操作系统 > 正文内容

【kernel】从 /proc/sys/net/ipv4/ip_forward 参数看怎么玩转 procfs 内核参数

邻居的猫1个月前 (12-09)操作系统1464

本文的开篇,咱们先从 sysctl 这个指令开端。

sysctl 运用

sysctl 是一个 Linux 体系东西,后台实践上是 syscall,它答应用户检查和动态修正内核参数。

# 检查当时设置的一切内核参数
sysctl -a
# 检查特定参数的值
sysctl net.ipv4.conf.all.forwarding
# 暂时修正内核参数
sysctl net.ipv4.conf.all.forwarding=1
# 从头加载装备文件,默许是 /etc/sysctl.conf
sysctl -p

修正 sysctl 的三种方法:

1)sysctl 指令直接修正(重启后失效)

2)echo 1 > /proc/sys/net/ipv4/ip_forward (重启后失效)

3)vim /etc/sysctl.conf,手动参加,sysctl -p 从头加载(永久收效)

到这儿,实践上能够给出一个定论:这几种方法,在原理上,都直接或直接更改了 Linux 中 /proc 文件体系下面的 /proc/sys/net/ipv4/ip_forward 文件。

那么,/proc 文件体系下的文件是怎么影响到内核参数的?咱们以 ip_forward 参数为例,来追寻一下。

ip_forward 参数

这个参数是内核 ip 报文转发开关。

这个参数有 2 个开关(ipv4 为例,ipv6 同理):

1 - /proc/sys/net/ipv4/ip_forward
2 - /proc/sys/net/ipv4/conf/=={all/default/enp8s0}==/forwarding

有几条规矩:

1)/proc/sys/net/ipv4/ip_forward 等价于 /proc/sys/net/ipv4/conf/all/forwarding

能够验证,设置 sysctl net.ipv4.conf.all.forwarding=1 后,检查这两个值:

2)实践真实操控网卡启用 ip 转发的,是网卡对应的 forwarding 参数:/proc/sys/net/ipv4/conf/enp8s0/forwarding

3)关于新创立的网卡设备,会启用 default/forwarding 参数来装备:/proc/sys/net/ipv4/conf/default/forwarding

4)conf/all/forwarding

能够装备当时一切设备,例如将 all 参数装备从 0 修正为 1,则包含 default 在内的一切 forwarding 装备都将被改成 1。要注意的是 all 装备只要在值被修正时才有用,重复写入 all 当时值不会对其他 forwarding 装备产生任何影响。

5)all/forwarding

装备只对当时 net namespace 收效,每个 netns 有自己的独立装备。

ipforward 参数怎么影响 ip 转发?

要害内核函数在 ip_route_input_slow()。<以下内核版别为 4.18>

这个函数中,会依据当时网络设备 in_dev 的 forwarding 参数,来决定是持续转发,仍是跳转到 ip_error。

内核经过一个宏界说 IN_DEV_FORWARD(in_dev) 来判别设备 in_dev 是否敞开了转发特点。

这个宏界说在 include/linux/inetdevice.h 文件中,指向了一个 IN_DEV_CONF_GET() 宏。后者持续指向了一个 ipv4_devconf_get() 函数。

在同文件中,ipv4_devconf_get() 函数给出了以下界说:

实践上是获取了这个网络设备 in_devcnf 结构体成员的 data 数组。传入的 index 实践上是字符串 IPV4_DEVCONF_FORWARDING 的拼接。

咱们来看一下这个 data 数组的结构:

include/uapi/linux/ip.h 中,界说了 ipv4_devconf 结构体的 data 变量 index

终究,总结来看,内核是经过 IN_DEV_CONF_GET 宏来获取网卡设备的 forward 参数的。

pforward 参数怎么被设置的

首要,咱们都知道,/proc/sys 目录实践上是一个虚拟文件体系,里边保存了实时收效的内核参数。这个机制答应咱们实时检查和修正内核的参数,然后影响体系的运转行为。

和 ipv4 网络相关的参数坐落 /proc/sys/net/ipv4 目录下, 如下(5.10 内核):

怎么修正?上文现已说了,能够经过直接 echo,或许 sysctl 体系调用,亦或修正 /etc/sysctl.conf 装备文件,即可在不同的级别使他们收效。

/proc/sys/net/ipv4 目录下保存着许多大局变量,例如大局的 ip_forward。和详细网卡设备相关的变量保存在了其子目录 conf/ 下。

内核中的 ctl_table

其间,每一个目录代表当时体系的一个网络设备。当一个新的网络设备被注册或开除时,该目录下也会随之调整。

在内核中,/proc/sys/ 中的文件和目录都是以 ctl_table 结构界说的。下面是 devinet.c 文件中关于 /proc/sys/net/ipv4/ip_forward 这个变量的界说。

image

其间要害字段的意义为:

const char*   procname;    // 参数文件名
void*         data;        // 参数文件值
int           maxlen;      // 参数巨细
mode_t        mode;        // 文件或目录权限
proc_handler* proc_handler // 处理读写恳求的回调函数

详细解释为:当时文件名为“ip_forward”;参数值绑定为ipv4_devconfdata[0]的方位;644 代表root可读写,其他只读;终究,为这个参数文件绑定了一个读写回调函数 devinet_sysctl_forward

目录界说的 ctl_table 和文件的不太相同,多了个 child 字段:

{
	.procname	= "dev",
	.mode		= 0555,
	.child		= dev_table,
}

/proc/sys/net/ipv4/ip_forward 怎么被创立的?

上一节咱们了解了,例如 /proc/sys/net/ipv4/ip_forward 文件,在内核中实践上是一个 ctl_table 结构。

ctl_table 的创立,在 fs/proc/proc_sysctl.c 文件的 __register_sysctl_table() 中完结。其函数注释如下:

/**
 * __register_sysctl_table - register a leaf sysctl table
 * @set: Sysctl tree to register on
 * @path: The path to the directory the sysctl table is in.
 * @table: the top-level table structure
 *
 * Register a sysctl table hierarchy. @table should be a filled in ctl_table
 * array. A completely 0 filled entry terminates the table.
 */
 
struct ctl_table_header *__register_sysctl_table(
    struct ctl_table_set *set,
    const char *path, 
    struct ctl_table *table
) {...}

该函数的操作进程大体能够概述为:

  • 寻觅 ctl_table 适宜的目录,
  • 然后将其刺进。

关于这个函数,本文不再赘述了,能够去相关文件中详细了解。下面咱们来看 /proc/sys/net/ipv4/ip_forward 的创立进程。

网络设备初始化函数 devinet_init 履行时,将调用 register_pernet_subsys 函数,传入 devinet_ops 结构,并履行其 init 函数。devinet_ops 结构体绑定了 init 和 exit 两个函数,其 init 函数为 devinet_init_net。当他终究被调用履行时,会顺次引发 __devnet_sysctl_register()register_net_sysctl() 别离创立 all/default/ 以及 net/ipv4/ 三个目录。如下图。

image

实践上,__devnet_sysctl_register() 终究调用的也是 register_net_sysctl() 函数,完结 sysctl 目录的注册。

image

register_net_sysctl() 函数在 sysctl_net.c 文件中终究调用 __register_sysctl_table() 接口真实去注册一个 sysctl table 子项。

/proc/sys/net/ipv4/ip_forward 怎么被读写?

咱们再回到 ctl_table 的结构界说:

image

其间一个非常重要的函数 devinet_sysctl_forward() 便是 ctl_table 结构的读写回调函数。也便是说,当 /proc/sys/net/ipv4/ip_forward 文件被读或写时,会触发这个函数的调用。

咱们来详细看一下这个函数的完成:

image

devinet_sysctl_forward() 接纳几个参数,重要的,write表明当时操作:1 代表写,0 代表读;后边几个代表用户空间缓冲区,用于传递数据(buffer:缓冲区地址,lenp:缓冲区巨细,ppos:文件偏移量)。

/proc/sys/net/ipv4/ip_forward 内核变量类型为一个整数,因而其默许的读写函数为 proc_dointvec()。相似的,字符串内核变量读写函数为 proc_dostring(),整数数组读写函数为 proc_dointvec_jiffies() 等等。这些函数的详细界说在 kernel/sysctl.c 中,如下:

image

在写入 ip_forward 变量时,不仅仅要调用 proc_dointvec() 来写入详细 proc 文件,还需要写入一切网卡设备 cnf 的 data 数组,咱们在上文中给出了这部分的接口和介绍。

详细流程详见上面的伪代码,当写入 ip_forward 变量时,终究会遍历一切网卡设备,并调用 IN_DEV_CONF_SET() 宏履行写入操作。

总结:网卡设备装备参数

网卡设备的结构体 in_device 中有一个装备特点 ipv4_devconf,后者的结构中界说了一个 data[] 数组,里边存储了当时网卡的装备参数实践值。

内核中读写这个 data[] 数组,一般会用到 IN_DEV_CONF_GET()IN_DEV_CONF_SET()

怎么在 proc/sys/net/ 中自界说一个参数文件?

咱们来实战一下,从现在起,下文根据 kos5.8,kernel-5.10.134。

标题,经过编写一个内核模块,完成以下功用:

1)该模块加载时,在 /proc/sys/net/ 目录下创立一个文件 flag,卸载时该文件也随之移除。
2)flag 作为一个内核参数,其参数类型为 int,一切用户可对其读写。
3)当 flag 参数被写入时,向 messages 中打印一条日志。

代码样例:

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/sysctl.h> 
#include <linux/proc_fs.h> 

static int flag = 0; // 用于存储 flag 的值 

// 自界说的 proc_handler 函数 
static int flag_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { 
	int ret; 
	loff_t pos = *ppos; 
	
	// 运用 proc_dointvec 处理实践的读取/写入操作 
	ret = proc_dointvec(table, write, buffer, lenp, ppos); 
	
	// 当履行写操作时 
	if (write) { 
		// 打印日志,指示写操作产生 
		printk(KERN_INFO "Writing to /proc/sys/net/flag, new value: %s\n", (char *)buffer); 
	} 
	
	return ret; 
} 

// 界说 sysctl 的操控表 
static struct ctl_table sysctl_table[] = { 
	{ 
		.procname = "flag",           // 创立的 sysctl 途径 
		.data = &flag,                // 要处理的内核变量 
		.maxlen = sizeof(flag),       // 数据的最大长度 
		.mode = 0666,                 // 权限设置 
		.proc_handler = flag_handler, // 运用自界说的 proc_handler 
	}, 
	{ } // 结束符 
};

// 界说 sysctl 目录 
static struct ctl_table_header *header; 

static int __init proc_flag_init(void) { 
	printk(KERN_INFO "Initializing proc_flag_sysctl module...\n"); 
	
	// 运用 register_sysctl 创立 proc 文件 
	header = register_sysctl("net", sysctl_table); 
	
	// 在 /proc/sys/net/ 目录下创立 flag 文件 
	if (!header) { 
		printk(KERN_ERR "Unable to register sysctl table\n"); 
		return -ENOMEM; 
	} 
	
	printk(KERN_INFO "Proc file /proc/sys/net/flag created successfully\n"); 
	return 0; 
} 

static void __exit proc_flag_exit(void) { 
	// 卸载 sysctl 表 
	unregister_sysctl_table(header); 
	printk(KERN_INFO "Sysctl table for /proc/sys/net/flag removed\n"); 
} 

module_init(proc_flag_init); 
module_exit(proc_flag_exit); 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Hong"); 
MODULE_DESCRIPTION("A simple kernel module for flag using custom handler and sysctl");

扫描二维码推送至手机访问。

版权声明:本文由51Blog发布,如需转载请注明出处。

本文链接:https://www.51blog.vip/?id=586

分享给朋友:

“【kernel】从 /proc/sys/net/ipv4/ip_forward 参数看怎么玩转 procfs 内核参数” 的相关文章

win10图片预览图无法检查,资源管理器卡死奔溃问题排查

win10图片预览图无法检查,资源管理器卡死奔溃问题排查

问题 最近在翻开文件夹时,发现部分图片无法检查缩略图,且反常卡顿,资源管理器上方绿色加载条一直在加载中,别的只需在任意图片上右键,然后移动到 翻开更多(H) 上,就能稳定使资源管理器卡死溃散 问题排查 只要图片文件有问题,且卡死时资源占用没有太大改变,可能是软件的问题 由于电脑里没有相关图片软件,查...

装置第一台域控制器

装置第一台域控制器

试验介绍: 当电脑联入网络时,域控制器首先要辨别这台电脑是否是归于这个域的,用户运用的登录账号是否存在、暗码是否正确。假如以上信息有相同不正确,那么域控制器就会回绝这个用户从这台电脑登录,相当于一个单位的门卫相同。 一:dns1上装置AD域服务 翻开一台windows虚拟机,改名为dns1 增加a...

linux根据端口查进程,使用lsof命令查端口对应的进程

linux根据端口查进程,使用lsof命令查端口对应的进程

在Linux系统中,你可以使用`netstat`或`ss`命令来根据端口查找相关进程。以下是一个基本的步骤指南:1. 使用`netstat`或`ss`命令列出所有活动的网络连接和监听端口。2. 使用`grep`命令过滤出你感兴趣的端口。3. 使用`awk`或`cut`命令提取出与该端口关联的进程ID...

windows xp 密钥,揭秘与使用指南

以下是几个有效的Windows XP产品密钥,你可以尝试使用它们来安装或激活Windows XP系统:1. 简书 提供的密钥: DG8FVB9TKYFRT9J6CRCCXPQ4G2. CSDN博客 提供的密钥: MRX3F47B9T2487JKWKMFRPWBY QC98627D3...

linux查看java安装路径,linux下java编程

linux查看java安装路径,linux下java编程

在Linux系统中,你可以使用以下命令来查看Java的安装路径:```bashwhich java```这个命令会返回当前系统中Java命令的路径。如果你安装了多个版本的Java,并且设置了`JAVA_HOME`环境变量,你可能需要检查该环境变量的值来确定安装路径:```bashecho $JAVA...

全嵌入式洗碗机,打造现代厨房的智能生活新选择

全嵌入式洗碗机,打造现代厨房的智能生活新选择

全嵌入式洗碗机是一种将洗碗机完全嵌入橱柜中的洗碗机类型,具有以下几个主要特点:1. 美观度提升:全嵌入式洗碗机的操作面板通常位于门板的顶部,关上门后面板被隐藏,与橱柜完美融合,提升厨房的整体美观度。2. 操作便捷:由于操作面板位于顶部,用户在使用时无需弯腰,操作更加人性化。3. 功能全面:全嵌入式洗...