ipset源代码分析之kadt和uadt回调函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haolipengzhanshen/article/details/85109324

一定要清楚自己在干什么,每行代码在干什么,这样写的代码才能做到心中有数。

之前看到ip_set_hash_ip.chash_ip4_uadt和hash_ip4_kadt函数,就一直很好奇这两个函数是干什么呢?

下面我来带你一步步剖析这两个函数

一、kadt和uadt回调函数的注册

首先看下struct ip_set_type_variant结构体变量

**kadt回调函数的注册在以下三个位置**

1.ip_set_bitmap_gen.h的.kadt = mtype_kadt,

static const struct ip_set_type_variant mtype = {
.kadt = mtype_kadt,
.uadt = mtype_uadt,
.adt = {
[IPSET_ADD] = mtype_add,
[IPSET_DEL] = mtype_del,
[IPSET_TEST] = mtype_test,
},
......
};

2.ip_set_hash_gen.h的.kadt = mtype_kadt,

static const struct ip_set_type_variant mtype_variant = {
.kadt = mtype_kadt,
.uadt = mtype_uadt,
.adt = {
[IPSET_ADD] = mtype_add,
[IPSET_DEL] = mtype_del,
[IPSET_TEST] = mtype_test,
},
......
};

正好对应set模块的三种数据类型bitmap,hash。

其中

.kadt    = mtype_kadt,
.uadt    = mtype_uadt,

搜索mtype_kadt,是一个宏定义,将MTYPE宏定义和_kadt拼接起来
#define CONCAT(a, b)        a##b
#define TOKEN(a, b)        CONCAT(a, b)
#define mtype_kadt        TOKEN(MTYPE, _kadt)
   
MTYPE有不同的定义,对于hash:ip集合,为hash_ip4
#define MTYPE        hash_ip4
那么mtype_kadt宏经过拼装以后得到的是hash_ip4_kadt,即我之前一直疑惑的hash_ip4_kadt函数

ipset的每种类型都需要实现一个xxx_kadt的函数,不信的同学可以打开源代码自己看哦。

二、kadt回调函数的调用位置

调用位置有三处,分别对应于ip_set_test,ip_set_add,ip_set_del函数
1.ip_set_test函数
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);

2.ip_set_add函数
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);

3.ip_set_del函数
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);

以hash_ip4_kadt为例子进行讲解

hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
              const struct xt_action_param *par,
              enum ipset_adt adt, struct ip_set_adt_opt *opt)
    {
        const struct hash_ip *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ip4_elem e = {};
        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
        __be32 ip;
    
        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
        ip &= ip_set_netmask(h->netmask);
        if (ip == 0)
            return -EINVAL;
    
        e.ip = ip;
        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
    }

在kadt回调函数中会调用adtfn函数

 ipset_adtfn adtfn = set->variant->adt[adt];

因此其最终调用还是注册的adt回调函数

在ip_set_hash_gen.h文件中有mtype_add这个函数

那系统是在何时调用ip_set_add呢?

在target回调函数中

这点很好理解了,target回调函数可以说是执行一条指令的最后一步,一切都准备就绪,在target回调函数中调用添加、删除、修改等操作,也是有情可原的。

总结起来流程图如下所示

三、uadt回调函数的调用位置

uadt的调用位置有两个

1.call_ad函数

2.IPSET_CBFN(ip_set_utest, struct net *net, struct sock *ctnl,struct sk_buff *skb,const struct nlmsghdr *nlh,
       const struct nlattr * const attr[],struct netlink_ext_ack *extack)

其中IPSET_CBFN宏的功能是创建并实现一个以第一个参数为函数名称的函数,即ip_set_utest函数

搜索ip_set_utest函数,得到结果

 其中在IPSET_CMD_TEST项对应的call回调函数用ip_set_utest来赋值,那么call何时调用呢?我们猜测是当IPSET_CMD_TEST请求命令到来时调用call,这些call是内核模块调用的。

暂时没有找到call回调函数是谁来调用的

猜你喜欢

转载自blog.csdn.net/haolipengzhanshen/article/details/85109324
今日推荐