Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30976
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-25 14:08
文章分类
文章存档

2018年(21)

我的朋友

分类: LINUX

2018-09-19 15:48:57


上篇我们举例看了一下大致一个conntrack的建立过程。在我们开始分析实现上述过程的源码前,先来看一看conntrack提供的功能扩展机制,因为类似tftp  helper功能是基于这个扩展机制来实现的。

 

该功能的代码源文件在如下路径:

net/netfilter/nf_conntrack_extend.c

include/net/netfilter/nf_conntrack_extend.h

 

数据结构图


如图,每个连接conntrack结构体有一个指针ext,指向一个扩展功能结构体。该结构体下带着一些扩展功能的私有数据。根据这些功能的私有数据来进行扩展功能的处理。

 

定义一个扩展:

struct nf_ct_ext_type

{

    /* Destroys relationships (can be NULL). */

    void (*destroy)(struct nf_conn *ct);

    /* Called when realloacted (can be NULL).
       Contents has already been moved. */


    void (*move)(void *new, void *old);

 

    enum nf_ct_ext_id id;  //标识扩展功能的id

 

    unsigned int flags;

 

    /* Length and min alignment. */

    u8 len;  //扩展功能私有数据的长度

    u8 align;  //扩展功能私有数据的对齐字节

    /* initial size of nf_ct_ext. */    
    //
给连接添加第一个扩展功能时,这时struct nf_ct_ext还没创建,
    需要申请
struct nf_ct_ext  和扩展功能私有数据一起的内存大小。


    u8 alloc_size;

};

 

每种类型的扩展需要实例化一个struct nf_ct_ext_type结构体,并注册到Netfilter管理的数组中。这样每次给连接添加扩展功能时,根据要添加的扩展功能id,找到对应的struct nf_ct_ext_type实例,根据实例中的数值来申请内存并初始化私有数据。

 

Netfilter中已定义的扩展功能

enum nf_ct_ext_id

{

    NF_CT_EXT_HELPER, //helper机制

    NF_CT_EXT_NAT,//网络地址转换

    NF_CT_EXT_ACCT,//连接统计计数

    NF_CT_EXT_ECACHE,//Netfilter事件通知机制

    NF_CT_EXT_NUM,

};


注册扩展功能

int nf_ct_extend_register(struct nf_ct_ext_type *type)

{

    int ret = 0;

 

    mutex_lock(&nf_ct_ext_type_mutex);

    if (nf_ct_ext_types[type->id]) {

        ret = -EBUSY;

        goto out;

    }

 

    /* This ensures that nf_ct_ext_create() can allocate enough area

       before updating alloc_size */
    /*根据扩展功能的私有数据长度初始化alloc_size*/


    type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align) + type->len;
    /*根据扩展功能的id号,加入Netfilter管理的全局数组中*/


    rcu_assign_pointer(nf_ct_ext_types[type->id], type);
    /*根据Netfilter中已经注册了的扩展功能类型,重新设置所有已注册的扩展功能类型的

alloc_size字段。这样每次第一次给连接申请扩展功能的内存时,就可以把Netfilter

已注册的所有扩展功能的内存申请好了,防止每次给连接添加扩展功能时重复申请内

存,提高处理速度*/

    update_alloc_size(type);

out:

    mutex_unlock(&nf_ct_ext_type_mutex);

    return ret;

}

EXPORT_SYMBOL_GPL(nf_ct_extend_register);

 

 

static void update_alloc_size(struct nf_ct_ext_type *type)

{

    int i, j;

    struct nf_ct_ext_type *t1, *t2;

    enum nf_ct_ext_id min = 0, max = NF_CT_EXT_NUM - 1;

 

    /* unnecessary to update all types */    
    /*
如果该扩展功能需要每次添加时要重新申请内存,
    就不用更新其他扩展功能类型的
alloc_size,只需更新自己的即可*/


    if ((type->flags & NF_CT_EXT_F_PREALLOC) == 0) {

        min = type->id;

        max = type->id;

    }

 

    /* This assumes that extended areas in conntrack for the types

       whose NF_CT_EXT_F_PREALLOC bit set are allocated in order */
    /*循环操作,更新所有的已注册的扩展功能类型的alloc_size*/


    for (i = min; i <= max; i++) {

        t1 = nf_ct_ext_types[i];

        if (!t1)

            continue;

 

        t1->alloc_size = sizeof(struct nf_ct_ext) + ALIGN(sizeof(struct nf_ct_ext), t1->align) + t1->len;


        for (j = 0; j < NF_CT_EXT_NUM; j++) {

            t2 = nf_ct_ext_types[j];

            if (t2 == NULL || t2 == t1 || (t2->flags & NF_CT_EXT_F_PREALLOC) == 0)


                continue;

 

            t1->alloc_size = ALIGN(t1->alloc_size, t2->align) + t2->len;


        }

    }

}

 

给连接添加扩展功能

 

#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help

#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat

#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter

#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache

 

#define nf_ct_ext_add(ct, id, gfp) \

    ((id##_TYPE *)__nf_ct_ext_add((ct), (id), (gfp)))

 

void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)

{

    struct nf_ct_ext *new;

    int i, newlen, newoff;

    struct nf_ct_ext_type *t;

 

    /* Conntrack must not be confirmed to avoid races on reallocation. */
    /*conntrack添加扩展功能时,该conntrak必须是没被确认过得状态*/


    NF_CT_ASSERT(!nf_ct_is_confirmed(ct));

 
    /*如果该conntrack的扩展功能的内存还没用申请,就申请内存并添加该扩展功能*/


    if (!ct->ext)

        return nf_ct_ext_create(&ct->ext, id, gfp);


    /*
如果该contrack的扩展功能内存已经申请好了,就不需要再处理了*/


    if (nf_ct_ext_exist(ct, id))

        return NULL;

 
    /*扩展功能内存还没申请好,需要重新申请新的内存,
    把已经初始化好的其他扩展功能数据重新添加到新的内存中
*/


    rcu_read_lock();

    t = rcu_dereference(nf_ct_ext_types[id]);

    BUG_ON(t == NULL);

 

    newoff = ALIGN(ct->ext->len, t->align);

    newlen = newoff + t->len;

    rcu_read_unlock();

    new = __krealloc(ct->ext, newlen, gfp);

    if (!new)

        return NULL;

 

    if (new != ct->ext)
    {

        for (i = 0; i < NF_CT_EXT_NUM; i++)
        {

            if (!nf_ct_ext_exist(ct, i))

                continue;

 

            rcu_read_lock();

            t = rcu_dereference(nf_ct_ext_types[i]);

            if (t && t->move)

                t->move((void *)new + new->offset[i],

            (void *)ct->ext + ct->ext->offset[i]);

            rcu_read_unlock();

        }
        /*释放旧的扩展功能内存*/


        call_rcu(&ct->ext->rcu, __nf_ct_ext_free_rcu);
        /*替换旧的扩展功能内存*/


        ct->ext = new;

    }

 

    new->offset[id] = newoff;

    new->len = newlen;

    memset((void *)new + newoff, 0, newlen - newoff);

    return (void *)new + newoff;

}

EXPORT_SYMBOL(__nf_ct_ext_add);

 

具体的添加操作在conntrack的建立和处理过程中添加,比如添加相应的helper扩展功能时,调用如下

nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp)

(未完待续)


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