1. 程式人生 > >ipset原始碼分析之kadt和uadt回撥函式

ipset原始碼分析之kadt和uadt回撥函式

一定要清楚自己在幹什麼,每行程式碼在幹什麼,這樣寫的程式碼才能做到心中有數。

之前看到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回撥函式是誰來呼叫的