我是靠谱客的博主 俏皮枕头,最近开发中收集的这篇文章主要介绍linux内核协议栈 netfilter 之连接跟踪子系统初始化1 连接跟踪模块概述2 核心初始化入口 module_init(nf_conntrack_standalone_init);3 核心初始化 nf_conntrack_init(),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

1 连接跟踪模块概述

2 核心初始化入口 module_init(nf_conntrack_standalone_init);

2.1 创建/proc/net/nf_conntrack只读文件 nf_conntrack_standalone_init_proc()

2.2 注册 /proc/sys/ 下相关文件

3 核心初始化 nf_conntrack_init()

3.1 hash表大小计算、L3L4协议栈模块、helper模块初始化

3.1.1 L3L4协议栈模块初始化

3.1.2 helper 模块初始化

3.2 hash表初始化、期望连接子模块初始化

3.2.1 期望连接子模块初始化


1 连接跟踪模块概述

连接跟踪模块的初始化过程分别在三个地方进行:

  1. 一个用于创建连接跟踪项与期望连接项相关的slab缓存;
  2. 一个用于注册连接跟踪模块相关的hook回调函数;
  3. 一个用于注册连接跟踪中协议相关的变量。

连接跟踪模块的意义:

  • 连接跟踪模块的helper结构能够实现期望连接的建立以及相关协议的ALG功能。
  • 连接跟踪为NAT或者状态防火墙的实现提供了依据

2 核心初始化入口 module_init(nf_conntrack_standalone_init);

nf_conntrack_standalone_init() 除了在/proc文件系统下面创建一些节点外,核心的初始化过程都是调用nf_conntrack_init()完成的。

static int nf_conntrack_net_init(struct net *net)
{
	int ret;

	//连接跟踪子系统的核心初始化过程
	ret = nf_conntrack_init(net);
	if (ret < 0)
		goto out_init;
    
	ret = nf_conntrack_standalone_init_proc(net);
	if (ret < 0)
		goto out_proc;
	net->ct.sysctl_checksum = 1;
	net->ct.sysctl_log_invalid = 0;
	ret = nf_conntrack_standalone_init_sysctl(net);
	if (ret < 0)
		goto out_sysctl;
	return 0;

out_sysctl:
	nf_conntrack_standalone_fini_proc(net);
out_proc:
	nf_conntrack_cleanup(net);
out_init:
	return ret;
}

static void nf_conntrack_net_exit(struct net *net)
{
	nf_conntrack_standalone_fini_sysctl(net);
	nf_conntrack_standalone_fini_proc(net);
	nf_conntrack_cleanup(net);
}

static struct pernet_operations nf_conntrack_net_ops = {
	.init = nf_conntrack_net_init,
	.exit = nf_conntrack_net_exit,
};

static int __init nf_conntrack_standalone_init(void)
{
	return register_pernet_subsys(&nf_conntrack_net_ops);
}

static void __exit nf_conntrack_standalone_fini(void)
{
	unregister_pernet_subsys(&nf_conntrack_net_ops);
}

module_init(nf_conntrack_standalone_init);
module_exit(nf_conntrack_standalone_fini);

2.1 创建/proc/net/nf_conntrack只读文件 nf_conntrack_standalone_init_proc()

static int nf_conntrack_standalone_init_proc(struct net *net)
{
	struct proc_dir_entry *pde;

    //创建/proc/net/nf_conntrack文件,该文件只读,
	//读取该文件可以获取当前内核中跟踪的所有连接的信息
	pde = proc_net_fops_create(net, "nf_conntrack", 0440, &ct_file_ops);
	if (!pde)
		goto out_nf_conntrack;

    //创建/proc/net/stat/nf_conntrack文件,获取连接跟踪子系统的统计信息
	pde = proc_create("nf_conntrack", S_IRUGO, net->proc_net_stat,
			  &ct_cpu_seq_fops);
	if (!pde)
		goto out_stat_nf_conntrack;
	return 0;

out_stat_nf_conntrack:
	proc_net_remove(net, "nf_conntrack");
out_nf_conntrack:
	return -ENOMEM;
}

2.2 注册 /proc/sys/ 下相关文件

static int nf_conntrack_standalone_init_sysctl(struct net *net)
{
	struct ctl_table *table;

	//在/proc/sys/net/netfilter子目录,暴露一部分内核变量给用户态
	if (net_eq(net, &init_net)) {
		nf_ct_netfilter_header =
		       register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table);
		if (!nf_ct_netfilter_header)
			goto out;
	}

	table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
			GFP_KERNEL);
	if (!table)
		goto out_kmemdup;

	table[1].data = &net->ct.count;
	table[3].data = &net->ct.sysctl_checksum;
	table[4].data = &net->ct.sysctl_log_invalid;

	net->ct.sysctl_header = register_net_sysctl_table(net,
					nf_net_netfilter_sysctl_path, table);
	if (!net->ct.sysctl_header)
		goto out_unregister_netfilter;

	return 0;

out_unregister_netfilter:
	kfree(table);
