Chinaunix首页 | 论坛 | 博客
  • 博客访问: 125780
  • 博文数量: 42
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 354
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-01 15:34
个人简介

不晓得说啥子

文章分类

全部博文(42)

文章存档

2015年(41)

2014年(1)

我的朋友

分类: LINUX

2015-04-03 11:35:44


还是从源代码开始分析(以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]))


最后附上一张图片,初始化并注册好的表的样子:






阅读(2459) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~