还是从源代码开始分析(以filter表为例)
在iptable_filter.c中可以看到函数:
static int __net_init iptable_filter_net_init(struct net *net)
{
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
/* Entry 1 is the FORWARD hook */
((struct ipt_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
net->ipv4.iptable_filter =
ipt_register_table(net, &packet_filter, repl);
kfree(repl);
return PTR_RET(net->ipv4.iptable_filter);
}
之所以需要一个参数struct net *net, 是因为在内核3.10中,表的信息已经交由net结构来管理
首先该函数定义了一个 ipt_replace 的结构repl, 该结构和struct ipt_table_info 结构相似
调用ipt_alloc_initial_table(& packet_filter)根据packet_filter结构的值来 初始化这个ipt_replace结构(之所以要用这个ipt_replace结构而不直接初始化所有的表的信息, 我的理解是为了统一接口,统一调用xt_replace_table函数来替换表的信息 )
packet_filter在之前初始化为(其中重要的private结构并没有在这里初始化,在之前的内核应该是在这里初始化了所有的信息):
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_FILTER,
};
初始化repl结构
ipt_alloc_initial_table(&packet_filter)
|
|
xt_alloc_initial_table( ipt, IPT)(是一个宏定义,通这个宏来初始化repl结构)
注册表
net->ipv4.iptable_filter =
ipt_register_table(net, &packet_filter, repl);
由于在内核3.10中表的信息已经交由net结构来管理,所以这里iptables_register_table()会返回一个表的指针,将该指针赋值给net结构中对应的信息
struct net {
。。。。
struct netns_unix unx;
struct netns_ipv4 ipv4; ----->管理表信息
#if IS_ENABLED(CONFIG_IPV6)
struct netns_ipv6 ipv6;
#endif
#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
struct netns_sctp sctp;
。。。。
}
struct xt_table *ipt_register_table(struct net *net,
const struct xt_table *table,
const struct ipt_replace *repl)
{
int ret;
struct xt_table_info *newinfo; //需要用repl结构来初始化的newinfo,这个newinfo最终会替换packet_filter中的空的private结构
struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; //cpu的入口地址
struct xt_table *new_table; //创建一个新表,并且需要返回该表用于net结构管理表信息
newinfo = xt_alloc_table_info(repl->size); //为newinfo结构申请相应大小的内存
if (!newinfo) {
ret = -ENOMEM;
goto out;
}
初始化newinfo结构中的相对于cpu的基地址, 是标记规则的base地址
loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
memcpy(loc_cpu_entry, repl->entries, repl->size);
结构来初始化这个newinfo结构
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
注册表 并返回一个表指针
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
goto out_free;
}
return new_table;
out_free:
xt_free_table_info(newinfo);
out:
return ERR_PTR(ret);
}
struct xt_table *xt_register_table(struct net *net,
const struct xt_table *input_table, //packet_filter
struct xt_table_info *bootstrap, //空信息
struct xt_table_info *newinfo) //newinfo替换掉bootstrap
{
int ret;
struct xt_table_info *private;
struct xt_table *t, *table;
/* Don't add one object to multiple lists. */
table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
if (!table) {
ret = -ENOMEM;
goto out;
}
ret = mutex_lock_interruptible(&xt[table->af].mutex);
if (ret != 0)
goto out_free;
/* Don't autoload: we'd eat our tail... */
//判断该表是否已经存在
list_for_each_entry(t, &net->xt.tables[table->af], list) {
if (strcmp(t->name, table->name) == 0) {
ret = -EEXIST;
goto unlock;
}
}
//替换表的信息
table->private = bootstrap;
if (!xt_replace_table(table, 0, newinfo, &ret))
goto unlock;
private = table->private;
pr_debug("table->private->number = %u\n", private->number);
/* save number of initial entries */
private->initial_entries = private->number;
//将表插入到net结构中的tables管理链表中
list_add(&table->list, &net->xt.tables[table->af]);
mutex_unlock(&xt[table->af].mutex);
return table;
unlock:
mutex_unlock(&xt[table->af].mutex);
out_free:
kfree(table);
out:
return ERR_PTR(ret);
}
总结:初始化并注册一个表在之前的内核好像是直接初始化表的所有信息,然后直接注册。而在3.10的内核中,是经过了一个很麻烦的一个过程:
初始化 struct xt_table * packet_filter 部分值 -----> 根据packet_filter 结构初始化一个 struct ipt_replace结构repl( ipt_alloc_initial_table) ------> 根据repl结构初始化一个 struct ipt_table_info newinfo结构(translate_table)
----->将packet_filter结构中的private用newinfo结构替换掉(xt_replace_table) ------>将table中的list插入到net结构中管理table的链表中 (list_add(&table->list, &net->xt.tables[table->af]))
最后附上一张图片,初始化并注册好的表的样子:
阅读(2572) | 评论(0) | 转发(0) |