out_kmemdup:
	if (net_eq(net, &init_net))
		unregister_sysctl_table(nf_ct_netfilter_header);
out:
	printk("nf_conntrack: can't register to sysctl.n");
	return -ENOMEM;
}

3 核心初始化 nf_conntrack_init()

该接口的核心功能:

  1. 设置nf_conntrack_htable_size、nf_conntrack_max的值;
  2. 为 nf_conntrack_hash 申请内存并初始化;
  3. 为连接跟踪项与期望连接跟踪项创建slab缓存。
  4. 初始化协议栈管理子模块、期望连接子模块、helper子模块
int nf_conntrack_init(struct net *net)
{
	int ret;

	if (net_eq(net, &init_net)) {
		ret = nf_conntrack_init_init_net();
		if (ret < 0)
			goto out_init_net;
	}
	ret = nf_conntrack_init_net(net);
	if (ret < 0)
		goto out_net;

	if (net_eq(net, &init_net)) {
		/* For use by REJECT target */
		rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach);
		rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
	}
	return 0;

out_net:
	if (net_eq(net, &init_net))
		nf_conntrack_cleanup_init_net();
out_init_net:
	return ret;
}

3.1 hash表大小计算、L3L4协议栈模块、helper模块初始化

static int nf_conntrack_init_init_net(void)
{
	int max_factor = 8;
	int ret;

	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
	 * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
	/* 当nf_conntrack_htable_size的值没有设置时,则在内存小于1GB时,
       使用内存的1/16384作为hash数组的最大值;在内存大于1GB时
	   则最大hash数组的值为8192*/
	   
	if (!nf_conntrack_htable_size) {
		nf_conntrack_htable_size
			= (((num_physpages << PAGE_SHIFT) / 16384)
			   / sizeof(struct hlist_head));
		if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
			nf_conntrack_htable_size = 16384;
		if (nf_conntrack_htable_size < 32)
			nf_conntrack_htable_size = 32;

		/* Use a max. factor of four by default to get the same max as
		 * with the old struct list_heads. When a table size is given
		 * we use the old value of 8 to avoid reducing the max.
		 * entries. */
		max_factor = 4;
	}
	/* 设置nf_conntrack_max的值,即连接跟踪项的最大值。
	   该值取决于nf_conntrack_hash[]数组的最大值,即为
		nf_conntrack_htable_size的8倍。*/
	nf_conntrack_max = max_factor * nf_conntrack_htable_size;
	...
	//为连接跟踪信息块struct nf_conn创建高速缓存
	nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
						sizeof(struct nf_conn),
						0, 0, NULL);
	if (!nf_conntrack_cachep) {
		printk(KERN_ERR "Unable to create nf_conn slab cachen");
		ret = -ENOMEM;
		goto err_cache;
	}
	
	//初始化协议管理子模块
	ret = nf_conntrack_proto_init();
	if (ret < 0)
		goto err_proto;
	
	//初始化helper子模块
	ret = nf_conntrack_helper_init();
	if (ret < 0)
		goto err_helper;

	return 0;
	...
}

3.1.1 L3L4协议栈模块初始化

参见xxx

3.1.2 helper 模块初始化

参见xxxx

3.2 hash表初始化、期望连接子模块初始化

static int nf_conntrack_init_net(struct net *net)
{
	int ret;

	atomic_set(&net->ct.count, 0);
	INIT_HLIST_HEAD(&net->ct.unconfirmed);
	net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
	if (!net->ct.stat) {
		ret = -ENOMEM;
		goto err_stat;
	}
	ret = nf_conntrack_ecache_init(net);
	if (ret < 0)
		goto err_ecache;
	//hash链表的初始化,申请 nf_conntrack_htable_size 个hash链表
	net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
						  &net->ct.hash_vmalloc);
	if (!net->ct.hash) {
		ret = -ENOMEM;
		printk(KERN_ERR "Unable to create nf_conntrack_hashn");
		goto err_hash;
	}
	
	//初始化期望连接子模块
	ret = nf_conntrack_expect_init(net);
	if (ret < 0)
		goto err_expect;
	ret = nf_conntrack_acct_init(net);
	if (ret < 0)
		goto err_acct;

	/* Set up fake conntrack:
	    - to never be deleted, not in any hashes */
#ifdef CONFIG_NET_NS
	nf_conntrack_untracked.ct_net = &init_net;
#endif
	atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
	/*  - and look it like as a confirmed connection */
	set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);

	return 0;
	....
}

3.2.1 期望连接子模块初始化

参见xxx

最后

以上就是俏皮枕头为你收集整理的linux内核协议栈 netfilter 之连接跟踪子系统初始化1 连接跟踪模块概述2 核心初始化入口 module_init(nf_conntrack_standalone_init);3 核心初始化 nf_conntrack_init()的全部内容,希望文章能够帮你解决linux内核协议栈 netfilter 之连接跟踪子系统初始化1 连接跟踪模块概述2 核心初始化入口 module_init(nf_conntrack_standalone_init);3 核心初始化 nf_conntrack_init()所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(71)

评论列表共有 0 条评论

立即
投稿
返回
顶部